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,55 @@
1
+ /*
2
+ * @Description: 图片平面(「加平面」)的瓦片纹理加载器 —— ⭐ 2026-10-22 晚旨配套:图片平面**不用拼合器 RT**,
3
+ * 直接把上传切好的 4 张瓦片纹理绑到材质。本类负责「按 url 下载 + 异步解码 + 缓存在本 renderer 上下文」,
4
+ * 并把第 i 片的采样窗口(inset)算好交出去。
5
+ *
6
+ * 设计要点:
7
+ * - 纹理是 **WebGL 上下文私有**资源:编辑页 / 预览页各持一个实例(各自 GL context),⛔ 不跨 renderer 共享同一 Texture。
8
+ * - 复用库里 `loadPanoTexture`(fetch + createImageBitmap 工作线程解码、`imageOrientation:"flipY"` 预翻 + flipY=false,
9
+ * 与全景同一套上下翻约定);本类只补 `colorSpace = SRGBColorSpace`(硬件采样即解 sRGB→linear,与旧 RT 方案逐字节同口径)。
10
+ * - inset 用库的 `rtStitchTileInset(i, tw, th, IMAGE_TILE_GRID)`:上传多切 8px、采样只取中间干净块 ⇒ 接缝不回潮,
11
+ * 与上传切片 `rtStitchTileRects` 共用同一份几何(⛔ 不许在这里另算一份)。
12
+ * - 逐张就绪、逐张显影:未就绪那张 `get()` 返回 null ⇒ 调方把那片传 null(材质显示灰),下一帧就绪后即亮。
13
+ */
14
+ import { SRGBColorSpace, Vector4 } from "three";
15
+ import { loadPanoTexture, releasePanoTexture } from "./panoBitmapTexture";
16
+ import { IMAGE_TILE_GRID, rtStitchTileInset } from "./mktShader";
17
+ export class ImagePlaneTileLoader {
18
+ cache = new Map();
19
+ inflight = new Map();
20
+ /** 触发某张瓦片下载 + 解码(已缓存 / 在途则跳过);完成后填入 cache,下一帧 feed 即取到 */
21
+ preload(url) {
22
+ if (!url || this.cache.has(url) || this.inflight.has(url))
23
+ return;
24
+ const p = loadPanoTexture(url)
25
+ .then((tex) => {
26
+ tex.colorSpace = SRGBColorSpace; // 硬件采样解 sRGB→linear(与旧 RT 方案逐字节同口径)
27
+ const img = tex.image;
28
+ this.cache.set(url, { tex, w: img?.width ?? 0, h: img?.height ?? 0 });
29
+ })
30
+ .catch(() => {
31
+ // 下载 / 解码失败:留空,下一帧 preload 重新触发(不把半截纹理绑上去)
32
+ })
33
+ .finally(() => {
34
+ this.inflight.delete(url);
35
+ });
36
+ this.inflight.set(url, p);
37
+ }
38
+ /** 取已就绪的瓦片(未就绪返回 null) */
39
+ get(url) {
40
+ return this.cache.get(url) || null;
41
+ }
42
+ /** 第 i 片(行优先、图像左上起)的采样窗口;瓦片未就绪时返回整张 [0,0,1,1] */
43
+ inset(entry, i) {
44
+ if (!entry.w || !entry.h)
45
+ return new Vector4(0, 0, 1, 1);
46
+ const [u0, v0, u1, v1] = rtStitchTileInset(i, entry.w, entry.h, IMAGE_TILE_GRID);
47
+ return new Vector4(u0, v0, u1, v1);
48
+ }
49
+ /** 释放本 loader 持有的全部瓦片纹理(项目重置 / 卸载场景时调用;⛔ 不关共享占位纹理) */
50
+ clear() {
51
+ this.cache.forEach((e) => e.tex && releasePanoTexture(e.tex));
52
+ this.cache.clear();
53
+ this.inflight.clear();
54
+ }
55
+ }
@@ -0,0 +1,64 @@
1
+ /*
2
+ * @Description: 图片平面(「加平面」)的瓦片纹理加载器 —— ⭐ 2026-10-22 晚旨配套:图片平面**不用拼合器 RT**,
3
+ * 直接把上传切好的 4 张瓦片纹理绑到材质。本类负责「按 url 下载 + 异步解码 + 缓存在本 renderer 上下文」,
4
+ * 并把第 i 片的采样窗口(inset)算好交出去。
5
+ *
6
+ * 设计要点:
7
+ * - 纹理是 **WebGL 上下文私有**资源:编辑页 / 预览页各持一个实例(各自 GL context),⛔ 不跨 renderer 共享同一 Texture。
8
+ * - 复用库里 `loadPanoTexture`(fetch + createImageBitmap 工作线程解码、`imageOrientation:"flipY"` 预翻 + flipY=false,
9
+ * 与全景同一套上下翻约定);本类只补 `colorSpace = SRGBColorSpace`(硬件采样即解 sRGB→linear,与旧 RT 方案逐字节同口径)。
10
+ * - inset 用库的 `rtStitchTileInset(i, tw, th, IMAGE_TILE_GRID)`:上传多切 8px、采样只取中间干净块 ⇒ 接缝不回潮,
11
+ * 与上传切片 `rtStitchTileRects` 共用同一份几何(⛔ 不许在这里另算一份)。
12
+ * - 逐张就绪、逐张显影:未就绪那张 `get()` 返回 null ⇒ 调方把那片传 null(材质显示灰),下一帧就绪后即亮。
13
+ */
14
+ import { SRGBColorSpace, Texture, Vector4 } from "three";
15
+ import { loadPanoTexture, releasePanoTexture } from "./panoBitmapTexture";
16
+ import { IMAGE_TILE_GRID, rtStitchTileInset } from "./mktShader";
17
+
18
+ interface TileEntry {
19
+ tex: Texture | null;
20
+ w: number;
21
+ h: number;
22
+ }
23
+
24
+ export class ImagePlaneTileLoader {
25
+ private cache = new Map<string, TileEntry>();
26
+ private inflight = new Map<string, Promise<void>>();
27
+
28
+ /** 触发某张瓦片下载 + 解码(已缓存 / 在途则跳过);完成后填入 cache,下一帧 feed 即取到 */
29
+ preload(url: string): void {
30
+ if (!url || this.cache.has(url) || this.inflight.has(url)) return;
31
+ const p = loadPanoTexture(url)
32
+ .then((tex) => {
33
+ tex.colorSpace = SRGBColorSpace; // 硬件采样解 sRGB→linear(与旧 RT 方案逐字节同口径)
34
+ const img = tex.image as { width?: number; height?: number } | undefined;
35
+ this.cache.set(url, { tex, w: img?.width ?? 0, h: img?.height ?? 0 });
36
+ })
37
+ .catch(() => {
38
+ // 下载 / 解码失败:留空,下一帧 preload 重新触发(不把半截纹理绑上去)
39
+ })
40
+ .finally(() => {
41
+ this.inflight.delete(url);
42
+ });
43
+ this.inflight.set(url, p);
44
+ }
45
+
46
+ /** 取已就绪的瓦片(未就绪返回 null) */
47
+ get(url: string): TileEntry | null {
48
+ return this.cache.get(url) || null;
49
+ }
50
+
51
+ /** 第 i 片(行优先、图像左上起)的采样窗口;瓦片未就绪时返回整张 [0,0,1,1] */
52
+ inset(entry: TileEntry, i: number): Vector4 {
53
+ if (!entry.w || !entry.h) return new Vector4(0, 0, 1, 1);
54
+ const [u0, v0, u1, v1] = rtStitchTileInset(i, entry.w, entry.h, IMAGE_TILE_GRID);
55
+ return new Vector4(u0, v0, u1, v1);
56
+ }
57
+
58
+ /** 释放本 loader 持有的全部瓦片纹理(项目重置 / 卸载场景时调用;⛔ 不关共享占位纹理) */
59
+ clear(): void {
60
+ this.cache.forEach((e) => e.tex && releasePanoTexture(e.tex));
61
+ this.cache.clear();
62
+ this.inflight.clear();
63
+ }
64
+ }
@@ -1,18 +1,19 @@
1
1
  import { ShaderMaterial } from "three";
