three-base 2.0.169 → 2.0.175

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.
Files changed (124) hide show
  1. package/FPScontrol.d.ts +55 -30
  2. package/FPScontrol.js +278 -225
  3. package/FPScontrol.ts +177 -127
  4. package/Ground1/Ground1.d.ts +4 -2
  5. package/Ground1/Ground1.js +77 -57
  6. package/Ground1/Ground1.ts +77 -57
  7. package/Mirror.js +0 -4
  8. package/Mirror.ts +0 -4
  9. package/MktMesh/MktMesh.d.ts +8 -3
  10. package/MktMesh/MktMesh.js +43 -14
  11. package/MktMesh/MktMesh.ts +40 -14
  12. package/MktMesh/mktMappingShader.d.ts +6 -5
  13. package/MktMesh/mktMappingShader.js +26 -19
  14. package/MktMesh/mktMappingShader.ts +28 -19
  15. package/MktMesh/mktShader.d.ts +127 -58
  16. package/MktMesh/mktShader.js +192 -117
  17. package/MktMesh/mktShader.ts +251 -127
  18. package/MktMesh/panoSlotRoster.d.ts +2 -2
  19. package/MktMesh/panoSlotRoster.js +9 -7
  20. package/MktMesh/panoSlotRoster.ts +9 -7
  21. package/MktMesh/panoTileStitcher.d.ts +20 -13
  22. package/MktMesh/panoTileStitcher.js +97 -76
  23. package/MktMesh/panoTileStitcher.ts +119 -90
  24. package/MktMesh/types.d.ts +5 -1
  25. package/MktMesh/types.ts +5 -1
  26. package/PipeMesh/PipeJoint.d.ts +22 -0
  27. package/PipeMesh/PipeJoint.js +33 -0
  28. package/PipeMesh/PipeJoint.ts +38 -0
  29. package/PipeMesh/PipeMesh.d.ts +94 -22
  30. package/PipeMesh/PipeMesh.js +192 -53
  31. package/PipeMesh/PipeMesh.ts +223 -76
  32. package/PipeMesh/PipeStraight.d.ts +19 -0
  33. package/PipeMesh/PipeStraight.js +34 -0
  34. package/PipeMesh/PipeStraight.ts +45 -0
  35. package/PipeMesh/axisSnap.d.ts +52 -0
  36. package/PipeMesh/axisSnap.js +52 -0
  37. package/PipeMesh/axisSnap.ts +93 -0
  38. package/PipeMesh/directRoute.d.ts +85 -0
  39. package/PipeMesh/directRoute.js +126 -0
  40. package/PipeMesh/directRoute.ts +190 -0
  41. package/PipeMesh/index.d.ts +6 -0
  42. package/PipeMesh/index.js +6 -0
  43. package/PipeMesh/index.ts +7 -1
  44. package/PipeMesh/pipeMaterial.d.ts +16 -0
  45. package/PipeMesh/pipeMaterial.js +23 -0
  46. package/PipeMesh/pipeMaterial.ts +26 -0
  47. package/ThreeBase.d.ts +2 -49
  48. package/ThreeBase.js +43 -164
  49. package/ThreeBase.ts +1176 -1314
  50. package/instanced/InstancedBatch.d.ts +14 -1
  51. package/instanced/InstancedBatch.js +53 -3
  52. package/instanced/InstancedBatch.ts +62 -3
  53. package/instanced/InstancedChild.d.ts +24 -0
  54. package/instanced/InstancedChild.js +40 -0
  55. package/instanced/InstancedChild.ts +41 -0
  56. package/instanced/InstancedGroup.d.ts +48 -0
  57. package/instanced/InstancedGroup.js +45 -1
  58. package/instanced/InstancedGroup.ts +85 -0
  59. package/package.json +2 -7
  60. package/pass/bloom_pass.js +7 -14
  61. package/pass/bloom_pass.ts +7 -16
  62. package/pass/cover_pass.js +7 -15
  63. package/pass/cover_pass.ts +7 -17
  64. package/pass/debugDepthState.d.ts +16 -8
  65. package/pass/debugDepthState.js +4 -0
  66. package/pass/debugDepthState.ts +27 -9
  67. package/pass/glow_pass.js +19 -110
  68. package/pass/glow_pass.ts +19 -115
  69. package/pass/ssao_pass.d.ts +14 -59
  70. package/pass/ssao_pass.js +66 -171
  71. package/pass/ssao_pass.ts +63 -207
  72. package/pass/stroke_pass.js +13 -16
  73. package/pass/stroke_pass.ts +14 -18
  74. package/shaders/baseDepthVisShader.d.ts +1 -1
  75. package/shaders/baseDepthVisShader.js +1 -1
  76. package/shaders/baseDepthVisShader.ts +1 -1
  77. package/shaders/debugDepthCompareShader.d.ts +2 -2
  78. package/shaders/debugDepthCompareShader.js +2 -2
  79. package/shaders/debugDepthCompareShader.ts +2 -2
  80. package/shaders/debugDepthJudgeShader.d.ts +1 -1
  81. package/shaders/debugDepthJudgeShader.js +1 -1
  82. package/shaders/debugDepthJudgeShader.ts +1 -1
  83. package/PipeMesh/PathGeometry.d.ts +0 -44
  84. package/PipeMesh/PathGeometry.js +0 -307
  85. package/PipeMesh/PathGeometry.ts +0 -343
  86. package/PipeMesh/PathPoint.d.ts +0 -17
  87. package/PipeMesh/PathPoint.js +0 -31
  88. package/PipeMesh/PathPoint.ts +0 -36
  89. package/PipeMesh/PathPointList.d.ts +0 -31
  90. package/PipeMesh/PathPointList.js +0 -209
  91. package/PipeMesh/PathPointList.ts +0 -227
  92. package/PipeMesh/PathTubeGeometry.d.ts +0 -25
  93. package/PipeMesh/PathTubeGeometry.js +0 -130
  94. package/PipeMesh/PathTubeGeometry.ts +0 -146
  95. package/WaterFlow/FloatingDuck.d.ts +0 -88
  96. package/WaterFlow/FloatingDuck.js +0 -307
  97. package/WaterFlow/FloatingDuck.ts +0 -445
  98. package/WaterFlow/GPUFluidSimulation.d.ts +0 -56
  99. package/WaterFlow/GPUFluidSimulation.js +0 -785
  100. package/WaterFlow/GPUFluidSimulation.ts +0 -827
  101. package/WaterFlow/ReservoirSystem.d.ts +0 -106
  102. package/WaterFlow/ReservoirSystem.js +0 -621
  103. package/WaterFlow/ReservoirSystem.ts +0 -754
  104. package/WaterFlow/SPHField.d.ts +0 -35
  105. package/WaterFlow/SPHField.js +0 -204
  106. package/WaterFlow/SPHField.ts +0 -228
  107. package/WaterFlow/ScreenSpaceFluidPass.d.ts +0 -69
  108. package/WaterFlow/ScreenSpaceFluidPass.js +0 -736
  109. package/WaterFlow/ScreenSpaceFluidPass.ts +0 -789
  110. package/WaterFlow/ShallowWaterSurface.d.ts +0 -45
  111. package/WaterFlow/ShallowWaterSurface.js +0 -441
  112. package/WaterFlow/ShallowWaterSurface.ts +0 -510
  113. package/WaterFlow/WaterFlow.d.ts +0 -87
  114. package/WaterFlow/WaterFlow.js +0 -171
  115. package/WaterFlow/WaterFlow.ts +0 -219
  116. package/WaterFlow/types.d.ts +0 -161
  117. package/WaterFlow/types.js +0 -1
  118. package/WaterFlow/types.ts +0 -189
  119. package/WaterFlow/waterFlowPass.d.ts +0 -3
  120. package/WaterFlow/waterFlowPass.js +0 -20
  121. package/WaterFlow/waterFlowPass.ts +0 -40
  122. package/shaders/debugExcludedShader.d.ts +0 -13
  123. package/shaders/debugExcludedShader.js +0 -46
  124. package/shaders/debugExcludedShader.ts +0 -48
