three-base 2.0.172 → 2.0.180

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 (127) hide show
  1. package/FPScontrol.d.ts +15 -24
  2. package/FPScontrol.js +63 -87
  3. package/FPScontrol.ts +64 -88
  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 +3 -2
  10. package/MktMesh/MktMesh.js +27 -8
  11. package/MktMesh/MktMesh.ts +24 -8
  12. package/MktMesh/boxLine2.d.ts +42 -0
  13. package/MktMesh/boxLine2.js +185 -0
  14. package/MktMesh/boxLine2.ts +222 -0
  15. package/MktMesh/imagePlane.d.ts +60 -0
  16. package/MktMesh/imagePlane.js +158 -0
  17. package/MktMesh/imagePlane.ts +203 -0
  18. package/MktMesh/imageTileLoader.d.ts +19 -0
  19. package/MktMesh/imageTileLoader.js +55 -0
  20. package/MktMesh/imageTileLoader.ts +64 -0
  21. package/MktMesh/mktMappingShader.d.ts +6 -5
  22. package/MktMesh/mktMappingShader.js +26 -19
  23. package/MktMesh/mktMappingShader.ts +28 -19
  24. package/MktMesh/mktShader.d.ts +127 -58
  25. package/MktMesh/mktShader.js +192 -117
  26. package/MktMesh/mktShader.ts +251 -127
  27. package/MktMesh/modelSlot.d.ts +123 -0
  28. package/MktMesh/modelSlot.js +339 -0
  29. package/MktMesh/modelSlot.ts +383 -0
  30. package/MktMesh/panoSlotRoster.d.ts +2 -2
  31. package/MktMesh/panoSlotRoster.js +9 -7
  32. package/MktMesh/panoSlotRoster.ts +9 -7
  33. package/MktMesh/panoTileStitcher.d.ts +20 -13
  34. package/MktMesh/panoTileStitcher.js +97 -76
  35. package/MktMesh/panoTileStitcher.ts +119 -90
  36. package/PipeMesh/PipeJoint.d.ts +22 -0
  37. package/PipeMesh/PipeJoint.js +33 -0
  38. package/PipeMesh/PipeJoint.ts +38 -0
  39. package/PipeMesh/PipeMesh.d.ts +94 -22
  40. package/PipeMesh/PipeMesh.js +192 -53
  41. package/PipeMesh/PipeMesh.ts +223 -76
  42. package/PipeMesh/PipeStraight.d.ts +19 -0
  43. package/PipeMesh/PipeStraight.js +34 -0
  44. package/PipeMesh/PipeStraight.ts +45 -0
  45. package/PipeMesh/axisSnap.d.ts +52 -0
  46. package/PipeMesh/axisSnap.js +52 -0
  47. package/PipeMesh/axisSnap.ts +93 -0
  48. package/PipeMesh/directRoute.d.ts +85 -0
  49. package/PipeMesh/directRoute.js +126 -0
  50. package/PipeMesh/directRoute.ts +190 -0
  51. package/PipeMesh/index.d.ts +6 -0
  52. package/PipeMesh/index.js +6 -0
  53. package/PipeMesh/index.ts +7 -1
  54. package/PipeMesh/pipeMaterial.d.ts +16 -0
  55. package/PipeMesh/pipeMaterial.js +23 -0
  56. package/PipeMesh/pipeMaterial.ts +26 -0
  57. package/ThreeBase.d.ts +1 -39
  58. package/ThreeBase.js +38 -147
  59. package/ThreeBase.ts +1176 -1302
  60. package/instanced/InstancedBatch.d.ts +14 -1
  61. package/instanced/InstancedBatch.js +53 -3
  62. package/instanced/InstancedBatch.ts +62 -3
  63. package/instanced/InstancedChild.d.ts +24 -0
  64. package/instanced/InstancedChild.js +40 -0
  65. package/instanced/InstancedChild.ts +41 -0
  66. package/instanced/InstancedGroup.d.ts +48 -0
  67. package/instanced/InstancedGroup.js +45 -1
  68. package/instanced/InstancedGroup.ts +85 -0
  69. package/package.json +22 -7
  70. package/pass/debugDepthState.d.ts +16 -8
  71. package/pass/debugDepthState.js +4 -0
  72. package/pass/debugDepthState.ts +27 -9
  73. package/pass/glow_pass.js +11 -94
  74. package/pass/glow_pass.ts +11 -97
  75. package/pass/ssao_pass.d.ts +9 -23
  76. package/pass/ssao_pass.js +41 -128
  77. package/pass/ssao_pass.ts +36 -166
  78. package/pass/stroke_pass.js +3 -0
  79. package/pass/stroke_pass.ts +4 -0
  80. package/shaders/debugDepthCompareShader.d.ts +1 -1
  81. package/shaders/debugDepthCompareShader.js +1 -1
  82. package/shaders/debugDepthCompareShader.ts +1 -1
  83. package/shaders/debugDepthJudgeShader.d.ts +1 -1
  84. package/shaders/debugDepthJudgeShader.js +1 -1
  85. package/shaders/debugDepthJudgeShader.ts +1 -1
  86. package/PipeMesh/PathGeometry.d.ts +0 -44
  87. package/PipeMesh/PathGeometry.js +0 -307
  88. package/PipeMesh/PathGeometry.ts +0 -343
  89. package/PipeMesh/PathPoint.d.ts +0 -17
  90. package/PipeMesh/PathPoint.js +0 -31
  91. package/PipeMesh/PathPoint.ts +0 -36
  92. package/PipeMesh/PathPointList.d.ts +0 -31
  93. package/PipeMesh/PathPointList.js +0 -209
  94. package/PipeMesh/PathPointList.ts +0 -227
  95. package/PipeMesh/PathTubeGeometry.d.ts +0 -25
  96. package/PipeMesh/PathTubeGeometry.js +0 -130
  97. package/PipeMesh/PathTubeGeometry.ts +0 -146
  98. package/WaterFlow/FloatingDuck.d.ts +0 -88
  99. package/WaterFlow/FloatingDuck.js +0 -307
  100. package/WaterFlow/FloatingDuck.ts +0 -445
  101. package/WaterFlow/GPUFluidSimulation.d.ts +0 -56
  102. package/WaterFlow/GPUFluidSimulation.js +0 -785
  103. package/WaterFlow/GPUFluidSimulation.ts +0 -827
  104. package/WaterFlow/ReservoirSystem.d.ts +0 -106
  105. package/WaterFlow/ReservoirSystem.js +0 -621
  106. package/WaterFlow/ReservoirSystem.ts +0 -754
  107. package/WaterFlow/SPHField.d.ts +0 -35
  108. package/WaterFlow/SPHField.js +0 -204
  109. package/WaterFlow/SPHField.ts +0 -228
  110. package/WaterFlow/ScreenSpaceFluidPass.d.ts +0 -69
  111. package/WaterFlow/ScreenSpaceFluidPass.js +0 -736
  112. package/WaterFlow/ScreenSpaceFluidPass.ts +0 -789
  113. package/WaterFlow/ShallowWaterSurface.d.ts +0 -45
  114. package/WaterFlow/ShallowWaterSurface.js +0 -441
  115. package/WaterFlow/ShallowWaterSurface.ts +0 -510
  116. package/WaterFlow/WaterFlow.d.ts +0 -87
  117. package/WaterFlow/WaterFlow.js +0 -171
  118. package/WaterFlow/WaterFlow.ts +0 -219
  119. package/WaterFlow/types.d.ts +0 -161
  120. package/WaterFlow/types.js +0 -1
  121. package/WaterFlow/types.ts +0 -189
  122. package/WaterFlow/waterFlowPass.d.ts +0 -3
  123. package/WaterFlow/waterFlowPass.js +0 -20
  124. package/WaterFlow/waterFlowPass.ts +0 -40
  125. package/shaders/debugExcludedShader.d.ts +0 -15
  126. package/shaders/debugExcludedShader.js +0 -48
  127. package/shaders/debugExcludedShader.ts +0 -50