2
2
  /**
3
- * ⭐ 融合材质的全景点数**上限**(皇上旨 10-06「一次能够展示 8 个全景纹理」):每点占 **2** 张拼合槽纹理
4
- * (32 片 8×4 → 左右 2 槽,每槽 4×4 格)⇒ **8 × 2 = 16 个 sampler**,再多样本编译不过。
5
- * (sampler 总数 16 是硬件硬顶,本机 `MAX_TEXTURE_IMAGE_UNITS` 实测 16。)
3
+ * ⭐ 融合材质的全景点数**上限**:每点占 **3** 张拼合槽纹理(皇上旨 2026-10-23「全景的 RT 由原来的 2 个分成 3 个、
4
+ * 每个 4096×6144、竖直排列 3 个瓦片」⇒ 原图切 3×3=9 片,按**列**分 3 槽)⇒ 点数 × 3 必须 ≤ sampler 硬顶。
5
+ * 本机 `MAX_TEXTURE_IMAGE_UNITS` 实测 **16**:旧版 8 点 × 2 槽 = 16 正好用满,现每点 3 槽 ⇒ 只能取 ⌊16/3⌋ = **5**
6
+ * (5 × 3 = 15)。皇上旨 2026-10-23 在「A」里拍板:保 3 槽不降画质,**同屏全景点数 8 → 5**。
6
7
  *
7
8
  * ⭐⭐ 2026-10-09 皇上旨「MktMesh 只有映射一种,blend/selected 归编辑器」⇒ 该常量从 `mktShader.ts`
8
9
  * **搬到这里**(映射材质的所在地)。它同时是库与编辑器那份 blend 的**共同上限**,两边必须同值。
9
10
  */