@@ -2,44 +2,39 @@
2
2
  * @Author: xiaosihan
3
3
  * @Date: 2022-09-20 23:06:00
4
4
  * @Last Modified by: xiaosihan
5
- * @Last Modified time: 2024-08-17 02:16:56
5
+ * @Last Modified time: 2026-10-12 00:00:00
6
6
  *
7
- * ⭐ 2026-09-20 皇上旨两改:
8
- * ① 原「科技感装饰地板」(三张格子贴图 + 紫色扩散动画 `#8D108E` + 格子线 `#263C56`)
9
- * → 深灰地板(每帧 3 次贴图采样、贴图平铺无各向异性 → 摩尔纹 + home 页卡顿元凶之一)。
10
- * ② 皇上再旨「地板就是**随机渐变**的深灰色、**不透明**」:
11
- * → 深灰区间内用 **value noise 做随机渐变**(无贴图、零采样,天然无摩尔纹);
12
- * → `transparent: false`、alpha 恒 1(不透明)。
7
+ * ⭐ 装饰地板 = 科技感格子贴图 + 紫色扩散动画(2026-10-12 皇上旨「整条退回旧科技感地板」+「装饰地板需要透明」)。
8
+ * 历史:2026-09-20 皇上曾两旨把它改成「随机渐变的深灰、不透明」,理由是每帧 3 次贴图采样 +
9
+ * 平铺无各向异性 → 摩尔纹,且是 home 页卡顿元凶之一。**当年那个摩尔纹根因现在已经在
10
+ * `threeLoader.getTexture` 里根治了**(anisotropy=16 + generateMipmaps + LinearMipmapLinear),
11
+ * 所以贴图路线的重画成本比 09-20 那版低一档,本次按皇上旨意恢复旧外观。
13
12
  *
14
- * ⚠️ 不透明带来的变化与对策:
15
- * - 原靠「径向 alpha 淡出」柔化 500×500 地板的边界;不透明后改用**径向压暗**(乘 0.72~1.0)
16
- * 弱化硬边 —— 若哪天皇上要「边界完全消失」,只能改回 alpha 淡出(即恢复 transparent)。
17
- * - 调试线(FPScontrol)两条口径分家(2026-09-25 皇上逐条定案):**10 条射线辅助线开深度测试**,
18
- * 正是靠本地板「不透明 + depthWrite:true」才挡得住埋进地里的那半截线;**8/9 两条回弹向量线
19
- * 保持穿透显示**(关深度测试 + renderOrder:9999),照旧常显在最前。
20
- * ⚠️ 若哪天把本地板改回 transparent + depthWrite:false,射线辅助线会重新穿地浮出来。
13
+ * ⭐ 2026-10-12 皇上旨「装饰地板需要透明」⇒ 恢复旧版的**外观**口径(逐字照抄 09-20 之前的写法):
14
+ * - `transparent: true` + 径向 alpha 淡出 `mapColor.a = 1 - dist(center)*2`(中心实、外缘全透)。
15
+ * - **但 `depthWrite: true` 保留**(旧版本来就是 transparent + depthWrite:true):主渲染的深度缓冲
16
+ * 照写 ⇒ FPScontrol 那 10 条射线辅助线仍被地板挡住埋进地里的那半截(09-25 定案口径不受影响)。
21
17
  *
22
- * ⚠️ 改动红线(这几条被别处依赖,**不许顺手改**):
23
- * - `userData.fpsCollision = true`:FPScontrol 把地板当碰撞体(见 FPScontrol.ts 地面处理段)。
24
- * - `userData.aoFloor = true`:ssao_pass / debugExcludedShader 的「地板类半透明」特例按此标记走
25
- * (默认不写进可见深度图;物体落在地板上仍有接触 AO)。
26
- * - ShaderMaterial 必须含 logdepthbuf chunk;linear 输出必须 `#include <colorspace_fragment>`;
27
- * 否则末端 sRGB 编码会二次编码 → 发白。
18
+ * ⭐ 2026-10-18 皇上旨「所有的对象都要进入到深度图里面了,不需要用参数过滤掉了」⇒ 当年为「可透视
19
+ * 地板」加的 `userData.aoFloor`(把地板从后处理的可见深度图里排除)连同 ssao_pass 里那整条过滤判据
20
+ * 一并删除。现在地板两张深度图都写 ⇒ 透过地板看到的实体,其描边/辉光/覆盖色/磨砂会被地板裁掉,
21
+ * 包括外缘 alpha≈0 那圈「看得见空、看不见地板」的区域。判据出处 three-base/pass/ssao_pass.ts 文件头,
22
+ * 护栏 test/depthDebug.test.js J 组。
28
23
  */
