three-base 2.0.188 → 2.0.192
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/MeshBase.d.ts +23 -0
- package/MeshBase.js +47 -1
- package/MeshBase.ts +301 -257
- package/MktMesh/MktMesh.d.ts +36 -3
- package/MktMesh/MktMesh.js +72 -5
- package/MktMesh/MktMesh.ts +1437 -1368
- package/MktMesh/imagePlane.d.ts +4 -0
- package/MktMesh/imagePlane.js +8 -0
- package/MktMesh/imagePlane.ts +7 -0
- package/MktMesh/mktMappingShader.d.ts +5 -3
- package/MktMesh/mktMappingShader.js +7 -5
- package/MktMesh/mktMappingShader.ts +7 -5
- package/MktMesh/mktShader.d.ts +58 -54
- package/MktMesh/mktShader.js +61 -57
- package/MktMesh/mktShader.ts +68 -64
- package/MktMesh/modelSlot.d.ts +8 -0
- package/MktMesh/modelSlot.js +26 -2
- package/MktMesh/modelSlot.ts +26 -2
- package/MktMesh/panoTileStitcher.d.ts +8 -6
- package/MktMesh/panoTileStitcher.js +36 -25
- package/MktMesh/panoTileStitcher.ts +37 -26
- package/MktMesh/types.d.ts +2 -1
- package/MktMesh/types.ts +2 -1
- package/ThreeBase.d.ts +4 -1
- package/ThreeBase.js +51 -42
- package/ThreeBase.ts +51 -42
- package/instanced/InstancedMeshBase.js +3 -0
- package/instanced/InstancedMeshBase.ts +3 -0
- package/package.json +1 -1
package/MktMesh/mktShader.js
CHANGED
|
@@ -321,7 +321,7 @@ export function setMktPanoPoints(material, matrices) {
|
|
|
321
321
|
* 修法 = `uPanoTiled`(单全景标量 / 融合每点数组):0 时把瓦片内 UV **还原成整图 UV**
|
|
322
322
|
* `panoU = u`、`panoV = v`(口径写死后这就是恒等式:横向 `0.5(2u)=u` / `0.5+0.5(2u−1)=u`;
|
|
323
323
|
* 纵向 10-06 晚起 localV 本就等于 v ⇒ 两个方向都退化成恒等式)。
|
|
324
|
-
* ⚠️ 判据与回退式**必须同源**(`mktPanoTiledFlag` = 「tiled 形态 且 tiles 有任意 1~
|
|
324
|
+
* ⚠️ 判据与回退式**必须同源**(`mktPanoTiledFlag` = 「tiled 形态 且 tiles 有任意 1~32 条」,现行只支持 8×4=32 张、不足涂灰),且每个回退喂料点都要写标记,
|
|
325
325
|
* 漏一处该对象就悄悄退回 1/2 拉伸。默认值取 1(已切片的真实上传数据行为不变)。
|
|
326
326
|
* 护栏:`test/panoVMapping.test.js`。
|
|
327
327
|
* 🔄 2026-09-22 追加(皇上口谕):本标记现由**用户可选的「全景纹理形态」`PanoTexMode`**(tiled/whole)与数据
|
|
@@ -395,43 +395,45 @@ const vertexShader = /* glsl */ `
|
|
|
395
395
|
*/
|
|
396
396
|
// ⭐ 下面这一组「切片 / 拼合槽」几何常量**必须排在 `fragmentShader` 之前**:单全景那份片元是模块级
|
|
397
397
|
// 常量字符串,里面要用 `${RT_STITCH_SLOT_COUNT}` 声明 sampler 数组长度(TS 的块级作用域禁止先用后声明)。
|
|
398
|
-
/** ⭐
|
|
399
|
-
* 1 张 **6144×6144** 槽纹理,**左/右 2
|
|
400
|
-
*
|
|
398
|
+
/** ⭐ 32 瓦片拼合(2026-10-27 需求:一张全景切 **横 8 × 竖 4 = 32 片**,每 **横 4 × 竖 4 = 16 片**离屏拼成
|
|
399
|
+
* 1 张 **6144×6144** 槽纹理,**左/右 2 槽**组成完整全景)的「槽虚拟地址」前缀。
|
|
400
|
+
* 历史档位(作废,仅留档):09-29 的 4×4=16 片 → 10-06 晚的 8×4=32 片 / 左右 2 槽 4096² →
|
|
401
|
+
* 10-23 的 3×3=9 片 / 按列 3 槽 4096×6144 → 10-26 的 6×3=18 片 / 左右 2 槽 6144² → 本次回到 8×4=32。
|
|
401
402
|
* 虚拟键不是真 URL,纹理由 `PanoTileStitcher` 用 shader 逐格画进 `WebGLRenderTarget` 提供,
|
|
402
403
|
* 消费方(基类 `_ensurePanoTiles` / 编辑器 `_peekTileAt`)见前缀即走拼合器,⛔ 不得当 URL 下载。
|
|
403
404
|
* ⚠️ 键协议 `rt:<batch>#<slot>` 与 `uPanoTiled` 这套对外接口**一字未改** —— 变的只有「每批几条地址」
|
|
404
405
|
* 和「槽怎么分」;`slot` 取值 0..1,消费方一律用 `RT_STITCH_SLOT_COUNT` 取,不许写死。
|
|
405
|
-
* ⚠️
|
|
406
|
+
* ⚠️ 旧存档不兼容(与历代同一口径):存档里 18 条(或历代 9/16/32/64 条)瓦片地址会因张数不符被判废
|
|
406
407
|
* ⇒ **老项目需重新上传**(本次已明确不兼容,用户会重传图片)。 */
|
|
407
408
|
export const RT_STITCH_KEY_PREFIX = "rt:";
|
|
408
|
-
/** 原图**横向**(经度方向 u)切几片(需求「横
|
|
409
|
-
export const RT_STITCH_COLS =
|
|
410
|
-
/** 原图**纵向**(纬度方向 v)切几片(需求「竖
|
|
411
|
-
export const RT_STITCH_ROWS =
|
|
412
|
-
/** 一个批次(= 一个全景点)的瓦片总数 =
|
|
409
|
+
/** 原图**横向**(经度方向 u)切几片(需求「横 8」) */
|
|
410
|
+
export const RT_STITCH_COLS = 8;
|
|
411
|
+
/** 原图**纵向**(纬度方向 v)切几片(需求「竖 4」⇒ 一槽在纵向上装满整幅 4 片,横向才分左/右) */
|
|
412
|
+
export const RT_STITCH_ROWS = 4;
|
|
413
|
+
/** 一个批次(= 一个全景点)的瓦片总数 = 8 × 4 = 32;`tiles` 存档数组的硬上限 */
|
|
413
414
|
export const RT_STITCH_TILES_PER_BATCH = RT_STITCH_COLS * RT_STITCH_ROWS;
|
|
414
|
-
/** 一个拼合槽**横向**几格(需求「每个 RT 上面
|
|
415
|
-
export const RT_STITCH_SLOT_CELL_COLS =
|
|
416
|
-
/** 一个拼合槽**纵向**几格(同上 ⇒ 竖
|
|
415
|
+
/** 一个拼合槽**横向**几格(需求「每个 RT 上面 4×4=16」⇒ 一槽 = 原图左半幅/右半幅 = 横 4 格)*/
|
|
416
|
+
export const RT_STITCH_SLOT_CELL_COLS = 4;
|
|
417
|
+
/** 一个拼合槽**纵向**几格(同上 ⇒ 竖 4 格)
|
|
417
418
|
* ⚠️ 横竖**不再同数**是 10-23 起的口径(旧字段 `RT_STITCH_SLOT_GRID`「方形假设」已整条作废),
|
|
418
419
|
* 格数、格位、quad 摆位一律分轴取(`rtStitchCellPos` / `PanoTileStitcher._stitchCell`)。 */
|
|
419
|
-
export const RT_STITCH_SLOT_CELL_ROWS =
|
|
420
|
-
/** 一个拼合槽的格数 =
|
|
420
|
+
export const RT_STITCH_SLOT_CELL_ROWS = 4;
|
|
421
|
+
/** 一个拼合槽的格数 = 4 × 4 = 16(画满 16 格 = 这一槽齐活) */
|
|
421
422
|
export const RT_STITCH_CELLS_PER_SLOT = RT_STITCH_SLOT_CELL_COLS * RT_STITCH_SLOT_CELL_ROWS;
|
|
422
|
-
/** 拼合槽个数 = **左/右 2 槽**(需求「一个全景是 2 个 RT,每个 RT 上面
|
|
423
|
-
* ⛔ 别以为
|
|
424
|
-
* 2 槽 × 同屏 8 景点 = 16 正好用满 ⇒ `MKT_PANO_MAX_SLOTS`
|
|
425
|
-
* ⭐ 分块口径:槽 `s` = 原图**第 `
|
|
426
|
-
* 与「一槽横
|
|
423
|
+
/** 拼合槽个数 = **左/右 2 槽**(需求「一个全景是 2 个 RT,每个 RT 上面 4×4=16」)⇒ 一个全景点占 **2 个 sampler**。
|
|
424
|
+
* ⛔ 别以为 32 片就要 32 个 sampler:本机 `MAX_TEXTURE_IMAGE_UNITS` 实测 **16** 是硬顶,
|
|
425
|
+
* 2 槽 × 同屏 8 景点 = 16 正好用满 ⇒ `MKT_PANO_MAX_SLOTS` 取 **8**(3 槽那版只能坐 5 点)。
|
|
426
|
+
* ⭐ 分块口径:槽 `s` = 原图**第 `4s`~`4s+3` 列**(行 0-3)⇒ 每槽覆盖 **横向 180° × 纵向 180°**,
|
|
427
|
+
* 与「一槽横 4 格 × 竖 4 格」同一条口径(槽纹理尺寸见下 `RT_STITCH_SLOT_W/H`)。 */
|
|
427
428
|
export const RT_STITCH_SLOT_COUNT = 2;
|
|
428
|
-
/** 单槽像素尺寸 **6144×6144
|
|
429
|
-
*
|
|
430
|
-
*
|
|
431
|
-
* ⚠️
|
|
432
|
-
* ⚠️
|
|
433
|
-
*
|
|
434
|
-
* ⚠️
|
|
429
|
+
/** 单槽像素尺寸 **6144×6144**:2 槽 = 有效分辨率 **12288×6144**,与 8×4 切片的原图(12288×6144 ⇒ 每片 1536×1536)
|
|
430
|
+
* **逐像素 1:1**;单全景 RT 总量 2×6144² = 75.5 Mpx ⇒ **与上一版 6×3=18 那片网格一字不差**
|
|
431
|
+
* (片数 18→32 只改「切几刀」,不改画质、不改显存,这是「千万不要降低质量」红线给的约束)。
|
|
432
|
+
* ⚠️ 为什么不取 10-06 那版的 4096²:那版每格 1024² ⇒ 有效分辨率 8192×4096,比现在少 2.25× 像素 = 降质,被禁令挡死。
|
|
433
|
+
* ⚠️ 为什么不取 8192²(每格 2048²):单槽 512MB、单全景 1GB+,且 8192 是不少设备的纹理硬顶,风险不对等。
|
|
434
|
+
* ⚠️ 每格 = 1536×1536(横竖**等**了,但摆格仍分轴取,见 `RT_STITCH_SLOT_CELL_COLS/ROWS`)。
|
|
435
|
+
* ⚠️ 代价(与上一版同档):单全景常驻显存 ≈ 384MB(含 mipmap);同屏 8 点常驻 ≈ 3GB,那是「同屏点数」这一档带来的,
|
|
436
|
+
* ⛔ 不许为此缩 RT。 */
|
|
435
437
|
export const RT_STITCH_SLOT_W = 6144;
|
|
436
438
|
export const RT_STITCH_SLOT_H = 6144;
|
|
437
439
|
export const floorVertexShader = /* glsl */ `
|
|
@@ -502,7 +504,7 @@ const fragmentShader = /* glsl */ `
|
|
|
502
504
|
// 对数深度缓冲(与顶点着色器配套,保证 MktMesh 深度与场景一致)
|
|
503
505
|
#include <logdepthbuf_pars_fragment>
|
|
504
506
|
|
|
505
|
-
// 一个全景点 = 2 张**拼合槽纹理**(原图切
|
|
507
|
+
// 一个全景点 = 2 张**拼合槽纹理**(原图切 8×4=32 片,每「横 4 × 竖 4」= 16 片拼成一张槽,2026-10-27 需求)。
|
|
506
508
|
// panoramas[0..1] = [左半幅, 右半幅] 两个 RT;片元按全景 UV 的 **u** 挑对应槽采样(v 恒全高)。
|
|
507
509
|
// ⚠️ ANGLE(D3D) 禁止动态索引 sampler 数组,故槽选择用「常量下标 if 链」(见 panoSlotBranches)。
|
|
508
510
|
uniform sampler2D panoramas[${RT_STITCH_SLOT_COUNT}];
|
|
@@ -551,10 +553,10 @@ const fragmentShader = /* glsl */ `
|
|
|
551
553
|
float lat = asin(clamp(dir.y, -1.0, 1.0));
|
|
552
554
|
float v = 0.5 + lat * 0.3183098861837907; // 1/PI
|
|
553
555
|
|
|
554
|
-
// 左/右两半幅 -> 拼合槽下标 [左半幅=0, 右半幅=1](每槽 =
|
|
555
|
-
// ⭐ 2026-10-
|
|
556
|
-
//
|
|
557
|
-
// ⛔ 采样式不用改:槽内 localU 一整张 RT 宽度铺满
|
|
556
|
+
// 左/右两半幅 -> 拼合槽下标 [左半幅=0, 右半幅=1](每槽 = 8×4 网格里「横 4 × 竖 4」= 16 片,见 RT_STITCH_SLOT_TILES)
|
|
557
|
+
// ⭐ 2026-10-27 需求「一个全景 2 个 RT,每个 RT 上面 4×4=16 片」:槽仍**只随 u 等分**(这里 N=2),
|
|
558
|
+
// 每一槽 = 原图左/右半幅(4 列 × 4 行)⇒ RT 里横向 4 格、纵向 4 格。
|
|
559
|
+
// ⛔ 采样式不用改:槽内 localU 一整张 RT 宽度铺满 4 格,格子边界由拼合器摆格时算好。
|
|
558
560
|
int tileIdx = int(clamp(floor(u * ${RT_STITCH_SLOT_COUNT}.0), 0.0, ${RT_STITCH_SLOT_COUNT - 1}.0));
|
|
559
561
|
// 槽内局部 UV(连续、无 fract 边界跳变):横向按槽数等分;
|
|
560
562
|
// ⛔ 纵向**不再切**(槽就是全高)⇒ localV 恒等于 v。写成 nv / nv-1 = 纵向分辨率白丢一档。
|
|
@@ -640,17 +642,17 @@ export function isPanoTexMode(v) {
|
|
|
640
642
|
export const MISSING_TILE_GRAY = "#767676";
|
|
641
643
|
/** 接缝余量(**原图像素**,每片向四边各多切这么多;贴原图边那侧裁到剩多少算多少)。
|
|
642
644
|
*
|
|
643
|
-
*
|
|
645
|
+
* 每槽装 4×4 = 16 格 ⇒ 一张槽内部的接缝是 **3 横 3 竖**(10-23 那版每槽一竖列时只有 2 横 0 竖),这一条是随之而来的画质护栏:
|
|
644
646
|
* ① 上传时每片**向四边多切 M 像素**(`rtStitchTileRects`);
|
|
645
647
|
* ② 拼合时**只采中间那块**(`rtStitchTileInset` 算出的 UV 内缩窗口),多切的那一圈**不画进格子**。
|
|
646
648
|
*
|
|
647
649
|
* 为什么这样就没了细亮/细暗线:缝的病根是「双线性 / mipmap 在瓦片边界外拿不到邻居像素,只能复制自己的
|
|
648
650
|
* 边缘像素」(就是 `PanoTexMode` 文件头 ② 那条)。多带的 M 像素就是**真的邻居像素**,插值不再靠复制。
|
|
649
651
|
*
|
|
650
|
-
* M 取 8 够不够:一格
|
|
651
|
-
*
|
|
652
|
-
* `2 × 1.45 ≈ 3` texel ⇒ 8px 有 ≈2.7
|
|
653
|
-
*
|
|
652
|
+
* M 取 8 够不够:一格 1536×1536px(6144² ÷ 4),一片取自 12288×6144 那类原图正好也是 1536×1536(横 W/8、竖 H/4)
|
|
653
|
+
* ⇒ 一比一不缩,三线性 mip 的 footprint 只在原图更宽时才 >1 texel;按上一版同口径估:原图 1.45× 缩小时 footprint
|
|
654
|
+
* 半径约 `2 × 1.45 ≈ 3` texel ⇒ 8px 有 ≈2.7 倍余量,再小一档(4px)也够用,取 8 是给「原图比 12288 宽 ⇒ 格子在缩」
|
|
655
|
+
* 那类点留边界。**代价**:每片文件比「正好 1/8 × 1/4」宽 16px、高 16px(1536² 上 ≈ +2% 面积),⛔ 不是降质。 */
|
|
654
656
|
export const RT_STITCH_SEAM_MARGIN_PX = 8;
|
|
655
657
|
/** 全景那一份网格 = 上面这组 `RT_STITCH_*` 常数的**同一份数值**(⛔ 不是另立一套:常数由它反向派生) */
|
|
656
658
|
export const PANO_TILE_GRID = {
|
|
@@ -692,7 +694,7 @@ export function cellsPerSlotOf(grid) {
|
|
|
692
694
|
* ⛔ 手抄下标表必然出错(全景那张表就是靠生成 + 护栏逐个数钉住的),故两种网格共用这一座生成器。
|
|
693
695
|
*/
|
|
694
696
|
export function slotTilesOf(grid) {
|
|
695
|
-
// 横向几个槽(cols/slotCellCols);纵向槽数 = rows/slotCellRows(全景
|
|
697
|
+
// 横向几个槽(cols/slotCellCols);纵向槽数 = rows/slotCellRows(全景 4/4=1 ⇒ sr 恒 0 = 全高)
|
|
696
698
|
const slotCols = grid.cols / grid.slotCellCols;
|
|
697
699
|
const slots = [];
|
|
698
700
|
for (let slot = 0; slot < grid.slotCount; slot++) {
|
|
@@ -707,7 +709,7 @@ export function slotTilesOf(grid) {
|
|
|
707
709
|
}
|
|
708
710
|
return slots;
|
|
709
711
|
}
|
|
710
|
-
/** 全景的标准布局(
|
|
712
|
+
/** 全景的标准布局(8×4 网格 / 2 槽 / 6144×6144 RT)—— 一槽 = 原图左/右半幅 */
|
|
711
713
|
export const PANO_TILE_LAYOUT = { ...PANO_TILE_GRID, rtW: RT_STITCH_SLOT_W, rtH: RT_STITCH_SLOT_H };
|
|
712
714
|
/**
|
|
713
715
|
* 图片平面的布局:2×2 网格 / 1 槽,RT 宽高比 = 原图宽高比,长边 4096(10-21 旨把 16 片改成 4 片,
|
|
@@ -721,7 +723,7 @@ export function imageTileLayout(natW, natH) {
|
|
|
721
723
|
const rtH = natH > natW ? LONG : Math.round(LONG * natH / natW);
|
|
722
724
|
return { ...IMAGE_TILE_GRID, rtW, rtH };
|
|
723
725
|
}
|
|
724
|
-
/**
|
|
726
|
+
/** 32 瓦片批次的标识 = 第一条**非空**瓦片地址(同批上传 URL 前缀一致,足以唯一;
|
|
725
727
|
* 09-29 晚旨「不足张数缺的地方涂灰」后批次里允许有空串占位 ⇒ 取首个非空,防首张缺失时键为空串互撞) */
|
|
726
728
|
export function rtStitchBatchOf(tiles) {
|
|
727
729
|
return tiles.find((u) => u) || "";
|
|
@@ -730,7 +732,7 @@ export function rtStitchBatchOf(tiles) {
|
|
|
730
732
|
export function rtStitchKey(batch, slot) {
|
|
731
733
|
return `${RT_STITCH_KEY_PREFIX}${batch}#${slot}`;
|
|
732
734
|
}
|
|
733
|
-
/** 是否拼合槽(`rt:<batch>#<slot>`)的虚拟键 —— 16 / 32 / 64 / 9
|
|
735
|
+
/** 是否拼合槽(`rt:<batch>#<slot>`)的虚拟键 —— 历代 16 / 32 / 64 / 9 / 18 片**同一个前缀**,键本身不含片数信息 */
|
|
734
736
|
export function isRtStitchKey(key) {
|
|
735
737
|
return key.startsWith(RT_STITCH_KEY_PREFIX);
|
|
736
738
|
}
|
|
@@ -744,15 +746,15 @@ export function rtStitchKeyParts(key) {
|
|
|
744
746
|
return null;
|
|
745
747
|
return { batch: body.slice(0, i), slot: Number(body.slice(i + 1)) };
|
|
746
748
|
}
|
|
747
|
-
/** 槽 slot 用哪
|
|
748
|
-
* 槽 0 = **左半幅**(列 0-
|
|
749
|
-
* ⭐ 只按 **u** 分槽(需求 2026-10-
|
|
750
|
-
* ⚠️ 表是**从上面那几个网格常数生成**的(⛔ 手抄
|
|
749
|
+
/** 槽 slot 用哪 16 张瓦片(原图 **8 列 × 4 行 行优先**下标 `r*8+c`;**槽内格序 = 横 4 × 竖 4、图像左上起**):
|
|
750
|
+
* 槽 0 = **左半幅**(列 0-3)→ `[0,1,2,3, 8,9,10,11, 16,17,18,19, 24,25,26,27]`;槽 1 = **右半幅**(列 4-7)→ `[4,5,6,7, 12,13,14,15, 20,21,22,23, 28,29,30,31]`。
|
|
751
|
+
* ⭐ 只按 **u** 分槽(需求 2026-10-27「一个全景是 2 个 RT,每个 RT 上面 4×4=16」⇒ 一槽 = 原图半幅 = 横 180° × 全高 180°),
|
|
752
|
+
* ⚠️ 表是**从上面那几个网格常数生成**的(⛔ 手抄 32 个数):正确性由护栏 `test/mktmesh.test.js` BE 组
|
|
751
753
|
* 对着手写死的字面量逐个数断言 —— 改了网格常数而护栏没跟着改,当场红。 */
|
|
752
754
|
export const RT_STITCH_SLOT_TILES = slotTilesOf(PANO_TILE_GRID);
|
|
753
755
|
/** 槽内第 cell 格在**图像方向**的位置 `[列, 行]`(0 起,与 `RT_STITCH_SLOT_TILES` 的格序同一口径)。
|
|
754
756
|
* ⚠️ 这是「图像方向」(行 0 = 图像最上),GL 的 y 向上 ⇒ 画进 RT 时 y 要翻(拼合器里那句 `1 - (2*r+1)/n`)。
|
|
755
|
-
* `slotCellCols` 默认全景那档(
|
|
757
|
+
* `slotCellCols` 默认全景那档(4 = 一槽就是原图半幅的左四列);图片平面传 2。 */
|
|
756
758
|
export function rtStitchCellPos(cell, slotCellCols = PANO_TILE_GRID.slotCellCols) {
|
|
757
759
|
return [cell % slotCellCols, Math.floor(cell / slotCellCols)];
|
|
758
760
|
}
|
|
@@ -763,12 +765,12 @@ export function rtStitchCellPos(cell, slotCellCols = PANO_TILE_GRID.slotCellCols
|
|
|
763
765
|
function gridLine(i, n, steps) {
|
|
764
766
|
return Math.round((i * n) / steps);
|
|
765
767
|
}
|
|
766
|
-
/**
|
|
767
|
-
* ⭐ 10-
|
|
768
|
+
/** 32 片瓦片的切图矩形(行优先、图像左上起,下标 `i = r*8+c` 与 `RT_STITCH_SLOT_TILES` 同源;
|
|
769
|
+
* ⭐ 2026-10-27 需求「横 8 × 竖 4 = 32」:`r` 走 `RT_STITCH_ROWS`(4)、`c` 走 `RT_STITCH_COLS`(8)。
|
|
768
770
|
*
|
|
769
771
|
* ⭐ **上传侧(`panoramaUpload`)与拼合侧(`PanoTileStitcher`)必须共用这一份几何**:
|
|
770
772
|
* 上传多切多少、拼合就内缩多少;两边各算一次就是「缝没治掉、反而把画面挤歪」。
|
|
771
|
-
* 拼合侧拿不到原图尺寸(它只有
|
|
773
|
+
* 拼合侧拿不到原图尺寸(它只有 32 个 URL 和 32 张已解码纹理),所以它用 `rtStitchTileInset`
|
|
772
774
|
* —— 那条只需「下标 + 该瓦片自己的像素尺寸」,两者等价的前提是「多切量 = 常数 M、只有贴边那几片被裁」,
|
|
773
775
|
* 而「贴不贴边」纯由下标决定 ⇒ 护栏 BE 组用同一批 (W,H) 把两条算路对表钉死。 */
|
|
774
776
|
export function rtStitchTileRects(w, h, grid = PANO_TILE_GRID) {
|
|
@@ -788,7 +790,7 @@ export function rtStitchTileRects(w, h, grid = PANO_TILE_GRID) {
|
|
|
788
790
|
}
|
|
789
791
|
return out;
|
|
790
792
|
}
|
|
791
|
-
/** 这片瓦片有没有贴原图边界(
|
|
793
|
+
/** 这片瓦片有没有贴原图边界(8×4 ⇒ 32 片里外圈那 20 片至少贴一条边,只有中间那 12 片四边都不贴;贴边的**那一侧**多切量被裁成 0)。
|
|
792
794
|
* 拼合侧靠它 + 瓦片自己的像素尺寸还原内缩量 ⇒ 不必知道原图多大。
|
|
793
795
|
* ⚠️ 下标拆分必须按 **列数 COLS**(`i = r*cols+c`),⛔ 不是 ROWS。 */
|
|
794
796
|
export function rtStitchTileEdgeClip(i, grid = PANO_TILE_GRID) {
|
|
@@ -823,9 +825,11 @@ export function rtStitchTileInset(i, tw, th, grid = PANO_TILE_GRID) {
|
|
|
823
825
|
* 「这 `RT_STITCH_SLOT_COUNT`(2) 个纹理槽到底喂哪几个地址」。⚠️ **必须**与 `mktPanoTiledFlag` 同源、同一时机调用:
|
|
824
826
|
* 只改标记不改地址(或反之)= 用整图 UV 去采一张瓦片 / 用瓦片内 UV 去采整图,画面立刻错乱。
|
|
825
827
|
* 非 tiled 态(或该点压根没切过片)一律回退成「各槽同为一张整图」。
|
|
826
|
-
* ⭐ 2026-10-
|
|
827
|
-
* 不足
|
|
828
|
-
* (「无须兼容正常使用,有异常我会重传」⇒ 旧存档的
|
|
828
|
+
* ⭐ 2026-10-27 需求「只支持 32 张(8×4)」:只要有瓦片(1~32 条)一律走拼合器(rt: 虚拟键),
|
|
829
|
+
* 不足 32 张的位置由拼合器**涂灰**(一眼看出数据不全);6×3=18 张、3×3=9 张、8×8=64 张与 4×4=16 张那几版**都不做兼容**
|
|
830
|
+
* (「无须兼容正常使用,有异常我会重传」⇒ 旧存档的 18 / 9 / 64 / 16 条地址张数不符被判废、重传即可)。
|
|
831
|
+
* ⚠️ 唯一按张数**能混进来**的是 10-06 那版同样 32 片的存档:它的瓦片是 1024²,会被画进 1536² 的格子
|
|
832
|
+
* = 1.5× 放大 ⇒ 发虚但不报红。那种老点重传一次即可(顺序与槽分组两版一致,所以不会错位)。
|
|
829
833
|
* ⚠️ 返回长度由 `RT_STITCH_SLOT_COUNT` 派生(⛔ 不许手写 2 个 rtStitchKey —— 槽数再变会漏改)。
|
|
830
834
|
*/
|
|
831
835
|
export function mktPanoTexUrls(url, tiles, mode = "tiled") {
|
|
@@ -837,7 +841,7 @@ export function mktPanoTexUrls(url, tiles, mode = "tiled") {
|
|
|
837
841
|
}
|
|
838
842
|
/**
|
|
839
843
|
* 「这 2 个纹理槽是不是真瓦片」的判据 —— **必须**与喂纹理处的回退式(`mktPanoTexUrls`)同源:
|
|
840
|
-
* `tiles` 有 **任意 1~
|
|
844
|
+
* `tiles` 有 **任意 1~32 条**地址(不足 32 = 数据不全,缺的格子拼合时涂灰)**且**当前形态选的是 tiled = 是瓦片;
|
|
841
845
|
* 否则各槽同为一张整图(旧数据 / 种子图 / 用户切整片)。
|
|
842
846
|
*/
|
|
843
847
|
export function mktPanoTiledFlag(tiles, mode = "tiled") {
|
|
@@ -871,9 +875,9 @@ export function setMktPanoTiled(material, tiled, slot = 0) {
|
|
|
871
875
|
export function createMktShaderMaterial() {
|
|
872
876
|
return new ShaderMaterial({
|
|
873
877
|
uniforms: {
|
|
874
|
-
// 一个全景点恒占 **
|
|
875
|
-
// panoramas[0..
|
|
876
|
-
//
|
|
878
|
+
// 一个全景点恒占 **2 个 sampler**(2026-10-26 起左右 2 槽,本次 8×4 网格沿用 2 槽):
|
|
879
|
+
// panoramas[0..1] = 2 张**离屏拼合槽纹理**([左半幅, 右半幅],每槽由 `RT_STITCH_CELLS_PER_SLOT`(16)
|
|
880
|
+
// 片瓦片拼成 4×4 格),片元按全景 UV 的 **u** 两等分挑槽采样(v 恒全高)。
|
|
877
881
|
// ⛔ 长度由 `RT_STITCH_SLOT_COUNT` 派生(不许手写 2 张)—— 槽数再变这里会漏改。
|
|
878
882
|
panoramas: {
|
|
879
883
|
value: Array.from({ length: RT_STITCH_SLOT_COUNT }, () => createPlaceholderTexture()),
|
package/MktMesh/mktShader.ts
CHANGED
|
@@ -333,7 +333,7 @@ export function setMktPanoPoints(
|
|
|
333
333
|
* 修法 = `uPanoTiled`(单全景标量 / 融合每点数组):0 时把瓦片内 UV **还原成整图 UV**
|
|
334
334
|
* `panoU = u`、`panoV = v`(口径写死后这就是恒等式:横向 `0.5(2u)=u` / `0.5+0.5(2u−1)=u`;
|
|
335
335
|
* 纵向 10-06 晚起 localV 本就等于 v ⇒ 两个方向都退化成恒等式)。
|
|
336
|
-
* ⚠️ 判据与回退式**必须同源**(`mktPanoTiledFlag` = 「tiled 形态 且 tiles 有任意 1~
|
|
336
|
+
* ⚠️ 判据与回退式**必须同源**(`mktPanoTiledFlag` = 「tiled 形态 且 tiles 有任意 1~32 条」,现行只支持 8×4=32 张、不足涂灰),且每个回退喂料点都要写标记,
|
|
337
337
|
* 漏一处该对象就悄悄退回 1/2 拉伸。默认值取 1(已切片的真实上传数据行为不变)。
|
|
338
338
|
* 护栏:`test/panoVMapping.test.js`。
|
|
339
339
|
* 🔄 2026-09-22 追加(皇上口谕):本标记现由**用户可选的「全景纹理形态」`PanoTexMode`**(tiled/whole)与数据
|
|
@@ -409,51 +409,53 @@ const vertexShader = /* glsl */ `
|
|
|
409
409
|
*/
|
|
410
410
|
// ⭐ 下面这一组「切片 / 拼合槽」几何常量**必须排在 `fragmentShader` 之前**:单全景那份片元是模块级
|
|
411
411
|
// 常量字符串,里面要用 `${RT_STITCH_SLOT_COUNT}` 声明 sampler 数组长度(TS 的块级作用域禁止先用后声明)。
|
|
412
|
-
/** ⭐
|
|
413
|
-
* 1 张 **6144×6144** 槽纹理,**左/右 2
|
|
414
|
-
*
|
|
412
|
+
/** ⭐ 32 瓦片拼合(2026-10-27 需求:一张全景切 **横 8 × 竖 4 = 32 片**,每 **横 4 × 竖 4 = 16 片**离屏拼成
|
|
413
|
+
* 1 张 **6144×6144** 槽纹理,**左/右 2 槽**组成完整全景)的「槽虚拟地址」前缀。
|
|
414
|
+
* 历史档位(作废,仅留档):09-29 的 4×4=16 片 → 10-06 晚的 8×4=32 片 / 左右 2 槽 4096² →
|
|
415
|
+
* 10-23 的 3×3=9 片 / 按列 3 槽 4096×6144 → 10-26 的 6×3=18 片 / 左右 2 槽 6144² → 本次回到 8×4=32。
|
|
415
416
|
* 虚拟键不是真 URL,纹理由 `PanoTileStitcher` 用 shader 逐格画进 `WebGLRenderTarget` 提供,
|
|
416
417
|
* 消费方(基类 `_ensurePanoTiles` / 编辑器 `_peekTileAt`)见前缀即走拼合器,⛔ 不得当 URL 下载。
|
|
417
418
|
* ⚠️ 键协议 `rt:<batch>#<slot>` 与 `uPanoTiled` 这套对外接口**一字未改** —— 变的只有「每批几条地址」
|
|
418
419
|
* 和「槽怎么分」;`slot` 取值 0..1,消费方一律用 `RT_STITCH_SLOT_COUNT` 取,不许写死。
|
|
419
|
-
* ⚠️
|
|
420
|
+
* ⚠️ 旧存档不兼容(与历代同一口径):存档里 18 条(或历代 9/16/32/64 条)瓦片地址会因张数不符被判废
|
|
420
421
|
* ⇒ **老项目需重新上传**(本次已明确不兼容,用户会重传图片)。 */
|
|
421
422
|
export const RT_STITCH_KEY_PREFIX = "rt:";
|
|
422
423
|
|
|
423
|
-
/** 原图**横向**(经度方向 u)切几片(需求「横
|
|
424
|
-
export const RT_STITCH_COLS =
|
|
424
|
+
/** 原图**横向**(经度方向 u)切几片(需求「横 8」) */
|
|
425
|
+
export const RT_STITCH_COLS = 8;
|
|
425
426
|
|
|
426
|
-
/** 原图**纵向**(纬度方向 v)切几片(需求「竖
|
|
427
|
-
export const RT_STITCH_ROWS =
|
|
427
|
+
/** 原图**纵向**(纬度方向 v)切几片(需求「竖 4」⇒ 一槽在纵向上装满整幅 4 片,横向才分左/右) */
|
|
428
|
+
export const RT_STITCH_ROWS = 4;
|
|
428
429
|
|
|
429
|
-
/** 一个批次(= 一个全景点)的瓦片总数 =
|
|
430
|
+
/** 一个批次(= 一个全景点)的瓦片总数 = 8 × 4 = 32;`tiles` 存档数组的硬上限 */
|
|
430
431
|
export const RT_STITCH_TILES_PER_BATCH = RT_STITCH_COLS * RT_STITCH_ROWS;
|
|
431
432
|
|
|
432
|
-
/** 一个拼合槽**横向**几格(需求「每个 RT 上面
|
|
433
|
-
export const RT_STITCH_SLOT_CELL_COLS =
|
|
433
|
+
/** 一个拼合槽**横向**几格(需求「每个 RT 上面 4×4=16」⇒ 一槽 = 原图左半幅/右半幅 = 横 4 格)*/
|
|
434
|
+
export const RT_STITCH_SLOT_CELL_COLS = 4;
|
|
434
435
|
|
|
435
|
-
/** 一个拼合槽**纵向**几格(同上 ⇒ 竖
|
|
436
|
+
/** 一个拼合槽**纵向**几格(同上 ⇒ 竖 4 格)
|
|
436
437
|
* ⚠️ 横竖**不再同数**是 10-23 起的口径(旧字段 `RT_STITCH_SLOT_GRID`「方形假设」已整条作废),
|
|
437
438
|
* 格数、格位、quad 摆位一律分轴取(`rtStitchCellPos` / `PanoTileStitcher._stitchCell`)。 */
|
|
438
|
-
export const RT_STITCH_SLOT_CELL_ROWS =
|
|
439
|
+
export const RT_STITCH_SLOT_CELL_ROWS = 4;
|
|
439
440
|
|
|
440
|
-
/** 一个拼合槽的格数 =
|
|
441
|
+
/** 一个拼合槽的格数 = 4 × 4 = 16(画满 16 格 = 这一槽齐活) */
|
|
441
442
|
export const RT_STITCH_CELLS_PER_SLOT = RT_STITCH_SLOT_CELL_COLS * RT_STITCH_SLOT_CELL_ROWS;
|
|
442
443
|
|
|
443
|
-
/** 拼合槽个数 = **左/右 2 槽**(需求「一个全景是 2 个 RT,每个 RT 上面
|
|
444
|
-
* ⛔ 别以为
|
|
445
|
-
* 2 槽 × 同屏 8 景点 = 16 正好用满 ⇒ `MKT_PANO_MAX_SLOTS`
|
|
446
|
-
* ⭐ 分块口径:槽 `s` = 原图**第 `
|
|
447
|
-
* 与「一槽横
|
|
444
|
+
/** 拼合槽个数 = **左/右 2 槽**(需求「一个全景是 2 个 RT,每个 RT 上面 4×4=16」)⇒ 一个全景点占 **2 个 sampler**。
|
|
445
|
+
* ⛔ 别以为 32 片就要 32 个 sampler:本机 `MAX_TEXTURE_IMAGE_UNITS` 实测 **16** 是硬顶,
|
|
446
|
+
* 2 槽 × 同屏 8 景点 = 16 正好用满 ⇒ `MKT_PANO_MAX_SLOTS` 取 **8**(3 槽那版只能坐 5 点)。
|
|
447
|
+
* ⭐ 分块口径:槽 `s` = 原图**第 `4s`~`4s+3` 列**(行 0-3)⇒ 每槽覆盖 **横向 180° × 纵向 180°**,
|
|
448
|
+
* 与「一槽横 4 格 × 竖 4 格」同一条口径(槽纹理尺寸见下 `RT_STITCH_SLOT_W/H`)。 */
|
|
448
449
|
export const RT_STITCH_SLOT_COUNT = 2;
|
|
449
450
|
|
|
450
|
-
/** 单槽像素尺寸 **6144×6144
|
|
451
|
-
*
|
|
452
|
-
*
|
|
453
|
-
* ⚠️
|
|
454
|
-
* ⚠️
|
|
455
|
-
*
|
|
456
|
-
* ⚠️
|
|
451
|
+
/** 单槽像素尺寸 **6144×6144**:2 槽 = 有效分辨率 **12288×6144**,与 8×4 切片的原图(12288×6144 ⇒ 每片 1536×1536)
|
|
452
|
+
* **逐像素 1:1**;单全景 RT 总量 2×6144² = 75.5 Mpx ⇒ **与上一版 6×3=18 那片网格一字不差**
|
|
453
|
+
* (片数 18→32 只改「切几刀」,不改画质、不改显存,这是「千万不要降低质量」红线给的约束)。
|
|
454
|
+
* ⚠️ 为什么不取 10-06 那版的 4096²:那版每格 1024² ⇒ 有效分辨率 8192×4096,比现在少 2.25× 像素 = 降质,被禁令挡死。
|
|
455
|
+
* ⚠️ 为什么不取 8192²(每格 2048²):单槽 512MB、单全景 1GB+,且 8192 是不少设备的纹理硬顶,风险不对等。
|
|
456
|
+
* ⚠️ 每格 = 1536×1536(横竖**等**了,但摆格仍分轴取,见 `RT_STITCH_SLOT_CELL_COLS/ROWS`)。
|
|
457
|
+
* ⚠️ 代价(与上一版同档):单全景常驻显存 ≈ 384MB(含 mipmap);同屏 8 点常驻 ≈ 3GB,那是「同屏点数」这一档带来的,
|
|
458
|
+
* ⛔ 不许为此缩 RT。 */
|
|
457
459
|
export const RT_STITCH_SLOT_W = 6144;
|
|
458
460
|
export const RT_STITCH_SLOT_H = 6144;
|
|
459
461
|
|
|
@@ -530,7 +532,7 @@ const fragmentShader = /* glsl */ `
|
|
|
530
532
|
// 对数深度缓冲(与顶点着色器配套,保证 MktMesh 深度与场景一致)
|
|
531
533
|
#include <logdepthbuf_pars_fragment>
|
|
532
534
|
|
|
533
|
-
// 一个全景点 = 2 张**拼合槽纹理**(原图切
|
|
535
|
+
// 一个全景点 = 2 张**拼合槽纹理**(原图切 8×4=32 片,每「横 4 × 竖 4」= 16 片拼成一张槽,2026-10-27 需求)。
|
|
534
536
|
// panoramas[0..1] = [左半幅, 右半幅] 两个 RT;片元按全景 UV 的 **u** 挑对应槽采样(v 恒全高)。
|
|
535
537
|
// ⚠️ ANGLE(D3D) 禁止动态索引 sampler 数组,故槽选择用「常量下标 if 链」(见 panoSlotBranches)。
|
|
536
538
|
uniform sampler2D panoramas[${RT_STITCH_SLOT_COUNT}];
|
|
@@ -579,10 +581,10 @@ const fragmentShader = /* glsl */ `
|
|
|
579
581
|
float lat = asin(clamp(dir.y, -1.0, 1.0));
|
|
580
582
|
float v = 0.5 + lat * 0.3183098861837907; // 1/PI
|
|
581
583
|
|
|
582
|
-
// 左/右两半幅 -> 拼合槽下标 [左半幅=0, 右半幅=1](每槽 =
|
|
583
|
-
// ⭐ 2026-10-
|
|
584
|
-
//
|
|
585
|
-
// ⛔ 采样式不用改:槽内 localU 一整张 RT 宽度铺满
|
|
584
|
+
// 左/右两半幅 -> 拼合槽下标 [左半幅=0, 右半幅=1](每槽 = 8×4 网格里「横 4 × 竖 4」= 16 片,见 RT_STITCH_SLOT_TILES)
|
|
585
|
+
// ⭐ 2026-10-27 需求「一个全景 2 个 RT,每个 RT 上面 4×4=16 片」:槽仍**只随 u 等分**(这里 N=2),
|
|
586
|
+
// 每一槽 = 原图左/右半幅(4 列 × 4 行)⇒ RT 里横向 4 格、纵向 4 格。
|
|
587
|
+
// ⛔ 采样式不用改:槽内 localU 一整张 RT 宽度铺满 4 格,格子边界由拼合器摆格时算好。
|
|
586
588
|
int tileIdx = int(clamp(floor(u * ${RT_STITCH_SLOT_COUNT}.0), 0.0, ${RT_STITCH_SLOT_COUNT - 1}.0));
|
|
587
589
|
// 槽内局部 UV(连续、无 fract 边界跳变):横向按槽数等分;
|
|
588
590
|
// ⛔ 纵向**不再切**(槽就是全高)⇒ localV 恒等于 v。写成 nv / nv-1 = 纵向分辨率白丢一档。
|
|
@@ -663,8 +665,8 @@ export function createPlaceholderTexture(): DataTexture {
|
|
|
663
665
|
/**
|
|
664
666
|
* 全景纹理形态(皇上旨 2026-09-22「全景球可以切成 4 片和一整片,两者效果很不一样,做个功能可以切换」)。
|
|
665
667
|
*
|
|
666
|
-
* "tiled" = 2 个 sampler 各装一张**离屏拼合好的槽纹理**(原图 **
|
|
667
|
-
* 2026-10-26
|
|
668
|
+
* "tiled" = 2 个 sampler 各装一张**离屏拼合好的槽纹理**(原图 **8×4 = 32 片**,每「横 4 × 竖 4」= 16 片拼一张;
|
|
669
|
+
* 2026-10-27 需求;历代档位:10-26 的 6×3 = 18 片、10-23 的 3×3 = 9 片 / 3 槽、10-06 晚的 8×4 = 32 片 / 2 槽 4096²、同日的 8×8 = 64 片 / 4 槽、09-29 的 4×4 = 16 片),
|
|
668
670
|
* `uPanoTiled` 写 1;
|
|
669
671
|
* "whole" = 2 个 sampler 都装**同一张完整等距柱状原图**,`uPanoTiled` 写 0(改用全图 UV)。
|
|
670
672
|
*
|
|
@@ -672,18 +674,18 @@ export function createPlaceholderTexture(): DataTexture {
|
|
|
672
674
|
* `test/panoVMapping.test.js` 的等价性数值证明)。所以线上若看着「很不一样」,差异只可能来自下面两条,
|
|
673
675
|
* 与本切换功能无关、也不会被它修掉:
|
|
674
676
|
* ① **分辨率**:`x-oss-process=image/resize,m_lfit,w_<ossSize>` 是**按 URL** 生效的,且 2026-09-23 皇上定
|
|
675
|
-
* 「**切片的瓦片不走该尺寸档,默认用原图**」(每片本就只有原图的 1/
|
|
677
|
+
* 「**切片的瓦片不走该尺寸档,默认用原图**」(每片本就只有原图的 1/8 宽 × 1/4 高,再按档缩是二次损失)⇒
|
|
676
678
|
* 判据 = `mktPanoTiledFlag(...)===1`(喂地址与写 `uPanoTiled` 同源,见 `resolveOssUrl` 两处)。
|
|
677
679
|
* 于是 tiled 态 = 拼合槽纹理**逐片取自原始分辨率**瓦片(合计像素≈整张原图,10-06 那版仍是 8192×4096 等效),
|
|
678
680
|
* whole 态 = 整图按档(w_1024 ⇒ 等效 1024×512)。
|
|
679
681
|
* ⚠️ 两档清晰度差**不是固定的倍数**,而取决于「原图宽 ÷ 所选档位」;又因 `m_lfit` 只缩不放,
|
|
680
682
|
* 原图宽 ≤ 2×档位时 whole 态其实也没被缩,两态清晰度自然接近 —— 别把这当成「切换坏了」。
|
|
681
|
-
* ② **瓦片边界**(10-06 晚切 32 片起这一条分两层,10-
|
|
683
|
+
* ② **瓦片边界**(10-06 晚切 32 片起这一条分两层,10-27 口径 =「2 槽 + 每槽 4×4」):
|
|
682
684
|
* · **拼合槽之间**(u=1/2 那**一道**竖;⭐ v 方向不再有横缝 —— 每槽就是全高):2 张槽是 2 张独立纹理,
|
|
683
685
|
* 各自 mip + ClampToEdge ⇒ 仍可能有细亮/细暗线,这一条**与 09-29 那版一字未变**,
|
|
684
686
|
* `RT_STITCH_SEAM_MARGIN_PX` 管不到它(它治的是「同一张纹理内」的格子边界);
|
|
685
687
|
* whole 态是同一张贴图,天然无此缝。
|
|
686
|
-
* · **拼合槽内部**(每张 6144×6144 里
|
|
688
|
+
* · **拼合槽内部**(每张 6144×6144 里 4×4 片 ⇒ 3 道横缝 + 3 道竖缝;上一版 3×3 是 2 横 2 竖):
|
|
687
689
|
* 靠「上传多切 `RT_STITCH_SEAM_MARGIN_PX` 像素 + 拼合只采中间那块」消掉,见该常量的说明。
|
|
688
690
|
*
|
|
689
691
|
* 旧数据 / 种子图没有 `tiles`(或只有 1 条)⇒ 两种形态都只能退回整图,`whole` 与 `tiled` 表现相同。
|
|
@@ -702,27 +704,27 @@ export const MISSING_TILE_GRAY = "#767676";
|
|
|
702
704
|
|
|
703
705
|
/** 接缝余量(**原图像素**,每片向四边各多切这么多;贴原图边那侧裁到剩多少算多少)。
|
|
704
706
|
*
|
|
705
|
-
*
|
|
707
|
+
* 每槽装 4×4 = 16 格 ⇒ 一张槽内部的接缝是 **3 横 3 竖**(10-23 那版每槽一竖列时只有 2 横 0 竖),这一条是随之而来的画质护栏:
|
|
706
708
|
* ① 上传时每片**向四边多切 M 像素**(`rtStitchTileRects`);
|
|
707
709
|
* ② 拼合时**只采中间那块**(`rtStitchTileInset` 算出的 UV 内缩窗口),多切的那一圈**不画进格子**。
|
|
708
710
|
*
|
|
709
711
|
* 为什么这样就没了细亮/细暗线:缝的病根是「双线性 / mipmap 在瓦片边界外拿不到邻居像素,只能复制自己的
|
|
710
712
|
* 边缘像素」(就是 `PanoTexMode` 文件头 ② 那条)。多带的 M 像素就是**真的邻居像素**,插值不再靠复制。
|
|
711
713
|
*
|
|
712
|
-
* M 取 8 够不够:一格
|
|
713
|
-
*
|
|
714
|
-
* `2 × 1.45 ≈ 3` texel ⇒ 8px 有 ≈2.7
|
|
715
|
-
*
|
|
714
|
+
* M 取 8 够不够:一格 1536×1536px(6144² ÷ 4),一片取自 12288×6144 那类原图正好也是 1536×1536(横 W/8、竖 H/4)
|
|
715
|
+
* ⇒ 一比一不缩,三线性 mip 的 footprint 只在原图更宽时才 >1 texel;按上一版同口径估:原图 1.45× 缩小时 footprint
|
|
716
|
+
* 半径约 `2 × 1.45 ≈ 3` texel ⇒ 8px 有 ≈2.7 倍余量,再小一档(4px)也够用,取 8 是给「原图比 12288 宽 ⇒ 格子在缩」
|
|
717
|
+
* 那类点留边界。**代价**:每片文件比「正好 1/8 × 1/4」宽 16px、高 16px(1536² 上 ≈ +2% 面积),⛔ 不是降质。 */
|
|
716
718
|
export const RT_STITCH_SEAM_MARGIN_PX = 8;
|
|
717
719
|
|
|
718
720
|
/**
|
|
719
721
|
* 「一张图切成几张瓦片、瓦片怎么分组进拼合槽」的**网格描述** —— 皇上旨 2026-10-20「上传的这个图切成
|
|
720
|
-
* 4*4=16 片吧,加载的时候,也是一帧载入一片」⇒ 拼合器从此要同时服务两种网格(全景
|
|
722
|
+
* 4*4=16 片吧,加载的时候,也是一帧载入一片」⇒ 拼合器从此要同时服务两种网格(全景 8×4 / 图片平面那一份),
|
|
721
723
|
* 于是这一组参数必须能**当数据传**,⛔ 不许在拼合器里再写死一遍全景那套数字(那就是两份实现)。
|
|
722
724
|
* ⭐ 同一条参数化让 10-21 旨「平面切成 2*2=4 份,不用切成 16 份了」只需要改 `IMAGE_TILE_GRID` 一处。
|
|
723
725
|
*
|
|
724
726
|
* ⚠️ 只描述「格子怎么排」,不含槽纹理像素尺寸(那是 GL 资源,由拼合器按消费方给的 layout 建)。
|
|
725
|
-
* ⚠️ `slotCellCols` / `slotCellRows` = **每槽横几格 / 竖几格**(10-23 起两个数独立,现行全景是每槽
|
|
727
|
+
* ⚠️ `slotCellCols` / `slotCellRows` = **每槽横几格 / 竖几格**(10-23 起两个数独立,现行全景是每槽 4×4 = 原图左/右半幅;
|
|
726
728
|
* 旧的单一 `slotGrid`「横竖同数」假设已整条作废 ⇒ 格数 = `slotCellCols * slotCellRows`)。
|
|
727
729
|
*/
|
|
728
730
|
export interface TileGridLayout {
|
|
@@ -784,7 +786,7 @@ export function cellsPerSlotOf(grid: TileGridLayout): number {
|
|
|
784
786
|
* ⛔ 手抄下标表必然出错(全景那张表就是靠生成 + 护栏逐个数钉住的),故两种网格共用这一座生成器。
|
|
785
787
|
*/
|
|
786
788
|
export function slotTilesOf(grid: TileGridLayout): number[][] {
|
|
787
|
-
// 横向几个槽(cols/slotCellCols);纵向槽数 = rows/slotCellRows(全景
|
|
789
|
+
// 横向几个槽(cols/slotCellCols);纵向槽数 = rows/slotCellRows(全景 4/4=1 ⇒ sr 恒 0 = 全高)
|
|
788
790
|
const slotCols = grid.cols / grid.slotCellCols;
|
|
789
791
|
const slots: number[][] = [];
|
|
790
792
|
for (let slot = 0; slot < grid.slotCount; slot++) {
|
|
@@ -802,7 +804,7 @@ export function slotTilesOf(grid: TileGridLayout): number[][] {
|
|
|
802
804
|
/** 拼合器内部使用的完整布局 = 网格描述 + RT 像素尺寸(GL 资源参数,消费方建组时传入)。 */
|
|
803
805
|
export type TileLayout = TileGridLayout & { rtW: number; rtH: number };
|
|
804
806
|
|
|
805
|
-
/** 全景的标准布局(
|
|
807
|
+
/** 全景的标准布局(8×4 网格 / 2 槽 / 6144×6144 RT)—— 一槽 = 原图左/右半幅 */
|
|
806
808
|
export const PANO_TILE_LAYOUT: TileLayout = { ...PANO_TILE_GRID, rtW: RT_STITCH_SLOT_W, rtH: RT_STITCH_SLOT_H };
|
|
807
809
|
|
|
808
810
|
/**
|
|
@@ -818,7 +820,7 @@ export function imageTileLayout(natW: number, natH: number): TileLayout {
|
|
|
818
820
|
return { ...IMAGE_TILE_GRID, rtW, rtH };
|
|
819
821
|
}
|
|
820
822
|
|
|
821
|
-
/**
|
|
823
|
+
/** 32 瓦片批次的标识 = 第一条**非空**瓦片地址(同批上传 URL 前缀一致,足以唯一;
|
|
822
824
|
* 09-29 晚旨「不足张数缺的地方涂灰」后批次里允许有空串占位 ⇒ 取首个非空,防首张缺失时键为空串互撞) */
|
|
823
825
|
export function rtStitchBatchOf(tiles: string[]): string {
|
|
824
826
|
return tiles.find((u) => u) || "";
|
|
@@ -829,7 +831,7 @@ export function rtStitchKey(batch: string, slot: number): string {
|
|
|
829
831
|
return `${RT_STITCH_KEY_PREFIX}${batch}#${slot}`;
|
|
830
832
|
}
|
|
831
833
|
|
|
832
|
-
/** 是否拼合槽(`rt:<batch>#<slot>`)的虚拟键 —— 16 / 32 / 64 / 9
|
|
834
|
+
/** 是否拼合槽(`rt:<batch>#<slot>`)的虚拟键 —— 历代 16 / 32 / 64 / 9 / 18 片**同一个前缀**,键本身不含片数信息 */
|
|
833
835
|
export function isRtStitchKey(key: string): boolean {
|
|
834
836
|
return key.startsWith(RT_STITCH_KEY_PREFIX);
|
|
835
837
|
}
|
|
@@ -843,16 +845,16 @@ export function rtStitchKeyParts(key: string): { batch: string; slot: number } |
|
|
|
843
845
|
return { batch: body.slice(0, i), slot: Number(body.slice(i + 1)) };
|
|
844
846
|
}
|
|
845
847
|
|
|
846
|
-
/** 槽 slot 用哪
|
|
847
|
-
* 槽 0 = **左半幅**(列 0-
|
|
848
|
-
* ⭐ 只按 **u** 分槽(需求 2026-10-
|
|
849
|
-
* ⚠️ 表是**从上面那几个网格常数生成**的(⛔ 手抄
|
|
848
|
+
/** 槽 slot 用哪 16 张瓦片(原图 **8 列 × 4 行 行优先**下标 `r*8+c`;**槽内格序 = 横 4 × 竖 4、图像左上起**):
|
|
849
|
+
* 槽 0 = **左半幅**(列 0-3)→ `[0,1,2,3, 8,9,10,11, 16,17,18,19, 24,25,26,27]`;槽 1 = **右半幅**(列 4-7)→ `[4,5,6,7, 12,13,14,15, 20,21,22,23, 28,29,30,31]`。
|
|
850
|
+
* ⭐ 只按 **u** 分槽(需求 2026-10-27「一个全景是 2 个 RT,每个 RT 上面 4×4=16」⇒ 一槽 = 原图半幅 = 横 180° × 全高 180°),
|
|
851
|
+
* ⚠️ 表是**从上面那几个网格常数生成**的(⛔ 手抄 32 个数):正确性由护栏 `test/mktmesh.test.js` BE 组
|
|
850
852
|
* 对着手写死的字面量逐个数断言 —— 改了网格常数而护栏没跟着改,当场红。 */
|
|
851
853
|
export const RT_STITCH_SLOT_TILES: ReadonlyArray<ReadonlyArray<number>> = slotTilesOf(PANO_TILE_GRID);
|
|
852
854
|
|
|
853
855
|
/** 槽内第 cell 格在**图像方向**的位置 `[列, 行]`(0 起,与 `RT_STITCH_SLOT_TILES` 的格序同一口径)。
|
|
854
856
|
* ⚠️ 这是「图像方向」(行 0 = 图像最上),GL 的 y 向上 ⇒ 画进 RT 时 y 要翻(拼合器里那句 `1 - (2*r+1)/n`)。
|
|
855
|
-
* `slotCellCols` 默认全景那档(
|
|
857
|
+
* `slotCellCols` 默认全景那档(4 = 一槽就是原图半幅的左四列);图片平面传 2。 */
|
|
856
858
|
export function rtStitchCellPos(cell: number, slotCellCols: number = PANO_TILE_GRID.slotCellCols): [number, number] {
|
|
857
859
|
return [cell % slotCellCols, Math.floor(cell / slotCellCols)];
|
|
858
860
|
}
|
|
@@ -878,12 +880,12 @@ function gridLine(i: number, n: number, steps: number): number {
|
|
|
878
880
|
return Math.round((i * n) / steps);
|
|
879
881
|
}
|
|
880
882
|
|
|
881
|
-
/**
|
|
882
|
-
* ⭐ 10-
|
|
883
|
+
/** 32 片瓦片的切图矩形(行优先、图像左上起,下标 `i = r*8+c` 与 `RT_STITCH_SLOT_TILES` 同源;
|
|
884
|
+
* ⭐ 2026-10-27 需求「横 8 × 竖 4 = 32」:`r` 走 `RT_STITCH_ROWS`(4)、`c` 走 `RT_STITCH_COLS`(8)。
|
|
883
885
|
*
|
|
884
886
|
* ⭐ **上传侧(`panoramaUpload`)与拼合侧(`PanoTileStitcher`)必须共用这一份几何**:
|
|
885
887
|
* 上传多切多少、拼合就内缩多少;两边各算一次就是「缝没治掉、反而把画面挤歪」。
|
|
886
|
-
* 拼合侧拿不到原图尺寸(它只有
|
|
888
|
+
* 拼合侧拿不到原图尺寸(它只有 32 个 URL 和 32 张已解码纹理),所以它用 `rtStitchTileInset`
|
|
887
889
|
* —— 那条只需「下标 + 该瓦片自己的像素尺寸」,两者等价的前提是「多切量 = 常数 M、只有贴边那几片被裁」,
|
|
888
890
|
* 而「贴不贴边」纯由下标决定 ⇒ 护栏 BE 组用同一批 (W,H) 把两条算路对表钉死。 */
|
|
889
891
|
export function rtStitchTileRects(w: number, h: number, grid: TileGridLayout = PANO_TILE_GRID): RtStitchTileRect[] {
|
|
@@ -904,7 +906,7 @@ export function rtStitchTileRects(w: number, h: number, grid: TileGridLayout = P
|
|
|
904
906
|
return out;
|
|
905
907
|
}
|
|
906
908
|
|
|
907
|
-
/** 这片瓦片有没有贴原图边界(
|
|
909
|
+
/** 这片瓦片有没有贴原图边界(8×4 ⇒ 32 片里外圈那 20 片至少贴一条边,只有中间那 12 片四边都不贴;贴边的**那一侧**多切量被裁成 0)。
|
|
908
910
|
* 拼合侧靠它 + 瓦片自己的像素尺寸还原内缩量 ⇒ 不必知道原图多大。
|
|
909
911
|
* ⚠️ 下标拆分必须按 **列数 COLS**(`i = r*cols+c`),⛔ 不是 ROWS。 */
|
|
910
912
|
export function rtStitchTileEdgeClip(
|
|
@@ -949,9 +951,11 @@ export function rtStitchTileInset(
|
|
|
949
951
|
* 「这 `RT_STITCH_SLOT_COUNT`(2) 个纹理槽到底喂哪几个地址」。⚠️ **必须**与 `mktPanoTiledFlag` 同源、同一时机调用:
|
|
950
952
|
* 只改标记不改地址(或反之)= 用整图 UV 去采一张瓦片 / 用瓦片内 UV 去采整图,画面立刻错乱。
|
|
951
953
|
* 非 tiled 态(或该点压根没切过片)一律回退成「各槽同为一张整图」。
|
|
952
|
-
* ⭐ 2026-10-
|
|
953
|
-
* 不足
|
|
954
|
-
* (「无须兼容正常使用,有异常我会重传」⇒ 旧存档的
|
|
954
|
+
* ⭐ 2026-10-27 需求「只支持 32 张(8×4)」:只要有瓦片(1~32 条)一律走拼合器(rt: 虚拟键),
|
|
955
|
+
* 不足 32 张的位置由拼合器**涂灰**(一眼看出数据不全);6×3=18 张、3×3=9 张、8×8=64 张与 4×4=16 张那几版**都不做兼容**
|
|
956
|
+
* (「无须兼容正常使用,有异常我会重传」⇒ 旧存档的 18 / 9 / 64 / 16 条地址张数不符被判废、重传即可)。
|
|
957
|
+
* ⚠️ 唯一按张数**能混进来**的是 10-06 那版同样 32 片的存档:它的瓦片是 1024²,会被画进 1536² 的格子
|
|
958
|
+
* = 1.5× 放大 ⇒ 发虚但不报红。那种老点重传一次即可(顺序与槽分组两版一致,所以不会错位)。
|
|
955
959
|
* ⚠️ 返回长度由 `RT_STITCH_SLOT_COUNT` 派生(⛔ 不许手写 2 个 rtStitchKey —— 槽数再变会漏改)。
|
|
956
960
|
*/
|
|
957
961
|
export function mktPanoTexUrls(url: string, tiles: string[] | undefined, mode: PanoTexMode = "tiled"): string[] {
|
|
@@ -964,7 +968,7 @@ export function mktPanoTexUrls(url: string, tiles: string[] | undefined, mode: P
|
|
|
964
968
|
|
|
965
969
|
/**
|
|
966
970
|
* 「这 2 个纹理槽是不是真瓦片」的判据 —— **必须**与喂纹理处的回退式(`mktPanoTexUrls`)同源:
|
|
967
|
-
* `tiles` 有 **任意 1~
|
|
971
|
+
* `tiles` 有 **任意 1~32 条**地址(不足 32 = 数据不全,缺的格子拼合时涂灰)**且**当前形态选的是 tiled = 是瓦片;
|
|
968
972
|
* 否则各槽同为一张整图(旧数据 / 种子图 / 用户切整片)。
|
|
969
973
|
*/
|
|
970
974
|
export function mktPanoTiledFlag(tiles: string[] | undefined, mode: PanoTexMode = "tiled"): 0 | 1 {
|
|
@@ -1000,9 +1004,9 @@ export function setMktPanoTiled(
|
|
|
1000
1004
|
export function createMktShaderMaterial(): ShaderMaterial {
|
|
1001
1005
|
return new ShaderMaterial({
|
|
1002
1006
|
uniforms: {
|
|
1003
|
-
// 一个全景点恒占 **
|
|
1004
|
-
// panoramas[0..
|
|
1005
|
-
//
|
|
1007
|
+
// 一个全景点恒占 **2 个 sampler**(2026-10-26 起左右 2 槽,本次 8×4 网格沿用 2 槽):
|
|
1008
|
+
// panoramas[0..1] = 2 张**离屏拼合槽纹理**([左半幅, 右半幅],每槽由 `RT_STITCH_CELLS_PER_SLOT`(16)
|
|
1009
|
+
// 片瓦片拼成 4×4 格),片元按全景 UV 的 **u** 两等分挑槽采样(v 恒全高)。
|
|
1006
1010
|
// ⛔ 长度由 `RT_STITCH_SLOT_COUNT` 派生(不许手写 2 张)—— 槽数再变这里会漏改。
|
|
1007
1011
|
panoramas: {
|
|
1008
1012
|
value: Array.from({ length: RT_STITCH_SLOT_COUNT }, () => createPlaceholderTexture()),
|
package/MktMesh/modelSlot.d.ts
CHANGED
|
@@ -66,6 +66,12 @@ export declare class ModelSlot extends Group {
|
|
|
66
66
|
private _staged;
|
|
67
67
|
/** 载入令牌:换地址/删除后迟到的回调靠它作废(否则旧模型会挂进新槽) */
|
|
68
68
|
private _loadToken;
|
|
69
|
+
/**
|
|
70
|
+
* 内容是否已落定:真模型挂进了 `_contentRoot`,或这一颗压根没在等什么(空地址 / 取回失败 ⇒ 停在占位小立方体)。
|
|
71
|
+
* ⚠️ 落定**不等于**已经画进 GPU —— 顶点缓冲与首次 program 编译发生在「亮出来的那一帧」,
|
|
72
|
+
* 所以逐帧限流必须闸在点亮这一下(`MktMesh.tickProgressiveReveal`),闸在挂载那一下拦不住 GPU 侧的账。
|
|
73
|
+
*/
|
|
74
|
+
private _loaded;
|
|
69
75
|
private _disposed;
|
|
70
76
|
constructor(name?: string);
|
|
71
77
|
get size(): number;
|
|
@@ -78,6 +84,8 @@ export declare class ModelSlot extends Group {
|
|
|
78
84
|
} | undefined;
|
|
79
85
|
/** 是否已经挂上真模型(false = 仍是占位小立方体) */
|
|
80
86
|
get hasModel(): boolean;
|
|
87
|
+
/** 这一颗的内容落定没有 —— 库的逐帧点亮闸只认这一条(`MktMesh.tickProgressiveReveal`)。 */
|
|
88
|
+
get loaded(): boolean;
|
|
81
89
|
/** 改尺寸档(米,最长边):立刻重缩内容 */
|
|
82
90
|
setSize(size: number): void;
|
|
83
91
|
/**
|