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.
@@ -6,7 +6,7 @@ import { type TileLayout } from "./mktShader";
6
6
  */
7
7
  export interface PanoStitcher {
8
8
  /** 确保批次已在册并发起瓦片加载(幂等;同批已在册 ⇒ 什么都不做)。
9
- * 新增可选 `layout` 参数:缺省 = PANO_TILE_LAYOUT(全景 3×3 / 3 槽 / 4096×6144,10-23 旨);
9
+ * 新增可选 `layout` 参数:缺省 = PANO_TILE_LAYOUT(全景 6×3 / 2 槽 / 6144×6144,10-26 需求);
10
10
  * 图片平面传 `imageTileLayout(natW, natH)`(2×2 / 1 槽 / RT 宽高比=原图)。 */
11
11
  ensure(urls: string[], layout?: TileLayout): void;
12
12
  /**
@@ -67,11 +67,11 @@ export declare class PanoTileStitcher implements PanoStitcher {
67
67
  private _rtTextures;
68
68
  constructor();
69
69
  /** 确保批次已建组、加载已发起。幂等:同批已在册 ⇒ 直接返回(一片瓦片终身只下载、只解码一次)。
70
- * ⭐ 09-29 晚旨「不足的涂灰」+ 10-23 旨「3×3 = 9 片」:1~9 条皆可入组,内部补空串占位到 9;
70
+ * ⭐ 09-29「不足的涂灰」+ 10-26「6×3 = 18 片」:1~18 条皆可入组,内部补空串占位到 18;
71
71
  * 空串 / 死链的格子拼合时涂灰(一眼看出该全景数据不全)。
72
- * ⛔ 旧版 16 条(4×4)、32 条(8×4)与 64 条(8×8)的数据**都不做兼容**(皇上「无须兼容正常使用, 有异常我会重传」):
73
- * 超 9 条会在上一行被判超限直接丢弃;真喂进来的短数据只占前几格 + 其余涂灰,那是**故意**让数据不全看得见。
74
- * ⚠️ 每槽数组长度由 `RT_STITCH_SLOT_COUNT` 派生(⛔ 不许手写 `[null,null,null]` —— 槽数再变会漏改)。 */
72
+ * ⛔ 旧版 16 条(4×4)、32 条(8×4)、64 条(8×8)与 9 条(3×3)的数据**都不做兼容**(用户「无须兼容正常使用, 有异常我会重传」):
73
+ * 超 18 条会在上一行被判超限直接丢弃;真喂进来的短数据只占前几格 + 其余涂灰,那是**故意**让数据不全看得见。
74
+ * ⚠️ 每槽数组长度由 `RT_STITCH_SLOT_COUNT` 派生(⛔ 不许手写 `[null,null]` —— 槽数再变会漏改)。 */
75
75
  ensure(urls: string[], layout?: TileLayout): void;
76
76
  /** 取某一拼合槽的纹理:**画过 ≥1 格就交出去**(同日旨「需要先喂给 shader」⇒ 不再等 `cellsPerSlot` 格画满)。
77
77
  * RT 建好时整张涂过缺失灰 ⇒ 交出去的那张里**没有未定义像素**,观感 = 该象限逐格显影。 */
@@ -121,7 +121,7 @@ export declare class PanoTileStitcher implements PanoStitcher {
121
121
  * (与 `MktMesh._uploadTileTexture` 的「排上队之后已被清掉 ⇒ 本项作废」同一口径。) */
122
122
  private _uploadTile;
123
123
  /** 画一格:把那片瓦片的**中间那块**铺进该槽第 `cell` 格(每槽 `slotCellCols × slotCellRows` 格里的一格,
124
- * 10-23 旨后全景是「横 1 × 竖 3」= 3 格、图片平面是 2×2 = 4 格)。
124
+ * 10-26 起全景是「横 3 × 竖 3」= 9 格、图片平面是 2×2 = 4 格)。
125
125
  * ⚠️⚠️ `autoClear` 必须关掉:three 每次 `render()` 默认清屏,而这里**同一张 RT 要连画 cellsPerSlot 帧**,
126
126
  * 清一次就把前面画好的格子抹了 ⇒ 槽纹理只剩最后一格。清屏交给我们自己(见 `_clearRt`)。 */
127
127
  private _stitchCell;
@@ -140,7 +140,7 @@ export declare class PanoTileStitcher implements PanoStitcher {
140
140
  /** 换 renderer:RT 是旧上下文的私有资源,留着既画不了也释放不掉 ⇒ 在册组整份作废,
141
141
  * 靠消费方每帧照旧的 `ensure()` 重建(瓦片走浏览器 HTTP 缓存,不重新编码)。 */
142
142
  private _switchRenderer;
143
- /** 懒建某槽的渲染目标:尺寸取自 `g.layout.rtW/rtH`(全景档 = **4096×6144**,10-23 旨)、RGBA8 + sRGB + mipmap,
143
+ /** 懒建某槽的渲染目标:尺寸取自 `g.layout.rtW/rtH`(全景档 = **6144×6144**,10-26 需求)、RGBA8 + sRGB + mipmap,
144
144
  * 并**立刻整张涂缺失灰**(⛔ 未定义像素不许进 shader:`peek()` 现在画过 1 格就交出去)。
145
145
  * ⚠️ 6144 这个数受本机 `MAX_TEXTURE_SIZE` / 最大渲染目标尺寸约束(ANGLE/D3D11 的 11_0 是 16384,远超;
146
146
  * 只有老 Intel 集显才可能卡 4096 —— 真建不出来 three 会报 `GL_INVALID_VALUE`,届时墙上整片缺失灰)。 */
@@ -1,5 +1,5 @@
1
1
  /*
2
- * @Description: 9 瓦片全景的「离屏拼合器」= **shader 逐格画进 WebGLRenderTarget**(本项目唯一一份拼合实现)。
2
+ * @Description: 18 瓦片全景的「离屏拼合器」= **shader 逐格画进 WebGLRenderTarget**(本项目唯一一份拼合实现)。
3
3
  *
4
4
  * 三道旨意叠成现在这一份:
5
5
  * ① 2026-09-29:一张全景切多片(每片所有 GPU 都装得下),运行时离屏拼回若干张固定尺寸的「槽纹理」,
@@ -23,9 +23,14 @@
23
23
  * ⇒ 改 **3×3=9 片 / 按列 3 槽**,每槽 = 原图一整列(横 1 格 × 竖 3 格)= **4096×6144**、与原图 1:1(不再缩小)。
24
24
  * ⚠️ 代价(皇上在「A/B/C/D」里点了 **A**):sampler = 同屏景点数 × 3,硬顶 16 ⇒ **同屏全景点数 8 → 5**(5×3=15)。
25
25
  * 单全景 RT 显存 170MB → **288MB**(含 mipmap ≈384MB)。旧存档 32 条地址**不兼容**,「有异常我会重传」。
26
+ * ⑤ 2026-10-26(需求,逐字):「目前的 全景球是 9片瓦片图的方案, 我想要换成6*3 的18片的方案呢, 就像之前一样的
27
+ * 方案一样 一个全景是 2个RT 每个 RT上面是 4*4 的方案, 现在我想要改成 2个RT 每个RT 上面 3*3=9 的方案」
28
+ * ⇒ 改 **6×3=18 片 / 左右 2 槽**,每槽 = 原图半幅(横 3 格 × 竖 3 格)= **6144×6144**、与原图 1:1。
29
+ * ⭐ 净效果:单全景有效分辨率与显存**一字未动**(仍是 75.5Mpx / ≈384MB),sampler = 点数 × 2 ⇒
30
+ * **同屏全景点数 5 → 8**(8×2=16 正好用满硬顶)。旧存档 9 条地址**不兼容**,用户重传即可。
26
31
  *
27
32
  * ⚠️ **仍然有 canvas,但只在上传切图那一步**(`src/views/MktMeshEdit/panoramaUpload.ts` 用 2D 画布把原图
28
- * 切成 9 个 JPEG 传 OSS)—— 那是**离线、一次性、产出的是数据**;运行时这条路上一个 canvas 都没有。
33
+ * 切成 18 个 JPEG 传 OSS)—— 那是**离线、一次性、产出的是数据**;运行时这条路上一个 canvas 都没有。
29
34
  *
30
35
  * ── 每帧的三道工序(旨②那两句话逐条落地,顺序固定)────────────────────────────────
31
36
  * 1. `_pumpDownloads()`:补发缺图的下载(每帧 ≤2 张、在册 ≤8、已解码待上传 ≤8)⇒ ⛔ 一批几十条 XHR 一起炸。
@@ -35,49 +40,49 @@
35
40
  * 到 GPU 里面去」)。这一趟**只上传、不画** ⇒ 上传与绘制永不落在同一拍(09-29 那句「两个大头别在同一
36
41
  * 帧」的延续),而且第 2 步天然只能画「上一帧及更早」传上去的图 ⇒ 每帧 = 1 上传 + 1 绘制(稳态)。
37
42
  *
38
- * ⚠️ 于是「一帧一片」的帧数随网格走:16 片 → 32 片(30ms/帧 ⇒ 全量到位约 1.0s)→ **9 片/组 = 9 帧**(约 0.27s,
39
- * 10-23 旨)。每格像素 = `RT_STITCH_SLOT_W/1 × RT_STITCH_SLOT_H/3` = **4096×2048**(原图切出来那片多大就多大,一比一)。
40
- * 且因为下面那条「先喂 shader」的旨意,第一格画完墙上就有东西了,不必等 9 帧。
43
+ * ⚠️ 于是「一帧一片」的帧数随网格走:16 片 → 32 片 → 9 片 → **18 片/组 = 18 帧**(30ms/帧 ⇒ 约 0.55s,
44
+ * 10-26 需求)。每格像素 = `RT_STITCH_SLOT_W/3 × RT_STITCH_SLOT_H/3` = **2048×2048**(原图切出来那片多大就多大,一比一)。
45
+ * 且因为下面那条「先喂 shader」的旨意,第一格画完墙上就有东西了,不必等 18 帧。
41
46
  *
42
47
  * ⭐ 部分就绪就先喂(同日旨「1. 需要先喂给 shader」):`peek()` 不再等一个槽的 `cellsPerSlot` 格画满,
43
48
  * **画过 ≥1 格就交出去**。为了保证交出去的那张 RT 里绝无未定义像素,RT 建好后的第一件事是
44
49
  * 整张涂成缺失灰(`_clearRt`)⇒ 观感 = 该象限从左上角起逐格显影,缺数据的格子一直是灰的。
45
50
  *
46
51
  * ── 画质四条(⛔ 改任何一条都是改画质,先请旨)──────────────────────────────
47
- * 1. **尺寸 / 格子几何**:槽 `RT_STITCH_SLOT_W/H` = **4096×6144**、每槽「横 1 格 × 竖 3 格」、原图**横 3 × 竖 3** 片,
52
+ * 1. **尺寸 / 格子几何**:槽 `RT_STITCH_SLOT_W/H` = **6144×6144**、每槽「横 3 格 × 竖 3 格」、原图**横 6 × 竖 3** 片,
48
53
  * 全在 `./mktShader`(单一来源)。⭐ 10-23 旨后格子尺寸 = 那片瓦片的尺寸 ⇒ **一比一**:11968×5984 那类原图
49
- * 切 3×3 得 ~3989×1994 的片,铺进 4096×2048 的格子几乎不缩(缩放比 0.97,上一版 8×4 是 1.46 = 缩小)
54
+ * 切 6×3 得 ~1995×1995 的片,铺进 2048×2048 的格子几乎不缩(缩放比 1.03,与上一版同一档)
50
55
  * ⇒ 单全景有效分辨率 33.5Mpx → **75.5Mpx**,是**升**画质,与「千万不要降低质量」红线同向。
51
- * ⛔ 不许把槽改回 4096² 正方形:那是上一版「每槽覆盖横 180°×竖 180°」的产物;现口径每槽只覆盖**横 120° × 竖 180°**,
52
- * 宽高比 2:3 必须与「原图一整列」一致,否则格子被强行拉伸 = 几何挤歪。
56
+ * ⛔ 不许拿槽尺寸当省显存的旋钮:现口径每槽覆盖**横 180° × 竖 180°**(原图左/右半幅),
57
+ * 宽高比 1:1 与「半幅(3 列 × 3 行)」一致;上一版一槽装一整列时是 2:3,两版各自都对,⛔ 别混着抄。
53
58
  * 2. **色彩**:瓦片纹理 `colorSpace = SRGBColorSpace` ⇒ WebGL2 内部格式 `SRGB8_ALPHA8`,采样时硬件解码成
54
59
  * linear;RT 纹理同样标 sRGB ⇒ 写入时硬件再编码回 sRGB。一进一出**逐字节还原**。
55
60
  * ⚠️ 另一半证据在 three 里:写进非 XR 的 render target 时片元末尾的 `linearToOutputTexel` 恒按
56
61
  * LinearSRGB(= 不转换),编码完全交给硬件 ⇒ ⛔ 我们的片元绝不 `#include <colorspace_fragment>`,
57
62
  * 也不带 tone mapping 的 chunk(那两处都会再转一遍 ⇒ 画面发白)。
58
63
  * 3. **摩尔纹**:两层都开 mipmap ——
59
- * ① 瓦片纹理 `generateMipmaps` + `LinearMipmapLinearFilter`:10-23 旨后一片原图(~3989×1994)铺进 4096×2048
64
+ * ① 瓦片纹理 `generateMipmaps` + `LinearMipmapLinearFilter`:一片原图(~1995×1995)铺进 2048×2048
60
65
  * 的格子是**一比一**,但墙面在远处仍会缩到格子以下 ⇒ ⛔ 单点双线性会采出锯齿,mipmap 照旧开
61
66
  * (WebGL2 对 NPOT 也能生成 mipmap,three r163 起只支持 WebGL2)。
62
67
  * ② 槽 RT 标 `generateMipmaps`:three 每次渲染进 RT 后自己 `glGenerateMipmap`(`WebGLRenderer.js`
63
68
  * `updateRenderTargetMipmap`)⇒ 与当年 CanvasTexture 上传后生成 mipmap 同一口径。
64
69
  * ⚠️ 代价:每格一次(旧版每格也是一次),都在 GPU 上、不占主线程。
65
- * 4. **接缝**:槽内「横 1 × 竖 3」⇒ 一张槽内部的格子线是 **2 横 0 竖**(上一版 4096² 是 3 横 3 竖);
66
- * 槽与槽之间另有 u=1/3、u=2/3 两道**跨纹理**竖缝,那道治不了(见 `PanoTexMode` 说明②)。治法 = 上传时每片向四边**多切**
70
+ * 4. **接缝**:槽内「横 3 × 竖 3」⇒ 一张槽内部的格子线是 **2 横 2 竖**(上一版一槽一整列时只有 2 横 0 竖);
71
+ * 槽与槽之间另有 u=1/2 **一道**跨纹理竖缝,那道治不了(见 `PanoTexMode` 说明②;上一版是两道)。治法 = 上传时每片向四边**多切**
67
72
  * `RT_STITCH_SEAM_MARGIN_PX` 像素、拼合时**只采中间那块**(`uSrcRect`)⇒ 边界插值拿得到真邻居像素,
68
73
  * 不再复制自己的边缘。⛔ 这条不许「顺手简化」成直接铺满格子:几何会挤歪,缝也还在。
69
74
  * 详见 `./mktShader` 里那三个 `rtStitch*` 纯函数 —— **上传侧与拼合侧必须共用同一份几何**。
70
75
  *
71
- * 资源账(⚠️ 如实记;10-23 旨改 3×3=9 片 / 按列 3 槽 / 4096×6144 后重算):
72
- * - 常驻显存:3 槽 × (4096×**6144**×4B + mipmap≈33%) ≈ **384MB/全景**(不含 mipmap 288MB)
73
- * —— 上一版 2 槽 4096² 是 **170MB/全景** ⇒ 单全景变成 **2.26 倍**,代价来自「槽与原图一比一」那次**升分辨率**,
76
+ * 资源账(⚠️ 如实记;10-26 需求改 6×3=18 片 / 左右 2 槽 / 6144×6144 后重算):
77
+ * - 常驻显存:2 槽 × (6144×**6144**×4B + mipmap≈33%) ≈ **384MB/全景**(不含 mipmap 288MB —— 与上一版**一字不差**)
78
+ * —— 更早那版 8×4=32 片 / 2 槽 4096² 只有 **170MB/全景** ⇒ 单全景 **2.26 倍**,代价来自「槽与原图一比一」那次**升分辨率**,
74
79
  * 不是浪费:33.5Mpx → 75.5Mpx 的有效像素全在 RT 里。
75
- * ⚠️ 组**运行中不淘汰**(见文末那条旨)⇒ 13 张全景全常驻 ≈ **4.9GB**(上一版 2.2GB)。同屏景点数虽收到 5,
76
- * 那只省 sampler 绑定、**不省显存**。⚠️ 这是本轮最大的风险项,已另记待皇上裁决(见「RT 不回收」)。
77
- * - 上传总量:同一张原图切完 ⇒ **总像素与 32 片那版逐字节同量**,只是片数 32 → 9、单片边长 ~2.7 倍
78
- * ⇒ 下载发起数减 72%、单请求变大。
80
+ * ⚠️ 组**运行中不淘汰**(见文末那条需求)⇒ 13 张全景全常驻 ≈ **4.9GB**(上一版 2.2GB)。同屏景点数虽回到 8,
81
+ * 那只省 sampler 绑定、**不省显存**。⚠️ 这是这一轮最大的风险项,已另记待用户裁决(见「RT 不回收」)。
82
+ * - 上传总量:同一张原图切完 ⇒ **总像素与上一版逐字节同量**,片数 9 → 18、每片 4096×2048 → 2048×2048(单片像素减半)
83
+ * ⇒ 下载发起数比 9 片那版**翻倍**(仍比 32 片那版少 14 条)、单请求变小。
79
84
  * - 瓦片纹理画完即弃 ⇒ 同时在册的只有「下载中 + 已解码待上传」那些,上限 8+8 片;
80
- * ⚠️ 每片解码位图 4096×2048×4B = **32MB**(上一版每片 8.5MB)⇒ 峰值 CPU 侧 ≈ **512MB**(原 ~136MB)。
85
+ * ⚠️ 每片解码位图 2048×2048×4B = **16MB**(上一版每片 4096×2048 = 32MB)⇒ 峰值 CPU 侧 ≈ **256MB**(原 512MB)。
81
86
  *
82
87
  * ⚠️ RT 是 GL 上下文私有资源:`pump(renderer)` 换 renderer 时整组作废(`_switchRenderer`),下一帧消费方
83
88
  * 照旧的 `ensure()` 重建(瓦片走浏览器 HTTP 缓存重新下载)。现况是**每个持有者一份拼合器 + 一个 renderer**
@@ -98,7 +103,7 @@ import { MISSING_TILE_GRAY, rtStitchBatchOf, rtStitchCellPos, rtStitchTileInset,
98
103
  * ⛔ 别再拿它去写 budget 循环:那正是「一帧上传 2 张」的根因(消费方 onBeforeRender 里 pump 了两次)。
99
104
  */
100
105
  const PANO_STITCH_UPLOADS_PER_FRAME = 1;
101
- /** 每帧最多发起几张下载(10-23 起一批 9 片,⛔ 不加以限制就是一帧甩 9 条 XHR + 9 次 800 万像素解码) */
106
+ /** 每帧最多发起几张下载(现行一批 18 片,⛔ 不加以限制就是一帧甩 18 条 XHR + 18 次 400 万像素解码) */
102
107
  const PANO_STITCH_DOWNLOADS_PER_FRAME = 2;
103
108
  /** 「下载中」的片数上限(跨所有批次) */
104
109
  const PANO_STITCH_MAX_INFLIGHT = 8;
@@ -199,11 +204,11 @@ export class PanoTileStitcher {
199
204
  this._blank.needsUpdate = true;
200
205
  }
201
206
  /** 确保批次已建组、加载已发起。幂等:同批已在册 ⇒ 直接返回(一片瓦片终身只下载、只解码一次)。
202
- * ⭐ 09-29 晚旨「不足的涂灰」+ 10-23 旨「3×3 = 9 片」:1~9 条皆可入组,内部补空串占位到 9;
207
+ * ⭐ 09-29「不足的涂灰」+ 10-26「6×3 = 18 片」:1~18 条皆可入组,内部补空串占位到 18;
203
208
  * 空串 / 死链的格子拼合时涂灰(一眼看出该全景数据不全)。
204
- * ⛔ 旧版 16 条(4×4)、32 条(8×4)与 64 条(8×8)的数据**都不做兼容**(皇上「无须兼容正常使用, 有异常我会重传」):
205
- * 超 9 条会在上一行被判超限直接丢弃;真喂进来的短数据只占前几格 + 其余涂灰,那是**故意**让数据不全看得见。
206
- * ⚠️ 每槽数组长度由 `RT_STITCH_SLOT_COUNT` 派生(⛔ 不许手写 `[null,null,null]` —— 槽数再变会漏改)。 */
209
+ * ⛔ 旧版 16 条(4×4)、32 条(8×4)、64 条(8×8)与 9 条(3×3)的数据**都不做兼容**(用户「无须兼容正常使用, 有异常我会重传」):
210
+ * 超 18 条会在上一行被判超限直接丢弃;真喂进来的短数据只占前几格 + 其余涂灰,那是**故意**让数据不全看得见。
211
+ * ⚠️ 每槽数组长度由 `RT_STITCH_SLOT_COUNT` 派生(⛔ 不许手写 `[null,null]` —— 槽数再变会漏改)。 */
207
212
  ensure(urls, layout) {
208
213
  const L = layout ?? PANO_TILE_LAYOUT;
209
214
  const maxTiles = tilesPerBatchOf(L);
@@ -437,14 +442,14 @@ export class PanoTileStitcher {
437
442
  }
438
443
  // ───────────────────────── 内部:单格绘制 ─────────────────────────
439
444
  /** 画一格:把那片瓦片的**中间那块**铺进该槽第 `cell` 格(每槽 `slotCellCols × slotCellRows` 格里的一格,
440
- * 10-23 旨后全景是「横 1 × 竖 3」= 3 格、图片平面是 2×2 = 4 格)。
445
+ * 10-26 起全景是「横 3 × 竖 3」= 9 格、图片平面是 2×2 = 4 格)。
441
446
  * ⚠️⚠️ `autoClear` 必须关掉:three 每次 `render()` 默认清屏,而这里**同一张 RT 要连画 cellsPerSlot 帧**,
442
447
  * 清一次就把前面画好的格子抹了 ⇒ 槽纹理只剩最后一格。清屏交给我们自己(见 `_clearRt`)。 */
443
448
  _stitchCell(renderer, g, slot, cell, tex) {
444
449
  const rt = this._ensureRt(renderer, g, slot);
445
450
  const tileIdx = g.slotTiles[slot][cell];
446
451
  const [cc, rr] = rtStitchCellPos(cell, g.layout.slotCellCols);
447
- // ⚠️ 横竖**分轴**缩放/摆位(旧的单一 `slotGrid` 方形假设整条作废):10-23 旨一槽 = 原图一整列 ⇒ 1 横 3 竖
452
+ // ⚠️ 横竖**分轴**缩放/摆位(旧的单一 `slotGrid` 方形假设整条作废):10-26 起全景一槽 = 原图半幅 ⇒ 3 横 3 竖,图片平面那档 2 横 2 竖
448
453
  const cw = g.layout.slotCellCols;
449
454
  const ch = g.layout.slotCellRows;
450
455
  this._quad.scale.set(1 / cw, 1 / ch, 1);
@@ -558,7 +563,7 @@ export class PanoTileStitcher {
558
563
  this._fails.clear();
559
564
  this._dead.clear();
560
565
  }
561
- /** 懒建某槽的渲染目标:尺寸取自 `g.layout.rtW/rtH`(全景档 = **4096×6144**,10-23 旨)、RGBA8 + sRGB + mipmap,
566
+ /** 懒建某槽的渲染目标:尺寸取自 `g.layout.rtW/rtH`(全景档 = **6144×6144**,10-26 需求)、RGBA8 + sRGB + mipmap,
562
567
  * 并**立刻整张涂缺失灰**(⛔ 未定义像素不许进 shader:`peek()` 现在画过 1 格就交出去)。
563
568
  * ⚠️ 6144 这个数受本机 `MAX_TEXTURE_SIZE` / 最大渲染目标尺寸约束(ANGLE/D3D11 的 11_0 是 16384,远超;
564
569
  * 只有老 Intel 集显才可能卡 4096 —— 真建不出来 three 会报 `GL_INVALID_VALUE`,届时墙上整片缺失灰)。 */
@@ -1,5 +1,5 @@
1
1
  /*
2
- * @Description: 9 瓦片全景的「离屏拼合器」= **shader 逐格画进 WebGLRenderTarget**(本项目唯一一份拼合实现)。
2
+ * @Description: 18 瓦片全景的「离屏拼合器」= **shader 逐格画进 WebGLRenderTarget**(本项目唯一一份拼合实现)。
3
3
  *
4
4
  * 三道旨意叠成现在这一份:
5
5
  * ① 2026-09-29:一张全景切多片(每片所有 GPU 都装得下),运行时离屏拼回若干张固定尺寸的「槽纹理」,
@@ -23,9 +23,14 @@
23
23
  * ⇒ 改 **3×3=9 片 / 按列 3 槽**,每槽 = 原图一整列(横 1 格 × 竖 3 格)= **4096×6144**、与原图 1:1(不再缩小)。
24
24
  * ⚠️ 代价(皇上在「A/B/C/D」里点了 **A**):sampler = 同屏景点数 × 3,硬顶 16 ⇒ **同屏全景点数 8 → 5**(5×3=15)。
25
25
  * 单全景 RT 显存 170MB → **288MB**(含 mipmap ≈384MB)。旧存档 32 条地址**不兼容**,「有异常我会重传」。
26
+ * ⑤ 2026-10-26(需求,逐字):「目前的 全景球是 9片瓦片图的方案, 我想要换成6*3 的18片的方案呢, 就像之前一样的
27
+ * 方案一样 一个全景是 2个RT 每个 RT上面是 4*4 的方案, 现在我想要改成 2个RT 每个RT 上面 3*3=9 的方案」
28
+ * ⇒ 改 **6×3=18 片 / 左右 2 槽**,每槽 = 原图半幅(横 3 格 × 竖 3 格)= **6144×6144**、与原图 1:1。
29
+ * ⭐ 净效果:单全景有效分辨率与显存**一字未动**(仍是 75.5Mpx / ≈384MB),sampler = 点数 × 2 ⇒
30
+ * **同屏全景点数 5 → 8**(8×2=16 正好用满硬顶)。旧存档 9 条地址**不兼容**,用户重传即可。
26
31
  *
27
32
  * ⚠️ **仍然有 canvas,但只在上传切图那一步**(`src/views/MktMeshEdit/panoramaUpload.ts` 用 2D 画布把原图
28
- * 切成 9 个 JPEG 传 OSS)—— 那是**离线、一次性、产出的是数据**;运行时这条路上一个 canvas 都没有。
33
+ * 切成 18 个 JPEG 传 OSS)—— 那是**离线、一次性、产出的是数据**;运行时这条路上一个 canvas 都没有。
29
34
  *
30
35
  * ── 每帧的三道工序(旨②那两句话逐条落地,顺序固定)────────────────────────────────
31
36
  * 1. `_pumpDownloads()`:补发缺图的下载(每帧 ≤2 张、在册 ≤8、已解码待上传 ≤8)⇒ ⛔ 一批几十条 XHR 一起炸。
@@ -35,49 +40,49 @@
35
40
  * 到 GPU 里面去」)。这一趟**只上传、不画** ⇒ 上传与绘制永不落在同一拍(09-29 那句「两个大头别在同一
36
41
  * 帧」的延续),而且第 2 步天然只能画「上一帧及更早」传上去的图 ⇒ 每帧 = 1 上传 + 1 绘制(稳态)。
37
42
  *
38
- * ⚠️ 于是「一帧一片」的帧数随网格走:16 片 → 32 片(30ms/帧 ⇒ 全量到位约 1.0s)→ **9 片/组 = 9 帧**(约 0.27s,
39
- * 10-23 旨)。每格像素 = `RT_STITCH_SLOT_W/1 × RT_STITCH_SLOT_H/3` = **4096×2048**(原图切出来那片多大就多大,一比一)。
40
- * 且因为下面那条「先喂 shader」的旨意,第一格画完墙上就有东西了,不必等 9 帧。
43
+ * ⚠️ 于是「一帧一片」的帧数随网格走:16 片 → 32 片 → 9 片 → **18 片/组 = 18 帧**(30ms/帧 ⇒ 约 0.55s,
44
+ * 10-26 需求)。每格像素 = `RT_STITCH_SLOT_W/3 × RT_STITCH_SLOT_H/3` = **2048×2048**(原图切出来那片多大就多大,一比一)。
45
+ * 且因为下面那条「先喂 shader」的旨意,第一格画完墙上就有东西了,不必等 18 帧。
41
46
  *
42
47
  * ⭐ 部分就绪就先喂(同日旨「1. 需要先喂给 shader」):`peek()` 不再等一个槽的 `cellsPerSlot` 格画满,
43
48
  * **画过 ≥1 格就交出去**。为了保证交出去的那张 RT 里绝无未定义像素,RT 建好后的第一件事是
44
49
  * 整张涂成缺失灰(`_clearRt`)⇒ 观感 = 该象限从左上角起逐格显影,缺数据的格子一直是灰的。
45
50
  *
46
51
  * ── 画质四条(⛔ 改任何一条都是改画质,先请旨)──────────────────────────────
47
- * 1. **尺寸 / 格子几何**:槽 `RT_STITCH_SLOT_W/H` = **4096×6144**、每槽「横 1 格 × 竖 3 格」、原图**横 3 × 竖 3** 片,
52
+ * 1. **尺寸 / 格子几何**:槽 `RT_STITCH_SLOT_W/H` = **6144×6144**、每槽「横 3 格 × 竖 3 格」、原图**横 6 × 竖 3** 片,
48
53
  * 全在 `./mktShader`(单一来源)。⭐ 10-23 旨后格子尺寸 = 那片瓦片的尺寸 ⇒ **一比一**:11968×5984 那类原图
49
- * 切 3×3 得 ~3989×1994 的片,铺进 4096×2048 的格子几乎不缩(缩放比 0.97,上一版 8×4 是 1.46 = 缩小)
54
+ * 切 6×3 得 ~1995×1995 的片,铺进 2048×2048 的格子几乎不缩(缩放比 1.03,与上一版同一档)
50
55
  * ⇒ 单全景有效分辨率 33.5Mpx → **75.5Mpx**,是**升**画质,与「千万不要降低质量」红线同向。
51
- * ⛔ 不许把槽改回 4096² 正方形:那是上一版「每槽覆盖横 180°×竖 180°」的产物;现口径每槽只覆盖**横 120° × 竖 180°**,
52
- * 宽高比 2:3 必须与「原图一整列」一致,否则格子被强行拉伸 = 几何挤歪。
56
+ * ⛔ 不许拿槽尺寸当省显存的旋钮:现口径每槽覆盖**横 180° × 竖 180°**(原图左/右半幅),
57
+ * 宽高比 1:1 与「半幅(3 列 × 3 行)」一致;上一版一槽装一整列时是 2:3,两版各自都对,⛔ 别混着抄。
53
58
  * 2. **色彩**:瓦片纹理 `colorSpace = SRGBColorSpace` ⇒ WebGL2 内部格式 `SRGB8_ALPHA8`,采样时硬件解码成
54
59
  * linear;RT 纹理同样标 sRGB ⇒ 写入时硬件再编码回 sRGB。一进一出**逐字节还原**。
55
60
  * ⚠️ 另一半证据在 three 里:写进非 XR 的 render target 时片元末尾的 `linearToOutputTexel` 恒按
56
61
  * LinearSRGB(= 不转换),编码完全交给硬件 ⇒ ⛔ 我们的片元绝不 `#include <colorspace_fragment>`,
57
62
  * 也不带 tone mapping 的 chunk(那两处都会再转一遍 ⇒ 画面发白)。
58
63
  * 3. **摩尔纹**:两层都开 mipmap ——
59
- * ① 瓦片纹理 `generateMipmaps` + `LinearMipmapLinearFilter`:10-23 旨后一片原图(~3989×1994)铺进 4096×2048
64
+ * ① 瓦片纹理 `generateMipmaps` + `LinearMipmapLinearFilter`:一片原图(~1995×1995)铺进 2048×2048
60
65
  * 的格子是**一比一**,但墙面在远处仍会缩到格子以下 ⇒ ⛔ 单点双线性会采出锯齿,mipmap 照旧开
61
66
  * (WebGL2 对 NPOT 也能生成 mipmap,three r163 起只支持 WebGL2)。
62
67
  * ② 槽 RT 标 `generateMipmaps`:three 每次渲染进 RT 后自己 `glGenerateMipmap`(`WebGLRenderer.js`
63
68
  * `updateRenderTargetMipmap`)⇒ 与当年 CanvasTexture 上传后生成 mipmap 同一口径。
64
69
  * ⚠️ 代价:每格一次(旧版每格也是一次),都在 GPU 上、不占主线程。
65
- * 4. **接缝**:槽内「横 1 × 竖 3」⇒ 一张槽内部的格子线是 **2 横 0 竖**(上一版 4096² 是 3 横 3 竖);
66
- * 槽与槽之间另有 u=1/3、u=2/3 两道**跨纹理**竖缝,那道治不了(见 `PanoTexMode` 说明②)。治法 = 上传时每片向四边**多切**
70
+ * 4. **接缝**:槽内「横 3 × 竖 3」⇒ 一张槽内部的格子线是 **2 横 2 竖**(上一版一槽一整列时只有 2 横 0 竖);
71
+ * 槽与槽之间另有 u=1/2 **一道**跨纹理竖缝,那道治不了(见 `PanoTexMode` 说明②;上一版是两道)。治法 = 上传时每片向四边**多切**
67
72
  * `RT_STITCH_SEAM_MARGIN_PX` 像素、拼合时**只采中间那块**(`uSrcRect`)⇒ 边界插值拿得到真邻居像素,
68
73
  * 不再复制自己的边缘。⛔ 这条不许「顺手简化」成直接铺满格子:几何会挤歪,缝也还在。
69
74
  * 详见 `./mktShader` 里那三个 `rtStitch*` 纯函数 —— **上传侧与拼合侧必须共用同一份几何**。
70
75
  *
71
- * 资源账(⚠️ 如实记;10-23 旨改 3×3=9 片 / 按列 3 槽 / 4096×6144 后重算):
72
- * - 常驻显存:3 槽 × (4096×**6144**×4B + mipmap≈33%) ≈ **384MB/全景**(不含 mipmap 288MB)
73
- * —— 上一版 2 槽 4096² 是 **170MB/全景** ⇒ 单全景变成 **2.26 倍**,代价来自「槽与原图一比一」那次**升分辨率**,
76
+ * 资源账(⚠️ 如实记;10-26 需求改 6×3=18 片 / 左右 2 槽 / 6144×6144 后重算):
77
+ * - 常驻显存:2 槽 × (6144×**6144**×4B + mipmap≈33%) ≈ **384MB/全景**(不含 mipmap 288MB —— 与上一版**一字不差**)
78
+ * —— 更早那版 8×4=32 片 / 2 槽 4096² 只有 **170MB/全景** ⇒ 单全景 **2.26 倍**,代价来自「槽与原图一比一」那次**升分辨率**,
74
79
  * 不是浪费:33.5Mpx → 75.5Mpx 的有效像素全在 RT 里。
75
- * ⚠️ 组**运行中不淘汰**(见文末那条旨)⇒ 13 张全景全常驻 ≈ **4.9GB**(上一版 2.2GB)。同屏景点数虽收到 5,
76
- * 那只省 sampler 绑定、**不省显存**。⚠️ 这是本轮最大的风险项,已另记待皇上裁决(见「RT 不回收」)。
77
- * - 上传总量:同一张原图切完 ⇒ **总像素与 32 片那版逐字节同量**,只是片数 32 → 9、单片边长 ~2.7 倍
78
- * ⇒ 下载发起数减 72%、单请求变大。
80
+ * ⚠️ 组**运行中不淘汰**(见文末那条需求)⇒ 13 张全景全常驻 ≈ **4.9GB**(上一版 2.2GB)。同屏景点数虽回到 8,
81
+ * 那只省 sampler 绑定、**不省显存**。⚠️ 这是这一轮最大的风险项,已另记待用户裁决(见「RT 不回收」)。
82
+ * - 上传总量:同一张原图切完 ⇒ **总像素与上一版逐字节同量**,片数 9 → 18、每片 4096×2048 → 2048×2048(单片像素减半)
83
+ * ⇒ 下载发起数比 9 片那版**翻倍**(仍比 32 片那版少 14 条)、单请求变小。
79
84
  * - 瓦片纹理画完即弃 ⇒ 同时在册的只有「下载中 + 已解码待上传」那些,上限 8+8 片;
80
- * ⚠️ 每片解码位图 4096×2048×4B = **32MB**(上一版每片 8.5MB)⇒ 峰值 CPU 侧 ≈ **512MB**(原 ~136MB)。
85
+ * ⚠️ 每片解码位图 2048×2048×4B = **16MB**(上一版每片 4096×2048 = 32MB)⇒ 峰值 CPU 侧 ≈ **256MB**(原 512MB)。
81
86
  *
82
87
  * ⚠️ RT 是 GL 上下文私有资源:`pump(renderer)` 换 renderer 时整组作废(`_switchRenderer`),下一帧消费方
83
88
  * 照旧的 `ensure()` 重建(瓦片走浏览器 HTTP 缓存重新下载)。现况是**每个持有者一份拼合器 + 一个 renderer**
@@ -130,7 +135,7 @@ import {
130
135
  */
131
136
  const PANO_STITCH_UPLOADS_PER_FRAME = 1;
132
137
 
133
- /** 每帧最多发起几张下载(10-23 起一批 9 片,⛔ 不加以限制就是一帧甩 9 条 XHR + 9 次 800 万像素解码) */
138
+ /** 每帧最多发起几张下载(现行一批 18 片,⛔ 不加以限制就是一帧甩 18 条 XHR + 18 次 400 万像素解码) */
134
139
  const PANO_STITCH_DOWNLOADS_PER_FRAME = 2;
135
140
 
136
141
  /** 「下载中」的片数上限(跨所有批次) */
@@ -223,7 +228,7 @@ interface StitchGroup {
223
228
  */
224
229
  export interface PanoStitcher {
225
230
  /** 确保批次已在册并发起瓦片加载(幂等;同批已在册 ⇒ 什么都不做)。
226
- * 新增可选 `layout` 参数:缺省 = PANO_TILE_LAYOUT(全景 3×3 / 3 槽 / 4096×6144,10-23 旨);
231
+ * 新增可选 `layout` 参数:缺省 = PANO_TILE_LAYOUT(全景 6×3 / 2 槽 / 6144×6144,10-26 需求);
227
232
  * 图片平面传 `imageTileLayout(natW, natH)`(2×2 / 1 槽 / RT 宽高比=原图)。 */
228
233
  ensure(urls: string[], layout?: TileLayout): void;
229
234
  /**
@@ -305,11 +310,11 @@ private _uploadQueued: Set<TileRec> = new Set();
305
310
  }
306
311
 
307
312
  /** 确保批次已建组、加载已发起。幂等:同批已在册 ⇒ 直接返回(一片瓦片终身只下载、只解码一次)。
308
- * ⭐ 09-29 晚旨「不足的涂灰」+ 10-23 旨「3×3 = 9 片」:1~9 条皆可入组,内部补空串占位到 9;
313
+ * ⭐ 09-29「不足的涂灰」+ 10-26「6×3 = 18 片」:1~18 条皆可入组,内部补空串占位到 18;
309
314
  * 空串 / 死链的格子拼合时涂灰(一眼看出该全景数据不全)。
310
- * ⛔ 旧版 16 条(4×4)、32 条(8×4)与 64 条(8×8)的数据**都不做兼容**(皇上「无须兼容正常使用, 有异常我会重传」):
311
- * 超 9 条会在上一行被判超限直接丢弃;真喂进来的短数据只占前几格 + 其余涂灰,那是**故意**让数据不全看得见。
312
- * ⚠️ 每槽数组长度由 `RT_STITCH_SLOT_COUNT` 派生(⛔ 不许手写 `[null,null,null]` —— 槽数再变会漏改)。 */
315
+ * ⛔ 旧版 16 条(4×4)、32 条(8×4)、64 条(8×8)与 9 条(3×3)的数据**都不做兼容**(用户「无须兼容正常使用, 有异常我会重传」):
316
+ * 超 18 条会在上一行被判超限直接丢弃;真喂进来的短数据只占前几格 + 其余涂灰,那是**故意**让数据不全看得见。
317
+ * ⚠️ 每槽数组长度由 `RT_STITCH_SLOT_COUNT` 派生(⛔ 不许手写 `[null,null]` —— 槽数再变会漏改)。 */
313
318
  ensure(urls: string[], layout?: TileLayout): void {
314
319
  const L = layout ?? PANO_TILE_LAYOUT;
315
320
  const maxTiles = tilesPerBatchOf(L);
@@ -528,14 +533,14 @@ private _uploadQueued: Set<TileRec> = new Set();
528
533
  // ───────────────────────── 内部:单格绘制 ─────────────────────────
529
534
 
530
535
  /** 画一格:把那片瓦片的**中间那块**铺进该槽第 `cell` 格(每槽 `slotCellCols × slotCellRows` 格里的一格,
531
- * 10-23 旨后全景是「横 1 × 竖 3」= 3 格、图片平面是 2×2 = 4 格)。
536
+ * 10-26 起全景是「横 3 × 竖 3」= 9 格、图片平面是 2×2 = 4 格)。
532
537
  * ⚠️⚠️ `autoClear` 必须关掉:three 每次 `render()` 默认清屏,而这里**同一张 RT 要连画 cellsPerSlot 帧**,
533
538
  * 清一次就把前面画好的格子抹了 ⇒ 槽纹理只剩最后一格。清屏交给我们自己(见 `_clearRt`)。 */
534
539
  private _stitchCell(renderer: WebGLRenderer, g: StitchGroup, slot: number, cell: number, tex: Texture | null): void {
535
540
  const rt = this._ensureRt(renderer, g, slot);
536
541
  const tileIdx = g.slotTiles[slot][cell];
537
542
  const [cc, rr] = rtStitchCellPos(cell, g.layout.slotCellCols);
538
- // ⚠️ 横竖**分轴**缩放/摆位(旧的单一 `slotGrid` 方形假设整条作废):10-23 旨一槽 = 原图一整列 ⇒ 1 横 3 竖
543
+ // ⚠️ 横竖**分轴**缩放/摆位(旧的单一 `slotGrid` 方形假设整条作废):10-26 起全景一槽 = 原图半幅 ⇒ 3 横 3 竖,图片平面那档 2 横 2 竖
539
544
  const cw = g.layout.slotCellCols;
540
545
  const ch = g.layout.slotCellRows;
541
546
  this._quad.scale.set(1 / cw, 1 / ch, 1);
@@ -654,7 +659,7 @@ private _uploadQueued: Set<TileRec> = new Set();
654
659
  this._dead.clear();
655
660
  }
656
661
 
657
- /** 懒建某槽的渲染目标:尺寸取自 `g.layout.rtW/rtH`(全景档 = **4096×6144**,10-23 旨)、RGBA8 + sRGB + mipmap,
662
+ /** 懒建某槽的渲染目标:尺寸取自 `g.layout.rtW/rtH`(全景档 = **6144×6144**,10-26 需求)、RGBA8 + sRGB + mipmap,
658
663
  * 并**立刻整张涂缺失灰**(⛔ 未定义像素不许进 shader:`peek()` 现在画过 1 格就交出去)。
659
664
  * ⚠️ 6144 这个数受本机 `MAX_TEXTURE_SIZE` / 最大渲染目标尺寸约束(ANGLE/D3D11 的 11_0 是 16384,远超;
660
665
  * 只有老 Intel 集显才可能卡 4096 —— 真建不出来 three 会报 `GL_INVALID_VALUE`,届时墙上整片缺失灰)。 */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "three-base",
3
- "version": "2.0.181",
3
+ "version": "2.0.187",
4
4
  "description": "A Three.js extension library providing common 3D components, animations, materials, and utilities",
5
5
  "author": "xiaosihan",
6
6
  "publishConfig": {