three-base 2.0.181 → 2.0.187
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/MktMesh/MktMesh.d.ts +36 -6
- package/MktMesh/MktMesh.js +107 -27
- package/MktMesh/MktMesh.ts +103 -26
- package/MktMesh/imagePlane.d.ts +4 -1
- package/MktMesh/imagePlane.js +25 -10
- package/MktMesh/imagePlane.ts +26 -10
- package/MktMesh/imageTileLoader.d.ts +2 -0
- package/MktMesh/imageTileLoader.js +5 -1
- package/MktMesh/imageTileLoader.ts +6 -1
- package/MktMesh/mktMappingShader.d.ts +5 -5
- package/MktMesh/mktMappingShader.js +12 -12
- package/MktMesh/mktMappingShader.ts +12 -12
- package/MktMesh/mktShader.d.ts +57 -56
- package/MktMesh/mktShader.js +62 -60
- package/MktMesh/mktShader.ts +72 -70
- package/MktMesh/modelSlot.d.ts +21 -3
- package/MktMesh/modelSlot.js +39 -4
- package/MktMesh/modelSlot.ts +38 -4
- package/MktMesh/panoSlotRoster.d.ts +2 -2
- package/MktMesh/panoSlotRoster.js +4 -4
- package/MktMesh/panoSlotRoster.ts +4 -4
- package/MktMesh/panoTileStitcher.d.ts +7 -7
- package/MktMesh/panoTileStitcher.js +33 -28
- package/MktMesh/panoTileStitcher.ts +34 -29
- package/package.json +1 -1
package/MktMesh/imagePlane.ts
CHANGED
|
@@ -11,8 +11,9 @@
|
|
|
11
11
|
* - 几何 PlaneGeometry(width, height),原点在平面中心;position.y 由调用者设定(通常 height/2 让底部落地)。
|
|
12
12
|
* - ⭐ 2026-10-22 晚旨:纹理**不走拼合器 RT**,直接把上传切好的 4 张瓦片纹理绑到材质,片元按 UV 象限选片 +
|
|
13
13
|
* 用每片 `rtStitchTileInset` 窗口采样(与上传切片共用同一份几何 ⇒ 接缝不回潮)。材质用 onBeforeCompile 打补丁,
|
|
14
|
-
* 注入 4 个 sampler + 每片 inset +
|
|
15
|
-
* (⭐
|
|
14
|
+
* 注入 4 个 sampler + 每片 inset + 就绪标志;缺失那片整格 `discard`(一片像素都不落),逐张就绪逐张显影。
|
|
15
|
+
* (⭐ 2026-10-26 用户先要默认图、当晚收回改要灰,同一晚再收:「平面图的图片还没有加载出来的时候, 不是显示灰色,
|
|
16
|
+
* 而是直接 discrad 丢弃」⇒ 默认图与缺图灰两条都已删,没就绪就是透明没有。)
|
|
16
17
|
* - UV 标准 [0,1]²(PlaneGeometry 自带),4 张瓦片按 2×2 象限铺满 ⇒ 不需要投影 shader,也不需要离屏 RT。
|
|
17
18
|
*/
|
|
18
19
|
import {
|
|
@@ -49,21 +50,25 @@ const ZERO_INSET = new Vector4(0, 0, 1, 1);
|
|
|
49
50
|
export const IMAGE_PLANE_EDGE_CLIP_UV = 0.004;
|
|
50
51
|
const EDGE_MAX_UV = 1 - IMAGE_PLANE_EDGE_CLIP_UV;
|
|
51
52
|
|
|
52
|
-
/** 片元打补丁:4 张瓦片按 UV
|
|
53
|
+
/** 片元打补丁:4 张瓦片按 UV 象限选片;⭐ 2026-10-26 用户决定「图片还没有加载出来的时候, 不是显示灰色, 而是直接 discrad 丢弃」
|
|
54
|
+
* ⇒ 这一格没就绪就 `discard`(一片像素都不落,透过去看到的是平面背后的东西),⛔ 不铺灰、⛔ 不画默认图。
|
|
55
|
+
* 索引用字面量 0..3 ⇒ GLSL ES 1.00 合法。 */
|
|
53
56
|
const IMG_PLANE_MAP_FRAG = `
|
|
54
57
|
if ( vUv.x < ${IMAGE_PLANE_EDGE_CLIP_UV} || vUv.x > ${EDGE_MAX_UV} || vUv.y < ${IMAGE_PLANE_EDGE_CLIP_UV} || vUv.y > ${EDGE_MAX_UV} ) discard;
|
|
55
|
-
vec4 imgTexel
|
|
58
|
+
vec4 imgTexel;
|
|
59
|
+
bool ready = false;
|
|
56
60
|
vec2 cell = floor(vUv * 2.0);
|
|
57
61
|
vec2 local = fract(vUv * 2.0);
|
|
58
62
|
if (cell.y >= 0.5 && cell.x < 0.5) {
|
|
59
|
-
if (uValid[0] > 0.5) { vec4 ins = uInset[0]; imgTexel = texture2D(uTiles[0], mix(ins.xy, ins.zw, local)); }
|
|
63
|
+
if (uValid[0] > 0.5) { vec4 ins = uInset[0]; imgTexel = texture2D(uTiles[0], mix(ins.xy, ins.zw, local)); ready = true; }
|
|
60
64
|
} else if (cell.y >= 0.5 && cell.x >= 0.5) {
|
|
61
|
-
if (uValid[1] > 0.5) { vec4 ins = uInset[1]; imgTexel = texture2D(uTiles[1], mix(ins.xy, ins.zw, local)); }
|
|
65
|
+
if (uValid[1] > 0.5) { vec4 ins = uInset[1]; imgTexel = texture2D(uTiles[1], mix(ins.xy, ins.zw, local)); ready = true; }
|
|
62
66
|
} else if (cell.y < 0.5 && cell.x < 0.5) {
|
|
63
|
-
if (uValid[2] > 0.5) { vec4 ins = uInset[2]; imgTexel = texture2D(uTiles[2], mix(ins.xy, ins.zw, local)); }
|
|
67
|
+
if (uValid[2] > 0.5) { vec4 ins = uInset[2]; imgTexel = texture2D(uTiles[2], mix(ins.xy, ins.zw, local)); ready = true; }
|
|
64
68
|
} else {
|
|
65
|
-
if (uValid[3] > 0.5) { vec4 ins = uInset[3]; imgTexel = texture2D(uTiles[3], mix(ins.xy, ins.zw, local)); }
|
|
69
|
+
if (uValid[3] > 0.5) { vec4 ins = uInset[3]; imgTexel = texture2D(uTiles[3], mix(ins.xy, ins.zw, local)); ready = true; }
|
|
66
70
|
}
|
|
71
|
+
if (!ready) discard;
|
|
67
72
|
diffuseColor *= imgTexel;
|
|
68
73
|
`;
|
|
69
74
|
|
|
@@ -112,7 +117,7 @@ export class ImagePlane extends Mesh<PlaneGeometry, MeshBasicMaterial> {
|
|
|
112
117
|
});
|
|
113
118
|
// ⭐ 2026-10-22 晚旨:图片平面**不用拼合器 RT**,直接把上传切好的 4 张瓦片纹理绑到材质,
|
|
114
119
|
// 片元按 UV 象限选片 + 用每片 `rtStitchTileInset` 窗口采样(与上传切片共用同一份几何 ⇒ 接缝不回潮)。
|
|
115
|
-
// 材质打补丁(onBeforeCompile)注入 4 个 sampler + 每片 inset +
|
|
120
|
+
// 材质打补丁(onBeforeCompile)注入 4 个 sampler + 每片 inset + 就绪标志;缺失那片整格 discard。
|
|
116
121
|
mat.defines = { USE_UV: "" };
|
|
117
122
|
const uTiles = { value: [PLACEHOLDER_TEX, PLACEHOLDER_TEX, PLACEHOLDER_TEX, PLACEHOLDER_TEX] as Texture[] };
|
|
118
123
|
const uInset = { value: [ZERO_INSET.clone(), ZERO_INSET.clone(), ZERO_INSET.clone(), ZERO_INSET.clone()] };
|
|
@@ -155,7 +160,7 @@ export class ImagePlane extends Mesh<PlaneGeometry, MeshBasicMaterial> {
|
|
|
155
160
|
get naturalW(): number | undefined { return this._data.naturalW; }
|
|
156
161
|
get naturalH(): number | undefined { return this._data.naturalH; }
|
|
157
162
|
|
|
158
|
-
/** 把上传切好的 4 张瓦片纹理 + 每片 inset 绑到材质(缺图那片传 null ⇒
|
|
163
|
+
/** 把上传切好的 4 张瓦片纹理 + 每片 inset 绑到材质(缺图那片传 null ⇒ 那一片整格 discard,不落像素)。uTiles 用持久对象引用 ⇒ 改 value 实时生效 */
|
|
159
164
|
setTileTextures(texs: (Texture | null)[], insets: Vector4[]): void {
|
|
160
165
|
for (let i = 0; i < 4; i++) {
|
|
161
166
|
const t = texs[i] || null;
|
|
@@ -165,6 +170,17 @@ export class ImagePlane extends Mesh<PlaneGeometry, MeshBasicMaterial> {
|
|
|
165
170
|
}
|
|
166
171
|
}
|
|
167
172
|
|
|
173
|
+
/** 只读「此刻材质里绑了什么」的戳记:4 格就绪位 + 已绑纹理的版本号。
|
|
174
|
+
* 按需渲染的宿主拿它比对画面:逐帧绑定只写 uniform 值,⛔ 不动 `material.version`、也不动几何 ⇒ 场景指纹看不见这一变。 */
|
|
175
|
+
tilesBindingStamp(): string {
|
|
176
|
+
let s = "";
|
|
177
|
+
for (let i = 0; i < 4; i++) {
|
|
178
|
+
const t = this._uTiles.value[i];
|
|
179
|
+
s += this._uValid.value[i] ? `1@${t ? t.version : -1},` : "0,";
|
|
180
|
+
}
|
|
181
|
+
return s;
|
|
182
|
+
}
|
|
183
|
+
|
|
168
184
|
highlight(): void {
|
|
169
185
|
this.material.color.set(HIGHLIGHT_COLOR);
|
|
170
186
|
}
|
|
@@ -11,6 +11,8 @@ export declare class ImagePlaneTileLoader {
|
|
|
11
11
|
preload(url: string): void;
|
|
12
12
|
/** 取已就绪的瓦片(未就绪返回 null) */
|
|
13
13
|
get(url: string): TileEntry | null;
|
|
14
|
+
/** 这张是否还在下载/解码途中。既不在缓存又不在途 ⇒ 要么没发起、要么已经失败(调用方据此决定「再排一帧等」还是「就此收工」) */
|
|
15
|
+
isPending(url: string): boolean;
|
|
14
16
|
/** 第 i 片(行优先、图像左上起)的采样窗口;瓦片未就绪时返回整张 [0,0,1,1] */
|
|
15
17
|
inset(entry: TileEntry, i: number): Vector4;
|
|
16
18
|
/** 释放本 loader 持有的全部瓦片纹理(项目重置 / 卸载场景时调用;⛔ 不关共享占位纹理) */
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* 与全景同一套上下翻约定);本类只补 `colorSpace = SRGBColorSpace`(硬件采样即解 sRGB→linear,与旧 RT 方案逐字节同口径)。
|
|
10
10
|
* - inset 用库的 `rtStitchTileInset(i, tw, th, IMAGE_TILE_GRID)`:上传多切 8px、采样只取中间干净块 ⇒ 接缝不回潮,
|
|
11
11
|
* 与上传切片 `rtStitchTileRects` 共用同一份几何(⛔ 不许在这里另算一份)。
|
|
12
|
-
* - 逐张就绪、逐张显影:未就绪那张 `get()` 返回 null ⇒ 调方把那片传 null
|
|
12
|
+
* - 逐张就绪、逐张显影:未就绪那张 `get()` 返回 null ⇒ 调方把那片传 null(材质那一格整格 discard,不落像素),下一帧就绪后即亮。
|
|
13
13
|
*/
|
|
14
14
|
import { SRGBColorSpace, Vector4 } from "three";
|
|
15
15
|
import { loadPanoTexture, releasePanoTexture } from "./panoBitmapTexture";
|
|
@@ -39,6 +39,10 @@ export class ImagePlaneTileLoader {
|
|
|
39
39
|
get(url) {
|
|
40
40
|
return this.cache.get(url) || null;
|
|
41
41
|
}
|
|
42
|
+
/** 这张是否还在下载/解码途中。既不在缓存又不在途 ⇒ 要么没发起、要么已经失败(调用方据此决定「再排一帧等」还是「就此收工」) */
|
|
43
|
+
isPending(url) {
|
|
44
|
+
return this.inflight.has(url);
|
|
45
|
+
}
|
|
42
46
|
/** 第 i 片(行优先、图像左上起)的采样窗口;瓦片未就绪时返回整张 [0,0,1,1] */
|
|
43
47
|
inset(entry, i) {
|
|
44
48
|
if (!entry.w || !entry.h)
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* 与全景同一套上下翻约定);本类只补 `colorSpace = SRGBColorSpace`(硬件采样即解 sRGB→linear,与旧 RT 方案逐字节同口径)。
|
|
10
10
|
* - inset 用库的 `rtStitchTileInset(i, tw, th, IMAGE_TILE_GRID)`:上传多切 8px、采样只取中间干净块 ⇒ 接缝不回潮,
|
|
11
11
|
* 与上传切片 `rtStitchTileRects` 共用同一份几何(⛔ 不许在这里另算一份)。
|
|
12
|
-
* - 逐张就绪、逐张显影:未就绪那张 `get()` 返回 null ⇒ 调方把那片传 null
|
|
12
|
+
* - 逐张就绪、逐张显影:未就绪那张 `get()` 返回 null ⇒ 调方把那片传 null(材质那一格整格 discard,不落像素),下一帧就绪后即亮。
|
|
13
13
|
*/
|
|
14
14
|
import { SRGBColorSpace, Texture, Vector4 } from "three";
|
|
15
15
|
import { loadPanoTexture, releasePanoTexture } from "./panoBitmapTexture";
|
|
@@ -48,6 +48,11 @@ export class ImagePlaneTileLoader {
|
|
|
48
48
|
return this.cache.get(url) || null;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
/** 这张是否还在下载/解码途中。既不在缓存又不在途 ⇒ 要么没发起、要么已经失败(调用方据此决定「再排一帧等」还是「就此收工」) */
|
|
52
|
+
isPending(url: string): boolean {
|
|
53
|
+
return this.inflight.has(url);
|
|
54
|
+
}
|
|
55
|
+
|
|
51
56
|
/** 第 i 片(行优先、图像左上起)的采样窗口;瓦片未就绪时返回整张 [0,0,1,1] */
|
|
52
57
|
inset(entry: TileEntry, i: number): Vector4 {
|
|
53
58
|
if (!entry.w || !entry.h) return new Vector4(0, 0, 1, 1);
|
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import { ShaderMaterial } from "three";
|
|
2
2
|
/**
|
|
3
3
|
* ⭐ 融合材质的全景点数**上限**:每点占 **3** 张拼合槽纹理(皇上旨 2026-10-23「全景的 RT 由原来的 2 个分成 3 个、
|
|
4
|
-
* 每个
|
|
5
|
-
* 本机 `MAX_TEXTURE_IMAGE_UNITS` 实测 **16
|
|
6
|
-
* (
|
|
4
|
+
* 每个 RT 上面 3×3=9 片」⇒ 原图切 6×3=18 片,按**半幅**分 2 槽)⇒ 点数 × 2 必须 ≤ sampler 硬顶。
|
|
5
|
+
* 本机 `MAX_TEXTURE_IMAGE_UNITS` 实测 **16**:每点 2 槽 ⇒ 取 ⌊16/2⌋ = **8** 点(10-23 那版每点 3 槽只能坐 5 点)
|
|
6
|
+
* (8 × 2 = 16 正好用满)。2026-10-26 需求回到「2 个 RT / 每 RT 3×3」⇒ **同屏全景点数 5 → 8**。
|
|
7
7
|
*
|
|
8
8
|
* ⭐⭐ 2026-10-09 皇上旨「MktMesh 只有映射一种,blend/selected 归编辑器」⇒ 该常量从 `mktShader.ts`
|
|
9
9
|
* **搬到这里**(映射材质的所在地)。它同时是库与编辑器那份 blend 的**共同上限**,两边必须同值。
|
|
10
10
|
*/
|
|
11
|
-
export declare const MKT_PANO_MAX_SLOTS =
|
|
11
|
+
export declare const MKT_PANO_MAX_SLOTS = 8;
|
|
12
12
|
/**
|
|
13
13
|
* 创建「全景序号直取」着色器材质(皇上旨 2026-09-29「三模式三 shader」之二):
|
|
14
14
|
* 编辑器「映射设置模式」的墙材质 + **基类 MktMesh(发布/预览)的固定墙材质**
|
|
15
15
|
* (皇上旨:mktmesh 就只有按照 attribute 配置来显示全景这一种固定的 shader)。
|
|
16
|
-
* uniform 形状与 blend 工厂同档(panoramas[
|
|
16
|
+
* uniform 形状与 blend 工厂同档(panoramas[16]/textureMatrices[8]/weights[8]/uPanoTiled[8])⇒
|
|
17
17
|
* 喂料复用 feedBlendProjection 的槽位指派路(feedFaceMapping),零新喂料路。
|
|
18
18
|
* uFloorCoreRadius/uFloorFadeRange/uFloorOpacity 三根本 shader 不读,但喂料统一入口会写 ⇒ JS 侧留着(静默忽略)。
|
|
19
19
|
*/
|
|
@@ -9,29 +9,29 @@ import { BackSide, Matrix4, ShaderMaterial, Vector3 } from "three";
|
|
|
9
9
|
import { createPlaceholderTexture, floorVertexShader, RT_STITCH_SLOT_COUNT } from "./mktShader";
|
|
10
10
|
/**
|
|
11
11
|
* ⭐ 融合材质的全景点数**上限**:每点占 **3** 张拼合槽纹理(皇上旨 2026-10-23「全景的 RT 由原来的 2 个分成 3 个、
|
|
12
|
-
* 每个
|
|
13
|
-
* 本机 `MAX_TEXTURE_IMAGE_UNITS` 实测 **16
|
|
14
|
-
* (
|
|
12
|
+
* 每个 RT 上面 3×3=9 片」⇒ 原图切 6×3=18 片,按**半幅**分 2 槽)⇒ 点数 × 2 必须 ≤ sampler 硬顶。
|
|
13
|
+
* 本机 `MAX_TEXTURE_IMAGE_UNITS` 实测 **16**:每点 2 槽 ⇒ 取 ⌊16/2⌋ = **8** 点(10-23 那版每点 3 槽只能坐 5 点)
|
|
14
|
+
* (8 × 2 = 16 正好用满)。2026-10-26 需求回到「2 个 RT / 每 RT 3×3」⇒ **同屏全景点数 5 → 8**。
|
|
15
15
|
*
|
|
16
16
|
* ⭐⭐ 2026-10-09 皇上旨「MktMesh 只有映射一种,blend/selected 归编辑器」⇒ 该常量从 `mktShader.ts`
|
|
17
17
|
* **搬到这里**(映射材质的所在地)。它同时是库与编辑器那份 blend 的**共同上限**,两边必须同值。
|
|
18
18
|
*/
|
|
19
|
-
export const MKT_PANO_MAX_SLOTS =
|
|
19
|
+
export const MKT_PANO_MAX_SLOTS = 8;
|
|
20
20
|
/**
|
|
21
21
|
* 序号直取片元(皇上旨 2026-09-29「三模式三 shader」之二):
|
|
22
22
|
* 按三角面 aPanoIndex 在 panoIndices 槽里找对应全景纹理 —— **不看距离、不看夹角**(blend 那套打分/归约整段没有)。
|
|
23
|
-
* 槽内采样段(等距柱状投射 +
|
|
23
|
+
* 槽内采样段(等距柱状投射 + 左/右 2 张拼合槽 + 采样即线性、不再手动 pow 解码)与 blend **逐字同口径**;改采样口径两处同改。
|
|
24
24
|
* 未设序号 / 序号不在槽里 / 该槽瓦片没绑好(weights≤0)→ uFaceMissingColor 深灰兜底
|
|
25
25
|
* (皇上旨 09-28「装不下就深灰」;weights 闸是 09-29 拆分时补的 —— 原运行时分支没这道闸,
|
|
26
26
|
* 槽没绑好但序号命中会采到 vec3(0) 纯黑,深灰才是钦定兜底色)。
|
|
27
27
|
*/
|
|
28
28
|
function buildFloorMappingFragment(maxPano) {
|
|
29
|
-
// 每个全景点占 **
|
|
29
|
+
// 每个全景点占 **2** 张拼合槽纹理(18 片 6×3 按半幅分:左半幅 / 右半幅,每槽 3×3=9 片)⇒ 8 × 2 = 16 = sampler 硬顶
|
|
30
30
|
const tileCount = maxPano * RT_STITCH_SLOT_COUNT;
|
|
31
31
|
let slotCalc = ""; // 每槽各自采样出 linK(weights[k]>0 才采;没绑好保持 0,由 facePick 的 weights 闸兜成深灰)
|
|
32
32
|
let slotFacePick = ""; // 逐槽展开「panoIndices[k]==vPanoIndex 则取 lin{k}」(ANGLE 禁动态索引 ⇒ JS 常量展开)
|
|
33
33
|
for (let k = 0; k < maxPano; k++) {
|
|
34
|
-
const base = k * RT_STITCH_SLOT_COUNT; // 本点占
|
|
34
|
+
const base = k * RT_STITCH_SLOT_COUNT; // 本点占 2 个连续纹理槽:base=k*2 .. base+1(顺序 [左半幅, 右半幅])
|
|
35
35
|
// ⚠️ ANGLE(D3D) 禁止动态索引 sampler 数组 ⇒ 展开成「base + 字面量」常量下标 if 链;末条裸 else 兜住 u==1 边界
|
|
36
36
|
const slotSamples = [];
|
|
37
37
|
for (let s = 0; s < RT_STITCH_SLOT_COUNT; s++) {
|
|
@@ -56,13 +56,13 @@ function buildFloorMappingFragment(maxPano) {
|
|
|
56
56
|
float lat = asin(clamp(dir.y, -1.0, 1.0));
|
|
57
57
|
// 等距柱状线性 v(= 全图 UV),与 blend / 单全景分支**逐字同口径**
|
|
58
58
|
float v = 0.5 + lat * 0.3183098861837907; // 1/PI
|
|
59
|
-
//
|
|
60
|
-
// ⭐ 10-06
|
|
59
|
+
// 两等分经度 -> 拼合槽下标 [左半幅=0, 右半幅=1](每槽 = 6×3 网格里左/右 3 列、3×3=9 片拼成,见 RT_STITCH_SLOT_TILES)
|
|
60
|
+
// ⭐ 10-06「竖着不再分块」继续成立、10-26 把横向 3 等分收回 2 等分 ⇒ 槽只随 u 走(与 blend / 单全景分支**逐字同口径**)
|
|
61
61
|
int tileIdx = int(clamp(floor(u * ${RT_STITCH_SLOT_COUNT}.0), 0.0, ${RT_STITCH_SLOT_COUNT - 1}.0));
|
|
62
62
|
float localU = u * ${RT_STITCH_SLOT_COUNT}.0 - float(tileIdx);
|
|
63
63
|
// ⛔ 纵向不再减半(槽就是全高)⇒ localV 恒等于 v;写成 nv/nv-1 = 纵向分辨率白丢一档
|
|
64
64
|
float localV = v;
|
|
65
|
-
// 🧩 该点这
|
|
65
|
+
// 🧩 该点这 2 槽装的是整图(whole 形态 / 没切过片)⇒ 还原成全图 UV 再采样(与 blend 逐字同口径)
|
|
66
66
|
float panoU = (uPanoTiled[${k}] > 0.5) ? localU : u;
|
|
67
67
|
float panoV = (uPanoTiled[${k}] > 0.5) ? localV : v;
|
|
68
68
|
// ⭐ 采样即线性(与单全景 / blend / selected 三路同一条口径,10-07 旨「色彩空间统一使用 liner」):纹理都标了
|
|
@@ -112,13 +112,13 @@ ${slotFacePick}
|
|
|
112
112
|
* 创建「全景序号直取」着色器材质(皇上旨 2026-09-29「三模式三 shader」之二):
|
|
113
113
|
* 编辑器「映射设置模式」的墙材质 + **基类 MktMesh(发布/预览)的固定墙材质**
|
|
114
114
|
* (皇上旨:mktmesh 就只有按照 attribute 配置来显示全景这一种固定的 shader)。
|
|
115
|
-
* uniform 形状与 blend 工厂同档(panoramas[
|
|
115
|
+
* uniform 形状与 blend 工厂同档(panoramas[16]/textureMatrices[8]/weights[8]/uPanoTiled[8])⇒
|
|
116
116
|
* 喂料复用 feedBlendProjection 的槽位指派路(feedFaceMapping),零新喂料路。
|
|
117
117
|
* uFloorCoreRadius/uFloorFadeRange/uFloorOpacity 三根本 shader 不读,但喂料统一入口会写 ⇒ JS 侧留着(静默忽略)。
|
|
118
118
|
*/
|
|
119
119
|
export function createMktFloorMappingShaderMaterial(options = {}) {
|
|
120
120
|
const maxPano = Math.min(options.maxPano ?? MKT_PANO_MAX_SLOTS, MKT_PANO_MAX_SLOTS);
|
|
121
|
-
const tileCount = maxPano * RT_STITCH_SLOT_COUNT; //
|
|
121
|
+
const tileCount = maxPano * RT_STITCH_SLOT_COUNT; // 8 点 × 左/右 2 槽 = 16(sampler 硬顶 16)
|
|
122
122
|
const panoramas = [];
|
|
123
123
|
const matrices = [];
|
|
124
124
|
for (let i = 0; i < tileCount; i++)
|
|
@@ -10,30 +10,30 @@ import { createPlaceholderTexture, floorVertexShader, RT_STITCH_SLOT_COUNT } fro
|
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* ⭐ 融合材质的全景点数**上限**:每点占 **3** 张拼合槽纹理(皇上旨 2026-10-23「全景的 RT 由原来的 2 个分成 3 个、
|
|
13
|
-
* 每个
|
|
14
|
-
* 本机 `MAX_TEXTURE_IMAGE_UNITS` 实测 **16
|
|
15
|
-
* (
|
|
13
|
+
* 每个 RT 上面 3×3=9 片」⇒ 原图切 6×3=18 片,按**半幅**分 2 槽)⇒ 点数 × 2 必须 ≤ sampler 硬顶。
|
|
14
|
+
* 本机 `MAX_TEXTURE_IMAGE_UNITS` 实测 **16**:每点 2 槽 ⇒ 取 ⌊16/2⌋ = **8** 点(10-23 那版每点 3 槽只能坐 5 点)
|
|
15
|
+
* (8 × 2 = 16 正好用满)。2026-10-26 需求回到「2 个 RT / 每 RT 3×3」⇒ **同屏全景点数 5 → 8**。
|
|
16
16
|
*
|
|
17
17
|
* ⭐⭐ 2026-10-09 皇上旨「MktMesh 只有映射一种,blend/selected 归编辑器」⇒ 该常量从 `mktShader.ts`
|
|
18
18
|
* **搬到这里**(映射材质的所在地)。它同时是库与编辑器那份 blend 的**共同上限**,两边必须同值。
|
|
19
19
|
*/
|
|
20
|
-
export const MKT_PANO_MAX_SLOTS =
|
|
20
|
+
export const MKT_PANO_MAX_SLOTS = 8;
|
|
21
21
|
|
|
22
22
|
/**
|
|
23
23
|
* 序号直取片元(皇上旨 2026-09-29「三模式三 shader」之二):
|
|
24
24
|
* 按三角面 aPanoIndex 在 panoIndices 槽里找对应全景纹理 —— **不看距离、不看夹角**(blend 那套打分/归约整段没有)。
|
|
25
|
-
* 槽内采样段(等距柱状投射 +
|
|
25
|
+
* 槽内采样段(等距柱状投射 + 左/右 2 张拼合槽 + 采样即线性、不再手动 pow 解码)与 blend **逐字同口径**;改采样口径两处同改。
|
|
26
26
|
* 未设序号 / 序号不在槽里 / 该槽瓦片没绑好(weights≤0)→ uFaceMissingColor 深灰兜底
|
|
27
27
|
* (皇上旨 09-28「装不下就深灰」;weights 闸是 09-29 拆分时补的 —— 原运行时分支没这道闸,
|
|
28
28
|
* 槽没绑好但序号命中会采到 vec3(0) 纯黑,深灰才是钦定兜底色)。
|
|
29
29
|
*/
|
|
30
30
|
function buildFloorMappingFragment(maxPano: number): string {
|
|
31
|
-
// 每个全景点占 **
|
|
31
|
+
// 每个全景点占 **2** 张拼合槽纹理(18 片 6×3 按半幅分:左半幅 / 右半幅,每槽 3×3=9 片)⇒ 8 × 2 = 16 = sampler 硬顶
|
|
32
32
|
const tileCount = maxPano * RT_STITCH_SLOT_COUNT;
|
|
33
33
|
let slotCalc = ""; // 每槽各自采样出 linK(weights[k]>0 才采;没绑好保持 0,由 facePick 的 weights 闸兜成深灰)
|
|
34
34
|
let slotFacePick = ""; // 逐槽展开「panoIndices[k]==vPanoIndex 则取 lin{k}」(ANGLE 禁动态索引 ⇒ JS 常量展开)
|
|
35
35
|
for (let k = 0; k < maxPano; k++) {
|
|
36
|
-
const base = k * RT_STITCH_SLOT_COUNT; // 本点占
|
|
36
|
+
const base = k * RT_STITCH_SLOT_COUNT; // 本点占 2 个连续纹理槽:base=k*2 .. base+1(顺序 [左半幅, 右半幅])
|
|
37
37
|
// ⚠️ ANGLE(D3D) 禁止动态索引 sampler 数组 ⇒ 展开成「base + 字面量」常量下标 if 链;末条裸 else 兜住 u==1 边界
|
|
38
38
|
const slotSamples: string[] = [];
|
|
39
39
|
for (let s = 0; s < RT_STITCH_SLOT_COUNT; s++) {
|
|
@@ -60,13 +60,13 @@ function buildFloorMappingFragment(maxPano: number): string {
|
|
|
60
60
|
float lat = asin(clamp(dir.y, -1.0, 1.0));
|
|
61
61
|
// 等距柱状线性 v(= 全图 UV),与 blend / 单全景分支**逐字同口径**
|
|
62
62
|
float v = 0.5 + lat * 0.3183098861837907; // 1/PI
|
|
63
|
-
//
|
|
64
|
-
// ⭐ 10-06
|
|
63
|
+
// 两等分经度 -> 拼合槽下标 [左半幅=0, 右半幅=1](每槽 = 6×3 网格里左/右 3 列、3×3=9 片拼成,见 RT_STITCH_SLOT_TILES)
|
|
64
|
+
// ⭐ 10-06「竖着不再分块」继续成立、10-26 把横向 3 等分收回 2 等分 ⇒ 槽只随 u 走(与 blend / 单全景分支**逐字同口径**)
|
|
65
65
|
int tileIdx = int(clamp(floor(u * ${RT_STITCH_SLOT_COUNT}.0), 0.0, ${RT_STITCH_SLOT_COUNT - 1}.0));
|
|
66
66
|
float localU = u * ${RT_STITCH_SLOT_COUNT}.0 - float(tileIdx);
|
|
67
67
|
// ⛔ 纵向不再减半(槽就是全高)⇒ localV 恒等于 v;写成 nv/nv-1 = 纵向分辨率白丢一档
|
|
68
68
|
float localV = v;
|
|
69
|
-
// 🧩 该点这
|
|
69
|
+
// 🧩 该点这 2 槽装的是整图(whole 形态 / 没切过片)⇒ 还原成全图 UV 再采样(与 blend 逐字同口径)
|
|
70
70
|
float panoU = (uPanoTiled[${k}] > 0.5) ? localU : u;
|
|
71
71
|
float panoV = (uPanoTiled[${k}] > 0.5) ? localV : v;
|
|
72
72
|
// ⭐ 采样即线性(与单全景 / blend / selected 三路同一条口径,10-07 旨「色彩空间统一使用 liner」):纹理都标了
|
|
@@ -117,13 +117,13 @@ ${slotFacePick}
|
|
|
117
117
|
* 创建「全景序号直取」着色器材质(皇上旨 2026-09-29「三模式三 shader」之二):
|
|
118
118
|
* 编辑器「映射设置模式」的墙材质 + **基类 MktMesh(发布/预览)的固定墙材质**
|
|
119
119
|
* (皇上旨:mktmesh 就只有按照 attribute 配置来显示全景这一种固定的 shader)。
|
|
120
|
-
* uniform 形状与 blend 工厂同档(panoramas[
|
|
120
|
+
* uniform 形状与 blend 工厂同档(panoramas[16]/textureMatrices[8]/weights[8]/uPanoTiled[8])⇒
|
|
121
121
|
* 喂料复用 feedBlendProjection 的槽位指派路(feedFaceMapping),零新喂料路。
|
|
122
122
|
* uFloorCoreRadius/uFloorFadeRange/uFloorOpacity 三根本 shader 不读,但喂料统一入口会写 ⇒ JS 侧留着(静默忽略)。
|
|
123
123
|
*/
|
|
124
124
|
export function createMktFloorMappingShaderMaterial(options: { maxPano?: number } = {}): ShaderMaterial {
|
|
125
125
|
const maxPano = Math.min(options.maxPano ?? MKT_PANO_MAX_SLOTS, MKT_PANO_MAX_SLOTS);
|
|
126
|
-
const tileCount = maxPano * RT_STITCH_SLOT_COUNT; //
|
|
126
|
+
const tileCount = maxPano * RT_STITCH_SLOT_COUNT; // 8 点 × 左/右 2 槽 = 16(sampler 硬顶 16)
|
|
127
127
|
const panoramas: import("three").Texture[] = [];
|
|
128
128
|
const matrices: Matrix4[] = [];
|
|
129
129
|
for (let i = 0; i < tileCount; i++) panoramas.push(createPlaceholderTexture());
|
package/MktMesh/mktShader.d.ts
CHANGED
|
@@ -110,43 +110,44 @@ export declare function setMktPanoPoints(material: ShaderMaterial | null | undef
|
|
|
110
110
|
* 故「地板/墙体/立方体」共用这一个着色器,无需为立方体另写实例化版(消除原先的 instanced 分支)。
|
|
111
111
|
* instanceColor(逐实例染色,选中高亮)同样用 USE_INSTANCING_COLOR 宏在顶点→片段间传递。
|
|
112
112
|
*/
|
|
113
|
-
/** ⭐
|
|
114
|
-
* 1 张 **
|
|
115
|
-
*
|
|
113
|
+
/** ⭐ 18 瓦片拼合(2026-10-26 需求:一张全景切 **横 6 × 竖 3 = 18 片**,每 **横 3 × 竖 3 = 9 片**离屏拼成
|
|
114
|
+
* 1 张 **6144×6144** 槽纹理,**左/右 2 槽**组成完整全景;上一版是 10-23 的 3×3 = 9 片 / 按列 3 槽 4096×6144,
|
|
115
|
+
* 再上一版 10-06 晚的 8×4 = 32 片 / 左右 2 槽 4096²,最早 09-29 的 4×4 = 16 片)的「槽虚拟地址」前缀。
|
|
116
116
|
* 虚拟键不是真 URL,纹理由 `PanoTileStitcher` 用 shader 逐格画进 `WebGLRenderTarget` 提供,
|
|
117
117
|
* 消费方(基类 `_ensurePanoTiles` / 编辑器 `_peekTileAt`)见前缀即走拼合器,⛔ 不得当 URL 下载。
|
|
118
118
|
* ⚠️ 键协议 `rt:<batch>#<slot>` 与 `uPanoTiled` 这套对外接口**一字未改** —— 变的只有「每批几条地址」
|
|
119
|
-
* 和「槽怎么分」;`slot` 取值 0..
|
|
120
|
-
* ⚠️ 旧存档不兼容(与 10-06 同一口径):存档里
|
|
119
|
+
* 和「槽怎么分」;`slot` 取值 0..1,消费方一律用 `RT_STITCH_SLOT_COUNT` 取,不许写死。
|
|
120
|
+
* ⚠️ 旧存档不兼容(与 10-06 / 10-23 同一口径):存档里 9 条(或历代 16/32/64 条)瓦片地址会因张数不符被判废
|
|
121
|
+
* ⇒ **老项目需重新上传**(本次已明确不兼容,用户会重传图片)。 */
|
|
121
122
|
export declare const RT_STITCH_KEY_PREFIX = "rt:";
|
|
122
|
-
/** 原图**横向**(经度方向 u
|
|
123
|
-
export declare const RT_STITCH_COLS =
|
|
124
|
-
/** 原图**纵向**(纬度方向 v
|
|
123
|
+
/** 原图**横向**(经度方向 u)切几片(需求「横 6」) */
|
|
124
|
+
export declare const RT_STITCH_COLS = 6;
|
|
125
|
+
/** 原图**纵向**(纬度方向 v)切几片(需求「竖 3」)⇒ 一槽在纵向上装满整幅 3 片,横向才分左/右 */
|
|
125
126
|
export declare const RT_STITCH_ROWS = 3;
|
|
126
|
-
/** 一个批次(= 一个全景点)的瓦片总数 =
|
|
127
|
+
/** 一个批次(= 一个全景点)的瓦片总数 = 6 × 3 = 18;`tiles` 存档数组的硬上限 */
|
|
127
128
|
export declare const RT_STITCH_TILES_PER_BATCH: number;
|
|
128
|
-
/**
|
|
129
|
-
export declare const RT_STITCH_SLOT_CELL_COLS =
|
|
130
|
-
/**
|
|
131
|
-
* ⚠️ 10-23
|
|
129
|
+
/** 一个拼合槽**横向**几格(需求「每个 RT 上面 3×3=9」⇒ 一槽 = 原图左半幅/右半幅 = 横 3 格)*/
|
|
130
|
+
export declare const RT_STITCH_SLOT_CELL_COLS = 3;
|
|
131
|
+
/** 一个拼合槽**纵向**几格(同上 ⇒ 竖 3 格)
|
|
132
|
+
* ⚠️ 横竖**不再同数**是 10-23 起的口径(旧字段 `RT_STITCH_SLOT_GRID`「方形假设」已整条作废),
|
|
132
133
|
* 格数、格位、quad 摆位一律分轴取(`rtStitchCellPos` / `PanoTileStitcher._stitchCell`)。 */
|
|
133
134
|
export declare const RT_STITCH_SLOT_CELL_ROWS = 3;
|
|
134
|
-
/** 一个拼合槽的格数 =
|
|
135
|
+
/** 一个拼合槽的格数 = 3 × 3 = 9(画满 9 格 = 这一槽齐活) */
|
|
135
136
|
export declare const RT_STITCH_CELLS_PER_SLOT: number;
|
|
136
|
-
/** 拼合槽个数 =
|
|
137
|
-
* ⛔ 别以为
|
|
138
|
-
*
|
|
139
|
-
* ⭐ 分块口径:槽 `s` = 原图**第
|
|
140
|
-
*
|
|
141
|
-
export declare const RT_STITCH_SLOT_COUNT =
|
|
142
|
-
/** 单槽像素尺寸 **
|
|
143
|
-
*
|
|
144
|
-
*
|
|
145
|
-
* ⚠️ 每格 =
|
|
146
|
-
* ⚠️
|
|
147
|
-
*
|
|
137
|
+
/** 拼合槽个数 = **左/右 2 槽**(需求「一个全景是 2 个 RT,每个 RT 上面 3×3=9」)⇒ 一个全景点占 **2 个 sampler**。
|
|
138
|
+
* ⛔ 别以为 18 片就要 18 个 sampler:本机 `MAX_TEXTURE_IMAGE_UNITS` 实测 **16** 是硬顶,
|
|
139
|
+
* 2 槽 × 同屏 8 景点 = 16 正好用满 ⇒ `MKT_PANO_MAX_SLOTS` 回到 **8**(上一版 3 槽只能坐 5 点)。
|
|
140
|
+
* ⭐ 分块口径:槽 `s` = 原图**第 `3s`~`3s+2` 列**(行 0-2)⇒ 每槽覆盖 **横向 180° × 纵向 180°**,
|
|
141
|
+
* 与「一槽横 3 格 × 竖 3 格」同一条口径(槽纹理尺寸见下 `RT_STITCH_SLOT_W/H`)。 */
|
|
142
|
+
export declare const RT_STITCH_SLOT_COUNT = 2;
|
|
143
|
+
/** 单槽像素尺寸 **6144×6144**(需求 2026-10-26「2 个 RT,每个 RT 上面 3×3=9」):
|
|
144
|
+
* 2 槽 = 有效分辨率 **12288×6144**,与 6×3 切片的原图(12288×6144 ⇒ 每片 2048×2048)**逐像素 1:1**;
|
|
145
|
+
* 单全景 RT 总量 2×6144² = 75.5 Mpx 与上一版 3×(4096×6144) **一字不差** ⇒ 片数翻倍而画质、显存都不变。
|
|
146
|
+
* ⚠️ 每格 = 2048×2048(横竖**等**了,但摆格仍分轴取,见 `RT_STITCH_SLOT_CELL_COLS/ROWS`)。
|
|
147
|
+
* ⚠️ 代价(与上一版同档):单全景常驻显存 ≈ 384MB(含 mipmap);同屏点数因每点只占 2 sampler 回到 8 ⇒
|
|
148
|
+
* 8 点常驻 ≈ 3GB,那是「同屏点数」这一档带来的,⛔ 不许为此缩 RT。
|
|
148
149
|
* ⚠️ 红线(「千万不要降低质量」):这两个数与「原图切几片」无关,⛔ 不许当成省显存的旋钮去缩。 */
|
|
149
|
-
export declare const RT_STITCH_SLOT_W =
|
|
150
|
+
export declare const RT_STITCH_SLOT_W = 6144;
|
|
150
151
|
export declare const RT_STITCH_SLOT_H = 6144;
|
|
151
152
|
export declare const floorVertexShader = "\n #include <common>\n #include <logdepthbuf_pars_vertex>\n\n // \u6295\u5F71\u7A7A\u95F4\u9006\u77E9\u9635\uFF1A\u89C1\u5355\u5168\u666F\u9876\u70B9\u7740\u8272\u5668\u5904\u7684\u540C\u4E00\u6BB5\u8BF4\u660E\uFF08\u7687\u4E0A\u65E8 2026-09-19\uFF09\u3002\n // \u9ED8\u8BA4\u4FDD\u6301\u5355\u4F4D\u9635\uFF08\u5730\u677F / \u7ACB\u65B9\u4F53\u884C\u4E3A\u4E0E\u6539\u9020\u524D\u5B8C\u5168\u4E00\u81F4\uFF09\uFF1B\u7F16\u8F91\u5668\u5899\uFF08MktDevMesh\uFF09\u4E0E\u53D1\u5E03\u6001 MktMesh\n // \u4E00\u6837\u6BCF\u5E27\u5199\u5165 inverse(matrixWorld)\uFF0C\u6545\u5899\u4E0A\u7684\u7EB9\u7406\u540C\u6837\u4E0D\u968F\u6574\u4F53\u53D8\u6362\u6F02\u79FB\u3002\n uniform mat4 uProjInvMatrix;\n\n // \u5168\u666F\u5E8F\u53F7\u6620\u5C04\u6A21\u5F0F\uFF1A\u672C\u4E09\u89D2\u9762\u5F52\u5C5E\u7684\u5168\u5C40\u5168\u666F\u5E8F\u53F7\uFF08\u6765\u81EA geometry \u7684 aPanoIndex\uFF1B\u65E0\u6B64 attribute \u7684\u5BF9\u8C61\u6052\u4E3A 0\uFF0C\u4EC5 mode=1 \u65F6\u8BFB\u53D6\uFF09\n attribute float aPanoIndex;\n varying float vPanoIndex;\n\n varying vec3 vProjPos;\n // \u53D6\u56FE\u300C\u6B63\u9762\u5939\u89D2\u300D\u5224\u636E\u7528\uFF08\u7687\u4E0A\u65E8 2026-09-27 \u6DF1\u591C\uFF09\uFF1A\u51E0\u4F55\u6CD5\u7EBF\uFF0C\u53D8\u6362\u5230\u4E0E vProjPos **\u540C\u4E00\u7A7A\u95F4**\n // \uFF08uProjInvMatrix * modelMatrix * instanceMatrix \u7684\u65CB\u8F6C\u90E8\u5206\uFF09\uFF0C\u7247\u5143\u91CC\u4E0E\u300C\u70B9\u2192\u5168\u666F\u300D\u5411\u91CF\u70B9\u79EF\u7B97\u5939\u89D2\u3002\n // \u26D4 normal \u662F three.js \u81EA\u52A8\u6CE8\u5165\u7684\u6807\u51C6 attribute\uFF08\u5899=computeVertexNormals \u9010\u9762\u6CD5\u7EBF / \u5C01\u76D6=ShapeGeometry /\n // \u5730\u677F=PlaneGeometry / \u5BB6\u5177=BoxGeometry\uFF09\uFF0C\u6B64\u5904\u65E0\u9700\u81EA\u5DF1\u58F0\u660E\u3002\n varying vec3 vWNormal;\n #ifdef USE_INSTANCING_COLOR\n varying vec3 vInstanceColor;\n #endif\n\n void main() {\n // \u5B9E\u4F8B\u77E9\u9635\uFF1AInstancedMesh \u81EA\u52A8\u5B9A\u4E49 USE_INSTANCING \u5E76\u63D0\u4F9B instanceMatrix\uFF1B\n // \u666E\u901A Mesh\uFF08\u5899/\u5730\u677F\uFF09\u65E0\u5B9E\u4F8B\u77E9\u9635\uFF0C\u9000\u5316\u4E3A\u5355\u4F4D\u9635 \u2014\u2014 \u4E00\u4EFD\u7740\u8272\u5668\u540C\u65F6\u670D\u52A1\u5899/\u5730\u677F/\u7ACB\u65B9\u4F53\u3002\n #ifdef USE_INSTANCING\n mat4 im = instanceMatrix;\n #else\n mat4 im = mat4(1.0);\n #endif\n // \u6A21\u578B/\u5B9E\u4F8B\u5C40\u90E8\u5750\u6807\uFF1B\u7ACB\u65B9\u4F53\u5B9E\u4F8B\u7684\u53D8\u6362\u5728 instanceMatrix\uFF0C\u5899/\u5730\u677F\u5728 modelMatrix\n vec4 modelPos = im * vec4(position, 1.0);\n vProjPos = (uProjInvMatrix * modelMatrix * modelPos).xyz;\n // \u6CD5\u7EBF\u4E0E vProjPos \u8D70\u540C\u4E00\u6761\u77E9\u9635\u94FE\uFF08mat3 \u53D6\u65CB\u8F6C/\u7F29\u653E\u90E8\u5206\uFF0C\u7247\u5143\u91CC normalize \u62B5\u6D88\u7F29\u653E\uFF09\n vWNormal = mat3(uProjInvMatrix * modelMatrix * im) * normal;\n // \u5168\u666F\u5E8F\u53F7\u6620\u5C04\u6A21\u5F0F\uFF1A\u628A\u672C\u4E09\u89D2\u9762\u7684\u5F52\u5C5E\u5E8F\u53F7\u4F20\u7ED9\u7247\u5143\uFF08geometry \u65E0 aPanoIndex \u7684\u5BF9\u8C61\u6052\u4E3A 0\uFF0C\u4EC5 mode=1 \u65F6\u8BFB\u53D6\uFF09\n vPanoIndex = aPanoIndex;\n\n #ifdef USE_INSTANCING_COLOR\n vInstanceColor = instanceColor;\n #endif\n\n gl_Position = projectionMatrix * modelViewMatrix * modelPos;\n\n #include <logdepthbuf_vertex>\n }\n";
|
|
152
153
|
/** 1×1 **中性灰**占位纹理:panorama 在尚未激活任何纹理 / 该点还没设图片时使用,既避免空纹理采样报错,
|
|
@@ -160,27 +161,27 @@ export declare function createPlaceholderTexture(): DataTexture;
|
|
|
160
161
|
/**
|
|
161
162
|
* 全景纹理形态(皇上旨 2026-09-22「全景球可以切成 4 片和一整片,两者效果很不一样,做个功能可以切换」)。
|
|
162
163
|
*
|
|
163
|
-
* "tiled" =
|
|
164
|
-
* 10-23
|
|
164
|
+
* "tiled" = 2 个 sampler 各装一张**离屏拼合好的槽纹理**(原图 **6×3 = 18 片**,每「横 3 × 竖 3」= 9 片拼一张;
|
|
165
|
+
* 2026-10-26 需求;再早是 10-23 的 3×3 = 9 片 / 3 槽、10-06 晚的 8×4 = 32 片 / 2 槽、同日的 8×8 = 64 片 / 4 槽、09-29 的 4×4 = 16 片),
|
|
165
166
|
* `uPanoTiled` 写 1;
|
|
166
|
-
* "whole" =
|
|
167
|
+
* "whole" = 2 个 sampler 都装**同一张完整等距柱状原图**,`uPanoTiled` 写 0(改用全图 UV)。
|
|
167
168
|
*
|
|
168
169
|
* ⚠️ 两种形态在**几何上应当逐像素一致**(`panoU/panoV` 的还原式就是恒等式,见文件头 🧩 段与
|
|
169
170
|
* `test/panoVMapping.test.js` 的等价性数值证明)。所以线上若看着「很不一样」,差异只可能来自下面两条,
|
|
170
171
|
* 与本切换功能无关、也不会被它修掉:
|
|
171
172
|
* ① **分辨率**:`x-oss-process=image/resize,m_lfit,w_<ossSize>` 是**按 URL** 生效的,且 2026-09-23 皇上定
|
|
172
|
-
* 「**切片的瓦片不走该尺寸档,默认用原图**」(每片本就只有原图的 1/
|
|
173
|
+
* 「**切片的瓦片不走该尺寸档,默认用原图**」(每片本就只有原图的 1/6 宽 × 1/3 高,再按档缩是二次损失)⇒
|
|
173
174
|
* 判据 = `mktPanoTiledFlag(...)===1`(喂地址与写 `uPanoTiled` 同源,见 `resolveOssUrl` 两处)。
|
|
174
175
|
* 于是 tiled 态 = 拼合槽纹理**逐片取自原始分辨率**瓦片(合计像素≈整张原图,10-06 那版仍是 8192×4096 等效),
|
|
175
176
|
* whole 态 = 整图按档(w_1024 ⇒ 等效 1024×512)。
|
|
176
177
|
* ⚠️ 两档清晰度差**不是固定的倍数**,而取决于「原图宽 ÷ 所选档位」;又因 `m_lfit` 只缩不放,
|
|
177
178
|
* 原图宽 ≤ 2×档位时 whole 态其实也没被缩,两态清晰度自然接近 —— 别把这当成「切换坏了」。
|
|
178
|
-
* ② **瓦片边界**(10-06 晚切 32 片起这一条分两层,10-
|
|
179
|
-
* · **拼合槽之间**(u=1/
|
|
179
|
+
* ② **瓦片边界**(10-06 晚切 32 片起这一条分两层,10-26 回到「2 槽 + 每槽 3×3」后两层口径又换一档):
|
|
180
|
+
* · **拼合槽之间**(u=1/2 那**一道**竖;⭐ v 方向不再有横缝 —— 每槽就是全高):2 张槽是 2 张独立纹理,
|
|
180
181
|
* 各自 mip + ClampToEdge ⇒ 仍可能有细亮/细暗线,这一条**与 09-29 那版一字未变**,
|
|
181
182
|
* `RT_STITCH_SEAM_MARGIN_PX` 管不到它(它治的是「同一张纹理内」的格子边界);
|
|
182
183
|
* whole 态是同一张贴图,天然无此缝。
|
|
183
|
-
* · **拼合槽内部**(每张
|
|
184
|
+
* · **拼合槽内部**(每张 6144×6144 里 3×3 片 ⇒ 2 道横缝 + 2 道竖缝;上一版 4096×6144 只有 2 横 0 竖):
|
|
184
185
|
* 靠「上传多切 `RT_STITCH_SEAM_MARGIN_PX` 像素 + 拼合只采中间那块」消掉,见该常量的说明。
|
|
185
186
|
*
|
|
186
187
|
* 旧数据 / 种子图没有 `tiles`(或只有 1 条)⇒ 两种形态都只能退回整图,`whole` 与 `tiled` 表现相同。
|
|
@@ -194,7 +195,7 @@ export declare function isPanoTexMode(v: unknown): v is PanoTexMode;
|
|
|
194
195
|
export declare const MISSING_TILE_GRAY = "#767676";
|
|
195
196
|
/** 接缝余量(**原图像素**,每片向四边各多切这么多;贴原图边那侧裁到剩多少算多少)。
|
|
196
197
|
*
|
|
197
|
-
* 10-
|
|
198
|
+
* 10-26 每槽装 3×3 = 9 格 ⇒ 一张槽内部的接缝是 **2 横 2 竖**(上一版每槽一竖列时只有 2 横 0 竖),这一条是随之而来的画质护栏:
|
|
198
199
|
* ① 上传时每片**向四边多切 M 像素**(`rtStitchTileRects`);
|
|
199
200
|
* ② 拼合时**只采中间那块**(`rtStitchTileInset` 算出的 UV 内缩窗口),多切的那一圈**不画进格子**。
|
|
200
201
|
*
|
|
@@ -208,12 +209,12 @@ export declare const MISSING_TILE_GRAY = "#767676";
|
|
|
208
209
|
export declare const RT_STITCH_SEAM_MARGIN_PX = 8;
|
|
209
210
|
/**
|
|
210
211
|
* 「一张图切成几张瓦片、瓦片怎么分组进拼合槽」的**网格描述** —— 皇上旨 2026-10-20「上传的这个图切成
|
|
211
|
-
* 4*4=16 片吧,加载的时候,也是一帧载入一片」⇒ 拼合器从此要同时服务两种网格(全景
|
|
212
|
+
* 4*4=16 片吧,加载的时候,也是一帧载入一片」⇒ 拼合器从此要同时服务两种网格(全景 6×3 / 图片平面那一份),
|
|
212
213
|
* 于是这一组参数必须能**当数据传**,⛔ 不许在拼合器里再写死一遍全景那套数字(那就是两份实现)。
|
|
213
214
|
* ⭐ 同一条参数化让 10-21 旨「平面切成 2*2=4 份,不用切成 16 份了」只需要改 `IMAGE_TILE_GRID` 一处。
|
|
214
215
|
*
|
|
215
216
|
* ⚠️ 只描述「格子怎么排」,不含槽纹理像素尺寸(那是 GL 资源,由拼合器按消费方给的 layout 建)。
|
|
216
|
-
* ⚠️ `slotCellCols` / `slotCellRows` = **每槽横几格 / 竖几格**(10-23
|
|
217
|
+
* ⚠️ `slotCellCols` / `slotCellRows` = **每槽横几格 / 竖几格**(10-23 起两个数独立,现行全景是每槽 3×3 = 原图左/右半幅;
|
|
217
218
|
* 旧的单一 `slotGrid`「横竖同数」假设已整条作废 ⇒ 格数 = `slotCellCols * slotCellRows`)。
|
|
218
219
|
*/
|
|
219
220
|
export interface TileGridLayout {
|
|
@@ -257,7 +258,7 @@ export type TileLayout = TileGridLayout & {
|
|
|
257
258
|
rtW: number;
|
|
258
259
|
rtH: number;
|
|
259
260
|
};
|
|
260
|
-
/** 全景的标准布局(
|
|
261
|
+
/** 全景的标准布局(6×3 网格 / 2 槽 / 6144×6144 RT)—— 一槽 = 原图左/右半幅 */
|
|
261
262
|
export declare const PANO_TILE_LAYOUT: TileLayout;
|
|
262
263
|
/**
|
|
263
264
|
* 图片平面的布局:2×2 网格 / 1 槽,RT 宽高比 = 原图宽高比,长边 4096(10-21 旨把 16 片改成 4 片,
|
|
@@ -266,27 +267,27 @@ export declare const PANO_TILE_LAYOUT: TileLayout;
|
|
|
266
267
|
* 平面材质 UV [0,1]² ⇒ 不管平面尺寸多大都不会拉伸,RT 尺寸只跟原图走。
|
|
267
268
|
*/
|
|
268
269
|
export declare function imageTileLayout(natW: number, natH: number): TileLayout;
|
|
269
|
-
/**
|
|
270
|
+
/** 18 瓦片批次的标识 = 第一条**非空**瓦片地址(同批上传 URL 前缀一致,足以唯一;
|
|
270
271
|
* 09-29 晚旨「不足张数缺的地方涂灰」后批次里允许有空串占位 ⇒ 取首个非空,防首张缺失时键为空串互撞) */
|
|
271
272
|
export declare function rtStitchBatchOf(tiles: string[]): string;
|
|
272
273
|
/** 某一拼合槽的虚拟键:`rt:<batch>#<slot>` */
|
|
273
274
|
export declare function rtStitchKey(batch: string, slot: number): string;
|
|
274
|
-
/** 是否拼合槽(`rt:<batch>#<slot>`)的虚拟键 —— 16 / 32 / 64 / 现行
|
|
275
|
+
/** 是否拼合槽(`rt:<batch>#<slot>`)的虚拟键 —— 16 / 32 / 64 / 9 片 / 现行 18 片**同一个前缀**,键本身不含片数信息 */
|
|
275
276
|
export declare function isRtStitchKey(key: string): boolean;
|
|
276
277
|
/** 解析虚拟键 → { batch, slot };非 rt 键返回 null */
|
|
277
278
|
export declare function rtStitchKeyParts(key: string): {
|
|
278
279
|
batch: string;
|
|
279
280
|
slot: number;
|
|
280
281
|
} | null;
|
|
281
|
-
/** 槽 slot 用哪
|
|
282
|
-
* 槽 0 =
|
|
283
|
-
* ⭐ 只按 **u**
|
|
284
|
-
* ⚠️ 表是**从上面那几个网格常数生成**的(⛔ 手抄
|
|
282
|
+
/** 槽 slot 用哪 9 张瓦片(原图 **6 列 × 3 行 行优先**下标 `r*6+c`;**槽内格序 = 横 3 × 竖 3、图像左上起**):
|
|
283
|
+
* 槽 0 = **左半幅**(列 0-2)→ `[0,1,2, 6,7,8, 12,13,14]`;槽 1 = **右半幅**(列 3-5)→ `[3,4,5, 9,10,11, 15,16,17]`。
|
|
284
|
+
* ⭐ 只按 **u** 分槽(需求 2026-10-26「一个全景是 2 个 RT,每个 RT 上面 3×3=9」⇒ 一槽 = 原图半幅 = 横 180° × 全高 180°),
|
|
285
|
+
* ⚠️ 表是**从上面那几个网格常数生成**的(⛔ 手抄 18 个数):正确性由护栏 `test/mktmesh.test.js` BE 组
|
|
285
286
|
* 对着手写死的字面量逐个数断言 —— 改了网格常数而护栏没跟着改,当场红。 */
|
|
286
287
|
export declare const RT_STITCH_SLOT_TILES: ReadonlyArray<ReadonlyArray<number>>;
|
|
287
288
|
/** 槽内第 cell 格在**图像方向**的位置 `[列, 行]`(0 起,与 `RT_STITCH_SLOT_TILES` 的格序同一口径)。
|
|
288
289
|
* ⚠️ 这是「图像方向」(行 0 = 图像最上),GL 的 y 向上 ⇒ 画进 RT 时 y 要翻(拼合器里那句 `1 - (2*r+1)/n`)。
|
|
289
|
-
* `slotCellCols` 默认全景那档(
|
|
290
|
+
* `slotCellCols` 默认全景那档(3 = 一槽就是原图半幅的三列);图片平面传 2。 */
|
|
290
291
|
export declare function rtStitchCellPos(cell: number, slotCellCols?: number): [number, number];
|
|
291
292
|
/** 一片瓦片的切图矩形(原图像素)。`sx/sy/sw/sh` = **含多切余量**的实际切片区;
|
|
292
293
|
* `ml/mt/mr/mb` = 四边各多切了多少(贴原图边那侧被裁 ⇒ 0)。 */
|
|
@@ -300,16 +301,16 @@ export interface RtStitchTileRect {
|
|
|
300
301
|
mr: number;
|
|
301
302
|
mb: number;
|
|
302
303
|
}
|
|
303
|
-
/**
|
|
304
|
-
* ⭐ 10-
|
|
304
|
+
/** 18 片瓦片的切图矩形(行优先、图像左上起,下标 `i = r*6+c` 与 `RT_STITCH_SLOT_TILES` 同源;
|
|
305
|
+
* ⭐ 10-26 需求「横 6 × 竖 3 = 18」:`r` 走 `RT_STITCH_ROWS`(3)、`c` 走 `RT_STITCH_COLS`(6)。
|
|
305
306
|
*
|
|
306
307
|
* ⭐ **上传侧(`panoramaUpload`)与拼合侧(`PanoTileStitcher`)必须共用这一份几何**:
|
|
307
308
|
* 上传多切多少、拼合就内缩多少;两边各算一次就是「缝没治掉、反而把画面挤歪」。
|
|
308
|
-
* 拼合侧拿不到原图尺寸(它只有
|
|
309
|
+
* 拼合侧拿不到原图尺寸(它只有 18 个 URL 和 18 张已解码纹理),所以它用 `rtStitchTileInset`
|
|
309
310
|
* —— 那条只需「下标 + 该瓦片自己的像素尺寸」,两者等价的前提是「多切量 = 常数 M、只有贴边那几片被裁」,
|
|
310
311
|
* 而「贴不贴边」纯由下标决定 ⇒ 护栏 BE 组用同一批 (W,H) 把两条算路对表钉死。 */
|
|
311
312
|
export declare function rtStitchTileRects(w: number, h: number, grid?: TileGridLayout): RtStitchTileRect[];
|
|
312
|
-
/** 这片瓦片有没有贴原图边界(
|
|
313
|
+
/** 这片瓦片有没有贴原图边界(6×3 ⇒ 18 片里外圈那 14 片至少贴一条边,只有中间那 4 片四边都不贴;贴边的**那一侧**多切量被裁成 0)。
|
|
313
314
|
* 拼合侧靠它 + 瓦片自己的像素尺寸还原内缩量 ⇒ 不必知道原图多大。
|
|
314
315
|
* ⚠️ 下标拆分必须按 **列数 COLS**(`i = r*cols+c`),⛔ 不是 ROWS。 */
|
|
315
316
|
export declare function rtStitchTileEdgeClip(i: number, grid?: TileGridLayout): {
|
|
@@ -329,18 +330,18 @@ export declare function rtStitchTileEdgeClip(i: number, grid?: TileGridLayout):
|
|
|
329
330
|
* ⇒ 纹理 **v=0 = 图像下边**,所以图像顶部余量 `mt` 落在 `v1`、底部 `mb` 落在 `v0`。搞反 = 上下颠倒。 */
|
|
330
331
|
export declare function rtStitchTileInset(i: number, tw: number, th: number, grid?: TileGridLayout): [number, number, number, number];
|
|
331
332
|
/**
|
|
332
|
-
* 「这 `RT_STITCH_SLOT_COUNT`(
|
|
333
|
+
* 「这 `RT_STITCH_SLOT_COUNT`(2) 个纹理槽到底喂哪几个地址」。⚠️ **必须**与 `mktPanoTiledFlag` 同源、同一时机调用:
|
|
333
334
|
* 只改标记不改地址(或反之)= 用整图 UV 去采一张瓦片 / 用瓦片内 UV 去采整图,画面立刻错乱。
|
|
334
335
|
* 非 tiled 态(或该点压根没切过片)一律回退成「各槽同为一张整图」。
|
|
335
|
-
* ⭐ 2026-10-
|
|
336
|
-
* 不足 9
|
|
337
|
-
*
|
|
338
|
-
* ⚠️ 返回长度由 `RT_STITCH_SLOT_COUNT` 派生(⛔ 不许手写
|
|
336
|
+
* ⭐ 2026-10-26 需求「只支持 18 张(6×3)」:只要有瓦片(1~18 条)一律走拼合器(rt: 虚拟键),
|
|
337
|
+
* 不足 18 张的位置由拼合器**涂灰**(一眼看出数据不全);3×3=9 张、8×4=32 张、8×8=64 张与 4×4=16 张那几版**都不做兼容**
|
|
338
|
+
* (「无须兼容正常使用,有异常我会重传」⇒ 旧存档的 9 / 32 / 64 条地址张数不符被判废、重传即可)。
|
|
339
|
+
* ⚠️ 返回长度由 `RT_STITCH_SLOT_COUNT` 派生(⛔ 不许手写 2 个 rtStitchKey —— 槽数再变会漏改)。
|
|
339
340
|
*/
|
|
340
341
|
export declare function mktPanoTexUrls(url: string, tiles: string[] | undefined, mode?: PanoTexMode): string[];
|
|
341
342
|
/**
|
|
342
|
-
* 「这
|
|
343
|
-
* `tiles` 有 **任意 1~
|
|
343
|
+
* 「这 2 个纹理槽是不是真瓦片」的判据 —— **必须**与喂纹理处的回退式(`mktPanoTexUrls`)同源:
|
|
344
|
+
* `tiles` 有 **任意 1~18 条**地址(不足 18 = 数据不全,缺的格子拼合时涂灰)**且**当前形态选的是 tiled = 是瓦片;
|
|
344
345
|
* 否则各槽同为一张整图(旧数据 / 种子图 / 用户切整片)。
|
|
345
346
|
*/
|
|
346
347
|
export declare function mktPanoTiledFlag(tiles: string[] | undefined, mode?: PanoTexMode): 0 | 1;
|