10
- export declare const MKT_PANO_MAX_SLOTS = 8;
11
+ export declare const MKT_PANO_MAX_SLOTS = 5;
11
12
  /**
12
13
  * 创建「全景序号直取」着色器材质(皇上旨 2026-09-29「三模式三 shader」之二):
13
14
  * 编辑器「映射设置模式」的墙材质 + **基类 MktMesh(发布/预览)的固定墙材质**
14
15
  * (皇上旨:mktmesh 就只有按照 attribute 配置来显示全景这一种固定的 shader)。
15
- * uniform 形状与 blend 工厂同档(panoramas[16]/textureMatrices[8]/weights[8]/uPanoTiled[8])⇒
16
+ * uniform 形状与 blend 工厂同档(panoramas[15]/textureMatrices[5]/weights[5]/uPanoTiled[5])⇒
16
17
  * 喂料复用 feedBlendProjection 的槽位指派路(feedFaceMapping),零新喂料路。
17
18
  * uFloorCoreRadius/uFloorFadeRange/uFloorOpacity 三根本 shader 不读,但喂料统一入口会写 ⇒ JS 侧留着(静默忽略)。
18
19
  */
@@ -8,33 +8,42 @@
8
8
  import { BackSide, Matrix4, ShaderMaterial, Vector3 } from "three";
9
9
  import { createPlaceholderTexture, floorVertexShader, RT_STITCH_SLOT_COUNT } from "./mktShader";
10
10
  /**
11
- * ⭐ 融合材质的全景点数**上限**(皇上旨 10-06「一次能够展示 8 个全景纹理」):每点占 **2** 张拼合槽纹理
12
- * (32 片 8×4 → 左右 2 槽,每槽 4×4 格)⇒ **8 × 2 = 16 个 sampler**,再多样本编译不过。
13
- * (sampler 总数 16 是硬件硬顶,本机 `MAX_TEXTURE_IMAGE_UNITS` 实测 16。)
11
+ * ⭐ 融合材质的全景点数**上限**:每点占 **3** 张拼合槽纹理(皇上旨 2026-10-23「全景的 RT 由原来的 2 个分成 3 个、
12
+ * 每个 4096×6144、竖直排列 3 个瓦片」⇒ 原图切 3×3=9 片,按**列**分 3 槽)⇒ 点数 × 3 必须 ≤ sampler 硬顶。
13
+ * 本机 `MAX_TEXTURE_IMAGE_UNITS` 实测 **16**:旧版 8 点 × 2 槽 = 16 正好用满,现每点 3 槽 ⇒ 只能取 ⌊16/3⌋ = **5**
14
+ * (5 × 3 = 15)。皇上旨 2026-10-23 在「A」里拍板:保 3 槽不降画质,**同屏全景点数 8 → 5**。
14
15
  *
15
16
  * ⭐⭐ 2026-10-09 皇上旨「MktMesh 只有映射一种,blend/selected 归编辑器」⇒ 该常量从 `mktShader.ts`
16
17
  * **搬到这里**(映射材质的所在地)。它同时是库与编辑器那份 blend 的**共同上限**,两边必须同值。
17
18
  */
