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 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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "roxy-cobewebgl",
3
- "version": "1.1.1",
3
+ "version": "1.1.3",
4
4
  "description": "Cobe-style dotted globe with WebGL (ESM): OffscreenCanvas worker or main-thread fallback",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
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 fracV = fract(idx * phiMinusOne);
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
  }
@@ -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 fracV = fract(idx * phiMinusOne);
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', { antialias: false, alpha: false });
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);
@@ -146,6 +146,7 @@ export const RoxyCobewebgl = forwardRef(function RoxyCobewebgl(props, ref) {
146
146
  width: '100%',
147
147
  height: '100%',
148
148
  verticalAlign: 'middle',
149
+ backgroundColor: 'transparent',
149
150
  ...style,
150
151
  }}
151
152
  />
@@ -147,5 +147,6 @@ defineExpose({
147
147
  width: 100%;
148
148
  height: 100%;
149
149
  vertical-align: middle;
150
+ background: transparent;
150
151
  }
151
152
  </style>