@@ -0,0 +1,26 @@
1
+ import { DoubleSide, MeshStandardMaterial } from "three";
2
+
3
+ /**
4
+ * 直管与弯头共用一份材质。
5
+ *
6
+ * ⭐ 为什么底色是白:实例化那条路,逐实例颜色走 `InstancedMesh.instanceColor`(InstancedBatch 预填 1.0,
7
+ * setColor 覆盖),three 里最终 diffuse = material.color × instanceColor。材质底色若非白,setColor 的值
8
+ * 就会被整体压暗,面板上「这根管子涂什么色」就对不上画面了。
9
+ * ⭐ 为什么两边共享同一份:材质只有一份 ⇒ 粗糙度/金属度改一次,两个 batch(直管、弯头)同时跟上;
10
+ * 合批是按 geometry+material 分桶的,共享材质不会把它们并成一个 batch(几何不同),draw call 仍是 2。
11
+ * ⚠️ DoubleSide 是必需的:直管是开口圆柱(无端面),从管口往里看要能看到内壁,否则管子里是黑的空洞。
12
+ */
13
+ export function createPipeMaterial(): MeshStandardMaterial {
14
+ return new MeshStandardMaterial({
15
+ color: 0xffffff,
16
+ roughness: 0.35,
17
+ metalness: 0.5,
18
+ side: DoubleSide,
19
+ });
20
+ }
21
+
22
+ /** 全库共享的那一份材质实例(InstancedChild 的 static material 必须是同一个对象才会同桶/同改) */
23
+ export const pipeMaterial = createPipeMaterial();
24
+
25
+ /** 管道默认颜色,取自参考稿 */
26
+ export const PIPE_DEFAULT_COLOR = 0x4fc3f7;
package/ThreeBase.d.ts CHANGED
@@ -4,7 +4,6 @@ import ThreeMouse from "./ThreeMouse";
4
4
  import InstancedGroup from "./instanced/InstancedGroup";
