three-base 2.0.196 → 2.0.198
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/EventMap.d.ts +17 -0
- package/EventMap.ts +19 -0
- package/MktMesh/MktMesh.d.ts +83 -19
- package/MktMesh/MktMesh.js +247 -79
- package/MktMesh/MktMesh.ts +247 -75
- package/MktMesh/imagePlane.d.ts +14 -0
- package/MktMesh/imagePlane.js +79 -3
- package/MktMesh/imagePlane.ts +79 -2
- package/MktMesh/modelSlot.d.ts +2 -0
- package/MktMesh/modelSlot.js +15 -0
- package/MktMesh/modelSlot.ts +15 -0
- package/MktMesh/panoBitmapTexture.js +5 -1
- package/MktMesh/panoBitmapTexture.ts +6 -1
- package/ThreeBase.js +1 -10
- package/ThreeBase.ts +1 -9
- package/package.json +1 -1
- package/pass/debugDepthState.d.ts +4 -8
- package/pass/debugDepthState.js +0 -4
- package/pass/debugDepthState.ts +4 -10
- package/pass/stroke_pass.js +8 -90
- package/pass/stroke_pass.ts +8 -94
- package/threeLoader.d.ts +14 -0
- package/threeLoader.js +48 -3
- package/threeLoader.ts +45 -3
package/pass/stroke_pass.js
CHANGED
|
@@ -38,12 +38,6 @@ const selectDepthTestTextureTarget = new WebGLRenderTarget(1024, 1024, {
|
|
|
38
38
|
});
|
|
39
39
|
const blur1TextureTarget = new WebGLRenderTarget(1024, 1024, { minFilter: LinearFilter, magFilter: LinearFilter, format: RGBAFormat });
|
|
40
40
|
const blur2TextureTarget = new WebGLRenderTarget(1024, 1024, { minFilter: LinearFilter, magFilter: LinearFilter, format: RGBAFormat });
|
|
41
|
-
// 外扩深度临时/结果目标:depthMinBlurShader 把本体深度图随描边一起外扩,
|
|
42
|
-
// 外扩区取邻域最近深度(忽略背景 1.0),使外扩区 selD<1.0,depthTest 才能正确判遮挡(不漏光)。
|
|
43
|
-
const selectDepthBlurTmpTextureTarget = new WebGLRenderTarget(1024, 1024, { minFilter: LinearFilter, magFilter: LinearFilter, format: RGBAFormat });
|
|
44
|
-
const selectDepthBlurTextureTarget = new WebGLRenderTarget(1024, 1024, { minFilter: LinearFilter, magFilter: LinearFilter, format: RGBAFormat });
|
|
45
|
-
// 外扩描边经深度测试后的结果(步骤 5.6):独立 target,避免回写 blur1 触发历史回归 bug
|
|
46
|
-
const blurDepthTestTextureTarget = new WebGLRenderTarget(1024, 1024, { minFilter: LinearFilter, magFilter: LinearFilter, format: RGBAFormat });
|
|
47
41
|
const size = new Vector2();
|
|
48
42
|
const depthTestShader = new ShaderMaterial({
|
|
49
43
|
uniforms: {
|
|
@@ -383,52 +377,6 @@ const strokeShader = new RawShaderMaterial({
|
|
|
383
377
|
depthWrite: false,
|
|
384
378
|
transparent: true
|
|
385
379
|
});
|
|
386
|
-
// 深度 min-blur(最近深度,忽略背景 1.0):随描边一起把深度图向外扩,
|
|
387
|
-
// 外扩区 selD = 物体最近深度(<1.0) 而非清屏 1.0,depthTest 在外扩区才能正确判遮挡(不漏光),
|
|
388
|
-
// 同时本体区仍靠 depthTestShader 的 EPSILON 容差防自遮挡闪烁(无缝)。separable(direction 控制 H/V)。
|
|
389
|
-
const depthMinBlurShader = new ShaderMaterial({
|
|
390
|
-
uniforms: {
|
|
391
|
-
tDepth: { value: null },
|
|
392
|
-
resolution: { value: new Vector2(1 / 512, 1 / 512) },
|
|
393
|
-
radius: { value: 1.0 },
|
|
394
|
-
direction: { value: new Vector2(1, 0) },
|
|
395
|
-
},
|
|
396
|
-
vertexShader: `
|
|
397
|
-
${ShaderChunk.common}
|
|
398
|
-
${ShaderChunk.logdepthbuf_pars_vertex}
|
|
399
|
-
varying vec2 vUv;
|
|
400
|
-
void main() {
|
|
401
|
-
vUv = uv;
|
|
402
|
-
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
|
403
|
-
${ShaderChunk.logdepthbuf_vertex}
|
|
404
|
-
}
|
|
405
|
-
`,
|
|
406
|
-
fragmentShader: `
|
|
407
|
-
${ShaderChunk.logdepthbuf_pars_fragment}
|
|
408
|
-
uniform sampler2D tDepth;
|
|
409
|
-
uniform vec2 resolution;
|
|
410
|
-
uniform float radius;
|
|
411
|
-
uniform vec2 direction;
|
|
412
|
-
varying vec2 vUv;
|
|
413
|
-
void main() {
|
|
414
|
-
float minD = 1.0;
|
|
415
|
-
for (int i = -10; i <= 10; i++) {
|
|
416
|
-
float x = float(i);
|
|
417
|
-
vec2 off = direction * (x * radius * resolution);
|
|
418
|
-
float d = texture2D(tDepth, vUv + off).r;
|
|
419
|
-
if (d < 0.9999) {
|
|
420
|
-
minD = min(minD, d);
|
|
421
|
-
}
|
|
422
|
-
}
|
|
423
|
-
gl_FragColor = vec4(minD, 0.0, 0.0, 1.0);
|
|
424
|
-
${ShaderChunk.logdepthbuf_fragment}
|
|
425
|
-
}
|
|
426
|
-
`,
|
|
427
|
-
blending: NoBlending,
|
|
428
|
-
depthTest: false,
|
|
429
|
-
depthWrite: false,
|
|
430
|
-
transparent: true,
|
|
431
|
-
});
|
|
432
380
|
const filterSelectShader = new RawShaderMaterial({
|
|
433
381
|
uniforms: {
|
|
434
382
|
selectTexture: { value: null },
|
|
@@ -508,9 +456,6 @@ export default function stroke_pass(renderer, camera, object3d, baseDepthTexture
|
|
|
508
456
|
selectDepthTestTextureTarget.setSize(size.x, size.y);
|
|
509
457
|
blur1TextureTarget.setSize(size.x, size.y);
|
|
510
458
|
blur2TextureTarget.setSize(size.x, size.y);
|
|
511
|
-
selectDepthBlurTmpTextureTarget.setSize(size.x, size.y);
|
|
512
|
-
selectDepthBlurTextureTarget.setSize(size.x, size.y);
|
|
513
|
-
blurDepthTestTextureTarget.setSize(size.x, size.y);
|
|
514
459
|
// 1. 渲染物体本体 mask(灰度)。⭐ 本体深度由同一趟光栅化顺带写进 selectDepthTexture
|
|
515
460
|
// (挂在 selectTextureTarget 的 depth attachment 上)—— 原先这里还有第 2 趟「只渲深度」,
|
|
516
461
|
// 同材质/同相机/同几何 ⇒ 深度逐位相同,纯重复遍历,2026-10-11 皇上旨简化时删除。
|
|
@@ -532,7 +477,8 @@ export default function stroke_pass(renderer, camera, object3d, baseDepthTexture
|
|
|
532
477
|
depthTestShader.uniforms.cameraFar.value = camera.far;
|
|
533
478
|
depthTestShader.uniforms.uDebugVis.value = (window.__STROKE_DEPTH_VIS) ? 1.0 : 0.0;
|
|
534
479
|
fsQuad.render(renderer, depthTestShader);
|
|
535
|
-
// 4.
|
|
480
|
+
// 4. 从「深度测试后的本体描边」开始外扩(外扩的源头是本体判过的结果,被挡掉的本体不会再长出描边;
|
|
481
|
+
// 但外扩出来那圈像素本身不再判深度 ⇒ 贴着遮挡物时会压到遮挡物前面,见步骤 6 的代价点名),
|
|
536
482
|
// 描边粗细由 stroke_width 控制的迭代次数决定。
|
|
537
483
|
strokeShader.uniforms.resolution.value.set(1 / size.x, 1 / size.y);
|
|
538
484
|
FXAAShaderMaterial.uniforms.resolution.value.set(1 / size.x, 1 / size.y);
|
|
@@ -557,42 +503,14 @@ export default function stroke_pass(renderer, camera, object3d, baseDepthTexture
|
|
|
557
503
|
renderer.setRenderTarget(blur1TextureTarget);
|
|
558
504
|
FXAAShaderMaterial.uniforms.tDiffuse.value = blur2TextureTarget.texture;
|
|
559
505
|
fsQuad.render(renderer, FXAAShaderMaterial);
|
|
560
|
-
//
|
|
561
|
-
//
|
|
562
|
-
//
|
|
563
|
-
//
|
|
564
|
-
//
|
|
565
|
-
depthMinBlurShader.uniforms.resolution.value.set(1 / size.x, 1 / size.y);
|
|
566
|
-
depthMinBlurShader.uniforms.radius.value = Math.max(1, stroke_width);
|
|
567
|
-
// H:直接采 DepthTexture(selectDepthTexture),其 .r 即对数深度
|
|
568
|
-
depthMinBlurShader.uniforms.direction.value.set(1, 0);
|
|
569
|
-
depthMinBlurShader.uniforms.tDepth.value = selectDepthTexture;
|
|
570
|
-
renderer.setRenderTarget(selectDepthBlurTmpTextureTarget);
|
|
571
|
-
fsQuad.render(renderer, depthMinBlurShader);
|
|
572
|
-
// V
|
|
573
|
-
depthMinBlurShader.uniforms.direction.value.set(0, 1);
|
|
574
|
-
depthMinBlurShader.uniforms.tDepth.value = selectDepthBlurTmpTextureTarget.texture;
|
|
575
|
-
renderer.setRenderTarget(selectDepthBlurTextureTarget);
|
|
576
|
-
fsQuad.render(renderer, depthMinBlurShader);
|
|
577
|
-
// 调试:记录「外扩后的选区深度」,供面板「深度图(分步)」的步骤 5.5 档读取。
|
|
578
|
-
// 它是 RGBA8 目标、对数深度存在 .r 里(与 DepthTexture 取 .r 的读法一致)。
|
|
579
|
-
debugDepthState.lastSelectBlurDepth = selectDepthBlurTextureTarget.texture;
|
|
580
|
-
// 5.6 对外扩后的描边判遮挡:被更近几何挡住的外扩环像素 discard。
|
|
581
|
-
// ⚠️ 输出到独立 target,绝不回写 blur1(历史回归 bug:blur1 被 depthTest 结果覆盖
|
|
582
|
-
// 会导致步骤 6 相减归零、描边全不显示)。
|
|
583
|
-
renderer.setRenderTarget(blurDepthTestTextureTarget);
|
|
584
|
-
renderer.clear();
|
|
585
|
-
depthTestShader.uniforms.map.value = blur1TextureTarget.texture;
|
|
586
|
-
depthTestShader.uniforms.baseDepth.value = baseDepthTexture;
|
|
587
|
-
depthTestShader.uniforms.selectDepth.value = selectDepthBlurTextureTarget.texture;
|
|
588
|
-
depthTestShader.uniforms.cameraFar.value = camera.far;
|
|
589
|
-
depthTestShader.uniforms.uDebugVis.value = 0.0;
|
|
590
|
-
fsQuad.render(renderer, depthTestShader);
|
|
591
|
-
// 6. 合成:最终外扩描边(blurDepthTest,已判遮挡) 减去 深度测试后的本体描边
|
|
592
|
-
// = 仅保留描边外扩环;本体被减掉。filterSelectShader 用 NormalBlending 叠到场景上。
|
|
506
|
+
// 6. 合成:FXAA 后的外扩描边(blur1) 减去 深度测试后的本体 = 仅保留描边外扩环;本体被减掉。
|
|
507
|
+
// ⚠️ 2026-11-04 决定回到「年初口径」:原先这里有 5.5(本体深度随描边一起 separable min-blur 外扩)
|
|
508
|
+
// 与 5.6(用外扩后的深度再判一次遮挡)两趟,作用是外扩环也参与遮挡判定 ⇒ 物体被挡住时描边不漏光。
|
|
509
|
+
// 撤掉换来的是每个描边对象每帧全屏绘制 10 趟降 7 趟(min-blur 那两趟是 ±10 共 21 次采样/像素,最贵);
|
|
510
|
+
// 代价点名:只有本体参与判遮挡,外扩环不参与 ⇒ 物体贴着遮挡物边缘时,一圈描边会压在遮挡物前面。
|
|
593
511
|
renderer.setRenderTarget(originRenderTarget);
|
|
594
512
|
filterSelectShader.uniforms.selectTexture.value = selectDepthTestTextureTarget.texture;
|
|
595
|
-
filterSelectShader.uniforms.blurTexture.value =
|
|
513
|
+
filterSelectShader.uniforms.blurTexture.value = blur1TextureTarget.texture;
|
|
596
514
|
filterSelectShader.blending = NormalBlending;
|
|
597
515
|
fsQuad.render(renderer, filterSelectShader);
|
|
598
516
|
}
|
package/pass/stroke_pass.ts
CHANGED
|
@@ -44,12 +44,6 @@ const selectDepthTestTextureTarget: WebGLRenderTarget = new WebGLRenderTarget(10
|
|
|
44
44
|
const blur1TextureTarget: WebGLRenderTarget = new WebGLRenderTarget(1024, 1024, { minFilter: LinearFilter, magFilter: LinearFilter, format: RGBAFormat });
|
|
45
45
|
|
|
46
46
|
const blur2TextureTarget: WebGLRenderTarget = new WebGLRenderTarget(1024, 1024, { minFilter: LinearFilter, magFilter: LinearFilter, format: RGBAFormat });
|
|
47
|
-
// 外扩深度临时/结果目标:depthMinBlurShader 把本体深度图随描边一起外扩,
|
|
48
|
-
// 外扩区取邻域最近深度(忽略背景 1.0),使外扩区 selD<1.0,depthTest 才能正确判遮挡(不漏光)。
|
|
49
|
-
const selectDepthBlurTmpTextureTarget: WebGLRenderTarget = new WebGLRenderTarget(1024, 1024, { minFilter: LinearFilter, magFilter: LinearFilter, format: RGBAFormat });
|
|
50
|
-
const selectDepthBlurTextureTarget: WebGLRenderTarget = new WebGLRenderTarget(1024, 1024, { minFilter: LinearFilter, magFilter: LinearFilter, format: RGBAFormat });
|
|
51
|
-
// 外扩描边经深度测试后的结果(步骤 5.6):独立 target,避免回写 blur1 触发历史回归 bug
|
|
52
|
-
const blurDepthTestTextureTarget: WebGLRenderTarget = new WebGLRenderTarget(1024, 1024, { minFilter: LinearFilter, magFilter: LinearFilter, format: RGBAFormat });
|
|
53
47
|
|
|
54
48
|
const size: Vector2 = new Vector2();
|
|
55
49
|
|
|
@@ -394,53 +388,6 @@ const strokeShader: RawShaderMaterial = new RawShaderMaterial({
|
|
|
394
388
|
transparent: true
|
|
395
389
|
});
|
|
396
390
|
|
|
397
|
-
// 深度 min-blur(最近深度,忽略背景 1.0):随描边一起把深度图向外扩,
|
|
398
|
-
// 外扩区 selD = 物体最近深度(<1.0) 而非清屏 1.0,depthTest 在外扩区才能正确判遮挡(不漏光),
|
|
399
|
-
// 同时本体区仍靠 depthTestShader 的 EPSILON 容差防自遮挡闪烁(无缝)。separable(direction 控制 H/V)。
|
|
400
|
-
const depthMinBlurShader: ShaderMaterial = new ShaderMaterial({
|
|
401
|
-
uniforms: {
|
|
402
|
-
tDepth: { value: null },
|
|
403
|
-
resolution: { value: new Vector2(1 / 512, 1 / 512) },
|
|
404
|
-
radius: { value: 1.0 },
|
|
405
|
-
direction: { value: new Vector2(1, 0) },
|
|
406
|
-
},
|
|
407
|
-
vertexShader: `
|
|
408
|
-
${ShaderChunk.common}
|
|
409
|
-
${ShaderChunk.logdepthbuf_pars_vertex}
|
|
410
|
-
varying vec2 vUv;
|
|
411
|
-
void main() {
|
|
412
|
-
vUv = uv;
|
|
413
|
-
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
|
414
|
-
${ShaderChunk.logdepthbuf_vertex}
|
|
415
|
-
}
|
|
416
|
-
`,
|
|
417
|
-
fragmentShader: `
|
|
418
|
-
${ShaderChunk.logdepthbuf_pars_fragment}
|
|
419
|
-
uniform sampler2D tDepth;
|
|
420
|
-
uniform vec2 resolution;
|
|
421
|
-
uniform float radius;
|
|
422
|
-
uniform vec2 direction;
|
|
423
|
-
varying vec2 vUv;
|
|
424
|
-
void main() {
|
|
425
|
-
float minD = 1.0;
|
|
426
|
-
for (int i = -10; i <= 10; i++) {
|
|
427
|
-
float x = float(i);
|
|
428
|
-
vec2 off = direction * (x * radius * resolution);
|
|
429
|
-
float d = texture2D(tDepth, vUv + off).r;
|
|
430
|
-
if (d < 0.9999) {
|
|
431
|
-
minD = min(minD, d);
|
|
432
|
-
}
|
|
433
|
-
}
|
|
434
|
-
gl_FragColor = vec4(minD, 0.0, 0.0, 1.0);
|
|
435
|
-
${ShaderChunk.logdepthbuf_fragment}
|
|
436
|
-
}
|
|
437
|
-
`,
|
|
438
|
-
blending: NoBlending,
|
|
439
|
-
depthTest: false,
|
|
440
|
-
depthWrite: false,
|
|
441
|
-
transparent: true,
|
|
442
|
-
});
|
|
443
|
-
|
|
444
391
|
const filterSelectShader: RawShaderMaterial = new RawShaderMaterial({
|
|
445
392
|
uniforms: {
|
|
446
393
|
selectTexture: { value: null },
|
|
@@ -536,9 +483,6 @@ export default function stroke_pass(
|
|
|
536
483
|
selectDepthTestTextureTarget.setSize(size.x, size.y);
|
|
537
484
|
blur1TextureTarget.setSize(size.x, size.y);
|
|
538
485
|
blur2TextureTarget.setSize(size.x, size.y);
|
|
539
|
-
selectDepthBlurTmpTextureTarget.setSize(size.x, size.y);
|
|
540
|
-
selectDepthBlurTextureTarget.setSize(size.x, size.y);
|
|
541
|
-
blurDepthTestTextureTarget.setSize(size.x, size.y);
|
|
542
486
|
|
|
543
487
|
// 1. 渲染物体本体 mask(灰度)。⭐ 本体深度由同一趟光栅化顺带写进 selectDepthTexture
|
|
544
488
|
// (挂在 selectTextureTarget 的 depth attachment 上)—— 原先这里还有第 2 趟「只渲深度」,
|
|
@@ -563,7 +507,8 @@ export default function stroke_pass(
|
|
|
563
507
|
depthTestShader.uniforms.uDebugVis.value = ((window as unknown as { __STROKE_DEPTH_VIS?: boolean }).__STROKE_DEPTH_VIS) ? 1.0 : 0.0;
|
|
564
508
|
fsQuad.render(renderer, depthTestShader);
|
|
565
509
|
|
|
566
|
-
// 4.
|
|
510
|
+
// 4. 从「深度测试后的本体描边」开始外扩(外扩的源头是本体判过的结果,被挡掉的本体不会再长出描边;
|
|
511
|
+
// 但外扩出来那圈像素本身不再判深度 ⇒ 贴着遮挡物时会压到遮挡物前面,见步骤 6 的代价点名),
|
|
567
512
|
// 描边粗细由 stroke_width 控制的迭代次数决定。
|
|
568
513
|
strokeShader.uniforms.resolution.value.set(1 / size.x, 1 / size.y);
|
|
569
514
|
FXAAShaderMaterial.uniforms.resolution.value.set(1 / size.x, 1 / size.y);
|
|
@@ -590,45 +535,14 @@ export default function stroke_pass(
|
|
|
590
535
|
FXAAShaderMaterial.uniforms.tDiffuse.value = blur2TextureTarget.texture;
|
|
591
536
|
fsQuad.render(renderer, FXAAShaderMaterial);
|
|
592
537
|
|
|
593
|
-
//
|
|
594
|
-
//
|
|
595
|
-
//
|
|
596
|
-
//
|
|
597
|
-
//
|
|
598
|
-
depthMinBlurShader.uniforms.resolution.value.set(1 / size.x, 1 / size.y);
|
|
599
|
-
depthMinBlurShader.uniforms.radius.value = Math.max(1, stroke_width);
|
|
600
|
-
// H:直接采 DepthTexture(selectDepthTexture),其 .r 即对数深度
|
|
601
|
-
depthMinBlurShader.uniforms.direction.value.set(1, 0);
|
|
602
|
-
depthMinBlurShader.uniforms.tDepth.value = selectDepthTexture;
|
|
603
|
-
renderer.setRenderTarget(selectDepthBlurTmpTextureTarget);
|
|
604
|
-
fsQuad.render(renderer, depthMinBlurShader);
|
|
605
|
-
// V
|
|
606
|
-
depthMinBlurShader.uniforms.direction.value.set(0, 1);
|
|
607
|
-
depthMinBlurShader.uniforms.tDepth.value = selectDepthBlurTmpTextureTarget.texture;
|
|
608
|
-
renderer.setRenderTarget(selectDepthBlurTextureTarget);
|
|
609
|
-
fsQuad.render(renderer, depthMinBlurShader);
|
|
610
|
-
|
|
611
|
-
// 调试:记录「外扩后的选区深度」,供面板「深度图(分步)」的步骤 5.5 档读取。
|
|
612
|
-
// 它是 RGBA8 目标、对数深度存在 .r 里(与 DepthTexture 取 .r 的读法一致)。
|
|
613
|
-
debugDepthState.lastSelectBlurDepth = selectDepthBlurTextureTarget.texture;
|
|
614
|
-
|
|
615
|
-
// 5.6 对外扩后的描边判遮挡:被更近几何挡住的外扩环像素 discard。
|
|
616
|
-
// ⚠️ 输出到独立 target,绝不回写 blur1(历史回归 bug:blur1 被 depthTest 结果覆盖
|
|
617
|
-
// 会导致步骤 6 相减归零、描边全不显示)。
|
|
618
|
-
renderer.setRenderTarget(blurDepthTestTextureTarget);
|
|
619
|
-
renderer.clear();
|
|
620
|
-
depthTestShader.uniforms.map.value = blur1TextureTarget.texture;
|
|
621
|
-
depthTestShader.uniforms.baseDepth.value = baseDepthTexture;
|
|
622
|
-
depthTestShader.uniforms.selectDepth.value = selectDepthBlurTextureTarget.texture;
|
|
623
|
-
depthTestShader.uniforms.cameraFar.value = (camera as PerspectiveCamera).far;
|
|
624
|
-
depthTestShader.uniforms.uDebugVis.value = 0.0;
|
|
625
|
-
fsQuad.render(renderer, depthTestShader);
|
|
626
|
-
|
|
627
|
-
// 6. 合成:最终外扩描边(blurDepthTest,已判遮挡) 减去 深度测试后的本体描边
|
|
628
|
-
// = 仅保留描边外扩环;本体被减掉。filterSelectShader 用 NormalBlending 叠到场景上。
|
|
538
|
+
// 6. 合成:FXAA 后的外扩描边(blur1) 减去 深度测试后的本体 = 仅保留描边外扩环;本体被减掉。
|
|
539
|
+
// ⚠️ 2026-11-04 决定回到「年初口径」:原先这里有 5.5(本体深度随描边一起 separable min-blur 外扩)
|
|
540
|
+
// 与 5.6(用外扩后的深度再判一次遮挡)两趟,作用是外扩环也参与遮挡判定 ⇒ 物体被挡住时描边不漏光。
|
|
541
|
+
// 撤掉换来的是每个描边对象每帧全屏绘制 10 趟降 7 趟(min-blur 那两趟是 ±10 共 21 次采样/像素,最贵);
|
|
542
|
+
// 代价点名:只有本体参与判遮挡,外扩环不参与 ⇒ 物体贴着遮挡物边缘时,一圈描边会压在遮挡物前面。
|
|
629
543
|
renderer.setRenderTarget(originRenderTarget);
|
|
630
544
|
filterSelectShader.uniforms.selectTexture.value = selectDepthTestTextureTarget.texture;
|
|
631
|
-
filterSelectShader.uniforms.blurTexture.value =
|
|
545
|
+
filterSelectShader.uniforms.blurTexture.value = blur1TextureTarget.texture;
|
|
632
546
|
filterSelectShader.blending = NormalBlending;
|
|
633
547
|
fsQuad.render(renderer, filterSelectShader);
|
|
634
548
|
}
|
package/threeLoader.d.ts
CHANGED
|
@@ -9,6 +9,20 @@ import { PLYLoader } from "three/examples/jsm/Addons";
|
|
|
9
9
|
import type { ThreeLoaderEventMap } from "./EventMap";
|
|
10
10
|
declare class ThreeLoader extends EventDispatcher<ThreeLoaderEventMap> {
|
|
11
11
|
constructor();
|
|
12
|
+
/** 已经报过的失败地址(去重只服务「计数」,不影响事件本身 —— 事件仍每次发,页面可按 `isNew` 决定要不要提示) */
|
|
13
|
+
private _failedUrls;
|
|
14
|
+
/** 全站累计**失败地址数**(与 manager 的 itemsTotal/itemsLoaded 同口径:累加、永不清零 ⇒ 页面自己算「本次」) */
|
|
15
|
+
loadErrorCount: number;
|
|
16
|
+
/** 地址 → 服务端回的状态码。只有**拿到过回复**的那两路写得进来:`loadPanoTexture` 的非 2xx(全景整图/32 片切片、平面 4 片)
|
|
17
|
+
* 与 `loadModel` 的下载失败(GLB 等)。用来把「服务器明说没有」和「断网 / 解码失败」分开 —— 前者页面才敢删数据。 */
|
|
18
|
+
private _urlStatus;
|
|
19
|
+
/** 记下一个地址的服务端状态码(键必须与失败上报用的那一个地址串一致) */
|
|
20
|
+
markUrlStatus(url: string, status: number): void;
|
|
21
|
+
/** 失败的唯一上报口:`DefaultLoadingManager.onError`(素材那一路)与 `ModelSlot` 那颗 GLB 没出来(模型那一路)都走这里。 */
|
|
22
|
+
reportLoadError(url: string, kind: "asset" | "model", label?: string): void;
|
|
23
|
+
/** 从加载器抛出的错误里取 HTTP 状态码,记在**调用方那一个地址**上(`url` 原样,不是内部补全后的地址)。
|
|
24
|
+
* three 的 `FileLoader` 非 2xx 抛 `HttpError`(`err.response.status`),个别加载器只把码写进 message。 */
|
|
25
|
+
private _noteErrStatus;
|
|
12
26
|
getFilename(url: string): string;
|
|
13
27
|
uuid: string;
|
|
14
28
|
anisotropy: number;
|
package/threeLoader.js
CHANGED
|
@@ -40,6 +40,12 @@ class ThreeLoader extends EventDispatcher {
|
|
|
40
40
|
DefaultLoadingManager.onLoad = () => {
|
|
41
41
|
this.onload = true;
|
|
42
42
|
};
|
|
43
|
+
// 资源加载失败:走 manager 计数的每一条(全景整图/32 片切片、图片平面 4 片、GLB 下载与内嵌贴图)
|
|
44
|
+
// 都只从这里出,页面侧仍只订本类这一个出口(与 onProgress 同规矩,⛔ 页面不许自己占 manager 的槽位)。
|
|
45
|
+
// 同一地址去重:全景/平面那两路失败会每帧重发请求 ⇒ 不去重「失败数」会被刷成无穷大。
|
|
46
|
+
DefaultLoadingManager.onError = (url) => {
|
|
47
|
+
this.reportLoadError(url, "asset");
|
|
48
|
+
};
|
|
43
49
|
// 资源替换
|
|
44
50
|
DefaultLoadingManager.setURLModifier((url) => {
|
|
45
51
|
//全路径匹配资源
|
|
@@ -58,6 +64,40 @@ class ThreeLoader extends EventDispatcher {
|
|
|
58
64
|
return new_url;
|
|
59
65
|
});
|
|
60
66
|
}
|
|
67
|
+
/** 已经报过的失败地址(去重只服务「计数」,不影响事件本身 —— 事件仍每次发,页面可按 `isNew` 决定要不要提示) */
|
|
68
|
+
_failedUrls = new Set();
|
|
69
|
+
/** 全站累计**失败地址数**(与 manager 的 itemsTotal/itemsLoaded 同口径:累加、永不清零 ⇒ 页面自己算「本次」) */
|
|
70
|
+
loadErrorCount = 0;
|
|
71
|
+
/** 地址 → 服务端回的状态码。只有**拿到过回复**的那两路写得进来:`loadPanoTexture` 的非 2xx(全景整图/32 片切片、平面 4 片)
|
|
72
|
+
* 与 `loadModel` 的下载失败(GLB 等)。用来把「服务器明说没有」和「断网 / 解码失败」分开 —— 前者页面才敢删数据。 */
|
|
73
|
+
_urlStatus = new Map();
|
|
74
|
+
/** 记下一个地址的服务端状态码(键必须与失败上报用的那一个地址串一致) */
|
|
75
|
+
markUrlStatus(url, status) {
|
|
76
|
+
if (url)
|
|
77
|
+
this._urlStatus.set(url, status);
|
|
78
|
+
}
|
|
79
|
+
/** 失败的唯一上报口:`DefaultLoadingManager.onError`(素材那一路)与 `ModelSlot` 那颗 GLB 没出来(模型那一路)都走这里。 */
|
|
80
|
+
reportLoadError(url, kind, label) {
|
|
81
|
+
const isNew = !this._failedUrls.has(url);
|
|
82
|
+
if (isNew) {
|
|
83
|
+
this._failedUrls.add(url);
|
|
84
|
+
this.loadErrorCount++;
|
|
85
|
+
}
|
|
86
|
+
const status = this._urlStatus.get(url);
|
|
87
|
+
// 403 与 404 并一档:OSS 私有桶里「key 不存在」回的正是 403(AccessDenied 用来不泄露对象是否存在)。
|
|
88
|
+
const missing = status === 404 || status === 403;
|
|
89
|
+
this.dispatchEvent({ type: "loadError", url, kind, label, status, missing, failed: this.loadErrorCount, isNew });
|
|
90
|
+
}
|
|
91
|
+
/** 从加载器抛出的错误里取 HTTP 状态码,记在**调用方那一个地址**上(`url` 原样,不是内部补全后的地址)。
|
|
92
|
+
* three 的 `FileLoader` 非 2xx 抛 `HttpError`(`err.response.status`),个别加载器只把码写进 message。 */
|
|
93
|
+
_noteErrStatus(url, err) {
|
|
94
|
+
if (!isString(url))
|
|
95
|
+
return;
|
|
96
|
+
const e = err;
|
|
97
|
+
const raw = e?.status ?? e?.response?.status ?? Number(/(?:responded with|HTTP) (\d{3})/.exec(e?.message ?? "")?.[1]);
|
|
98
|
+
if (Number.isFinite(raw))
|
|
99
|
+
this.markUrlStatus(url, raw);
|
|
100
|
+
}
|
|
61
101
|
// 从url 中提取文件名
|
|
62
102
|
getFilename(url) {
|
|
63
103
|
// 移除URL的查询字符串和哈希部分
|
|
@@ -364,7 +404,8 @@ class ThreeLoader extends EventDispatcher {
|
|
|
364
404
|
});
|
|
365
405
|
return res;
|
|
366
406
|
})
|
|
367
|
-
.catch(() => {
|
|
407
|
+
.catch((err) => {
|
|
408
|
+
this._noteErrStatus(url, err);
|
|
368
409
|
console.error(`${url},加载失败`);
|
|
369
410
|
return undefined;
|
|
370
411
|
});
|
|
@@ -381,6 +422,7 @@ class ThreeLoader extends EventDispatcher {
|
|
|
381
422
|
return res.scene;
|
|
382
423
|
})
|
|
383
424
|
.catch((err) => {
|
|
425
|
+
this._noteErrStatus(url, err);
|
|
384
426
|
// 打印详细错误信息,方便调试
|
|
385
427
|
console.error(`${url},加载失败`, err);
|
|
386
428
|
return undefined;
|
|
@@ -398,7 +440,8 @@ class ThreeLoader extends EventDispatcher {
|
|
|
398
440
|
roughness: 0.5,
|
|
399
441
|
}));
|
|
400
442
|
})
|
|
401
|
-
.catch(() => {
|
|
443
|
+
.catch((err) => {
|
|
444
|
+
this._noteErrStatus(url, err);
|
|
402
445
|
console.error(`${url},加载失败`);
|
|
403
446
|
return undefined;
|
|
404
447
|
});
|
|
@@ -434,7 +477,8 @@ class ThreeLoader extends EventDispatcher {
|
|
|
434
477
|
}
|
|
435
478
|
return plyMesh;
|
|
436
479
|
})
|
|
437
|
-
.catch(() => {
|
|
480
|
+
.catch((err) => {
|
|
481
|
+
this._noteErrStatus(url, err);
|
|
438
482
|
console.error(`${url},加载失败`);
|
|
439
483
|
return undefined;
|
|
440
484
|
});
|
|
@@ -462,6 +506,7 @@ class ThreeLoader extends EventDispatcher {
|
|
|
462
506
|
return res;
|
|
463
507
|
})
|
|
464
508
|
.catch((err) => {
|
|
509
|
+
this._noteErrStatus(url, err);
|
|
465
510
|
console.error(`${url},加载失败`, err);
|
|
466
511
|
return undefined;
|
|
467
512
|
});
|
package/threeLoader.ts
CHANGED
|
@@ -44,6 +44,12 @@ class ThreeLoader extends EventDispatcher<ThreeLoaderEventMap> {
|
|
|
44
44
|
DefaultLoadingManager.onLoad = () => {
|
|
45
45
|
this.onload = true;
|
|
46
46
|
};
|
|
47
|
+
// 资源加载失败:走 manager 计数的每一条(全景整图/32 片切片、图片平面 4 片、GLB 下载与内嵌贴图)
|
|
48
|
+
// 都只从这里出,页面侧仍只订本类这一个出口(与 onProgress 同规矩,⛔ 页面不许自己占 manager 的槽位)。
|
|
49
|
+
// 同一地址去重:全景/平面那两路失败会每帧重发请求 ⇒ 不去重「失败数」会被刷成无穷大。
|
|
50
|
+
DefaultLoadingManager.onError = (url: string) => {
|
|
51
|
+
this.reportLoadError(url, "asset");
|
|
52
|
+
};
|
|
47
53
|
// 资源替换
|
|
48
54
|
DefaultLoadingManager.setURLModifier((url: string) => {
|
|
49
55
|
//全路径匹配资源
|
|
@@ -62,6 +68,37 @@ class ThreeLoader extends EventDispatcher<ThreeLoaderEventMap> {
|
|
|
62
68
|
return new_url;
|
|
63
69
|
});
|
|
64
70
|
}
|
|
71
|
+
/** 已经报过的失败地址(去重只服务「计数」,不影响事件本身 —— 事件仍每次发,页面可按 `isNew` 决定要不要提示) */
|
|
72
|
+
private _failedUrls: Set<string> = new Set();
|
|
73
|
+
/** 全站累计**失败地址数**(与 manager 的 itemsTotal/itemsLoaded 同口径:累加、永不清零 ⇒ 页面自己算「本次」) */
|
|
74
|
+
loadErrorCount: number = 0;
|
|
75
|
+
/** 地址 → 服务端回的状态码。只有**拿到过回复**的那两路写得进来:`loadPanoTexture` 的非 2xx(全景整图/32 片切片、平面 4 片)
|
|
76
|
+
* 与 `loadModel` 的下载失败(GLB 等)。用来把「服务器明说没有」和「断网 / 解码失败」分开 —— 前者页面才敢删数据。 */
|
|
77
|
+
private _urlStatus: Map<string, number> = new Map();
|
|
78
|
+
/** 记下一个地址的服务端状态码(键必须与失败上报用的那一个地址串一致) */
|
|
79
|
+
markUrlStatus(url: string, status: number): void {
|
|
80
|
+
if (url) this._urlStatus.set(url, status);
|
|
81
|
+
}
|
|
82
|
+
/** 失败的唯一上报口:`DefaultLoadingManager.onError`(素材那一路)与 `ModelSlot` 那颗 GLB 没出来(模型那一路)都走这里。 */
|
|
83
|
+
reportLoadError(url: string, kind: "asset" | "model", label?: string): void {
|
|
84
|
+
const isNew = !this._failedUrls.has(url);
|
|
85
|
+
if (isNew) {
|
|
86
|
+
this._failedUrls.add(url);
|
|
87
|
+
this.loadErrorCount++;
|
|
88
|
+
}
|
|
89
|
+
const status = this._urlStatus.get(url);
|
|
90
|
+
// 403 与 404 并一档:OSS 私有桶里「key 不存在」回的正是 403(AccessDenied 用来不泄露对象是否存在)。
|
|
91
|
+
const missing = status === 404 || status === 403;
|
|
92
|
+
this.dispatchEvent({ type: "loadError", url, kind, label, status, missing, failed: this.loadErrorCount, isNew });
|
|
93
|
+
}
|
|
94
|
+
/** 从加载器抛出的错误里取 HTTP 状态码,记在**调用方那一个地址**上(`url` 原样,不是内部补全后的地址)。
|
|
95
|
+
* three 的 `FileLoader` 非 2xx 抛 `HttpError`(`err.response.status`),个别加载器只把码写进 message。 */
|
|
96
|
+
private _noteErrStatus(url: string | File | Array<File>, err: unknown): void {
|
|
97
|
+
if (!isString(url)) return;
|
|
98
|
+
const e = err as { status?: number; response?: { status?: number }; message?: string };
|
|
99
|
+
const raw = e?.status ?? e?.response?.status ?? Number(/(?:responded with|HTTP) (\d{3})/.exec(e?.message ?? "")?.[1]);
|
|
100
|
+
if (Number.isFinite(raw)) this.markUrlStatus(url, raw);
|
|
101
|
+
}
|
|
65
102
|
// 从url 中提取文件名
|
|
66
103
|
getFilename(url: string): string {
|
|
67
104
|
// 移除URL的查询字符串和哈希部分
|
|
@@ -370,7 +407,8 @@ class ThreeLoader extends EventDispatcher<ThreeLoaderEventMap> {
|
|
|
370
407
|
});
|
|
371
408
|
return res;
|
|
372
409
|
})
|
|
373
|
-
.catch(() => {
|
|
410
|
+
.catch((err) => {
|
|
411
|
+
this._noteErrStatus(url, err);
|
|
374
412
|
console.error(`${url},加载失败`);
|
|
375
413
|
return undefined;
|
|
376
414
|
});
|
|
@@ -387,6 +425,7 @@ class ThreeLoader extends EventDispatcher<ThreeLoaderEventMap> {
|
|
|
387
425
|
return res.scene;
|
|
388
426
|
})
|
|
389
427
|
.catch((err) => {
|
|
428
|
+
this._noteErrStatus(url, err);
|
|
390
429
|
// 打印详细错误信息,方便调试
|
|
391
430
|
console.error(`${url},加载失败`, err);
|
|
392
431
|
return undefined;
|
|
@@ -404,7 +443,8 @@ class ThreeLoader extends EventDispatcher<ThreeLoaderEventMap> {
|
|
|
404
443
|
roughness: 0.5,
|
|
405
444
|
}));
|
|
406
445
|
})
|
|
407
|
-
.catch(() => {
|
|
446
|
+
.catch((err) => {
|
|
447
|
+
this._noteErrStatus(url, err);
|
|
408
448
|
console.error(`${url},加载失败`);
|
|
409
449
|
return undefined;
|
|
410
450
|
});
|
|
@@ -440,7 +480,8 @@ class ThreeLoader extends EventDispatcher<ThreeLoaderEventMap> {
|
|
|
440
480
|
}
|
|
441
481
|
return plyMesh;
|
|
442
482
|
})
|
|
443
|
-
.catch(() => {
|
|
483
|
+
.catch((err) => {
|
|
484
|
+
this._noteErrStatus(url, err);
|
|
444
485
|
console.error(`${url},加载失败`);
|
|
445
486
|
return undefined;
|
|
446
487
|
});
|
|
@@ -467,6 +508,7 @@ class ThreeLoader extends EventDispatcher<ThreeLoaderEventMap> {
|
|
|
467
508
|
return res;
|
|
468
509
|
})
|
|
469
510
|
.catch((err) => {
|
|
511
|
+
this._noteErrStatus(url, err);
|
|
470
512
|
console.error(`${url},加载失败`, err);
|
|
471
513
|
return undefined;
|
|
472
514
|
});
|