29
- import { Color, DoubleSide, Matrix4, Mesh, PlaneGeometry, ShaderChunk, ShaderMaterial } from "three";
24
+ import { Clock, Color, DoubleSide, Matrix4, Mesh, PlaneGeometry, ShaderChunk, ShaderMaterial, Vector2 } from "three";
30
25
  import { MathUtils } from "three";
31
26
  const { degToRad } = MathUtils;
32
- /** 装饰地板(随机渐变的深灰、不透明) */
27
+ import floorMap1PNG from "./floorMap1.png";
28
+ import floorMap2PNG from "./floorMap2.png";
29
+ import floorMap3PNG from "./floorMap3.png";
30
+ import threeLoader from "../threeLoader";
31
+ /** 装饰地板(科技感格子贴图 + 紫色扩散动画,半透明可透视外观) */
33
32
  export default class Ground1 extends Mesh {
34
33
  tempMatrix = new Matrix4();
35
34
  constructor() {
36
35
  super();
37
36
  // 标记为自己参与 FPS 碰撞检测
38
37
  this.userData.fpsCollision = true;
39
- // 标记为"地板类半透明":参与世界空间 AO(物体落在它上需要接触 AO),
40
- // 但透过它看到的物体(如从下方透视)仍照常显示描边/辉光、且不被它的接触 AO 乘黑。
41
- // 见 three-base/pass/ssao_pass.ts 的复合守卫说明。
42
- this.userData.aoFloor = true;
43
38
  }
44
39
  renderOrder = -1;
45
40
  geometry = (() => {
@@ -51,14 +46,22 @@ export default class Ground1 extends Mesh {
51
46
  setSize(width, height) {
52
47
  this.scale.set(width, 1, height);
53
48
  }
49
+ clock = new Clock();
50
+ onBeforeRender = (renderer, scene, camera, geometry, material, group) => {
51
+ const elapsedTime = this.clock.getElapsedTime();
52
+ this.material.uniforms.speed.value = (elapsedTime * 0.1) % 0.6;
53
+ this.material.uniforms.speed2.value = ((elapsedTime * 0.1) % 0.6) - 0.1;
54
+ };
54
55
  material = new ShaderMaterial({
55
56
  uniforms: {
56
- /** 随机渐变的**暗端**深灰(three 的 Color 存 linear,末端 colorspace_fragment 编码回 sRGB) */
57
- colorDark: { value: new Color("#2A2E33") },
58
- /** 随机渐变的**亮端**深灰 */
59
- colorLight: { value: new Color("#3D434B") },
60
- /** 低频噪声格数(越大斑块越碎;9 → 500×500 地板上每块约 55m 的大块渐变) */
61
- noiseScale: { value: 9 },
57
+ size: { value: new Vector2(10, 10) }, // 格子平铺格数
58
+ speed: { value: 0 }, // 扩散值0-1
59
+ speed2: { value: 0 }, // 扩散值0-1
60
+ speedColor: { value: new Color("#8D108E") }, // 格子扩散颜色
61
+ lineColor: { value: new Color("#263C56") }, // 格子线的颜色
62
+ map1: { value: threeLoader.getTexture(floorMap1PNG) }, // 贴图纹理
63
+ map2: { value: threeLoader.getTexture(floorMap2PNG) }, // 贴图纹理
64
+ map3: { value: threeLoader.getTexture(floorMap3PNG) }, // 贴图纹理
62
65
  },
63
66
  vertexShader: `
64
67
  ${ShaderChunk.common}
@@ -72,42 +75,59 @@ export default class Ground1 extends Mesh {
72
75
  `,
73
76
  fragmentShader: `
74
77
  ${ShaderChunk.logdepthbuf_pars_fragment}
75
- uniform vec3 colorDark;
76
- uniform vec3 colorLight;
77
- uniform float noiseScale;
78
+ uniform sampler2D map1;
79
+ uniform sampler2D map2;
80
+ uniform sampler2D map3;
81
+ uniform vec2 size;
82
+ uniform vec3 lineColor;
83
+ uniform float speed;
84
+ uniform float speed2;
85
+ uniform vec3 speedColor;
78
86
  varying vec2 vUv;
87
+ void main() {
79
88
 
80
- // 伪随机 hash → value noise:无贴图、零采样,天然没有平铺摩尔纹
81
- float hash21(vec2 p) {
82
- return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);
83
- }
84
- float valueNoise(vec2 p) {
85
- vec2 i = floor(p);
86
- vec2 f = fract(p);
87
- vec2 u = f * f * (3.0 - 2.0 * f); // smoothstep 插值 → 柔和渐变,不是硬格子
88
- return mix(mix(hash21(i), hash21(i + vec2(1.0, 0.0)), u.x),
89
- mix(hash21(i + vec2(0.0, 1.0)), hash21(i + vec2(1.0, 1.0)), u.x), u.y);
90
- }
89
+ // 中心点
90
+ vec2 center = vec2(0.5,0.5);
91
91
 
92
- void main() {
93
- // 两个八度叠加:低频大块渐变 + 中频细节 → 深灰区间内的**随机渐变**
94
- float n = valueNoise(vUv * noiseScale) * 0.65
95
- + valueNoise(vUv * noiseScale * 3.1) * 0.35;
96
- vec3 col = mix(colorDark, colorLight, clamp(n, 0.0, 1.0));
92
+ vec4 map1Color = texture2D(map1, fract( vUv * size) );
93
+
94
+ // 格子中心渐变颜色
95
+ if(distance( vUv , center ) < speed){
96
+ map1Color = mix(map1Color, vec4(speedColor, 1.0), clamp((1.0 - (distance(distance( vUv , center ), speed) * 8.0) ) * map1Color.a, 0.0, 1.0 ) );
97
+ }
98
+
99
+ vec4 map2Color = texture2D(map2, fract( vUv * size) );
100
+
101
+ vec4 map3Color = texture2D(map3, fract( vUv * size) );
102
+
103
+ // 正方形装饰中心渐变颜色
104
+ if(distance( vUv , center ) < speed2){
105
+ map3Color = mix(map3Color, map3Color * 3.0, clamp((1.0 - (distance(distance( vUv , center ), speed) * 4.0) ) * map3Color.a, 0.0, 1.0 ) );
106
+ }
107
+
108
+ vec4 mapColor = mix(map1Color, map2Color, map2Color.a);
109
+
110
+ mapColor = mix(mapColor, map3Color, map3Color.a);
111
+
112
+ //添加背景色
113
+ mapColor = mix(mapColor, vec4(lineColor.rgb, 1.0 ), 1.0 - mapColor.a);
114
+
115
+ // 设置透明度(中心实、外缘全透的径向淡出 —— 500×500 大地板的硬边靠它消失)
116
+ mapColor.a = 1.0 - (distance( vUv , center ) * 2.0);
97
117
 
98
- // ⚠️ 不透明地板无法用 alpha 淡出边界 → 改用径向压暗弱化 500×500 的硬边
99
- float edge = 1.0 - smoothstep(0.34, 0.5, distance(vUv, vec2(0.5, 0.5)));
100
- col *= mix(0.72, 1.0, edge);
118
+ gl_FragColor = mapColor;
101
119
 
102
- gl_FragColor = vec4(col, 1.0); // 不透明
103
120
  ${ShaderChunk.logdepthbuf_fragment}
104
121
  #include <colorspace_fragment>
105
122
  }
106
123
  `,
107
124
  depthTest: true,
108
125
  depthWrite: true,
109
- // ⭐ 皇上 2026-09-20 旨:地板**不透明**
110
- transparent: false,
126
+ // ⭐ 皇上 2026-10-12 旨「装饰地板需要透明」:恢复旧版 transparent:true(半透可透视)。
127
+ // ⚠️ depthWrite 保持 true —— 主渲染的深度缓冲照写,FPScontrol 的 10 条射线辅助线才挡得住
128
+ // 埋进地里的那半截(09-25 定案)。后处理特效的遮挡判定走 baseDepthTexture,2026-10-18
129
+ // 皇上旨「所有的对象都要进入到深度图里面了」⇒ 地板也写进那张图,会裁掉身后特效。
130
+ transparent: true,
111
131
  side: DoubleSide,
112
132
  });
113
133
  }
@@ -2,45 +2,40 @@
2
2
  * @Author: xiaosihan
3
3
  * @Date: 2022-09-20 23:06:00
4
4
  * @Last Modified by: xiaosihan
5
- * @Last Modified time: 2024-08-17 02:16:56
5
+ * @Last Modified time: 2026-10-12 00:00:00
6
6
  *
7
- * ⭐ 2026-09-20 皇上旨两改:
8
- * ① 原「科技感装饰地板」(三张格子贴图 + 紫色扩散动画 `#8D108E` + 格子线 `#263C56`)
9
- * → 深灰地板(每帧 3 次贴图采样、贴图平铺无各向异性 → 摩尔纹 + home 页卡顿元凶之一)。
10
- * ② 皇上再旨「地板就是**随机渐变**的深灰色、**不透明**」:
11
- * → 深灰区间内用 **value noise 做随机渐变**(无贴图、零采样,天然无摩尔纹);
12
- * → `transparent: false`、alpha 恒 1(不透明)。
7
+ * ⭐ 装饰地板 = 科技感格子贴图 + 紫色扩散动画(2026-10-12 皇上旨「整条退回旧科技感地板」+「装饰地板需要透明」)。
8
+ * 历史:2026-09-20 皇上曾两旨把它改成「随机渐变的深灰、不透明」,理由是每帧 3 次贴图采样 +
9
+ * 平铺无各向异性 → 摩尔纹,且是 home 页卡顿元凶之一。**当年那个摩尔纹根因现在已经在
10
+ * `threeLoader.getTexture` 里根治了**(anisotropy=16 + generateMipmaps + LinearMipmapLinear),
11
+ * 所以贴图路线的重画成本比 09-20 那版低一档,本次按皇上旨意恢复旧外观。
13
12
  *
14
- * ⚠️ 不透明带来的变化与对策:
15
- * - 原靠「径向 alpha 淡出」柔化 500×500 地板的边界;不透明后改用**径向压暗**(乘 0.72~1.0)
16
- * 弱化硬边 —— 若哪天皇上要「边界完全消失」,只能改回 alpha 淡出(即恢复 transparent)。
17
- * - 调试线(FPScontrol)两条口径分家(2026-09-25 皇上逐条定案):**10 条射线辅助线开深度测试**,
18
- * 正是靠本地板「不透明 + depthWrite:true」才挡得住埋进地里的那半截线;**8/9 两条回弹向量线
19
- * 保持穿透显示**(关深度测试 + renderOrder:9999),照旧常显在最前。
20
- * ⚠️ 若哪天把本地板改回 transparent + depthWrite:false,射线辅助线会重新穿地浮出来。
13
+ * ⭐ 2026-10-12 皇上旨「装饰地板需要透明」⇒ 恢复旧版的**外观**口径(逐字照抄 09-20 之前的写法):
14
+ * - `transparent: true` + 径向 alpha 淡出 `mapColor.a = 1 - dist(center)*2`(中心实、外缘全透)。
15
+ * - **但 `depthWrite: true` 保留**(旧版本来就是 transparent + depthWrite:true):主渲染的深度缓冲
16
+ * 照写 ⇒ FPScontrol 那 10 条射线辅助线仍被地板挡住埋进地里的那半截(09-25 定案口径不受影响)。
21
17
  *
22
- * ⚠️ 改动红线(这几条被别处依赖,**不许顺手改**):
23
- * - `userData.fpsCollision = true`:FPScontrol 把地板当碰撞体(见 FPScontrol.ts 地面处理段)。
24
- * - `userData.aoFloor = true`:ssao_pass / debugExcludedShader 的「地板类半透明」特例按此标记走
25
- * (默认不写进可见深度图;物体落在地板上仍有接触 AO)。
26
- * - ShaderMaterial 必须含 logdepthbuf chunk;linear 输出必须 `#include <colorspace_fragment>`;
27
- * 否则末端 sRGB 编码会二次编码 → 发白。
18
+ * ⭐ 2026-10-18 皇上旨「所有的对象都要进入到深度图里面了,不需要用参数过滤掉了」⇒ 当年为「可透视
19
+ * 地板」加的 `userData.aoFloor`(把地板从后处理的可见深度图里排除)连同 ssao_pass 里那整条过滤判据
20
+ * 一并删除。现在地板两张深度图都写 ⇒ 透过地板看到的实体,其描边/辉光/覆盖色/磨砂会被地板裁掉,
21
+ * 包括外缘 alpha≈0 那圈「看得见空、看不见地板」的区域。判据出处 three-base/pass/ssao_pass.ts 文件头,
22
+ * 护栏 test/depthDebug.test.js J 组。
28
23
  */
29
- import { Color, DoubleSide, Matrix4, Mesh, PlaneGeometry, ShaderChunk, ShaderMaterial } from "three";
24
+ import { Clock, Color, DoubleSide, BufferGeometry, Camera, Group, Material, Matrix4, Mesh, PlaneGeometry, Scene, ShaderChunk, ShaderMaterial, Vector2, WebGLRenderer } from "three";
30
25
  import { MathUtils } from "three";
31
26
  const { degToRad } = MathUtils;
27
+ import floorMap1PNG from "./floorMap1.png";
28
+ import floorMap2PNG from "./floorMap2.png";
29
+ import floorMap3PNG from "./floorMap3.png";
30
+ import threeLoader from "../threeLoader";
32
31
 
33
- /** 装饰地板(随机渐变的深灰、不透明) */
32
+ /** 装饰地板(科技感格子贴图 + 紫色扩散动画,半透明可透视外观) */
34
33
  export default class Ground1 extends Mesh {
35
34
  tempMatrix: Matrix4 = new Matrix4();
36
35
  constructor() {
37
36
  super();
38
37
  // 标记为自己参与 FPS 碰撞检测
39
38
  this.userData.fpsCollision = true;
40
- // 标记为"地板类半透明":参与世界空间 AO(物体落在它上需要接触 AO),
41
- // 但透过它看到的物体(如从下方透视)仍照常显示描边/辉光、且不被它的接触 AO 乘黑。
42
- // 见 three-base/pass/ssao_pass.ts 的复合守卫说明。
43
- this.userData.aoFloor = true;
44
39
  }
45
40
  renderOrder: number = -1;
46
41
  geometry: PlaneGeometry = (() => {
@@ -52,14 +47,22 @@ export default class Ground1 extends Mesh {
52
47
  setSize(width: number, height: number): void {
53
48
  this.scale.set(width, 1, height);
54
49
  }
50
+ clock: Clock = new Clock();
51
+ onBeforeRender: (renderer: WebGLRenderer, scene: Scene, camera: Camera, geometry: BufferGeometry, material: Material, group: Group) => void = (renderer, scene, camera, geometry, material, group) => {
52
+ const elapsedTime: number = this.clock.getElapsedTime();
53
+ this.material.uniforms.speed.value = (elapsedTime * 0.1) % 0.6;
54
+ this.material.uniforms.speed2.value = ((elapsedTime * 0.1) % 0.6) - 0.1;
55
+ };
55
56
  material: ShaderMaterial = new ShaderMaterial({
56
57
  uniforms: {
57
- /** 随机渐变的**暗端**深灰(three 的 Color 存 linear,末端 colorspace_fragment 编码回 sRGB) */
58
- colorDark: { value: new Color("#2A2E33") },
59
- /** 随机渐变的**亮端**深灰 */
60
- colorLight: { value: new Color("#3D434B") },
61
- /** 低频噪声格数(越大斑块越碎;9 → 500×500 地板上每块约 55m 的大块渐变) */
62
- noiseScale: { value: 9 },
58
+ size: { value: new Vector2(10, 10) }, // 格子平铺格数
59
+ speed: { value: 0 }, // 扩散值0-1
60
+ speed2: { value: 0 }, // 扩散值0-1
61
+ speedColor: { value: new Color("#8D108E") }, // 格子扩散颜色
62
+ lineColor: { value: new Color("#263C56") }, // 格子线的颜色
63
+ map1: { value: threeLoader.getTexture(floorMap1PNG) }, // 贴图纹理
64
+ map2: { value: threeLoader.getTexture(floorMap2PNG) }, // 贴图纹理
65
+ map3: { value: threeLoader.getTexture(floorMap3PNG) }, // 贴图纹理
63
66
  },
64
67
  vertexShader: `
65
68
  ${ShaderChunk.common}
@@ -73,42 +76,59 @@ export default class Ground1 extends Mesh {
73
76
  `,
74
77
  fragmentShader: `
75
78
  ${ShaderChunk.logdepthbuf_pars_fragment}
76
- uniform vec3 colorDark;
77
- uniform vec3 colorLight;
78
- uniform float noiseScale;
79
+ uniform sampler2D map1;
80
+ uniform sampler2D map2;
81
+ uniform sampler2D map3;
82
+ uniform vec2 size;
83
+ uniform vec3 lineColor;
84
+ uniform float speed;
85
+ uniform float speed2;
86
+ uniform vec3 speedColor;
79
87
  varying vec2 vUv;
88
+ void main() {
80
89
 
81
- // 伪随机 hash → value noise:无贴图、零采样,天然没有平铺摩尔纹
82
- float hash21(vec2 p) {
83
- return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);
84
- }
85
- float valueNoise(vec2 p) {
86
- vec2 i = floor(p);
87
- vec2 f = fract(p);
88
- vec2 u = f * f * (3.0 - 2.0 * f); // smoothstep 插值 → 柔和渐变,不是硬格子
89
- return mix(mix(hash21(i), hash21(i + vec2(1.0, 0.0)), u.x),
90
- mix(hash21(i + vec2(0.0, 1.0)), hash21(i + vec2(1.0, 1.0)), u.x), u.y);
91
- }
90
+ // 中心点
91
+ vec2 center = vec2(0.5,0.5);
92
92
 
93
- void main() {
94
- // 两个八度叠加:低频大块渐变 + 中频细节 → 深灰区间内的**随机渐变**
95
- float n = valueNoise(vUv * noiseScale) * 0.65
96
- + valueNoise(vUv * noiseScale * 3.1) * 0.35;
97
- vec3 col = mix(colorDark, colorLight, clamp(n, 0.0, 1.0));
93
+ vec4 map1Color = texture2D(map1, fract( vUv * size) );
94
+
95
+ // 格子中心渐变颜色
96
+ if(distance( vUv , center ) < speed){
97
+ map1Color = mix(map1Color, vec4(speedColor, 1.0), clamp((1.0 - (distance(distance( vUv , center ), speed) * 8.0) ) * map1Color.a, 0.0, 1.0 ) );
98
+ }
99
+
100
+ vec4 map2Color = texture2D(map2, fract( vUv * size) );
101
+
102
+ vec4 map3Color = texture2D(map3, fract( vUv * size) );
103
+
104
+ // 正方形装饰中心渐变颜色
105
+ if(distance( vUv , center ) < speed2){
106
+ map3Color = mix(map3Color, map3Color * 3.0, clamp((1.0 - (distance(distance( vUv , center ), speed) * 4.0) ) * map3Color.a, 0.0, 1.0 ) );
107
+ }
108
+
109
+ vec4 mapColor = mix(map1Color, map2Color, map2Color.a);
110
+
111
+ mapColor = mix(mapColor, map3Color, map3Color.a);
112
+
113
+ //添加背景色
114
+ mapColor = mix(mapColor, vec4(lineColor.rgb, 1.0 ), 1.0 - mapColor.a);
115
+
116
+ // 设置透明度(中心实、外缘全透的径向淡出 —— 500×500 大地板的硬边靠它消失)
117
+ mapColor.a = 1.0 - (distance( vUv , center ) * 2.0);
98
118
 
99
- // ⚠️ 不透明地板无法用 alpha 淡出边界 → 改用径向压暗弱化 500×500 的硬边
100
- float edge = 1.0 - smoothstep(0.34, 0.5, distance(vUv, vec2(0.5, 0.5)));
101
- col *= mix(0.72, 1.0, edge);
119
+ gl_FragColor = mapColor;
102
120
 
103
- gl_FragColor = vec4(col, 1.0); // 不透明
104
121
  ${ShaderChunk.logdepthbuf_fragment}
105
122
  #include <colorspace_fragment>
106
123
  }
107
124
  `,
108
125
  depthTest: true,
109
126
  depthWrite: true,
110
- // ⭐ 皇上 2026-09-20 旨:地板**不透明**
111
- transparent: false,
127
+ // ⭐ 皇上 2026-10-12 旨「装饰地板需要透明」:恢复旧版 transparent:true(半透可透视)。
128
+ // ⚠️ depthWrite 保持 true —— 主渲染的深度缓冲照写,FPScontrol 的 10 条射线辅助线才挡得住
129
+ // 埋进地里的那半截(09-25 定案)。后处理特效的遮挡判定走 baseDepthTexture,2026-10-18
130
+ // 皇上旨「所有的对象都要进入到深度图里面了」⇒ 地板也写进那张图,会裁掉身后特效。
131
+ transparent: true,
112
132
  side: DoubleSide,
113
133
  });
114
134
  }
package/Mirror.js CHANGED
@@ -9,10 +9,6 @@ import { Color, DoubleSide, HalfFloatType, Matrix4, Mesh, PerspectiveCamera, Pla
9
9
  export default class Mirror extends Mesh {
10
10
  constructor(geometry = Mirror.geometry) {
11
11
  super(geometry);
12
- // 镜子虽标了 transparent:true(为渲染顺序),但 fragment shader 实际输出 alpha=1.0,
13
- // 是实心反射面、并非可透视表面 → 必须参与 AO 与描边/辉光的深度遮挡。
14
- // SSAO 的 AO 数据准备会排除所有 transparent 物体,故此处显式声明保留。
15
- this.userData.aoOpaque = true;
16
12
  }
17
13
  // 正方形网格
18
14
  static geometry = (() => {
package/Mirror.ts CHANGED
@@ -10,10 +10,6 @@ import { Color, DoubleSide, HalfFloatType, Matrix4, Mesh, PerspectiveCamera, Pla
10
10
  export default class Mirror extends Mesh {
11
11
  constructor(geometry: BufferGeometry = Mirror.geometry) {
12
12
  super(geometry);
13
- // 镜子虽标了 transparent:true(为渲染顺序),但 fragment shader 实际输出 alpha=1.0,
14
- // 是实心反射面、并非可透视表面 → 必须参与 AO 与描边/辉光的深度遮挡。
15
- // SSAO 的 AO 数据准备会排除所有 transparent 物体,故此处显式声明保留。
16
- this.userData.aoOpaque = true;
17
13
  }
18
14
 
19
15
  // 正方形网格
@@ -61,8 +61,9 @@ export default class MktMesh extends Mesh<BufferGeometry, ShaderMaterial> {
61
61
  * ⇒ 与编辑态 `mktMeshEditRenderer._slotPanos` **同一份算法、同一个常数**(预览看到的那几张 = 编辑器里的那几张,均为 8 个全景槽)。
62
62
  * 存**对象引用**不存下标(删点会让下标整体前移,引用不会认错人)。
63
63
  * 消费方 = `feedFaceMapping`(墙 8 格);⭐ 10-03 旨② 后预览立方体与墙**共用同一份材质**,
64
- * 立方体几何无 `aPanoIndex` ⇒ `vPanoIndex ≡ 0` ⇒ 它显示的就是 0 号槽那张(墙与立方体天然同源,
65
- * 原来那条「把中心那几张抄给立方体单全景材质」的 `currentTiles` 旁路已整条删除)。
64
+ * ⭐ 10-12 旨后立方体**逐颗自带序号**(`InstancedChild.panoIndex` → 逐实例 `aPanoIndex`),
65
+ * 不再是从前那句「几何没这条 attribute ⇒ `vPanoIndex ≡ 0` ⇒ 全体看 0 号槽那张」;
66
+ * 原来那条「把中心那几张抄给立方体单全景材质」的 `currentTiles` 旁路已整条删除。
66
67
  */
67
68
  private _slotPanos;
68
69
  /**
@@ -72,9 +73,13 @@ export default class MktMesh extends Mesh<BufferGeometry, ShaderMaterial> {
72
73
  * · 只读 XZ ⇒ 与名册历代那把「水平距离」尺同一把(09-28 旨),高度差不进尺子。
73
74
  * · `null` ⇒ 回落 `camera.position`(老口径):发布页那一路没有控制器引用,不注入就一切照旧。
74
75
  * · 存的是**引用**(OrbitControls 原地改它那个 Vector3)⇒ 消费方设一次即可,不必每帧重设。
75
- * · ⚠️ 全景点矩阵本就是**世界矩阵**,锚点也取世界坐标;⛔ 别再乘一遍 `matrixWorld`(同 `updateTexture` 里那句提醒)。
76
+ * · 注入的是**世界坐标**;`updateTexture` 里先 `worldToLocal` 换算到本网格局部空间再比距离
77
+ * (全景矩阵与着色器取图的 `vProjPos` 都在局部空间,见那里的 2026-10-11 丙旨说明)。
78
+ * ⛔ 反过来去给全景矩阵乘 `matrixWorld` 是错的:那会让 JS 侧的尺子和 shader 里的取图各走一路。
76
79
  */
77
80
  private _rosterCenter;
81
+ /** 锚点换算到局部空间的落点(每帧复用同一只临时量,避免分配) */
82
+ private _rosterAnchorLocal;
78
83
  /**
79
84
  * ⭐ 皇上旨 2026-10-03「整套搬进库(彻底同源)」:库侧不再自养「按全景序号取整槽、齐活才写」那一路,
80
85
  * 改成与编辑态**同一份换绑策略**(`./panoSlotBind`)+ 同一口径的三张表:
@@ -107,8 +107,9 @@ export default class MktMesh extends Mesh {
107
107
  * ⇒ 与编辑态 `mktMeshEditRenderer._slotPanos` **同一份算法、同一个常数**(预览看到的那几张 = 编辑器里的那几张,均为 8 个全景槽)。
108
108
  * 存**对象引用**不存下标(删点会让下标整体前移,引用不会认错人)。
109
109
  * 消费方 = `feedFaceMapping`(墙 8 格);⭐ 10-03 旨② 后预览立方体与墙**共用同一份材质**,
110
- * 立方体几何无 `aPanoIndex` ⇒ `vPanoIndex ≡ 0` ⇒ 它显示的就是 0 号槽那张(墙与立方体天然同源,
111
- * 原来那条「把中心那几张抄给立方体单全景材质」的 `currentTiles` 旁路已整条删除)。
110
+ * ⭐ 10-12 旨后立方体**逐颗自带序号**(`InstancedChild.panoIndex` → 逐实例 `aPanoIndex`),
111
+ * 不再是从前那句「几何没这条 attribute ⇒ `vPanoIndex ≡ 0` ⇒ 全体看 0 号槽那张」;
112
+ * 原来那条「把中心那几张抄给立方体单全景材质」的 `currentTiles` 旁路已整条删除。
112
113
  */
113
114
  _slotPanos = [];
114
115
  /**
@@ -118,9 +119,13 @@ export default class MktMesh extends Mesh {
118
119
  * · 只读 XZ ⇒ 与名册历代那把「水平距离」尺同一把(09-28 旨),高度差不进尺子。
119
120
  * · `null` ⇒ 回落 `camera.position`(老口径):发布页那一路没有控制器引用,不注入就一切照旧。
120
121
  * · 存的是**引用**(OrbitControls 原地改它那个 Vector3)⇒ 消费方设一次即可,不必每帧重设。
121
- * · ⚠️ 全景点矩阵本就是**世界矩阵**,锚点也取世界坐标;⛔ 别再乘一遍 `matrixWorld`(同 `updateTexture` 里那句提醒)。
122
+ * · 注入的是**世界坐标**;`updateTexture` 里先 `worldToLocal` 换算到本网格局部空间再比距离
123
+ * (全景矩阵与着色器取图的 `vProjPos` 都在局部空间,见那里的 2026-10-11 丙旨说明)。
124
+ * ⛔ 反过来去给全景矩阵乘 `matrixWorld` 是错的:那会让 JS 侧的尺子和 shader 里的取图各走一路。
122
125
  */
123
126
  _rosterCenter = null;
127
+ /** 锚点换算到局部空间的落点(每帧复用同一只临时量,避免分配) */
128
+ _rosterAnchorLocal = new Vector3();
124
129
  /**
125
130
  * ⭐ 皇上旨 2026-10-03「整套搬进库(彻底同源)」:库侧不再自养「按全景序号取整槽、齐活才写」那一路,
126
131
  * 改成与编辑态**同一份换绑策略**(`./panoSlotBind`)+ 同一口径的三张表:
@@ -691,15 +696,21 @@ export default class MktMesh extends Mesh {
691
696
  this.activeIndex = -1;
692
697
  return;
693
698
  }
694
- const ref = this._rosterCenter ?? camera.position;
699
+ // ⭐ 皇上旨 2026-10-11 丙:尺子的两端必须落在**同一个空间**。注入的锚点是世界坐标,而下面那把尺子量的
700
+ // 全景位置记在本网格的**局部(制图)空间** —— 依据是着色器自己:`vProjPos = uProjInvMatrix·modelMatrix·pos`
701
+ // = M⁻¹·M·pos = 局部(`uProjInvMatrix` 正是 `syncProjInvMatrix` 里那句 `matrixWorld` 求逆),片元再拿
702
+ // `dir = vProjPos - tm[3].xyz` 取图 ⇒ 全景矩阵只可能和 `vProjPos` 同空间,即局部。
703
+ // 所以换算放在**锚点这一端**(`worldToLocal`),⛔ 不去给全景矩阵乘 `matrixWorld`:那是把 JS 的尺子
704
+ // 和 shader 的取图拆成两路。网格无变换时这一步是恒等 ⇒ 老项目逐字不变;有旋转时(消费方给 mkt 加了
705
+ // `rotation.y`)原来会把「往世界的某一头走」量成「往局部的另一头走」,人走到位了名册还不动。
706
+ const ref = this._rosterAnchorLocal.copy(this._rosterCenter ?? camera.position);
707
+ this.worldToLocal(ref);
695
708
  const dists = [];
696
709
  for (let i = 0; i < n; i++) {
697
710
  const e = this.textures[i].matrix.elements;
698
711
  this._tmpV3.set(e[12], e[13], e[14]);
699
- // ⚠️ 全景点矩阵**本身就是世界矩阵**(见上方 textures 字段注释),位置已在世界空间,
700
- // 可直接与锚点的世界坐标比距离 —— 这里**绝不能再乘 matrixWorld**:那是双重变换,
701
- // MktMesh 一有整体变换就会算错「离锚点最近的是哪张」(选错全景)。
702
- // (2026-09-19 曾误以为它记在模型空间而多乘了一次,趁 MktDevMesh 对齐时一并纠正。)
712
+ // ⚠️ 全景点矩阵记在本网格的局部空间(与 `wallPoints` 同一空间,见上面丙旨那段着色器推导),
713
+ // 所以拿来直接和**已换算到局部**的 `ref` 比距离;⛔ 这里绝不乘 `matrixWorld`(双重变换 = 选错全景)。
703
714
  // ⭐ 09-28 09:33 旨:挑图与编辑器取图同一把「**水平距离**」尺(XZ 平面,不含高度差)。
704
715
  // const d = this._tmpV3.distanceTo(camera.position); // 旧原理:三维直线距离——全景点同高(y 恒 1.6)时与本式排序等价,注释保留备查
705
716
  // ⭐ 10-07 第二十一道旨:尺子的另一端从相机位置换成 `ref`(控制器中心点;未注入时它就是相机位置)。
@@ -791,6 +802,10 @@ export default class MktMesh extends Mesh {
791
802
  * ⭐ `rt:` 虚拟键(32 瓦片拼合槽)走拼合器 peek;⛔ 不在这里 pump(每帧驱动点唯一,见 `updateTexture`,
792
803
  * 否则一帧画好几格 = 把「每帧只载入一张新纹理」那道闸从后门拆了)。 */
793
804
  _peekTileAt(key, original) {
805
+ // ⭐ 2026-10-25:空地址 = 「这个点还没设图片」,不是一条能加载的 URL ⇒ 直接判没有。
806
+ // 放过去会让 ensureTileTexture 拿空串请求当前文档地址、失败后每帧重试。
807
+ if (!key)
808
+ return null;
794
809
  if (isRtStitchKey(key)) {
795
810
  const p = rtStitchKeyParts(key);
796
811
  if (!p)
@@ -828,6 +843,9 @@ export default class MktMesh extends Mesh {
828
843
  * ⚠️ 皇上旨 2026-09-28「加载瓦片的时候, 瓦片纹理不需要添加 oss 的参数」⇒ 真瓦片(`original=true`,现行 32 片/全景)走原图,
829
844
  * 整图档才按 ossSize 档缩(`resolveOssUrl`)。 */
830
845
  ensureTileTexture(key, original = false) {
846
+ // ⭐ 2026-10-25:空地址直接判「没有」,不起载(与编辑态 ensureFloorTexture 同一道闸)。
847
+ if (!key)
848
+ return null;
831
849
  const cached = this._texCache.get(key);
832
850
  if (cached)
833
851
  return cached;
@@ -877,8 +895,9 @@ export default class MktMesh extends Mesh {
877
895
  if (this._glRenderer)
878
896
  this._glRenderer.initTexture(tex);
879
897
  }
880
- catch (e) {
881
- console.warn("[MktMesh] 瓦片预上传失败,交给常规渲染路径自行上传:", e);
898
+ catch {
899
+ // 皇上旨 2026-10-12「日志都去掉」⇒ 这里不再出声;降级路径本身不变(下面照记「已处理」,
900
+ // 最坏退回 three 在绑定那一帧自己上传的老路径)。
882
901
  }
883
902
  // ⚠️ 成败都记「已处理」。不记 ⇒ 这张永远进不了 `_texUploaded` ⇒ 那一格永远换不上新图,
884
903
  // 比「卡一下」严重得多;记了最坏也只是退回 three 在绑定那一帧自己上传的老路径。
@@ -922,6 +941,18 @@ export default class MktMesh extends Mesh {
922
941
  continue;
923
942
  }
924
943
  idxU[s] = this.textures.indexOf(info);
944
+ // ⭐ 2026-10-25 皇上旨「把默认图去掉,图片没有加载的时候就显示纯灰色」:
945
+ // 这个点**没设图片**(url 空且没有切片)⇒ 按空槽喂料,权重 0 ⇒ 片元回落 uFaceMissingColor 中性灰。
946
+ // ⛔ 别把空地址放下去:空 key 会走到 `_peekTileAt` → `ensureTileTexture("")` 发一次空请求
947
+ // (解析成当前文档地址),失败后下一帧再试 = 每帧一个废请求。序号照留(归属还在,只是没图)。
948
+ const hasSource = !!info.url || !!(info.tiles && info.tiles.length > 0);
949
+ if (!hasSource) {
950
+ for (let k = 0; k < RT_STITCH_SLOT_COUNT; k++)
951
+ panos[base + k] = this._placeholder;
952
+ mats[s].identity();
953
+ ws[s] = 0;
954
+ continue;
955
+ }
925
956
  // 各槽喂什么地址 = 「用户选的形态 + 该点有没有切过片」共同决定(whole 或无 tiles ⇒ 各槽同为一张整图)
926
957
  const tiles = mktPanoTexUrls(info.url, info.tiles, this._panoTexMode);
927
958
  // ⚠️ 「是不是真瓦片」只算一次:喂地址(走不走 OSS 尺寸档)与写 uPanoTiled 共用同一个值
@@ -1032,12 +1063,10 @@ export default class MktMesh extends Mesh {
1032
1063
  // setWallPoints 已按位置重算过映射(旧为空 → 全 -1),此处用存档里的逐面指派覆盖。
1033
1064
  // 几何拓扑由同一份 wallPoints 重建,面索引与导出时一致 ⇒ 逐面写入即可对齐。
1034
1065
  // ⭐ 皇上旨 2026-10-03「补」:长度不符**不再整份丢弃**——按较小长度逐面灌回(存档多出的面丢掉,
1035
- // 墙变长多出来的那些面保持 setWallPoints 按位置继承到的值),并把两个数 warn 出来(不静默吞)。
1066
+ // 墙变长多出来的那些面保持 setWallPoints 按位置继承到的值)。
1067
+ // 2026-10-12 旨「日志都去掉」⇒ 这一条不再 warn,差值只按较小者静默还原。
1036
1068
  const imported = (data.panoFaceMapping && data.panoFaceMapping.length ? data.panoFaceMapping : []);
1037
1069
  const faceCount = this.panoFaceMapping.length;
1038
- if (imported.length && imported.length !== faceCount) {
1039
- console.warn(`[MktMesh] 存档序号映射面数 ${imported.length} ≠ 当前墙体面数 ${faceCount},按较小者逐面还原(差值来自墙点/墙高变化)`);
1040
- }
1041
1070
  const restore = Math.min(imported.length, faceCount);
1042
1071
  if (restore > 0) {
1043
1072
  for (let f = 0; f < restore; f++)