18
- export const MKT_PANO_MAX_SLOTS = 8;
19
+ export const MKT_PANO_MAX_SLOTS = 5;
19
20
  /**
20
21
  * 序号直取片元(皇上旨 2026-09-29「三模式三 shader」之二):
21
22
  * 按三角面 aPanoIndex 在 panoIndices 槽里找对应全景纹理 —— **不看距离、不看夹角**(blend 那套打分/归约整段没有)。
22
- * 槽内采样段(等距柱状投射 + 左右 2 张拼合槽 + 采样即线性、不再手动 pow 解码)与 blend **逐字同口径**;改采样口径两处同改。
23
+ * 槽内采样段(等距柱状投射 + 左/中/右 3 张拼合槽 + 采样即线性、不再手动 pow 解码)与 blend **逐字同口径**;改采样口径两处同改。
23
24
  * 未设序号 / 序号不在槽里 / 该槽瓦片没绑好(weights≤0)→ uFaceMissingColor 深灰兜底
24
25
  * (皇上旨 09-28「装不下就深灰」;weights 闸是 09-29 拆分时补的 —— 原运行时分支没这道闸,
25
26
  * 槽没绑好但序号命中会采到 vec3(0) 纯黑,深灰才是钦定兜底色)。
26
27
  */
27
28
  function buildFloorMappingFragment(maxPano) {
28
- // 每个全景点占 **2** 张拼合槽纹理(32 片每 16 片拼一张:左半幅 / 右半幅)⇒ 8 × 2 = 16 = sampler 硬顶
29
+ // 每个全景点占 **3** 张拼合槽纹理(9 片 3×3 按列分:左列 / 中列 / 右列,每槽竖叠 3 片)⇒ 5 × 3 = 15 ≤ sampler 硬顶 16
29
30
  const tileCount = maxPano * RT_STITCH_SLOT_COUNT;
30
31
  let slotCalc = ""; // 每槽各自采样出 linK(weights[k]>0 才采;没绑好保持 0,由 facePick 的 weights 闸兜成深灰)
31
32
  let slotFacePick = ""; // 逐槽展开「panoIndices[k]==vPanoIndex 则取 lin{k}」(ANGLE 禁动态索引 ⇒ JS 常量展开)
32
33
  for (let k = 0; k < maxPano; k++) {
33
- const base = k * RT_STITCH_SLOT_COUNT; // 本点占 2 个连续纹理槽:base=k*2 .. base+1(顺序 [左半幅, 右半幅])
34
+ const base = k * RT_STITCH_SLOT_COUNT; // 本点占 3 个连续纹理槽:base=k*3 .. base+2(顺序 [左列, 中列, 右列])
35
+ // ⚠️ ANGLE(D3D) 禁止动态索引 sampler 数组 ⇒ 展开成「base + 字面量」常量下标 if 链;末条裸 else 兜住 u==1 边界
36
+ const slotSamples = [];
37
+ for (let s = 0; s < RT_STITCH_SLOT_COUNT; s++) {
38
+ const cond = s === RT_STITCH_SLOT_COUNT - 1
39
+ ? "else"
40
+ : `${s === 0 ? "if" : "else if"} (tileIdx == ${s})`;
41
+ slotSamples.push(` ${cond} lin${k} = texture2D(panoramas[${base + s}], vec2(panoU, panoV)).rgb;`);
42
+ }
34
43
  slotFacePick += `
35
44
  if (panoIndices[${k}] >= 0.0 && weights[${k}] > 0.0 && abs(panoIndices[${k}] - vPanoIndex) < 0.5) faceCol = lin${k};`;
36
45
  slotCalc += `
37
- // ── 点槽 ${k}(纹理 ${base}..${base + 1})──
46
+ // ── 点槽 ${k}(纹理 ${base}..${base + RT_STITCH_SLOT_COUNT - 1})──
38
47
  vec3 lin${k} = vec3(0.0);
39
48
  if (weights[${k}] > 0.0) {
40
49
  mat4 tm = textureMatrices[${k}];
@@ -47,21 +56,19 @@ function buildFloorMappingFragment(maxPano) {
47
56
  float lat = asin(clamp(dir.y, -1.0, 1.0));
48
57
  // 等距柱状线性 v(= 全图 UV),与 blend / 单全景分支**逐字同口径**
49
58
  float v = 0.5 + lat * 0.3183098861837907; // 1/PI
50
- // 左右两半 -> 拼合槽下标 [左半幅=0, 右半幅=1](每槽 = 8×4 网格里 4×4=16 片拼成,见 RT_STITCH_SLOT_TILES)
51
- // ⭐ 10-06 晚旨:竖着不再分块 ⇒ 槽只随 u 走(与 blend / 单全景分支**逐字同口径**)
52
- int tileIdx = (u >= 0.5) ? 1 : 0;
53
- float localU = (u < 0.5) ? (u * 2.0) : (u * 2.0 - 1.0);
54
- // ⛔ 纵向不再减半(槽就是全高)⇒ localV 恒等于 v;写成 2v/2v-1 = 纵向分辨率白丢一半
59
+ // 三等分经度 -> 拼合槽下标 [左列=0, 中列=1, 右列=2](每槽 = 3×3 网格里一整列、竖 3 片拼成,见 RT_STITCH_SLOT_TILES)
60
+ // ⭐ 10-06 晚旨「竖着不再分块」继续成立、10-23 旨把横向从 2 等分改成 3 等分 ⇒ 槽只随 u 走(与 blend / 单全景分支**逐字同口径**)
61
+ int tileIdx = int(clamp(floor(u * ${RT_STITCH_SLOT_COUNT}.0), 0.0, ${RT_STITCH_SLOT_COUNT - 1}.0));
62
+ float localU = u * ${RT_STITCH_SLOT_COUNT}.0 - float(tileIdx);
63
+ // ⛔ 纵向不再减半(槽就是全高)⇒ localV 恒等于 v;写成 nv/nv-1 = 纵向分辨率白丢一档
55
64
  float localV = v;
56
- // 🧩 该点这 2 槽装的是整图(whole 形态 / 没切过片)⇒ 还原成全图 UV 再采样(与 blend 逐字同口径)
65
+ // 🧩 该点这 3 槽装的是整图(whole 形态 / 没切过片)⇒ 还原成全图 UV 再采样(与 blend 逐字同口径)
57
66
  float panoU = (uPanoTiled[${k}] > 0.5) ? localU : u;
58
67
  float panoV = (uPanoTiled[${k}] > 0.5) ? localV : v;
59
- // ⚠️ ANGLE(D3D) 禁止动态索引 sampler 数组:以下 2 个采样下标均为「base + 字面量」常量表达式,编译安全
60
68
  // ⭐ 采样即线性(与单全景 / blend / selected 三路同一条口径,10-07 旨「色彩空间统一使用 liner」):纹理都标了
61
69
  // colorSpace = SRGBColorSpace ⇒ 硬件上传成 SRGB8_ALPHA8、texture2D 已解码一次;
62
70
  // 这里**不再手动 pow 解码**(那遍是二次解码 = 整体压暗),末端只编码一次 ⇒ 与源图逐字节还原。
63
- if (tileIdx == 0) lin${k} = texture2D(panoramas[${base}], vec2(panoU, panoV)).rgb;
64
- else lin${k} = texture2D(panoramas[${base + 1}], vec2(panoU, panoV)).rgb;
71
+ ${slotSamples.join("\n")}
65
72
  }`;
66
73
  }
67
74
  return /* glsl */ `
@@ -105,13 +112,13 @@ ${slotFacePick}
105
112
  * 创建「全景序号直取」着色器材质(皇上旨 2026-09-29「三模式三 shader」之二):
106
113
  * 编辑器「映射设置模式」的墙材质 + **基类 MktMesh(发布/预览)的固定墙材质**
107
114
  * (皇上旨:mktmesh 就只有按照 attribute 配置来显示全景这一种固定的 shader)。
108
- * uniform 形状与 blend 工厂同档(panoramas[16]/textureMatrices[8]/weights[8]/uPanoTiled[8])⇒
115
+ * uniform 形状与 blend 工厂同档(panoramas[15]/textureMatrices[5]/weights[5]/uPanoTiled[5])⇒
109
116
  * 喂料复用 feedBlendProjection 的槽位指派路(feedFaceMapping),零新喂料路。
110
117
  * uFloorCoreRadius/uFloorFadeRange/uFloorOpacity 三根本 shader 不读,但喂料统一入口会写 ⇒ JS 侧留着(静默忽略)。
111
118
  */
112
119
  export function createMktFloorMappingShaderMaterial(options = {}) {
113
120
  const maxPano = Math.min(options.maxPano ?? MKT_PANO_MAX_SLOTS, MKT_PANO_MAX_SLOTS);
114
- const tileCount = maxPano * RT_STITCH_SLOT_COUNT; // 8 点 × 左/右 2 槽 = 16 = sampler 硬顶
121
+ const tileCount = maxPano * RT_STITCH_SLOT_COUNT; // 5 点 × 左/中/右 3 槽 = 15(sampler 硬顶 16)
115
122
  const panoramas = [];
116
123
  const matrices = [];
117
124
  for (let i = 0; i < tileCount; i++)
@@ -9,34 +9,45 @@ import { BackSide, Matrix4, ShaderMaterial, Vector3 } from "three";
9
9
  import { createPlaceholderTexture, floorVertexShader, RT_STITCH_SLOT_COUNT } from "./mktShader";
10
10
 
11
11
  /**
12
- * ⭐ 融合材质的全景点数**上限**(皇上旨 10-06「一次能够展示 8 个全景纹理」):每点占 **2** 张拼合槽纹理
13
- * (32 片 8×4 → 左右 2 槽,每槽 4×4 格)⇒ **8 × 2 = 16 个 sampler**,再多样本编译不过。
14
- * (sampler 总数 16 是硬件硬顶,本机 `MAX_TEXTURE_IMAGE_UNITS` 实测 16。)
12
+ * ⭐ 融合材质的全景点数**上限**:每点占 **3** 张拼合槽纹理(皇上旨 2026-10-23「全景的 RT 由原来的 2 个分成 3 个、
13
+ * 每个 4096×6144、竖直排列 3 个瓦片」⇒ 原图切 3×3=9 片,按**列**分 3 槽)⇒ 点数 × 3 必须 ≤ sampler 硬顶。
14
+ * 本机 `MAX_TEXTURE_IMAGE_UNITS` 实测 **16**:旧版 8 点 × 2 槽 = 16 正好用满,现每点 3 槽 ⇒ 只能取 ⌊16/3⌋ = **5**
15
+ * (5 × 3 = 15)。皇上旨 2026-10-23 在「A」里拍板:保 3 槽不降画质,**同屏全景点数 8 → 5**。
15
16
  *
16
17
  * ⭐⭐ 2026-10-09 皇上旨「MktMesh 只有映射一种,blend/selected 归编辑器」⇒ 该常量从 `mktShader.ts`
17
18
  * **搬到这里**(映射材质的所在地)。它同时是库与编辑器那份 blend 的**共同上限**,两边必须同值。
18
19
  */
19
- export const MKT_PANO_MAX_SLOTS = 8;
20
+ export const MKT_PANO_MAX_SLOTS = 5;
20
21
 
21
22
  /**
22
23
  * 序号直取片元(皇上旨 2026-09-29「三模式三 shader」之二):
23
24
  * 按三角面 aPanoIndex 在 panoIndices 槽里找对应全景纹理 —— **不看距离、不看夹角**(blend 那套打分/归约整段没有)。
24
- * 槽内采样段(等距柱状投射 + 左右 2 张拼合槽 + 采样即线性、不再手动 pow 解码)与 blend **逐字同口径**;改采样口径两处同改。
25
+ * 槽内采样段(等距柱状投射 + 左/中/右 3 张拼合槽 + 采样即线性、不再手动 pow 解码)与 blend **逐字同口径**;改采样口径两处同改。
25
26
  * 未设序号 / 序号不在槽里 / 该槽瓦片没绑好(weights≤0)→ uFaceMissingColor 深灰兜底
26
27
  * (皇上旨 09-28「装不下就深灰」;weights 闸是 09-29 拆分时补的 —— 原运行时分支没这道闸,
27
28
  * 槽没绑好但序号命中会采到 vec3(0) 纯黑,深灰才是钦定兜底色)。
28
29
  */
29
30
  function buildFloorMappingFragment(maxPano: number): string {
30
- // 每个全景点占 **2** 张拼合槽纹理(32 片每 16 片拼一张:左半幅 / 右半幅)⇒ 8 × 2 = 16 = sampler 硬顶
31
+ // 每个全景点占 **3** 张拼合槽纹理(9 片 3×3 按列分:左列 / 中列 / 右列,每槽竖叠 3 片)⇒ 5 × 3 = 15 ≤ sampler 硬顶 16
31
32
  const tileCount = maxPano * RT_STITCH_SLOT_COUNT;
32
33
  let slotCalc = ""; // 每槽各自采样出 linK(weights[k]>0 才采;没绑好保持 0,由 facePick 的 weights 闸兜成深灰)
33
34
  let slotFacePick = ""; // 逐槽展开「panoIndices[k]==vPanoIndex 则取 lin{k}」(ANGLE 禁动态索引 ⇒ JS 常量展开)
34
35
  for (let k = 0; k < maxPano; k++) {
35
- const base = k * RT_STITCH_SLOT_COUNT; // 本点占 2 个连续纹理槽:base=k*2 .. base+1(顺序 [左半幅, 右半幅])
36
+ const base = k * RT_STITCH_SLOT_COUNT; // 本点占 3 个连续纹理槽:base=k*3 .. base+2(顺序 [左列, 中列, 右列])
37
+ // ⚠️ ANGLE(D3D) 禁止动态索引 sampler 数组 ⇒ 展开成「base + 字面量」常量下标 if 链;末条裸 else 兜住 u==1 边界
38
+ const slotSamples: string[] = [];
39
+ for (let s = 0; s < RT_STITCH_SLOT_COUNT; s++) {
40
+ const cond = s === RT_STITCH_SLOT_COUNT - 1
41
+ ? "else"
42
+ : `${s === 0 ? "if" : "else if"} (tileIdx == ${s})`;
43
+ slotSamples.push(
44
+ ` ${cond} lin${k} = texture2D(panoramas[${base + s}], vec2(panoU, panoV)).rgb;`,
45
+ );
46
+ }
36
47
  slotFacePick += `
37
48
  if (panoIndices[${k}] >= 0.0 && weights[${k}] > 0.0 && abs(panoIndices[${k}] - vPanoIndex) < 0.5) faceCol = lin${k};`;
38
49
  slotCalc += `
39
- // ── 点槽 ${k}(纹理 ${base}..${base + 1})──
50
+ // ── 点槽 ${k}(纹理 ${base}..${base + RT_STITCH_SLOT_COUNT - 1})──
40
51
  vec3 lin${k} = vec3(0.0);
41
52
  if (weights[${k}] > 0.0) {
42
53
  mat4 tm = textureMatrices[${k}];
@@ -49,21 +60,19 @@ function buildFloorMappingFragment(maxPano: number): string {
49
60
  float lat = asin(clamp(dir.y, -1.0, 1.0));
50
61
  // 等距柱状线性 v(= 全图 UV),与 blend / 单全景分支**逐字同口径**
51
62
  float v = 0.5 + lat * 0.3183098861837907; // 1/PI
52
- // 左右两半 -> 拼合槽下标 [左半幅=0, 右半幅=1](每槽 = 8×4 网格里 4×4=16 片拼成,见 RT_STITCH_SLOT_TILES)
53
- // ⭐ 10-06 晚旨:竖着不再分块 ⇒ 槽只随 u 走(与 blend / 单全景分支**逐字同口径**)
54
- int tileIdx = (u >= 0.5) ? 1 : 0;
55
- float localU = (u < 0.5) ? (u * 2.0) : (u * 2.0 - 1.0);
56
- // ⛔ 纵向不再减半(槽就是全高)⇒ localV 恒等于 v;写成 2v/2v-1 = 纵向分辨率白丢一半
63
+ // 三等分经度 -> 拼合槽下标 [左列=0, 中列=1, 右列=2](每槽 = 3×3 网格里一整列、竖 3 片拼成,见 RT_STITCH_SLOT_TILES)
64
+ // ⭐ 10-06 晚旨「竖着不再分块」继续成立、10-23 旨把横向从 2 等分改成 3 等分 ⇒ 槽只随 u 走(与 blend / 单全景分支**逐字同口径**)
65
+ int tileIdx = int(clamp(floor(u * ${RT_STITCH_SLOT_COUNT}.0), 0.0, ${RT_STITCH_SLOT_COUNT - 1}.0));
66
+ float localU = u * ${RT_STITCH_SLOT_COUNT}.0 - float(tileIdx);
67
+ // ⛔ 纵向不再减半(槽就是全高)⇒ localV 恒等于 v;写成 nv/nv-1 = 纵向分辨率白丢一档
57
68
  float localV = v;
58
- // 🧩 该点这 2 槽装的是整图(whole 形态 / 没切过片)⇒ 还原成全图 UV 再采样(与 blend 逐字同口径)
69
+ // 🧩 该点这 3 槽装的是整图(whole 形态 / 没切过片)⇒ 还原成全图 UV 再采样(与 blend 逐字同口径)
59
70
  float panoU = (uPanoTiled[${k}] > 0.5) ? localU : u;
60
71
  float panoV = (uPanoTiled[${k}] > 0.5) ? localV : v;
61
- // ⚠️ ANGLE(D3D) 禁止动态索引 sampler 数组:以下 2 个采样下标均为「base + 字面量」常量表达式,编译安全
62
72
  // ⭐ 采样即线性(与单全景 / blend / selected 三路同一条口径,10-07 旨「色彩空间统一使用 liner」):纹理都标了
63
73
  // colorSpace = SRGBColorSpace ⇒ 硬件上传成 SRGB8_ALPHA8、texture2D 已解码一次;
64
74
  // 这里**不再手动 pow 解码**(那遍是二次解码 = 整体压暗),末端只编码一次 ⇒ 与源图逐字节还原。
65
- if (tileIdx == 0) lin${k} = texture2D(panoramas[${base}], vec2(panoU, panoV)).rgb;
66
- else lin${k} = texture2D(panoramas[${base + 1}], vec2(panoU, panoV)).rgb;
75
+ ${slotSamples.join("\n")}
67
76
  }`;
68
77
  }
69
78
  return /* glsl */ `
@@ -108,13 +117,13 @@ ${slotFacePick}
108
117
  * 创建「全景序号直取」着色器材质(皇上旨 2026-09-29「三模式三 shader」之二):
109
118
  * 编辑器「映射设置模式」的墙材质 + **基类 MktMesh(发布/预览)的固定墙材质**
110
119
  * (皇上旨:mktmesh 就只有按照 attribute 配置来显示全景这一种固定的 shader)。
111
- * uniform 形状与 blend 工厂同档(panoramas[16]/textureMatrices[8]/weights[8]/uPanoTiled[8])⇒
120
+ * uniform 形状与 blend 工厂同档(panoramas[15]/textureMatrices[5]/weights[5]/uPanoTiled[5])⇒
112
121
  * 喂料复用 feedBlendProjection 的槽位指派路(feedFaceMapping),零新喂料路。
113
122
  * uFloorCoreRadius/uFloorFadeRange/uFloorOpacity 三根本 shader 不读,但喂料统一入口会写 ⇒ JS 侧留着(静默忽略)。
114
123
  */
115
124
  export function createMktFloorMappingShaderMaterial(options: { maxPano?: number } = {}): ShaderMaterial {
116
125
  const maxPano = Math.min(options.maxPano ?? MKT_PANO_MAX_SLOTS, MKT_PANO_MAX_SLOTS);
117
- const tileCount = maxPano * RT_STITCH_SLOT_COUNT; // 8 点 × 左/右 2 槽 = 16 = sampler 硬顶
126
+ const tileCount = maxPano * RT_STITCH_SLOT_COUNT; // 5 点 × 左/中/右 3 槽 = 15(sampler 硬顶 16)
118
127
  const panoramas: import("three").Texture[] = [];
119
128
  const matrices: Matrix4[] = [];
120
129
  for (let i = 0; i < tileCount; i++) panoramas.push(createPlaceholderTexture());