three-base 2.0.193 → 2.0.195
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 +25 -66
- package/MktMesh/MktMesh.js +29 -150
- package/MktMesh/MktMesh.ts +28 -155
- package/MktMesh/panoTileStitcher.d.ts +36 -11
- package/MktMesh/panoTileStitcher.js +89 -47
- package/MktMesh/panoTileStitcher.ts +94 -42
- package/MktMesh/types.d.ts +0 -6
- package/MktMesh/types.ts +0 -6
- package/package.json +1 -6
- package/MktMesh/glassPane.d.ts +0 -43
- package/MktMesh/glassPane.js +0 -97
- package/MktMesh/glassPane.ts +0 -116
package/MktMesh/MktMesh.d.ts
CHANGED
|
@@ -4,7 +4,6 @@ import { type PanoStitcher } from "./panoTileStitcher";
|
|
|
4
4
|
import type { MktMeshData, MktTextureInfo, WallPoint, WallSide } from "./types";
|
|
5
5
|
import { ImagePlane, type ImagePlaneData } from "./imagePlane";
|
|
6
6
|
import { ModelSlot, type ModelSlotData } from "./modelSlot";
|
|
7
|
-
import { GlassPane, type GlassPaneData } from "./glassPane";
|
|
8
7
|
export default class MktMesh extends Mesh<BufferGeometry, ShaderMaterial> {
|
|
9
8
|
/** 纹理列表(每个纹理的 url + 世界矩阵) */
|
|
10
9
|
textures: MktTextureInfo[];
|
|
@@ -129,23 +128,6 @@ export default class MktMesh extends Mesh<BufferGeometry, ShaderMaterial> {
|
|
|
129
128
|
imagePlanes: ImagePlane[];
|
|
130
129
|
/** 模型槽层(同一棵子树,口径同上) */
|
|
131
130
|
models: ModelSlot[];
|
|
132
|
-
/**
|
|
133
|
-
* 玻璃面层(⭐ 2026-10-28 需求「正方的面」):同一棵子树,口径与上面两层一致。
|
|
134
|
-
* 与那两层的区别只在材质(MeshPhysicalMaterial + transmission + DoubleSide,见 `./glassPane.ts`)
|
|
135
|
-
* ⇒ 它**没有自己的内容纹理**,反射源共用下面那一张 `_glassEnvTex`。
|
|
136
|
-
*/
|
|
137
|
-
glassPanes: GlassPane[];
|
|
138
|
-
/**
|
|
139
|
-
* 玻璃面反射环境的**源地址** = 第一个全景的整图地址(`textures[0].url`),空串 = 还没有全景可用。
|
|
140
|
-
* ⚠️ 这里存的是**未拼尺寸参数的原始地址**(与 `_texCache` 的键同一口径)⇒ 全景换了地址才发现要重载;
|
|
141
|
-
* 下载时按当前 `_ossSize` 档过 `resolveOssUrl`(默认为 1024 那一档)。PMREM 卷积输出的分辨率上限远小于 1024
|
|
142
|
-
* ⇒ 反射精度由那一步决定,用缩放副本不降低观感,换来的是省掉整张原图(实测 11904×5952 ≈ 283MB)的解码内存。
|
|
143
|
-
* ⚠️ 为什么不用「第一个全景那两张拼合槽 RT」:每张 RT 装的是原图**左/右半幅**且压成 1:1 方图,
|
|
144
|
-
* 当等距柱状环境采会横向拉伸一倍 + 缺半边;且它的 mapping 是 UVMapping,three 不会替它做 PMREM ⇒ 采出花屏。
|
|
145
|
-
*/
|
|
146
|
-
private _glassEnvKey;
|
|
147
|
-
/** 已就绪的反射环境纹理(null = 未就绪 / 没有全景);同一张共用给所有玻璃面 ⇒ 只下载、只卷积一次 */
|
|
148
|
-
private _glassEnvTex;
|
|
149
131
|
/**
|
|
150
132
|
* 那 4 张瓦片的下载/解码缓存。⭐ 与全景 `_texCache` 同一条旨(10-02「纹理都缓存在对象里面,执行 dispose 时才销毁」)
|
|
151
133
|
* ⇒ 切工程**不**清它,回来那一圈直接命中缓存、不会再空一格;只随本对象 `dispose()` 释放。
|
|
@@ -392,32 +374,6 @@ export default class MktMesh extends Mesh<BufferGeometry, ShaderMaterial> {
|
|
|
392
374
|
private _queueModelMount;
|
|
393
375
|
/** 全局队列里的那一帧:只挂这一槽,挂好才回调(`onEachLoad` = 按需渲染宿主的标脏钩子) */
|
|
394
376
|
private _mountModelStep;
|
|
395
|
-
/** 单颗玻璃面入层(编辑态双击落点用):进数组 + 挂进本对象子树 + 先吃当前反射源,再确认源在下路没有 */
|
|
396
|
-
addGlassPane(gp: GlassPane): GlassPane;
|
|
397
|
-
/** 摘掉一颗并释放它的几何/材质;反射纹理是共用那张 ⇒ 最后一颗也摘掉时才由 `syncGlassEnvironment` 收(按源地址记账,⛔ 不在这里直接 dispose) */
|
|
398
|
-
removeGlassPane(gp: GlassPane): void;
|
|
399
|
-
/**
|
|
400
|
-
* 整层重建玻璃面(`importData` 与预览那一路)。玻璃面不引用任何素材文件 ⇒ ⛔ 不过 `absAssetUrl`
|
|
401
|
-
* (地址只有反射源那一处,而它取的是**本对象内存里**的 `textures[0].url`,已经是补过域名的形态)。
|
|
402
|
-
*/
|
|
403
|
-
setGlassPanes(datas: GlassPaneData[]): void;
|
|
404
|
-
/**
|
|
405
|
-
* 把「第一个全景」的整图当成玻璃面的反射环境(2026-10-28 需求)。
|
|
406
|
-
*
|
|
407
|
-
* 判据 = 源地址变了没有(⛔ 不按下标记:删掉 0 号景点后原 1 号自动顶上来,那时地址会变 ⇒ 自愈)。
|
|
408
|
-
* 调用点只有四处,⛔ 不进 `onBeforeRender` 自驱:① 单颗入层 ② 单颗摘除 ③ 整层重建 ④ 编辑态每帧 tick 里与
|
|
409
|
-
* `feedImagePlaneTiles()` 并排那一句(源地址没变就一句比较直接返回 ⇒ 无玻璃面的场景零成本,
|
|
410
|
-
* 而全景被增删/换图那些路都不必各自记得再来点一次)。
|
|
411
|
-
*
|
|
412
|
-
* ⚠️ 换源那一步必须**先摘后放**:材质还指着这张、位图却已 `close()` ⇒ 采出来是空图。
|
|
413
|
-
* ⚠️ 下载走 `loadPanoTexture`(解码在工作线程)并自动向 `DefaultLoadingManager` 记账 ⇒ 预览弹窗那个
|
|
414
|
-
* 加载进度条能看见它,与全景瓦片同一本账。
|
|
415
|
-
* ⚠️ 结果只存进 `_glassEnvTex`,⛔ 不进 `_texCache`:那张表在 `setOssSize` 换档时会被整批 dispose
|
|
416
|
-
* (`_reloadActiveTexture`),而正在被材质引用的这张不能被那样顺手清掉。
|
|
417
|
-
*/
|
|
418
|
-
syncGlassEnvironment(): void;
|
|
419
|
-
/** 把同一张反射源发给每一颗玻璃面(`GlassPane` 内部按对象判等 ⇒ 重复发同一张不会重编译)。 */
|
|
420
|
-
private _applyGlassEnv;
|
|
421
377
|
/**
|
|
422
378
|
* 把各颗平面那 4 张瓦片的纹理绑进材质(10-22 晚定的口径:不走拼合器 RT)。
|
|
423
379
|
* 2026-10-26 决定改成**逐帧**:一次把整层地址全丢给下载器(下载/解码在网络与工作线程侧,不占这一帧),
|
|
@@ -450,34 +406,37 @@ export default class MktMesh extends Mesh<BufferGeometry, ShaderMaterial> {
|
|
|
450
406
|
* @param onModelLoad 每只 GLB 落地时回调一次(可选)——按需渲染的宿主(编辑器)拿它标脏;每帧真画的预览不传 */
|
|
451
407
|
importData(data: MktMeshData, projName?: string, onModelLoad?: () => void): void;
|
|
452
408
|
/**
|
|
453
|
-
* 把**存档里前 `PANO_IMPORT_PRIORITY`
|
|
409
|
+
* 把**存档里前 `PANO_IMPORT_PRIORITY` 个全景**按存档顺序登记进拼合器的**加载任务队列**
|
|
410
|
+
*(2026-10-29 需求「优先加载前 2 个全景素材」+ 2026-10-30 需求逐字:「给 mktmesh 内部加一个加载任务队列,
|
|
411
|
+
* 把模型和平面图排在最前面,然后按照顺序,依次把前 2 个全景的顺序把瓦片加载任务添加到任务队列里面,
|
|
412
|
+
* 第一个加载完了,就把这个加载任务从任务队列里面去掉,然后加载第二个;
|
|
413
|
+
* 如果后续再按照距离计算需要加载哪个全景的时候,同样地添加到加载任务队列的后面等待加载」)。
|
|
454
414
|
* 由两处渲染循环每帧点一次:基类 `onBeforeRender`(预览弹窗 / 发布页)与编辑器的 `updateFloorTexture`
|
|
455
415
|
*(`MktDevMesh` 覆写了 `onBeforeRender`,只点 `syncProjInvMatrix` + `tickProgressiveReveal`,库内那句在编辑态不跑)。
|
|
456
416
|
*
|
|
457
|
-
*
|
|
458
|
-
*
|
|
459
|
-
*
|
|
460
|
-
*
|
|
461
|
-
*
|
|
462
|
-
*
|
|
463
|
-
*
|
|
464
|
-
*
|
|
465
|
-
*
|
|
466
|
-
*
|
|
467
|
-
*
|
|
468
|
-
*
|
|
469
|
-
*
|
|
470
|
-
* ⚠️
|
|
471
|
-
*
|
|
472
|
-
*
|
|
473
|
-
*
|
|
474
|
-
*
|
|
417
|
+
* 队列怎么排(`panoTileStitcher` 的 `_queue`,一处排队一张尺):
|
|
418
|
+
* ① **模型与平面图天然在最前面** —— 这两族的下载不在拼合器里,`importData` 当场同步发起
|
|
419
|
+
* (GLB 逐只 `loadModel` 不 throttle;平面那 4 片一次性 `_imgTileLoader.preload`),
|
|
420
|
+
* 而全景瓦片最早也要等下一帧的 `pump` 才发第一片 ⇒ 发起次序天然是「模型 → 平面图 → 全景」,
|
|
421
|
+
* ⛔ 这里不再把它们塞进队列重复管一遍(塞了就是第二把尺)。
|
|
422
|
+
* ② 本方法把存档 0 号、1 号依次 `prioritize` 进队列 ⇒ 拼合器每帧**只喂队首那一组**,
|
|
423
|
+
* 0 号 32 格全落定(画进 RT,或该格本就缺地址/判死)才出队、1 号才开始发第一片。
|
|
424
|
+
* 比 10-29 那版(只是把两批挪到在册顺序前面、额度仍被两批分摊)更硬:**第 1 颗独享额度,最快出全图**。
|
|
425
|
+
* ③ 名册按距离点到的其他全景走 `feedFaceMapping` 里那句 `ensure(t.tiles)`(不带队列)⇒ 只入册、
|
|
426
|
+
* 排在队列后面等,队列空了才按在册顺序补料(现行口径不变)。
|
|
427
|
+
* ⚠️⚠️ 为什么每帧点而⛔ 只在 `importData` 里点一记:预览每开一次都换渲染器,`_switchRenderer` 把在册组
|
|
428
|
+
* 整份作废(队列里的键也在同一刻失效);只在载入那次点名等于白点。本方法点在 `pump` 之后、名册逐槽
|
|
429
|
+
* `ensure` 之前 ⇒ 每帧把这两记任务补回队列头部(`prioritize` 幂等,已在队列里就不挪,所以 0 号恒在 1 号前)。
|
|
430
|
+
* ⚠️ 代价如实记:
|
|
431
|
+
* · 队列非空时**其他全景一片都不发** ⇒ 开机那几秒里,离注视点最近、但不在存档前两颗的那面墙会多灰一会儿。
|
|
432
|
+
* · 一颗「永远下不完」的瓦片(下载失败还没累计到判死)会压住队列;判死阈值是解码失败 3 次
|
|
433
|
+
* (`_dead`),退避重试期间队首不落定 ⇒ 第 2 颗跟着延后。真实数据里缺片是「地址为空/404」,
|
|
434
|
+
* 404 走三次即判死、那一格拼合涂灰 ⇒ 队列照样出清。
|
|
435
|
+
* · 这两颗全景若本来不在开机那一刻的名册里,它们的瓦片与拼合槽 RT 会被**提前**建出来
|
|
436
|
+
* (现行口径每颗全景 2 槽 × 6144² ≈ 384MB 显存)—— 组在运行中不淘汰,走进这两个景点迟早要建。
|
|
475
437
|
* ⚠️ 形态判据读 `this._panoTexMode`(整图形态那一档一张全景只有一张整图,走 `_texCache` 那条路,
|
|
476
438
|
* 走错档就是白下 32 片)⇒ 宿主若用自己那份形态变量(编辑器的 `store.panoTexMode`),
|
|
477
439
|
* 要在调 `importData` 之前先 `setPanoTexMode` 推进来,编辑器那侧已按此接线。
|
|
478
|
-
* ⚠️ 代价如实记:这两颗全景若本来不在开机那一刻的名册里,它们的瓦片与拼合槽 RT 会被**提前**建出来
|
|
479
|
-
* (现行口径每颗全景 2 槽 × 6144² ≈ 400MB 显存)—— 组在运行中不淘汰,走进那两个景点迟早要建,
|
|
480
|
-
* 这里只是把这一笔挪到了载入的第一帧。
|
|
481
440
|
*/
|
|
482
441
|
prefetchHeadPanoramas(): void;
|
|
483
442
|
/** 释放 GPU 资源:瓦片缓存(**只有这里**清,2026-10-02 决定)、拼合器、平面图 / 模型 / 玻璃面三层、几何、材质 */
|
package/MktMesh/MktMesh.js
CHANGED
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
* 说明:所有实例共享同一份 material(单一 panorama uniform),
|
|
24
24
|
* 同一时刻只激活名册 0 号槽(中心)那一个纹理(全局共享单激活方案)。
|
|
25
25
|
*/
|
|
26
|
-
import { BufferGeometry, BackSide,
|
|
26
|
+
import { BufferGeometry, BackSide, Float32BufferAttribute, Matrix4, Mesh, Shape, ShapeGeometry, SRGBColorSpace, Vector3, Vector4, } from "three";
|
|
27
27
|
import { createPlaceholderTexture, isPanoTexMode, mktPanoTiledFlag, mktPanoTexUrls, isRtStitchKey, rtStitchKeyParts, RT_STITCH_KEY_PREFIX, RT_STITCH_SLOT_COUNT } from "./mktShader";
|
|
28
28
|
import { MKT_PANO_MAX_SLOTS } from "./mktMappingShader";
|
|
29
29
|
import { createMktFloorMappingShaderMaterial } from "./mktMappingShader";
|
|
@@ -51,9 +51,6 @@ import { stripAssetHost, absAssetUrl } from "./assetUrl";
|
|
|
51
51
|
import { ImagePlane } from "./imagePlane";
|
|
52
52
|
import { ModelSlot } from "./modelSlot";
|
|
53
53
|
import { ImagePlaneTileLoader } from "./imageTileLoader";
|
|
54
|
-
// ⭐ 2026-10-28 需求「正方的面 + 双面 + 反射用第一个全景 + 进 json 回显」:第三层,形状与上面两层同口径
|
|
55
|
-
// (挂在本网格子树、随展品一起走;数据由自己的 `toData/applyData` 逐字存)。
|
|
56
|
-
import { GlassPane } from "./glassPane";
|
|
57
54
|
/** 载入 JSON 时**优先**加载几个全景的素材(2026-10-29 需求「优先加载前 2 个全景图的素材,然后再加载其他的」)。
|
|
58
55
|
* 口径 = 存档 `textures` 数组的前 n 项;其余全景照常按每帧的槽位名册(离注视点最近 8 个)排队,只是排在它们后面。 */
|
|
59
56
|
const PANO_IMPORT_PRIORITY = 2;
|
|
@@ -191,23 +188,6 @@ export default class MktMesh extends Mesh {
|
|
|
191
188
|
imagePlanes = [];
|
|
192
189
|
/** 模型槽层(同一棵子树,口径同上) */
|
|
193
190
|
models = [];
|
|
194
|
-
/**
|
|
195
|
-
* 玻璃面层(⭐ 2026-10-28 需求「正方的面」):同一棵子树,口径与上面两层一致。
|
|
196
|
-
* 与那两层的区别只在材质(MeshPhysicalMaterial + transmission + DoubleSide,见 `./glassPane.ts`)
|
|
197
|
-
* ⇒ 它**没有自己的内容纹理**,反射源共用下面那一张 `_glassEnvTex`。
|
|
198
|
-
*/
|
|
199
|
-
glassPanes = [];
|
|
200
|
-
/**
|
|
201
|
-
* 玻璃面反射环境的**源地址** = 第一个全景的整图地址(`textures[0].url`),空串 = 还没有全景可用。
|
|
202
|
-
* ⚠️ 这里存的是**未拼尺寸参数的原始地址**(与 `_texCache` 的键同一口径)⇒ 全景换了地址才发现要重载;
|
|
203
|
-
* 下载时按当前 `_ossSize` 档过 `resolveOssUrl`(默认为 1024 那一档)。PMREM 卷积输出的分辨率上限远小于 1024
|
|
204
|
-
* ⇒ 反射精度由那一步决定,用缩放副本不降低观感,换来的是省掉整张原图(实测 11904×5952 ≈ 283MB)的解码内存。
|
|
205
|
-
* ⚠️ 为什么不用「第一个全景那两张拼合槽 RT」:每张 RT 装的是原图**左/右半幅**且压成 1:1 方图,
|
|
206
|
-
* 当等距柱状环境采会横向拉伸一倍 + 缺半边;且它的 mapping 是 UVMapping,three 不会替它做 PMREM ⇒ 采出花屏。
|
|
207
|
-
*/
|
|
208
|
-
_glassEnvKey = "";
|
|
209
|
-
/** 已就绪的反射环境纹理(null = 未就绪 / 没有全景);同一张共用给所有玻璃面 ⇒ 只下载、只卷积一次 */
|
|
210
|
-
_glassEnvTex = null;
|
|
211
191
|
/**
|
|
212
192
|
* 那 4 张瓦片的下载/解码缓存。⭐ 与全景 `_texCache` 同一条旨(10-02「纹理都缓存在对象里面,执行 dispose 时才销毁」)
|
|
213
193
|
* ⇒ 切工程**不**清它,回来那一圈直接命中缓存、不会再空一格;只随本对象 `dispose()` 释放。
|
|
@@ -1211,91 +1191,6 @@ export default class MktMesh extends Mesh {
|
|
|
1211
1191
|
if (ms.mountStaged() && onEachLoad)
|
|
1212
1192
|
onEachLoad();
|
|
1213
1193
|
}
|
|
1214
|
-
// ───────────── 玻璃面层(⭐ 2026-10-28 需求「正方的面:双面 + 反射用第一个全景 + 进 json 回显」) ─────────────
|
|
1215
|
-
/** 单颗玻璃面入层(编辑态双击落点用):进数组 + 挂进本对象子树 + 先吃当前反射源,再确认源在下路没有 */
|
|
1216
|
-
addGlassPane(gp) {
|
|
1217
|
-
this.glassPanes.push(gp);
|
|
1218
|
-
this.add(gp);
|
|
1219
|
-
gp.setEnvironmentTexture(this._glassEnvTex);
|
|
1220
|
-
this.syncGlassEnvironment();
|
|
1221
|
-
return gp;
|
|
1222
|
-
}
|
|
1223
|
-
/** 摘掉一颗并释放它的几何/材质;反射纹理是共用那张 ⇒ 最后一颗也摘掉时才由 `syncGlassEnvironment` 收(按源地址记账,⛔ 不在这里直接 dispose) */
|
|
1224
|
-
removeGlassPane(gp) {
|
|
1225
|
-
const i = this.glassPanes.indexOf(gp);
|
|
1226
|
-
if (i >= 0)
|
|
1227
|
-
this.glassPanes.splice(i, 1);
|
|
1228
|
-
this.remove(gp);
|
|
1229
|
-
gp.dispose();
|
|
1230
|
-
this.syncGlassEnvironment();
|
|
1231
|
-
}
|
|
1232
|
-
/**
|
|
1233
|
-
* 整层重建玻璃面(`importData` 与预览那一路)。玻璃面不引用任何素材文件 ⇒ ⛔ 不过 `absAssetUrl`
|
|
1234
|
-
* (地址只有反射源那一处,而它取的是**本对象内存里**的 `textures[0].url`,已经是补过域名的形态)。
|
|
1235
|
-
*/
|
|
1236
|
-
setGlassPanes(datas) {
|
|
1237
|
-
for (const gp of this.glassPanes) {
|
|
1238
|
-
this.remove(gp);
|
|
1239
|
-
gp.dispose();
|
|
1240
|
-
}
|
|
1241
|
-
this.glassPanes = [];
|
|
1242
|
-
for (const d of datas) {
|
|
1243
|
-
const gp = new GlassPane(d.name);
|
|
1244
|
-
gp.applyData(d);
|
|
1245
|
-
this.glassPanes.push(gp);
|
|
1246
|
-
this.add(gp);
|
|
1247
|
-
}
|
|
1248
|
-
this.syncGlassEnvironment();
|
|
1249
|
-
}
|
|
1250
|
-
/**
|
|
1251
|
-
* 把「第一个全景」的整图当成玻璃面的反射环境(2026-10-28 需求)。
|
|
1252
|
-
*
|
|
1253
|
-
* 判据 = 源地址变了没有(⛔ 不按下标记:删掉 0 号景点后原 1 号自动顶上来,那时地址会变 ⇒ 自愈)。
|
|
1254
|
-
* 调用点只有四处,⛔ 不进 `onBeforeRender` 自驱:① 单颗入层 ② 单颗摘除 ③ 整层重建 ④ 编辑态每帧 tick 里与
|
|
1255
|
-
* `feedImagePlaneTiles()` 并排那一句(源地址没变就一句比较直接返回 ⇒ 无玻璃面的场景零成本,
|
|
1256
|
-
* 而全景被增删/换图那些路都不必各自记得再来点一次)。
|
|
1257
|
-
*
|
|
1258
|
-
* ⚠️ 换源那一步必须**先摘后放**:材质还指着这张、位图却已 `close()` ⇒ 采出来是空图。
|
|
1259
|
-
* ⚠️ 下载走 `loadPanoTexture`(解码在工作线程)并自动向 `DefaultLoadingManager` 记账 ⇒ 预览弹窗那个
|
|
1260
|
-
* 加载进度条能看见它,与全景瓦片同一本账。
|
|
1261
|
-
* ⚠️ 结果只存进 `_glassEnvTex`,⛔ 不进 `_texCache`:那张表在 `setOssSize` 换档时会被整批 dispose
|
|
1262
|
-
* (`_reloadActiveTexture`),而正在被材质引用的这张不能被那样顺手清掉。
|
|
1263
|
-
*/
|
|
1264
|
-
syncGlassEnvironment() {
|
|
1265
|
-
// 没有玻璃面 ⇒ 源地址按「空」算:下面那一段照常走换源流程,把共用那张位图关干净(⛔ 不让它悬着)
|
|
1266
|
-
const key = this.glassPanes.length === 0 ? "" : (this.textures[0]?.url ?? "");
|
|
1267
|
-
if (key === this._glassEnvKey)
|
|
1268
|
-
return;
|
|
1269
|
-
this._glassEnvKey = key;
|
|
1270
|
-
if (this._glassEnvTex) {
|
|
1271
|
-
this._applyGlassEnv(null);
|
|
1272
|
-
releasePanoTexture(this._glassEnvTex);
|
|
1273
|
-
this._glassEnvTex = null;
|
|
1274
|
-
}
|
|
1275
|
-
if (!key)
|
|
1276
|
-
return;
|
|
1277
|
-
loadPanoTexture(this.resolveOssUrl(key, false)).then((tex) => {
|
|
1278
|
-
// 这一张到货时源可能已被后来的换源(切项目 / 换全景)顶掉 ⇒ 就地释放,⛔ 不许写回材质
|
|
1279
|
-
if (this._glassEnvKey !== key) {
|
|
1280
|
-
releasePanoTexture(tex);
|
|
1281
|
-
return;
|
|
1282
|
-
}
|
|
1283
|
-
tex.colorSpace = SRGBColorSpace;
|
|
1284
|
-
// three 的 `WebGLCubeUVMaps` 只对这个标记才自动 PMREM 卷积(示例也是把等距柱状图直接挂 material.envMap)
|
|
1285
|
-
tex.mapping = EquirectangularReflectionMapping;
|
|
1286
|
-
this._glassEnvTex = tex;
|
|
1287
|
-
this._applyGlassEnv(tex);
|
|
1288
|
-
}, () => {
|
|
1289
|
-
// 单次失败:清掉记账 ⇒ 下一次有人调本方法(新增/重建玻璃面、编辑态 tick)自然重试,
|
|
1290
|
-
// 与全景瓦片那条「失败后下一帧同键再试」同口径,只是这里由调用点驱动而非每帧驱动。
|
|
1291
|
-
this._glassEnvKey = "";
|
|
1292
|
-
});
|
|
1293
|
-
}
|
|
1294
|
-
/** 把同一张反射源发给每一颗玻璃面(`GlassPane` 内部按对象判等 ⇒ 重复发同一张不会重编译)。 */
|
|
1295
|
-
_applyGlassEnv(tex) {
|
|
1296
|
-
for (const gp of this.glassPanes)
|
|
1297
|
-
gp.setEnvironmentTexture(tex);
|
|
1298
|
-
}
|
|
1299
1194
|
/**
|
|
1300
1195
|
* 把各颗平面那 4 张瓦片的纹理绑进材质(10-22 晚定的口径:不走拼合器 RT)。
|
|
1301
1196
|
* 2026-10-26 决定改成**逐帧**:一次把整层地址全丢给下载器(下载/解码在网络与工作线程侧,不占这一帧),
|
|
@@ -1417,9 +1312,6 @@ export default class MktMesh extends Mesh {
|
|
|
1417
1312
|
const d = ms.toData();
|
|
1418
1313
|
return { ...d, url: d.url ? stripAssetHost(d.url, pn) : "" };
|
|
1419
1314
|
}),
|
|
1420
|
-
// 玻璃面层(2026-10-28 需求):只有位置/旋转/边长,⛔ 不过 `stripAssetHost` —— 它不引用任何素材,
|
|
1421
|
-
// 反射源是运行时从 `textures[0].url` 取的(上面那个键自己就落进存档了)。
|
|
1422
|
-
glass: this.glassPanes.map((gp) => gp.toData()),
|
|
1423
1315
|
};
|
|
1424
1316
|
}
|
|
1425
1317
|
/** 导入数据:重建墙体几何与纹理列表,并激活第一个纹理
|
|
@@ -1475,51 +1367,48 @@ export default class MktMesh extends Mesh {
|
|
|
1475
1367
|
tiles: (d.tiles ?? []).map((u) => absAssetUrl(u, pn)),
|
|
1476
1368
|
})));
|
|
1477
1369
|
this.setModels((data.models ?? []).map((d) => ({ ...d, url: d.url ? absAssetUrl(d.url, pn) : "" })), onModelLoad);
|
|
1478
|
-
// 玻璃面层(2026-10-28 需求):排在 setTextures **之后**是硬要求 —— 它的反射源读的就是刚还原好的
|
|
1479
|
-
// `textures[0].url`(补过域名的形态),排在前面会用上一次项目的地址起一次错的载。
|
|
1480
|
-
// 旧存档没有这个键 ⇒ 空数组 = 整层清空,与上面两层的口径逐字一致。
|
|
1481
|
-
this.setGlassPanes(data.glass ?? []);
|
|
1482
1370
|
}
|
|
1483
1371
|
/**
|
|
1484
|
-
* 把**存档里前 `PANO_IMPORT_PRIORITY`
|
|
1372
|
+
* 把**存档里前 `PANO_IMPORT_PRIORITY` 个全景**按存档顺序登记进拼合器的**加载任务队列**
|
|
1373
|
+
*(2026-10-29 需求「优先加载前 2 个全景素材」+ 2026-10-30 需求逐字:「给 mktmesh 内部加一个加载任务队列,
|
|
1374
|
+
* 把模型和平面图排在最前面,然后按照顺序,依次把前 2 个全景的顺序把瓦片加载任务添加到任务队列里面,
|
|
1375
|
+
* 第一个加载完了,就把这个加载任务从任务队列里面去掉,然后加载第二个;
|
|
1376
|
+
* 如果后续再按照距离计算需要加载哪个全景的时候,同样地添加到加载任务队列的后面等待加载」)。
|
|
1485
1377
|
* 由两处渲染循环每帧点一次:基类 `onBeforeRender`(预览弹窗 / 发布页)与编辑器的 `updateFloorTexture`
|
|
1486
1378
|
*(`MktDevMesh` 覆写了 `onBeforeRender`,只点 `syncProjInvMatrix` + `tickProgressiveReveal`,库内那句在编辑态不跑)。
|
|
1487
1379
|
*
|
|
1488
|
-
*
|
|
1489
|
-
*
|
|
1490
|
-
*
|
|
1491
|
-
*
|
|
1492
|
-
*
|
|
1493
|
-
*
|
|
1494
|
-
*
|
|
1495
|
-
*
|
|
1496
|
-
*
|
|
1497
|
-
*
|
|
1498
|
-
*
|
|
1499
|
-
*
|
|
1500
|
-
*
|
|
1501
|
-
* ⚠️
|
|
1502
|
-
*
|
|
1503
|
-
*
|
|
1504
|
-
*
|
|
1505
|
-
*
|
|
1380
|
+
* 队列怎么排(`panoTileStitcher` 的 `_queue`,一处排队一张尺):
|
|
1381
|
+
* ① **模型与平面图天然在最前面** —— 这两族的下载不在拼合器里,`importData` 当场同步发起
|
|
1382
|
+
* (GLB 逐只 `loadModel` 不 throttle;平面那 4 片一次性 `_imgTileLoader.preload`),
|
|
1383
|
+
* 而全景瓦片最早也要等下一帧的 `pump` 才发第一片 ⇒ 发起次序天然是「模型 → 平面图 → 全景」,
|
|
1384
|
+
* ⛔ 这里不再把它们塞进队列重复管一遍(塞了就是第二把尺)。
|
|
1385
|
+
* ② 本方法把存档 0 号、1 号依次 `prioritize` 进队列 ⇒ 拼合器每帧**只喂队首那一组**,
|
|
1386
|
+
* 0 号 32 格全落定(画进 RT,或该格本就缺地址/判死)才出队、1 号才开始发第一片。
|
|
1387
|
+
* 比 10-29 那版(只是把两批挪到在册顺序前面、额度仍被两批分摊)更硬:**第 1 颗独享额度,最快出全图**。
|
|
1388
|
+
* ③ 名册按距离点到的其他全景走 `feedFaceMapping` 里那句 `ensure(t.tiles)`(不带队列)⇒ 只入册、
|
|
1389
|
+
* 排在队列后面等,队列空了才按在册顺序补料(现行口径不变)。
|
|
1390
|
+
* ⚠️⚠️ 为什么每帧点而⛔ 只在 `importData` 里点一记:预览每开一次都换渲染器,`_switchRenderer` 把在册组
|
|
1391
|
+
* 整份作废(队列里的键也在同一刻失效);只在载入那次点名等于白点。本方法点在 `pump` 之后、名册逐槽
|
|
1392
|
+
* `ensure` 之前 ⇒ 每帧把这两记任务补回队列头部(`prioritize` 幂等,已在队列里就不挪,所以 0 号恒在 1 号前)。
|
|
1393
|
+
* ⚠️ 代价如实记:
|
|
1394
|
+
* · 队列非空时**其他全景一片都不发** ⇒ 开机那几秒里,离注视点最近、但不在存档前两颗的那面墙会多灰一会儿。
|
|
1395
|
+
* · 一颗「永远下不完」的瓦片(下载失败还没累计到判死)会压住队列;判死阈值是解码失败 3 次
|
|
1396
|
+
* (`_dead`),退避重试期间队首不落定 ⇒ 第 2 颗跟着延后。真实数据里缺片是「地址为空/404」,
|
|
1397
|
+
* 404 走三次即判死、那一格拼合涂灰 ⇒ 队列照样出清。
|
|
1398
|
+
* · 这两颗全景若本来不在开机那一刻的名册里,它们的瓦片与拼合槽 RT 会被**提前**建出来
|
|
1399
|
+
* (现行口径每颗全景 2 槽 × 6144² ≈ 384MB 显存)—— 组在运行中不淘汰,走进这两个景点迟早要建。
|
|
1506
1400
|
* ⚠️ 形态判据读 `this._panoTexMode`(整图形态那一档一张全景只有一张整图,走 `_texCache` 那条路,
|
|
1507
1401
|
* 走错档就是白下 32 片)⇒ 宿主若用自己那份形态变量(编辑器的 `store.panoTexMode`),
|
|
1508
1402
|
* 要在调 `importData` 之前先 `setPanoTexMode` 推进来,编辑器那侧已按此接线。
|
|
1509
|
-
* ⚠️ 代价如实记:这两颗全景若本来不在开机那一刻的名册里,它们的瓦片与拼合槽 RT 会被**提前**建出来
|
|
1510
|
-
* (现行口径每颗全景 2 槽 × 6144² ≈ 400MB 显存)—— 组在运行中不淘汰,走进那两个景点迟早要建,
|
|
1511
|
-
* 这里只是把这一笔挪到了载入的第一帧。
|
|
1512
1403
|
*/
|
|
1513
1404
|
prefetchHeadPanoramas() {
|
|
1514
1405
|
const n = Math.min(PANO_IMPORT_PRIORITY, this.textures.length);
|
|
1515
|
-
//
|
|
1516
|
-
|
|
1517
|
-
for (let i = n - 1; i >= 0; i--) {
|
|
1406
|
+
// 正着点:0 号先入队 ⇒ 队首是它,落定后才轮到 1 号(`prioritize` 对已在队列里的键不挪位置)
|
|
1407
|
+
for (let i = 0; i < n; i++) {
|
|
1518
1408
|
const info = this.textures[i];
|
|
1519
1409
|
// 与 `feedFaceMapping` 里那一句同判据:真瓦片才进拼合器,整图形态进瓦片缓存
|
|
1520
|
-
// 第三个参 `true` = 把这批**挪到在册顺序最前**(⛔ 光靠「先入册」押不住顺序,见方法头)
|
|
1521
1410
|
if (mktPanoTiledFlag(info.tiles, this._panoTexMode) === 1)
|
|
1522
|
-
this._stitcher.
|
|
1411
|
+
this._stitcher.prioritize(info.tiles);
|
|
1523
1412
|
else if (info.url)
|
|
1524
1413
|
this.ensureTileTexture(info.url, false);
|
|
1525
1414
|
}
|
|
@@ -1548,16 +1437,6 @@ export default class MktMesh extends Mesh {
|
|
|
1548
1437
|
ms.dispose();
|
|
1549
1438
|
}
|
|
1550
1439
|
this.models = [];
|
|
1551
|
-
// 玻璃面层:几何/材质各归各颗释放;那张共用的反射纹理在这里连位图一起关
|
|
1552
|
-
// (⛔ 它从不在 `_texCache` 里 ⇒ 上面那一轮清不到它,漏了这一句就是每次换页漏一张全景整图)。
|
|
1553
|
-
for (const gp of this.glassPanes) {
|
|
1554
|
-
this.remove(gp);
|
|
1555
|
-
gp.dispose();
|
|
1556
|
-
}
|
|
1557
|
-
this.glassPanes = [];
|
|
1558
|
-
releasePanoTexture(this._glassEnvTex);
|
|
1559
|
-
this._glassEnvTex = null;
|
|
1560
|
-
this._glassEnvKey = "";
|
|
1561
1440
|
this._imgTileLoader.clear();
|
|
1562
1441
|
this._imgBindQueued.clear();
|
|
1563
1442
|
this._imgBindDone.clear();
|
package/MktMesh/MktMesh.ts
CHANGED
|
@@ -28,7 +28,6 @@ import {
|
|
|
28
28
|
BufferGeometry,
|
|
29
29
|
Camera,
|
|
30
30
|
BackSide,
|
|
31
|
-
EquirectangularReflectionMapping,
|
|
32
31
|
Float32BufferAttribute,
|
|
33
32
|
Material,
|
|
34
33
|
Matrix4,
|
|
@@ -72,9 +71,6 @@ import { stripAssetHost, absAssetUrl } from "./assetUrl";
|
|
|
72
71
|
import { ImagePlane, type ImagePlaneData } from "./imagePlane";
|
|
73
72
|
import { ModelSlot, type ModelSlotData } from "./modelSlot";
|
|
74
73
|
import { ImagePlaneTileLoader } from "./imageTileLoader";
|
|
75
|
-
// ⭐ 2026-10-28 需求「正方的面 + 双面 + 反射用第一个全景 + 进 json 回显」:第三层,形状与上面两层同口径
|
|
76
|
-
// (挂在本网格子树、随展品一起走;数据由自己的 `toData/applyData` 逐字存)。
|
|
77
|
-
import { GlassPane, type GlassPaneData } from "./glassPane";
|
|
78
74
|
|
|
79
75
|
/** 载入 JSON 时**优先**加载几个全景的素材(2026-10-29 需求「优先加载前 2 个全景图的素材,然后再加载其他的」)。
|
|
80
76
|
* 口径 = 存档 `textures` 数组的前 n 项;其余全景照常按每帧的槽位名册(离注视点最近 8 个)排队,只是排在它们后面。 */
|
|
@@ -219,23 +215,6 @@ export default class MktMesh extends Mesh<BufferGeometry, ShaderMaterial> {
|
|
|
219
215
|
imagePlanes: ImagePlane[] = [];
|
|
220
216
|
/** 模型槽层(同一棵子树,口径同上) */
|
|
221
217
|
models: ModelSlot[] = [];
|
|
222
|
-
/**
|
|
223
|
-
* 玻璃面层(⭐ 2026-10-28 需求「正方的面」):同一棵子树,口径与上面两层一致。
|
|
224
|
-
* 与那两层的区别只在材质(MeshPhysicalMaterial + transmission + DoubleSide,见 `./glassPane.ts`)
|
|
225
|
-
* ⇒ 它**没有自己的内容纹理**,反射源共用下面那一张 `_glassEnvTex`。
|
|
226
|
-
*/
|
|
227
|
-
glassPanes: GlassPane[] = [];
|
|
228
|
-
/**
|
|
229
|
-
* 玻璃面反射环境的**源地址** = 第一个全景的整图地址(`textures[0].url`),空串 = 还没有全景可用。
|
|
230
|
-
* ⚠️ 这里存的是**未拼尺寸参数的原始地址**(与 `_texCache` 的键同一口径)⇒ 全景换了地址才发现要重载;
|
|
231
|
-
* 下载时按当前 `_ossSize` 档过 `resolveOssUrl`(默认为 1024 那一档)。PMREM 卷积输出的分辨率上限远小于 1024
|
|
232
|
-
* ⇒ 反射精度由那一步决定,用缩放副本不降低观感,换来的是省掉整张原图(实测 11904×5952 ≈ 283MB)的解码内存。
|
|
233
|
-
* ⚠️ 为什么不用「第一个全景那两张拼合槽 RT」:每张 RT 装的是原图**左/右半幅**且压成 1:1 方图,
|
|
234
|
-
* 当等距柱状环境采会横向拉伸一倍 + 缺半边;且它的 mapping 是 UVMapping,three 不会替它做 PMREM ⇒ 采出花屏。
|
|
235
|
-
*/
|
|
236
|
-
private _glassEnvKey: string = "";
|
|
237
|
-
/** 已就绪的反射环境纹理(null = 未就绪 / 没有全景);同一张共用给所有玻璃面 ⇒ 只下载、只卷积一次 */
|
|
238
|
-
private _glassEnvTex: Texture | null = null;
|
|
239
218
|
/**
|
|
240
219
|
* 那 4 张瓦片的下载/解码缓存。⭐ 与全景 `_texCache` 同一条旨(10-02「纹理都缓存在对象里面,执行 dispose 时才销毁」)
|
|
241
220
|
* ⇒ 切工程**不**清它,回来那一圈直接命中缓存、不会再空一格;只随本对象 `dispose()` 释放。
|
|
@@ -1247,96 +1226,6 @@ export default class MktMesh extends Mesh<BufferGeometry, ShaderMaterial> {
|
|
|
1247
1226
|
if (ms.mountStaged() && onEachLoad) onEachLoad();
|
|
1248
1227
|
}
|
|
1249
1228
|
|
|
1250
|
-
// ───────────── 玻璃面层(⭐ 2026-10-28 需求「正方的面:双面 + 反射用第一个全景 + 进 json 回显」) ─────────────
|
|
1251
|
-
|
|
1252
|
-
/** 单颗玻璃面入层(编辑态双击落点用):进数组 + 挂进本对象子树 + 先吃当前反射源,再确认源在下路没有 */
|
|
1253
|
-
addGlassPane(gp: GlassPane): GlassPane {
|
|
1254
|
-
this.glassPanes.push(gp);
|
|
1255
|
-
this.add(gp);
|
|
1256
|
-
gp.setEnvironmentTexture(this._glassEnvTex);
|
|
1257
|
-
this.syncGlassEnvironment();
|
|
1258
|
-
return gp;
|
|
1259
|
-
}
|
|
1260
|
-
|
|
1261
|
-
/** 摘掉一颗并释放它的几何/材质;反射纹理是共用那张 ⇒ 最后一颗也摘掉时才由 `syncGlassEnvironment` 收(按源地址记账,⛔ 不在这里直接 dispose) */
|
|
1262
|
-
removeGlassPane(gp: GlassPane): void {
|
|
1263
|
-
const i = this.glassPanes.indexOf(gp);
|
|
1264
|
-
if (i >= 0) this.glassPanes.splice(i, 1);
|
|
1265
|
-
this.remove(gp);
|
|
1266
|
-
gp.dispose();
|
|
1267
|
-
this.syncGlassEnvironment();
|
|
1268
|
-
}
|
|
1269
|
-
|
|
1270
|
-
/**
|
|
1271
|
-
* 整层重建玻璃面(`importData` 与预览那一路)。玻璃面不引用任何素材文件 ⇒ ⛔ 不过 `absAssetUrl`
|
|
1272
|
-
* (地址只有反射源那一处,而它取的是**本对象内存里**的 `textures[0].url`,已经是补过域名的形态)。
|
|
1273
|
-
*/
|
|
1274
|
-
setGlassPanes(datas: GlassPaneData[]): void {
|
|
1275
|
-
for (const gp of this.glassPanes) {
|
|
1276
|
-
this.remove(gp);
|
|
1277
|
-
gp.dispose();
|
|
1278
|
-
}
|
|
1279
|
-
this.glassPanes = [];
|
|
1280
|
-
for (const d of datas) {
|
|
1281
|
-
const gp = new GlassPane(d.name);
|
|
1282
|
-
gp.applyData(d);
|
|
1283
|
-
this.glassPanes.push(gp);
|
|
1284
|
-
this.add(gp);
|
|
1285
|
-
}
|
|
1286
|
-
this.syncGlassEnvironment();
|
|
1287
|
-
}
|
|
1288
|
-
|
|
1289
|
-
/**
|
|
1290
|
-
* 把「第一个全景」的整图当成玻璃面的反射环境(2026-10-28 需求)。
|
|
1291
|
-
*
|
|
1292
|
-
* 判据 = 源地址变了没有(⛔ 不按下标记:删掉 0 号景点后原 1 号自动顶上来,那时地址会变 ⇒ 自愈)。
|
|
1293
|
-
* 调用点只有四处,⛔ 不进 `onBeforeRender` 自驱:① 单颗入层 ② 单颗摘除 ③ 整层重建 ④ 编辑态每帧 tick 里与
|
|
1294
|
-
* `feedImagePlaneTiles()` 并排那一句(源地址没变就一句比较直接返回 ⇒ 无玻璃面的场景零成本,
|
|
1295
|
-
* 而全景被增删/换图那些路都不必各自记得再来点一次)。
|
|
1296
|
-
*
|
|
1297
|
-
* ⚠️ 换源那一步必须**先摘后放**:材质还指着这张、位图却已 `close()` ⇒ 采出来是空图。
|
|
1298
|
-
* ⚠️ 下载走 `loadPanoTexture`(解码在工作线程)并自动向 `DefaultLoadingManager` 记账 ⇒ 预览弹窗那个
|
|
1299
|
-
* 加载进度条能看见它,与全景瓦片同一本账。
|
|
1300
|
-
* ⚠️ 结果只存进 `_glassEnvTex`,⛔ 不进 `_texCache`:那张表在 `setOssSize` 换档时会被整批 dispose
|
|
1301
|
-
* (`_reloadActiveTexture`),而正在被材质引用的这张不能被那样顺手清掉。
|
|
1302
|
-
*/
|
|
1303
|
-
syncGlassEnvironment(): void {
|
|
1304
|
-
// 没有玻璃面 ⇒ 源地址按「空」算:下面那一段照常走换源流程,把共用那张位图关干净(⛔ 不让它悬着)
|
|
1305
|
-
const key = this.glassPanes.length === 0 ? "" : (this.textures[0]?.url ?? "");
|
|
1306
|
-
if (key === this._glassEnvKey) return;
|
|
1307
|
-
this._glassEnvKey = key;
|
|
1308
|
-
if (this._glassEnvTex) {
|
|
1309
|
-
this._applyGlassEnv(null);
|
|
1310
|
-
releasePanoTexture(this._glassEnvTex);
|
|
1311
|
-
this._glassEnvTex = null;
|
|
1312
|
-
}
|
|
1313
|
-
if (!key) return;
|
|
1314
|
-
loadPanoTexture(this.resolveOssUrl(key, false)).then(
|
|
1315
|
-
(tex) => {
|
|
1316
|
-
// 这一张到货时源可能已被后来的换源(切项目 / 换全景)顶掉 ⇒ 就地释放,⛔ 不许写回材质
|
|
1317
|
-
if (this._glassEnvKey !== key) {
|
|
1318
|
-
releasePanoTexture(tex);
|
|
1319
|
-
return;
|
|
1320
|
-
}
|
|
1321
|
-
tex.colorSpace = SRGBColorSpace;
|
|
1322
|
-
// three 的 `WebGLCubeUVMaps` 只对这个标记才自动 PMREM 卷积(示例也是把等距柱状图直接挂 material.envMap)
|
|
1323
|
-
tex.mapping = EquirectangularReflectionMapping;
|
|
1324
|
-
this._glassEnvTex = tex;
|
|
1325
|
-
this._applyGlassEnv(tex);
|
|
1326
|
-
},
|
|
1327
|
-
() => {
|
|
1328
|
-
// 单次失败:清掉记账 ⇒ 下一次有人调本方法(新增/重建玻璃面、编辑态 tick)自然重试,
|
|
1329
|
-
// 与全景瓦片那条「失败后下一帧同键再试」同口径,只是这里由调用点驱动而非每帧驱动。
|
|
1330
|
-
this._glassEnvKey = "";
|
|
1331
|
-
}
|
|
1332
|
-
);
|
|
1333
|
-
}
|
|
1334
|
-
|
|
1335
|
-
/** 把同一张反射源发给每一颗玻璃面(`GlassPane` 内部按对象判等 ⇒ 重复发同一张不会重编译)。 */
|
|
1336
|
-
private _applyGlassEnv(tex: Texture | null): void {
|
|
1337
|
-
for (const gp of this.glassPanes) gp.setEnvironmentTexture(tex);
|
|
1338
|
-
}
|
|
1339
|
-
|
|
1340
1229
|
/**
|
|
1341
1230
|
* 把各颗平面那 4 张瓦片的纹理绑进材质(10-22 晚定的口径:不走拼合器 RT)。
|
|
1342
1231
|
* 2026-10-26 决定改成**逐帧**:一次把整层地址全丢给下载器(下载/解码在网络与工作线程侧,不占这一帧),
|
|
@@ -1454,9 +1343,6 @@ export default class MktMesh extends Mesh<BufferGeometry, ShaderMaterial> {
|
|
|
1454
1343
|
const d = ms.toData();
|
|
1455
1344
|
return { ...d, url: d.url ? stripAssetHost(d.url, pn) : "" };
|
|
1456
1345
|
}),
|
|
1457
|
-
// 玻璃面层(2026-10-28 需求):只有位置/旋转/边长,⛔ 不过 `stripAssetHost` —— 它不引用任何素材,
|
|
1458
|
-
// 反射源是运行时从 `textures[0].url` 取的(上面那个键自己就落进存档了)。
|
|
1459
|
-
glass: this.glassPanes.map((gp) => gp.toData()),
|
|
1460
1346
|
};
|
|
1461
1347
|
}
|
|
1462
1348
|
|
|
@@ -1519,51 +1405,48 @@ export default class MktMesh extends Mesh<BufferGeometry, ShaderMaterial> {
|
|
|
1519
1405
|
(data.models ?? []).map((d) => ({ ...d, url: d.url ? absAssetUrl(d.url, pn) : "" })),
|
|
1520
1406
|
onModelLoad
|
|
1521
1407
|
);
|
|
1522
|
-
// 玻璃面层(2026-10-28 需求):排在 setTextures **之后**是硬要求 —— 它的反射源读的就是刚还原好的
|
|
1523
|
-
// `textures[0].url`(补过域名的形态),排在前面会用上一次项目的地址起一次错的载。
|
|
1524
|
-
// 旧存档没有这个键 ⇒ 空数组 = 整层清空,与上面两层的口径逐字一致。
|
|
1525
|
-
this.setGlassPanes(data.glass ?? []);
|
|
1526
1408
|
}
|
|
1527
1409
|
|
|
1528
1410
|
/**
|
|
1529
|
-
* 把**存档里前 `PANO_IMPORT_PRIORITY`
|
|
1411
|
+
* 把**存档里前 `PANO_IMPORT_PRIORITY` 个全景**按存档顺序登记进拼合器的**加载任务队列**
|
|
1412
|
+
*(2026-10-29 需求「优先加载前 2 个全景素材」+ 2026-10-30 需求逐字:「给 mktmesh 内部加一个加载任务队列,
|
|
1413
|
+
* 把模型和平面图排在最前面,然后按照顺序,依次把前 2 个全景的顺序把瓦片加载任务添加到任务队列里面,
|
|
1414
|
+
* 第一个加载完了,就把这个加载任务从任务队列里面去掉,然后加载第二个;
|
|
1415
|
+
* 如果后续再按照距离计算需要加载哪个全景的时候,同样地添加到加载任务队列的后面等待加载」)。
|
|
1530
1416
|
* 由两处渲染循环每帧点一次:基类 `onBeforeRender`(预览弹窗 / 发布页)与编辑器的 `updateFloorTexture`
|
|
1531
1417
|
*(`MktDevMesh` 覆写了 `onBeforeRender`,只点 `syncProjInvMatrix` + `tickProgressiveReveal`,库内那句在编辑态不跑)。
|
|
1532
1418
|
*
|
|
1533
|
-
*
|
|
1534
|
-
*
|
|
1535
|
-
*
|
|
1536
|
-
*
|
|
1537
|
-
*
|
|
1538
|
-
*
|
|
1539
|
-
*
|
|
1540
|
-
*
|
|
1541
|
-
*
|
|
1542
|
-
*
|
|
1543
|
-
*
|
|
1544
|
-
*
|
|
1545
|
-
*
|
|
1546
|
-
* ⚠️
|
|
1547
|
-
*
|
|
1548
|
-
*
|
|
1549
|
-
*
|
|
1550
|
-
*
|
|
1419
|
+
* 队列怎么排(`panoTileStitcher` 的 `_queue`,一处排队一张尺):
|
|
1420
|
+
* ① **模型与平面图天然在最前面** —— 这两族的下载不在拼合器里,`importData` 当场同步发起
|
|
1421
|
+
* (GLB 逐只 `loadModel` 不 throttle;平面那 4 片一次性 `_imgTileLoader.preload`),
|
|
1422
|
+
* 而全景瓦片最早也要等下一帧的 `pump` 才发第一片 ⇒ 发起次序天然是「模型 → 平面图 → 全景」,
|
|
1423
|
+
* ⛔ 这里不再把它们塞进队列重复管一遍(塞了就是第二把尺)。
|
|
1424
|
+
* ② 本方法把存档 0 号、1 号依次 `prioritize` 进队列 ⇒ 拼合器每帧**只喂队首那一组**,
|
|
1425
|
+
* 0 号 32 格全落定(画进 RT,或该格本就缺地址/判死)才出队、1 号才开始发第一片。
|
|
1426
|
+
* 比 10-29 那版(只是把两批挪到在册顺序前面、额度仍被两批分摊)更硬:**第 1 颗独享额度,最快出全图**。
|
|
1427
|
+
* ③ 名册按距离点到的其他全景走 `feedFaceMapping` 里那句 `ensure(t.tiles)`(不带队列)⇒ 只入册、
|
|
1428
|
+
* 排在队列后面等,队列空了才按在册顺序补料(现行口径不变)。
|
|
1429
|
+
* ⚠️⚠️ 为什么每帧点而⛔ 只在 `importData` 里点一记:预览每开一次都换渲染器,`_switchRenderer` 把在册组
|
|
1430
|
+
* 整份作废(队列里的键也在同一刻失效);只在载入那次点名等于白点。本方法点在 `pump` 之后、名册逐槽
|
|
1431
|
+
* `ensure` 之前 ⇒ 每帧把这两记任务补回队列头部(`prioritize` 幂等,已在队列里就不挪,所以 0 号恒在 1 号前)。
|
|
1432
|
+
* ⚠️ 代价如实记:
|
|
1433
|
+
* · 队列非空时**其他全景一片都不发** ⇒ 开机那几秒里,离注视点最近、但不在存档前两颗的那面墙会多灰一会儿。
|
|
1434
|
+
* · 一颗「永远下不完」的瓦片(下载失败还没累计到判死)会压住队列;判死阈值是解码失败 3 次
|
|
1435
|
+
* (`_dead`),退避重试期间队首不落定 ⇒ 第 2 颗跟着延后。真实数据里缺片是「地址为空/404」,
|
|
1436
|
+
* 404 走三次即判死、那一格拼合涂灰 ⇒ 队列照样出清。
|
|
1437
|
+
* · 这两颗全景若本来不在开机那一刻的名册里,它们的瓦片与拼合槽 RT 会被**提前**建出来
|
|
1438
|
+
* (现行口径每颗全景 2 槽 × 6144² ≈ 384MB 显存)—— 组在运行中不淘汰,走进这两个景点迟早要建。
|
|
1551
1439
|
* ⚠️ 形态判据读 `this._panoTexMode`(整图形态那一档一张全景只有一张整图,走 `_texCache` 那条路,
|
|
1552
1440
|
* 走错档就是白下 32 片)⇒ 宿主若用自己那份形态变量(编辑器的 `store.panoTexMode`),
|
|
1553
1441
|
* 要在调 `importData` 之前先 `setPanoTexMode` 推进来,编辑器那侧已按此接线。
|
|
1554
|
-
* ⚠️ 代价如实记:这两颗全景若本来不在开机那一刻的名册里,它们的瓦片与拼合槽 RT 会被**提前**建出来
|
|
1555
|
-
* (现行口径每颗全景 2 槽 × 6144² ≈ 400MB 显存)—— 组在运行中不淘汰,走进那两个景点迟早要建,
|
|
1556
|
-
* 这里只是把这一笔挪到了载入的第一帧。
|
|
1557
1442
|
*/
|
|
1558
1443
|
prefetchHeadPanoramas(): void {
|
|
1559
1444
|
const n = Math.min(PANO_IMPORT_PRIORITY, this.textures.length);
|
|
1560
|
-
//
|
|
1561
|
-
|
|
1562
|
-
for (let i = n - 1; i >= 0; i--) {
|
|
1445
|
+
// 正着点:0 号先入队 ⇒ 队首是它,落定后才轮到 1 号(`prioritize` 对已在队列里的键不挪位置)
|
|
1446
|
+
for (let i = 0; i < n; i++) {
|
|
1563
1447
|
const info = this.textures[i];
|
|
1564
1448
|
// 与 `feedFaceMapping` 里那一句同判据:真瓦片才进拼合器,整图形态进瓦片缓存
|
|
1565
|
-
|
|
1566
|
-
if (mktPanoTiledFlag(info.tiles, this._panoTexMode) === 1) this._stitcher.ensure(info.tiles, undefined, true);
|
|
1449
|
+
if (mktPanoTiledFlag(info.tiles, this._panoTexMode) === 1) this._stitcher.prioritize(info.tiles);
|
|
1567
1450
|
else if (info.url) this.ensureTileTexture(info.url, false);
|
|
1568
1451
|
}
|
|
1569
1452
|
}
|
|
@@ -1592,16 +1475,6 @@ export default class MktMesh extends Mesh<BufferGeometry, ShaderMaterial> {
|
|
|
1592
1475
|
ms.dispose();
|
|
1593
1476
|
}
|
|
1594
1477
|
this.models = [];
|
|
1595
|
-
// 玻璃面层:几何/材质各归各颗释放;那张共用的反射纹理在这里连位图一起关
|
|
1596
|
-
// (⛔ 它从不在 `_texCache` 里 ⇒ 上面那一轮清不到它,漏了这一句就是每次换页漏一张全景整图)。
|
|
1597
|
-
for (const gp of this.glassPanes) {
|
|
1598
|
-
this.remove(gp);
|
|
1599
|
-
gp.dispose();
|
|
1600
|
-
}
|
|
1601
|
-
this.glassPanes = [];
|
|
1602
|
-
releasePanoTexture(this._glassEnvTex);
|
|
1603
|
-
this._glassEnvTex = null;
|
|
1604
|
-
this._glassEnvKey = "";
|
|
1605
1478
|
this._imgTileLoader.clear();
|
|
1606
1479
|
this._imgBindQueued.clear();
|
|
1607
1480
|
this._imgBindDone.clear();
|