5
5
  import Transition from "./Transition";
6
6
  import { type DebugDepthMode } from "./pass/debugDepthState";
7
- import { WaterFlow } from "./WaterFlow/WaterFlow";
8
7
  import type { ThreeBaseEventTypeMap } from "./EventMap";
9
8
  type CameraType = "perspectiveCamera" | "orthographicCamera";
10
9
  type ControlType = "OrbitControls" | "MapControls";
@@ -79,22 +78,14 @@ export default class ThreeBase extends EventDispatcher<ThreeBaseEventTypeMap> {
79
78
  get effectiveRatio(): number;
80
79
  baseDepthTexture: DepthTexture;
81
80
  baseRenderTarget: WebGLRenderTarget<Texture>;
82
- /** 可选的屏幕空间水流对象(WaterFlow)。默认 null;调用 enableWaterFlow() 后创建。启用时
83
- * 每帧消费 baseRenderTarget/baseDepthTexture,把水面合成进后处理链(不额外渲染主场景)。 */
84
- waterFlow: WaterFlow | null;
85
- private _waterFlowLastTime;
86
- waterFlowElapsed: number;
87
- excludedMaskRenderTarget: WebGLRenderTarget<Texture>;
88
81
  depthRenderTarget: WebGLRenderTarget<Texture>;
89
82
  aoDepthTexture: DepthTexture;
90
83
  /**
91
84
  * 调试用:深度预览模式。由面板「深度调试」切换,便于逐一看各深度图排查"深度测试全部失效"根因。
92
85
  * - "none" :正常渲染(默认)
93
- * - "global" :仅预览可见深度图(baseDepthTexture,含地板)。全白=深度为空→renderVisibleDepthPass 没写进深度。
86
+ * - "global" :仅预览可见深度图(baseDepthTexture;2026-10-18 起收全场景对象,含地板)。全白=深度为空→renderVisibleDepthPass 没写进深度。
94
87
  * - "ao" :仅预览 AO 深度图(aoDepthTexture = 法线 pass 顺带写入)。用于确认深度管线本身是否工作。
95
88
  * - "compare" :R=全局 base 深度,G=最近一次 glow/stroke 选区 select 深度。两路任一全白即该侧写入失败。
96
- * - "excluded":深度图灰度 + 「被排除出深度图的面」叠红(红=该面写不进深度,永远挡不住后处理)。
97
- * 物体区域(G 暗)若 B 全黑 → 判定从不触发;再看该区 R/G 谁大即可定位是谁缺深度。
98
89
  * 兼容旧控制台入口:设置 `window.__BASE_DEPTH_VIS = true` 等价于切到 "global"。
99
90
  * 通用控制台入口:任意页面都可 `window.__TB_DEBUG_DEPTH = "judge"`(优先级高于面板属性)。
100
91
  */
@@ -165,35 +156,6 @@ export default class ThreeBase extends EventDispatcher<ThreeBaseEventTypeMap> {
165
156
  gridHelper: GridHelper;
166
157
  axesHelper: AxesHelper;
167
158
  init(): void;
168
- /**
169
- * 启用屏幕空间水流(GPGPU 粒子流体)。默认关闭,需显式调用或携带 ?waterflow=1。
170
- * 创建后每帧自动消费 base 深度 + 当前合成画面,把水面合成进后处理链,不自渲染主场景。
171
- * @param options.size 粒子网格边长(size×size 粒子),越大越细腻、越费
172
- * @param options.speed 射流初速
173
- * @param options.aperture 喷嘴开度
174
- * @param options.nozzle 喷流起点坐标 [x,y,z],默认 [0.58,1.55,0]
175
- * @param options.jetDirection 喷流方向(轴向,会被归一化),默认 [1,0,0](沿 +X)
176
- * @param options.collision 是否开启粒子与 basin/地面碰撞回弹,默认 true
177
- */
178
- enableWaterFlow(options?: {
179
- size?: number;
180
- speed?: number;
181
- aperture?: number;
182
- nozzle?: [number, number, number];
183
- jetDirection?: [number, number, number];
184
- collision?: boolean;
185
- }): void;
186
- /** 运行时改喷流起点(喷嘴)坐标(WaterFlow 已启用时有效) */
187
- setWaterFlowNozzle(x: number, y: number, z: number): void;
188
- /** 运行时改喷流方向(轴向,会被归一化) */
189
- setWaterFlowJetDirection(x: number, y: number, z: number): void;
190
- /** 运行时开关粒子与 basin/地面碰撞回弹 */
191
- setWaterFlowCollision(enabled: boolean): void;
192
- /**
193
- * 关闭屏幕空间水流并释放其 GPU 资源(enableWaterFlow 的反操作)。
194
- * 切走页面时必须调用,否则其它页面 render 仍会合成水面(this.waterFlow 非空)。
195
- */
196
- disableWaterFlow(): void;
197
159
  resetLookAt({ position, center, }: {
198
160
  position: Vector3;
199
161
  center: Vector3;
package/ThreeBase.js CHANGED
@@ -18,17 +18,14 @@ import frosted_glass_pass from "./pass/frosted_glass_pass";
18
18
  import { flushLensflareOverlays } from "./lensflare/LensFlare";
19
19
  import glow_pass from "./pass/glow_pass";
20
20
  import stroke_pass from "./pass/stroke_pass";
21
- import ssao_pass, { renderVisibleDepthPass, renderExcludedMaskPass } from "./pass/ssao_pass";
21
+ import ssao_pass, { renderVisibleDepthPass } from "./pass/ssao_pass";
22
22
  import screenBloomPass from "./pass/screen_bloom_pass";
23
23
  import copyShader from "./shaders/copyShader";
24
24
  import { baseTextureToRenderShader } from "./shaders/baseTextureToRenderShader";
25
25
  import baseDepthVisShader from "./shaders/baseDepthVisShader";
26
26
  import debugDepthCompareShader from "./shaders/debugDepthCompareShader";
27
27
  import debugDepthJudgeShader from "./shaders/debugDepthJudgeShader";
28
- import debugExcludedShader from "./shaders/debugExcludedShader";
29
28
  import { debugDepthState } from "./pass/debugDepthState";
30
- import { WaterFlow } from "./WaterFlow/WaterFlow";
31
- import waterFlowPass from "./WaterFlow/waterFlowPass";
32
29
  import threeLoader from "./threeLoader";
33
30
  import threeUtils from "./threeUtils";
34
31
  import fsQuad from "./pass/fsQuad";
@@ -78,21 +75,23 @@ export default class ThreeBase extends EventDispatcher {
78
75
  // 全局超采样/分辨率倍率(SSAA):base / 深度 / 法线 / 效果 mask / 屏幕合成 全部按
79
76
  // effectiveRatio × resolution 内部超采样渲染,终处理 FXAA 降采样输出到屏幕。
80
77
  // 全链路同倍率 → 各 RT 严格 1:1 对齐:几何锯齿、效果边缘锯齿、辉光漏光(深度 vs mask 错位)、
81
- // mask 合成 UV 缩放错位、SSAO 深度错位变黑 一并消除。默认 2 = 每维 2×、总像素 4×;
82
- // 代价全链路填充 ×4(base + 深度 + 法线 + 后处理 SSAO/cover/frosted)。要省性能整体降 1
83
- // (关超采样,仅 FXAA 兜底,几何硬边锯齿回弹)。历史坑:baseRenderScale/auxRenderScale/
84
- // effectRenderScale 三参各自为政,倍率不同步必错位,故统一为单参数 resolution 管全局。
78
+ // mask 合成 UV 缩放错位、SSAO 深度错位变黑 一并消除。
79
+ // ⭐ 默认 1(原生分辨率):2026-10-21 皇上旨「有点卡,分辨率改成 1」。原默认 2 = 每维 2×、
80
+ // 总像素 4×,全链路填充 ×4 且 35 张 RT 显存约 1.1 GB(1920×1080 画布)。降到 1 后填充与显存
81
+ // 均降约 75%,几何硬边锯齿由终处理 FXAA 兜底。需要纹理摩尔纹治本时,面板上再调回 2。
82
+ // 历史坑:baseRenderScale/auxRenderScale/effectRenderScale 三参各自为政,倍率不同步必错位,
83
+ // 故统一为单参数 resolution 管全局。
85
84
  // ⚠️ 必须用 getter/setter,不能是普通字段:所有 RT 尺寸只在 updateRenderTargetSizes()
86
85
  // 里按 effectiveRatio × resolution 计算,而该方法过去只被 setSize()(容器尺寸变化)调用
87
86
  // → 运行时改 resolution 不会重建任何 RT,画面毫无变化(表现为"调分辨率没感觉")。
88
87
  // 故 setter 里改动倍率后立刻重建全部 RT。
89
- _resolution = 2;
88
+ _resolution = 1;
90
89
  get resolution() {
91
90
  return this._resolution;
92
91
  }
93
92
  set resolution(value) {
94
93
  // 夹到合理区间:0 或负值会让 RT 尺寸为 0,WebGL 报 framebuffer incomplete
95
- const next = Math.min(4, Math.max(0.25, Number.isFinite(value) ? value : 2));
94
+ const next = Math.min(4, Math.max(0.25, Number.isFinite(value) ? value : 1));
96
95
  if (next === this._resolution) {
97
96
  return;
98
97
  }
@@ -239,19 +238,6 @@ export default class ThreeBase extends EventDispatcher {
239
238
  });
240
239
  return baseRenderTarget;
241
240
  })();
242
- /** 可选的屏幕空间水流对象(WaterFlow)。默认 null;调用 enableWaterFlow() 后创建。启用时
243
- * 每帧消费 baseRenderTarget/baseDepthTexture,把水面合成进后处理链(不额外渲染主场景)。 */
244
- waterFlow = null;
245
- _waterFlowLastTime = 0;
246
- waterFlowElapsed = 0;
247
- // 调试用:被排除面 mask 渲染目标(仅「排除面标记」调试档使用,尺寸随主渲染目标同步)
248
- excludedMaskRenderTarget = new WebGLRenderTarget(128, 128, {
249
- minFilter: LinearFilter,
250
- magFilter: LinearFilter,
251
- format: RGBAFormat,
252
- stencilBuffer: false,
253
- depthBuffer: false,
254
- });
255
241
  // 深度专用渲染目标(无 MSAA,深度值稳定,供后处理深度比对使用)
256
242
  depthRenderTarget = new WebGLRenderTarget(128, 128, {
257
243
  minFilter: LinearFilter,
@@ -261,12 +247,13 @@ export default class ThreeBase extends EventDispatcher {
261
247
  depthTexture: this.baseDepthTexture,
262
248
  });
263
249
  // AO 深度纹理:**不再单独渲染一遍** —— 它挂在 normalRenderTarget 上当 depth attachment,
264
- // 法线 pass(renderAoNormalPass,excludeTransparent=true)渲染时深度由光栅器顺带写入,白拿一张。
265
- // (2026-09-14 优化:删掉原 ssao_pass 内那次独立的含地板深度 pass,每帧省一次全场景遍历。)
250
+ // 法线 pass(renderAoNormalPass)渲染时深度由光栅器顺带写入,白拿一张。
251
+ // (2026-09-14 优化:删掉原 ssao_pass 内那次独立的深度 pass,每帧省一次全场景遍历。)
266
252
  // SSAO 的 GTAO 采样它(与法线同源);合成时再与 depthRenderTarget(可见深度 = 各物体自身材质渲染)
267
253
  // 比对:AO 侧更近说明那像素记到屏幕上不可见的面(抠图空隙 / 单面墙背面)→ 作废该像素 AO。
268
- // ⚠️ 2026-10-11:地板(Ground1)现在两张图都写(旧的 aoFloor 排除特例已整条拆除),
269
- // 见 three-base/pass/ssao_pass.ts 文件头与复合守卫说明。
254
+ // ⚠️ 2026-10-18 皇上旨「所有的对象都要进入到深度图里面了,不需要用参数过滤掉了」⇒ 这张 AO 深度
255
+ // 和 baseDepthTexture 都收全场景对象(含地板、含半透明面、含 sprite/线条/点);原 excludeTransparent
256
+ // 参数与 userData.aoFloor 特例整条删除。见 three-base/pass/ssao_pass.ts 文件头(代价清单写在那里)。
270
257
  aoDepthTexture = (() => {
271
258
  const t = new DepthTexture(4096, 4096);
272
259
  t.format = DepthFormat;
@@ -277,11 +264,9 @@ export default class ThreeBase extends EventDispatcher {
277
264
  /**
278
265
  * 调试用:深度预览模式。由面板「深度调试」切换,便于逐一看各深度图排查"深度测试全部失效"根因。
279
266
  * - "none" :正常渲染(默认)
280
- * - "global" :仅预览可见深度图(baseDepthTexture,含地板)。全白=深度为空→renderVisibleDepthPass 没写进深度。
267
+ * - "global" :仅预览可见深度图(baseDepthTexture;2026-10-18 起收全场景对象,含地板)。全白=深度为空→renderVisibleDepthPass 没写进深度。
281
268
  * - "ao" :仅预览 AO 深度图(aoDepthTexture = 法线 pass 顺带写入)。用于确认深度管线本身是否工作。
282
269
  * - "compare" :R=全局 base 深度,G=最近一次 glow/stroke 选区 select 深度。两路任一全白即该侧写入失败。
283
- * - "excluded":深度图灰度 + 「被排除出深度图的面」叠红(红=该面写不进深度,永远挡不住后处理)。
284
- * 物体区域(G 暗)若 B 全黑 → 判定从不触发;再看该区 R/G 谁大即可定位是谁缺深度。
285
270
  * 兼容旧控制台入口:设置 `window.__BASE_DEPTH_VIS = true` 等价于切到 "global"。
286
271
  * 通用控制台入口:任意页面都可 `window.__TB_DEBUG_DEPTH = "judge"`(优先级高于面板属性)。
287
272
  */
@@ -531,11 +516,8 @@ export default class ThreeBase extends EventDispatcher {
531
516
  // 强制同步为 depthRenderTarget 尺寸,下面再手动对齐一次避免首帧抖动。
532
517
  this.depthRenderTarget.setSize(w, h);
533
518
  this.normalRenderTarget.setSize(w, h);
534
- this.excludedMaskRenderTarget.setSize(w, h);
535
519
  // 屏幕合成目标:同样跟随 resolution,全链路 1:1 对齐
536
520
  this.screenRenderTarget.setSize(w, h);
537
- // 水流后处理目标跟随同倍率重建(pass 内部粒子 RT 仍按 scale 降采样,compositeTarget 全分辨率)
538
- this.waterFlow?.resize(w, h);
539
521
  this.baseDepthTexture.image.width = w;
540
522
  this.baseDepthTexture.image.height = h;
541
523
  // 立即渲染一帧,避免静态场景下改了倍率却停在旧画面
@@ -607,92 +589,7 @@ export default class ThreeBase extends EventDispatcher {
607
589
  return axesHelper;
608
590
  })();
609
591
  init() {
610
- // 屏幕空间水流:?waterflow=1 时自动启用(默认关闭,需显式 enableWaterFlow 或此 URL 参数)。
611
- // 创建后每帧消费 base 深度 + 后处理合成画面,把水面合成进后处理链,不自渲染主场景。
612
- try {
613
- const params = new URLSearchParams(typeof location !== 'undefined' ? location.search : '');
614
- if (params.get('waterflow') === '1') {
615
- this.enableWaterFlow();
616
- }
617
- }
618
- catch (_e) {
619
- // 非浏览器环境(如 Node 测试/SSR)忽略
620
- }
621
- }
622
- /**
623
- * 启用屏幕空间水流(GPGPU 粒子流体)。默认关闭,需显式调用或携带 ?waterflow=1。
624
- * 创建后每帧自动消费 base 深度 + 当前合成画面,把水面合成进后处理链,不自渲染主场景。
625
- * @param options.size 粒子网格边长(size×size 粒子),越大越细腻、越费
626
- * @param options.speed 射流初速
627
- * @param options.aperture 喷嘴开度
628
- * @param options.nozzle 喷流起点坐标 [x,y,z],默认 [0.58,1.55,0]
629
- * @param options.jetDirection 喷流方向(轴向,会被归一化),默认 [1,0,0](沿 +X)
630
- * @param options.collision 是否开启粒子与 basin/地面碰撞回弹,默认 true
631
- */
632
- enableWaterFlow(options = {}) {
633
- if (this.waterFlow) {
634
- console.warn('[ThreeBase] WaterFlow 已启用,重复调用无效');
635
- return;
636
- }
637
- const { size = 200, speed = 2.4, aperture = 0.78, nozzle, jetDirection, collision = true, } = options;
638
- const waterFlow = new WaterFlow(this.renderer, {
639
- size,
640
- speed,
641
- aperture,
642
- nozzle: nozzle ? new Vector3(nozzle[0], nozzle[1], nozzle[2]) : undefined,
643
- jetDirection: jetDirection ? new Vector3(jetDirection[0], jetDirection[1], jetDirection[2]) : undefined,
644
- collision,
645
- });
646
- if (!waterFlow.supported) {
647
- console.warn('[ThreeBase] 当前环境不支持浮点纹理,WaterFlow 未启用');
648
- waterFlow.dispose();
649
- return;
650
- }
651
- // 创建 pass 并注入基础纹理(externalBase 模式);后续每帧 renderInto 会刷新注入的纹理。
652
- // ⚠️ 2026-10-08(WaterFlow 全量 TS 化):ScreenSpaceFluidPass 内部按透视相机建模
653
- // (setSize 读 camera.fov 算 pointScale、depthMaterial 走 projectionMatrix 重建深度),
654
- // 故此处显式窄化。getCamera() 在 cameraType==="orthographicCamera" 时会返回
655
- // OrthographicCamera —— 原 JS 同样会把 fov=undefined 传进去(pointScale 变 NaN),
656
- // 本次**只补类型、未改运行时行为**,保持与线上一致。
657
- waterFlow.createPass(this.scene, this.getCamera(), {
658
- colorTexture: this.baseRenderTarget.texture,
659
- depthTexture: this.baseDepthTexture,
660
- depthMode: 'logarithmic',
661
- });
662
- // 首帧按当前容器尺寸对齐(后续 setSize/resolution 变化由 updateRenderTargetSizes 兜底)。
663
- const w = Math.max(1, Math.round(this.size.x * this.effectiveRatio * this._resolution));
664
- const h = Math.max(1, Math.round(this.size.y * this.effectiveRatio * this._resolution));
665
- if (this.size.x > 1 && this.size.y > 1)
666
- waterFlow.resize(w, h);
667
- this.waterFlow = waterFlow;
668
- this._waterFlowLastTime = 0;
669
- this.waterFlowElapsed = 0;
670
- console.info('[ThreeBase] WaterFlow 已启用');
671
- }
672
- /** 运行时改喷流起点(喷嘴)坐标(WaterFlow 已启用时有效) */
673
- setWaterFlowNozzle(x, y, z) {
674
- this.waterFlow?.setNozzle(x, y, z);
675
- }
676
- /** 运行时改喷流方向(轴向,会被归一化) */
677
- setWaterFlowJetDirection(x, y, z) {
678
- this.waterFlow?.setJetDirection(x, y, z);
679
- }
680
- /** 运行时开关粒子与 basin/地面碰撞回弹 */
681
- setWaterFlowCollision(enabled) {
682
- this.waterFlow?.setCollision(enabled);
683
- }
684
- /**
685
- * 关闭屏幕空间水流并释放其 GPU 资源(enableWaterFlow 的反操作)。
686
- * 切走页面时必须调用,否则其它页面 render 仍会合成水面(this.waterFlow 非空)。
687
- */
688
- disableWaterFlow() {
689
- if (!this.waterFlow)
690
- return;
691
- this.waterFlow.dispose();
692
- this.waterFlow = null;
693
- this._waterFlowLastTime = 0;
694
- this.waterFlowElapsed = 0;
695
- console.info('[ThreeBase] WaterFlow 已关闭');
592
+ // 生命周期钩子:子类重写后调用 super.init()。当前无内置初始化动作。
696
593
  }
697
594
  // 重置控制器的位置
698
595
  resetLookAt({ position = this.perspectiveCamera.position, center = this.controls.target, }) {
@@ -959,17 +856,6 @@ export default class ThreeBase extends EventDispatcher {
959
856
  return; // 标识未渲染
960
857
  }
961
858
  this.needRender = false;
962
- // 水流模拟推进:独立于相机控制,按真实帧间隔累计时间推进 GPGPU 粒子模拟。
963
- // 默认 this.waterFlow 为 null(关闭),调用 enableWaterFlow() 或 ?waterflow=1 才创建。
964
- if (this.waterFlow && this.waterFlow.supported) {
965
- const wnow = performance.now();
966
- const wdt = this._waterFlowLastTime > 0
967
- ? Math.min((wnow - this._waterFlowLastTime) / 1000, 0.05)
968
- : 1 / 60;
969
- this._waterFlowLastTime = wnow;
970
- this.waterFlowElapsed += wdt;
971
- this.waterFlow.update(wdt, this.waterFlowElapsed);
972
- }
973
859
  if (this.controls.enabled) {
974
860
  // 让 OrbitControls 始终接管"当前渲染相机":OrbitControls 构造时只绑定了
975
861
  // perspectiveCamera,但渲染相机随 cameraType 切换。若切到正交相机时仍让 OrbitControls
@@ -1006,8 +892,8 @@ export default class ThreeBase extends EventDispatcher {
1006
892
  this.renderer.setRenderTarget(this.baseRenderTarget);
1007
893
  this.renderer.clear();
1008
894
  this.renderer.render(this.scene, camera);
1009
- // 可见深度 pass:用各物体自身材质渲染(含地板;sprite/线条/点与显式 aoTransparent 面除外),
1010
- // 产出 baseDepthTexture 供描边/发光/覆盖/磨砂做遮挡判定。
895
+ // 可见深度 pass:用各物体自身材质渲染整个场景(2026-10-18 起不再排除任何对象:含地板、
896
+ // 含半透明面、含 sprite/线条/点),产出 baseDepthTexture 供描边/发光/覆盖/磨砂做遮挡判定。
1011
897
  // 必须在 base render 之后、所有依赖深度的特效(描边/发光/覆盖/磨砂)之前更新,
1012
898
  // 否则这些特效会用到上一帧旧深度 → 遮挡判定错乱。法线 pass 已收进 ssao_pass 内部。
1013
899
  renderVisibleDepthPass(this.renderer, camera, this.scene, this.depthRenderTarget);
@@ -1057,12 +943,6 @@ export default class ThreeBase extends EventDispatcher {
1057
943
  }
1058
944
  // 一次性处理所有支持毛玻璃特效的对象
1059
945
  frosted_glass_pass(this.renderer, camera, this.scene, this.baseRenderTarget, this.baseDepthTexture, dpr);
1060
- // 屏幕空间水流:消费 base 深度 + 当前合成画面(含 ssao/覆盖/磨砂),把水面合成进
1061
- // screenRenderTarget。插在磨砂之后、screenBloom 之前,使水面高光也能被泛光处理。
1062
- // 默认关闭(this.waterFlow 为 null 时不产生任何开销)。
1063
- if (this.waterFlow && this.waterFlow.supported) {
1064
- waterFlowPass(this.renderer, camera, this.scene, this.baseRenderTarget, this.baseDepthTexture, this.waterFlow);
1065
- }
1066
946
  // 屏幕空间辉光(经典 gaussian bloom):纯颜色、无深度依赖,把亮度超阈值的部分做
1067
947
  // 连续高斯模糊后加性叠加回 screenRenderTarget。单分辨率多迭代,柔和均匀、无 mip 分层。
1068
948
  if (this.bloom.enable) {
@@ -1076,12 +956,16 @@ export default class ThreeBase extends EventDispatcher {
1076
956
  // 分辨率按实际帧缓冲像素(已乘 dpr)设置,修复高分屏下 FXAA 采样比例偏大失效的问题。
1077
957
  // ⚠️ 深度调试预览(面板「深度调试」切换,定位"深度测试全部失效"根因):
1078
958
  // 旧控制台入口 `window.__BASE_DEPTH_VIS = true` 仍可用,等价于切到 "global"。
1079
- // global → baseDepthTexture 灰度。全白=深度为空(renderVisibleDepthPass 没写进)→后处理一律显示在前;有灰阶=深度正常,问题在比对侧。
1080
- // ao → aoDepthTexture 灰度(含地板)。确认深度管线本身是否工作(GTAO 是否拿到正确深度)。
959
+ // global → baseDepthTexture 灰度(含全部对象,含地板)。全白=深度为空(renderVisibleDepthPass 没写进)→后处理一律显示在前;有灰阶=深度正常,问题在比对侧。
960
+ // ao → aoDepthTexture 灰度(同样含全部对象)。确认深度管线本身是否工作(GTAO 是否拿到正确深度)。
1081
961
  // compare → R=全局 base 深度,G=最近一次 glow/stroke 选区的 select 深度。两路任一全白即该侧写入失败。
1082
962
  // judge → R=base 原始深度、G=select 原始深度、B=判定结果(1=判为被遮挡应 discard)。
963
+ // strokeSelect → 【描边步骤 1】选区本体深度(selectDepthTexture),白色=空背景、灰=物体本体。
964
+ // strokeSelectBlur → 【描边步骤 5.5】描边外扩后的选区深度(selectDepthBlurTextureTarget),
965
+ // 物体轮廓比本体档更胖一圈即外扩生效。
1083
966
  // 通用控制台入口(任意页面可用,优先级高于面板属性):
1084
- // `window.__TB_DEBUG_DEPTH = "global" | "ao" | "compare" | "judge"`,设回 "none" 恢复。
967
+ // `window.__TB_DEBUG_DEPTH = "global" | "ao" | "compare" | "judge" | "strokeSelect" | "strokeSelectBlur"`,
968
+ // 设回 "none" 恢复。
1085
969
  const dbgWin = window.__TB_DEBUG_DEPTH;
1086
970
  const dbgMode = window.__BASE_DEPTH_VIS
1087
971
  ? "global"
@@ -1110,12 +994,19 @@ export default class ThreeBase extends EventDispatcher {
1110
994
  debugDepthState.lastSelectDepth ?? this.baseDepthTexture;
1111
995
  fsQuad.render(this.renderer, debugDepthJudgeShader);
1112
996
  }
1113
- else if (dbgMode === "excluded") {
1114
- // 先渲「被排除面 mask」,再与深度图叠加:红=挡不住任何后处理的面
1115
- renderExcludedMaskPass(this.renderer, camera, this.scene, this.excludedMaskRenderTarget);
1116
- debugExcludedShader.uniforms.tDepth.value = this.baseDepthTexture;
1117
- debugExcludedShader.uniforms.tMask.value = this.excludedMaskRenderTarget.texture;
1118
- fsQuad.render(this.renderer, debugExcludedShader);
997
+ else if (dbgMode === "strokeSelect") {
998
+ // 描边步骤 1:选区本体深度(selectDepthTexture,挂在 mask 目标上当 depth attachment,
999
+ // 由那趟光栅化顺带写入 ⇒ 零额外渲染代价)。
1000
+ baseDepthVisShader.uniforms.tDepth.value =
1001
+ debugDepthState.lastSelectDepth ?? this.baseDepthTexture;
1002
+ fsQuad.render(this.renderer, baseDepthVisShader);
1003
+ }
1004
+ else if (dbgMode === "strokeSelectBlur") {
1005
+ // 描边步骤 5.5:外扩后的选区深度(RGBA8 目标,对数深度存在 .r 通道)。
1006
+ // 与本体档对比看:外扩生效时物体轮廓会「胖一圈」,被遮挡的外扩环则被判 discard 后不参与。
1007
+ baseDepthVisShader.uniforms.tDepth.value =
1008
+ debugDepthState.lastSelectBlurDepth ?? this.baseDepthTexture;
1009
+ fsQuad.render(this.renderer, baseDepthVisShader);
1119
1010
  }
1120
1011
  flushLensflareOverlays(this.renderer, camera);
1121
1012
  return;