roxy-cobewebgl 1.1.1 → 1.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/package.json +1 -1
- package/src/fallback.js +33 -5
- package/src/globe.worker.js +37 -6
- package/src/react/RoxyCobewebgl.jsx +1 -0
- package/src/vue/RoxyCobewebgl.vue +1 -0
package/README.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
Cobe 风格的高性能点阵地球:纯 WebGL + GLSL,可选 **OffscreenCanvas Worker** 渲染(主线程只做交互),不支持时自动 **主线程 WebGL 回退**。以 **ESM** 发布,可在 Vite / Webpack 5+ 等打包器中使用。
|
|
4
4
|
|
|
5
|
+
**画布背景**:WebGL 使用带 **alpha** 的上下文(`premultipliedAlpha: false`),每帧以**透明色**清空缓冲,并用 `SRC_ALPHA` 混合绘制;球圆外(**`glowOn` 为关**时)为**全透明**,可透出下层。若仍看到暗边,多为**外圈光晕**,可把 `glowOn` 设为 `0`。`<canvas>` 建议配合 CSS `background: transparent`。
|
|
6
|
+
|
|
5
7
|
## 安装
|
|
6
8
|
|
|
7
9
|
```bash
|
package/package.json
CHANGED
package/src/fallback.js
CHANGED
|
@@ -57,6 +57,31 @@ const FRAGMENT_SHADER = `
|
|
|
57
57
|
-s, 0., c);
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
+
float goldenFract(float idx) {
|
|
61
|
+
float a = idx, b = 0.0;
|
|
62
|
+
if (a >= 524288.) { a -= 524288.; b += 0.803894; }
|
|
63
|
+
if (a >= 262144.) { a -= 262144.; b += 0.901947; }
|
|
64
|
+
if (a >= 131072.) { a -= 131072.; b += 0.950973; }
|
|
65
|
+
if (a >= 65536.) { a -= 65536.; b += 0.475487; }
|
|
66
|
+
if (a >= 32768.) { a -= 32768.; b += 0.737743; }
|
|
67
|
+
if (a >= 16384.) { a -= 16384.; b += 0.868872; }
|
|
68
|
+
if (a >= 8192.) { a -= 8192.; b += 0.934436; }
|
|
69
|
+
if (a >= 4096.) { a -= 4096.; b += 0.467218; }
|
|
70
|
+
if (a >= 2048.) { a -= 2048.; b += 0.733609; }
|
|
71
|
+
if (a >= 1024.) { a -= 1024.; b += 0.866804; }
|
|
72
|
+
if (a >= 512.) { a -= 512.; b += 0.433402; }
|
|
73
|
+
if (a >= 256.) { a -= 256.; b += 0.216701; }
|
|
74
|
+
if (a >= 128.) { a -= 128.; b += 0.108351; }
|
|
75
|
+
if (a >= 64.) { a -= 64.; b += 0.554175; }
|
|
76
|
+
if (a >= 32.) { a -= 32.; b += 0.777088; }
|
|
77
|
+
if (a >= 16.) { a -= 16.; b += 0.888544; }
|
|
78
|
+
if (a >= 8.) { a -= 8.; b += 0.944272; }
|
|
79
|
+
if (a >= 4.) { a -= 4.; b += 0.472136; }
|
|
80
|
+
if (a >= 2.) { a -= 2.; b += 0.236068; }
|
|
81
|
+
if (a >= 1.) { a -= 1.; b += 0.618034; }
|
|
82
|
+
return fract(b);
|
|
83
|
+
}
|
|
84
|
+
|
|
60
85
|
vec3 nearestFibonacciLattice(vec3 p, out float m) {
|
|
61
86
|
float dots = u_dots;
|
|
62
87
|
float byDots = 1.0 / dots;
|
|
@@ -80,8 +105,7 @@ const FRAGMENT_SHADER = `
|
|
|
80
105
|
vec2 o = vec2(mod(s, 2.), floor(s * .5));
|
|
81
106
|
float idx = dot(f, c + o);
|
|
82
107
|
if (idx > dots || idx < 0.) continue;
|
|
83
|
-
float
|
|
84
|
-
float theta = fract(fracV) * kTau;
|
|
108
|
+
float theta = goldenFract(idx) * kTau;
|
|
85
109
|
float cosphi = 1. - 2. * idx * byDots;
|
|
86
110
|
float sinphi = sqrt(1. - cosphi * cosphi);
|
|
87
111
|
vec3 sample2 = vec3(cos(theta) * sinphi, sin(theta) * sinphi, cosphi);
|
|
@@ -431,6 +455,8 @@ export async function createFallbackGlobe(canvas, config) {
|
|
|
431
455
|
return null;
|
|
432
456
|
}
|
|
433
457
|
|
|
458
|
+
gl.clearColor(0, 0, 0, 0);
|
|
459
|
+
|
|
434
460
|
const program = createProgram(gl, VERTEX_SHADER, FRAGMENT_SHADER);
|
|
435
461
|
if (!program) {
|
|
436
462
|
onError(new Error('主着色器编译失败'));
|
|
@@ -515,6 +541,11 @@ export async function createFallbackGlobe(canvas, config) {
|
|
|
515
541
|
|
|
516
542
|
const debugVal = typeof state.debug === 'number' ? state.debug : (typeof window !== 'undefined' && window.__GLOBE_DEBUG__) || 0;
|
|
517
543
|
|
|
544
|
+
gl.clearColor(0, 0, 0, 0);
|
|
545
|
+
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
546
|
+
gl.enable(gl.BLEND);
|
|
547
|
+
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
|
548
|
+
|
|
518
549
|
gl.useProgram(program);
|
|
519
550
|
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
|
|
520
551
|
gl.enableVertexAttribArray(loc.a_position);
|
|
@@ -538,8 +569,6 @@ export async function createFallbackGlobe(canvas, config) {
|
|
|
538
569
|
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
|
539
570
|
|
|
540
571
|
if (arcProgram && arcAnimator) {
|
|
541
|
-
gl.enable(gl.BLEND);
|
|
542
|
-
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
|
543
572
|
gl.useProgram(arcProgram);
|
|
544
573
|
const aspect = canvas.width / canvas.height;
|
|
545
574
|
gl.uniform1f(arcLoc.u_phi, state.phi);
|
|
@@ -559,7 +588,6 @@ export async function createFallbackGlobe(canvas, config) {
|
|
|
559
588
|
gl.vertexAttribPointer(arcLoc.a_arcPos, 3, gl.FLOAT, false, 0, 0);
|
|
560
589
|
gl.drawArrays(gl.LINE_STRIP, st.startIdx, st.drawCount);
|
|
561
590
|
}
|
|
562
|
-
gl.disable(gl.BLEND);
|
|
563
591
|
}
|
|
564
592
|
rafId = requestAnimationFrame(render);
|
|
565
593
|
}
|
package/src/globe.worker.js
CHANGED
|
@@ -58,6 +58,31 @@ const FRAGMENT_SHADER = `
|
|
|
58
58
|
-s, 0., c);
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
+
float goldenFract(float idx) {
|
|
62
|
+
float a = idx, b = 0.0;
|
|
63
|
+
if (a >= 524288.) { a -= 524288.; b += 0.803894; }
|
|
64
|
+
if (a >= 262144.) { a -= 262144.; b += 0.901947; }
|
|
65
|
+
if (a >= 131072.) { a -= 131072.; b += 0.950973; }
|
|
66
|
+
if (a >= 65536.) { a -= 65536.; b += 0.475487; }
|
|
67
|
+
if (a >= 32768.) { a -= 32768.; b += 0.737743; }
|
|
68
|
+
if (a >= 16384.) { a -= 16384.; b += 0.868872; }
|
|
69
|
+
if (a >= 8192.) { a -= 8192.; b += 0.934436; }
|
|
70
|
+
if (a >= 4096.) { a -= 4096.; b += 0.467218; }
|
|
71
|
+
if (a >= 2048.) { a -= 2048.; b += 0.733609; }
|
|
72
|
+
if (a >= 1024.) { a -= 1024.; b += 0.866804; }
|
|
73
|
+
if (a >= 512.) { a -= 512.; b += 0.433402; }
|
|
74
|
+
if (a >= 256.) { a -= 256.; b += 0.216701; }
|
|
75
|
+
if (a >= 128.) { a -= 128.; b += 0.108351; }
|
|
76
|
+
if (a >= 64.) { a -= 64.; b += 0.554175; }
|
|
77
|
+
if (a >= 32.) { a -= 32.; b += 0.777088; }
|
|
78
|
+
if (a >= 16.) { a -= 16.; b += 0.888544; }
|
|
79
|
+
if (a >= 8.) { a -= 8.; b += 0.944272; }
|
|
80
|
+
if (a >= 4.) { a -= 4.; b += 0.472136; }
|
|
81
|
+
if (a >= 2.) { a -= 2.; b += 0.236068; }
|
|
82
|
+
if (a >= 1.) { a -= 1.; b += 0.618034; }
|
|
83
|
+
return fract(b);
|
|
84
|
+
}
|
|
85
|
+
|
|
61
86
|
vec3 nearestFibonacciLattice(vec3 p, out float m) {
|
|
62
87
|
float dots = u_dots;
|
|
63
88
|
float byDots = 1.0 / dots;
|
|
@@ -80,8 +105,7 @@ const FRAGMENT_SHADER = `
|
|
|
80
105
|
vec2 o = vec2(mod(s, 2.), floor(s * .5));
|
|
81
106
|
float idx = dot(f, c + o);
|
|
82
107
|
if (idx > dots || idx < 0.) continue;
|
|
83
|
-
float
|
|
84
|
-
float theta = fract(fracV) * kTau;
|
|
108
|
+
float theta = goldenFract(idx) * kTau;
|
|
85
109
|
float cosphi = 1. - 2. * idx * byDots;
|
|
86
110
|
float sinphi = sqrt(1. - cosphi * cosphi);
|
|
87
111
|
vec3 sample2 = vec3(cos(theta) * sinphi, sin(theta) * sinphi, cosphi);
|
|
@@ -441,11 +465,16 @@ async function init(msg) {
|
|
|
441
465
|
if (msg.params) Object.assign(params, msg.params);
|
|
442
466
|
|
|
443
467
|
console.log('[Worker] init, canvas size:', canvas.width, canvas.height);
|
|
444
|
-
gl = canvas.getContext('webgl', {
|
|
468
|
+
gl = canvas.getContext('webgl', {
|
|
469
|
+
antialias: false,
|
|
470
|
+
alpha: true,
|
|
471
|
+
premultipliedAlpha: false,
|
|
472
|
+
});
|
|
445
473
|
if (!gl) {
|
|
446
474
|
self.postMessage({ type: 'error', msg: 'WebGL 不可用' });
|
|
447
475
|
return;
|
|
448
476
|
}
|
|
477
|
+
gl.clearColor(0, 0, 0, 0);
|
|
449
478
|
console.log('[Worker] WebGL context OK');
|
|
450
479
|
|
|
451
480
|
program = createProgram(gl, VERTEX_SHADER, FRAGMENT_SHADER);
|
|
@@ -521,6 +550,11 @@ function render(t) {
|
|
|
521
550
|
const timeSec = t * 0.001;
|
|
522
551
|
if (params.autoRotate) params.phi += params.rotationSpeed || 0.003;
|
|
523
552
|
|
|
553
|
+
gl.clearColor(0, 0, 0, 0);
|
|
554
|
+
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
555
|
+
gl.enable(gl.BLEND);
|
|
556
|
+
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
|
557
|
+
|
|
524
558
|
// Pass 1: 球体
|
|
525
559
|
gl.useProgram(program);
|
|
526
560
|
gl.bindBuffer(gl.ARRAY_BUFFER, quadBuffer);
|
|
@@ -547,8 +581,6 @@ function render(t) {
|
|
|
547
581
|
|
|
548
582
|
// Pass 2: 弧线
|
|
549
583
|
if (arcProgram && arcAnimator) {
|
|
550
|
-
gl.enable(gl.BLEND);
|
|
551
|
-
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
|
552
584
|
gl.useProgram(arcProgram);
|
|
553
585
|
const aspect = canvas.width / canvas.height;
|
|
554
586
|
gl.uniform1f(arcLoc.u_phi, params.phi);
|
|
@@ -570,7 +602,6 @@ function render(t) {
|
|
|
570
602
|
gl.vertexAttribPointer(arcLoc.a_arcPos, 3, gl.FLOAT, false, 0, 0);
|
|
571
603
|
gl.drawArrays(gl.LINE_STRIP, state.startIdx, state.drawCount);
|
|
572
604
|
}
|
|
573
|
-
gl.disable(gl.BLEND);
|
|
574
605
|
}
|
|
575
606
|
|
|
576
607
|
rafId = requestAnimationFrame(render);
|