s3m-three 0.4.20 → 0.4.22
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/dist/browser/s3m-three.iife.ext-three.js +30 -30
- package/dist/browser/s3m-three.iife.js +30 -30
- package/dist/render/DatasetManager.d.ts +20 -1
- package/dist/render/DatasetManager.d.ts.map +1 -1
- package/dist/render/DatasetManager.js +23 -1
- package/dist/render/DatasetManager.js.map +1 -1
- package/dist/render/GeometryBuilder.d.ts +8 -0
- package/dist/render/GeometryBuilder.d.ts.map +1 -1
- package/dist/render/GeometryBuilder.js +25 -0
- package/dist/render/GeometryBuilder.js.map +1 -1
- package/dist/render/S3MViewer.d.ts +23 -6
- package/dist/render/S3MViewer.d.ts.map +1 -1
- package/dist/render/S3MViewer.js +53 -12
- package/dist/render/S3MViewer.js.map +1 -1
- package/dist/render/StyleMaterial.d.ts +13 -1
- package/dist/render/StyleMaterial.d.ts.map +1 -1
- package/dist/render/StyleMaterial.js +26 -4
- package/dist/render/StyleMaterial.js.map +1 -1
- package/dist/render/viewer/types.d.ts +10 -2
- package/dist/render/viewer/types.d.ts.map +1 -1
- package/dist/render/viewer/types.js.map +1 -1
- package/dist/tileset/S3MTileset.d.ts +44 -2
- package/dist/tileset/S3MTileset.d.ts.map +1 -1
- package/dist/tileset/S3MTileset.js +110 -4
- package/dist/tileset/S3MTileset.js.map +1 -1
- package/docs/API.md +11 -30
- package/package.json +1 -1
- package/src/render/DatasetManager.ts +31 -1
- package/src/render/GeometryBuilder.ts +30 -0
- package/src/render/S3MViewer.ts +53 -12
- package/src/render/StyleMaterial.ts +32 -4
- package/src/render/viewer/types.ts +10 -2
- package/src/tileset/S3MTileset.ts +125 -5
|
@@ -233,7 +233,7 @@ export interface TileNode {
|
|
|
233
233
|
/** 该瓦片引用的纹理 key 清单,用于引用计数与显存释放 */
|
|
234
234
|
textureKeys?: string[];
|
|
235
235
|
/** 瓦片构建产生的统计信息,用于淘汰时准确扣减 stats */
|
|
236
|
-
stats?: { meshes: number; vertices: number; triangles: number };
|
|
236
|
+
stats?: { meshes: number; vertices: number; triangles: number; memory?: number };
|
|
237
237
|
}
|
|
238
238
|
|
|
239
239
|
/** 瓦片构建器可注入,用于测试 / 服务端渲染(此时不需要 three) */
|
|
@@ -246,6 +246,8 @@ export type BuildTileFn = (
|
|
|
246
246
|
assembled?: TileGeometryData;
|
|
247
247
|
/** 深度偏移配置(透传给 buildTileObjects),见 BuildTileOptions.polygonOffset */
|
|
248
248
|
polygonOffset?: { factor: number; units: number };
|
|
249
|
+
/** 光照模型档位(透传给 buildTileObjects),见 BuildTileOptions.materialQuality */
|
|
250
|
+
materialQuality?: 'pbr' | 'lambert';
|
|
249
251
|
}
|
|
250
252
|
) => Promise<{ group: Group; stats: Partial<Stats> }>;
|
|
251
253
|
|
|
@@ -258,6 +260,11 @@ export interface S3MTilesetOptions {
|
|
|
258
260
|
buildTile?: BuildTileFn | null;
|
|
259
261
|
/** 三角面材质深度偏移(共面摩尔纹 / 重合面归属),透传给 buildTileObjects */
|
|
260
262
|
polygonOffset?: { factor: number; units: number };
|
|
263
|
+
/**
|
|
264
|
+
* 光照模型档位,透传给 buildTileObjects。不传 = 读模块级默认。
|
|
265
|
+
* 由 DatasetManager 从图层 / 数据集设置带下来。
|
|
266
|
+
*/
|
|
267
|
+
materialQuality?: 'pbr' | 'lambert';
|
|
261
268
|
/**
|
|
262
269
|
* 是否用 Web Worker 解析经典 `.s3mb` 瓦片(默认开)。
|
|
263
270
|
*
|
|
@@ -287,6 +294,14 @@ export interface S3MTilesetOptions {
|
|
|
287
294
|
* 不传 = 不限制,行为与旧版完全一致。运行时可用 `setMaxTriangles()` 调整。
|
|
288
295
|
*/
|
|
289
296
|
maxTriangles?: number;
|
|
297
|
+
/**
|
|
298
|
+
* 本数据集**驻留显存/内存字节数**的软上限(默认不限制)。
|
|
299
|
+
* 包含几何顶点缓冲(精确字节)与纹理显存估计。超限时按同一套 make-before-break
|
|
300
|
+
* 主动淘汰非显示瓦片及其独占纹理。
|
|
301
|
+
*
|
|
302
|
+
* 不传 = 不限制(Infinity),行为与旧版完全一致。运行时可用 `setMaxMemory()` 调整。
|
|
303
|
+
*/
|
|
304
|
+
maxMemory?: number;
|
|
290
305
|
/**
|
|
291
306
|
* 是否请求 `.texblock` 子图集(S3MBLOCK 根图集的清晰版)。**默认关**。
|
|
292
307
|
*
|
|
@@ -315,6 +330,54 @@ export interface S3MTilesetOptions {
|
|
|
315
330
|
unsupported?: UnsupportedPolicy;
|
|
316
331
|
}
|
|
317
332
|
|
|
333
|
+
/** 估算单个纹理占用的显存字节数 */
|
|
334
|
+
export function estimateTextureBytes(tex: any): number {
|
|
335
|
+
if (!tex) return 0;
|
|
336
|
+
if (Array.isArray(tex.mipmaps) && tex.mipmaps.length > 0) {
|
|
337
|
+
let bytes = 0;
|
|
338
|
+
for (const m of tex.mipmaps) {
|
|
339
|
+
if (m?.data?.byteLength) bytes += m.data.byteLength;
|
|
340
|
+
}
|
|
341
|
+
if (bytes > 0) return bytes;
|
|
342
|
+
}
|
|
343
|
+
const img = tex.image;
|
|
344
|
+
if (!img) return 0;
|
|
345
|
+
if (img.data && typeof img.data.byteLength === 'number') {
|
|
346
|
+
return img.data.byteLength;
|
|
347
|
+
}
|
|
348
|
+
const w = img.width ?? 0;
|
|
349
|
+
const h = img.height ?? 0;
|
|
350
|
+
if (w > 0 && h > 0) {
|
|
351
|
+
const factor = tex.generateMipmaps ? 1.3333333333333333 : 1;
|
|
352
|
+
return Math.round(w * h * 4 * factor);
|
|
353
|
+
}
|
|
354
|
+
return 0;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/** 估算三维对象树中包含的几何缓冲字节数 */
|
|
358
|
+
export function estimateObjectGeometryBytes(obj: any): number {
|
|
359
|
+
let bytes = 0;
|
|
360
|
+
if (!obj) return 0;
|
|
361
|
+
obj.traverse?.((child: any) => {
|
|
362
|
+
const geo = child.geometry;
|
|
363
|
+
if (geo) {
|
|
364
|
+
if (geo.attributes) {
|
|
365
|
+
for (const attr of Object.values(geo.attributes) as any[]) {
|
|
366
|
+
if (attr?.array?.byteLength) bytes += attr.array.byteLength;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
if (geo.index?.array?.byteLength) {
|
|
370
|
+
bytes += geo.index.array.byteLength;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
if (child.isInstancedMesh) {
|
|
374
|
+
if (child.instanceMatrix?.array?.byteLength) bytes += child.instanceMatrix.array.byteLength;
|
|
375
|
+
if (child.instanceColor?.array?.byteLength) bytes += child.instanceColor.array.byteLength;
|
|
376
|
+
}
|
|
377
|
+
});
|
|
378
|
+
return bytes;
|
|
379
|
+
}
|
|
380
|
+
|
|
318
381
|
export class S3MTileset {
|
|
319
382
|
configUrl: string;
|
|
320
383
|
config: Record<string, unknown> | null = null;
|
|
@@ -377,6 +440,10 @@ export class S3MTileset {
|
|
|
377
440
|
* 判据与旧版逐字一致,不会多算一次面数。
|
|
378
441
|
*/
|
|
379
442
|
maxTriangles: number;
|
|
443
|
+
/**
|
|
444
|
+
* 驻留显存/内存字节数的软上限。`Infinity` = 不限制(默认)。
|
|
445
|
+
*/
|
|
446
|
+
maxMemory: number;
|
|
380
447
|
lodRangeScale: number;
|
|
381
448
|
|
|
382
449
|
/** 数据集配置声明的高度范围(米),若配置未声明则返回 null */
|
|
@@ -411,6 +478,7 @@ export class S3MTileset {
|
|
|
411
478
|
private isS3MV1 = false;
|
|
412
479
|
private _buildTile: BuildTileFn | null;
|
|
413
480
|
private readonly _polygonOffset: { factor: number; units: number } | undefined;
|
|
481
|
+
private _materialQuality: 'pbr' | 'lambert' | undefined;
|
|
414
482
|
private readonly _uniforms: StyleUniforms | null;
|
|
415
483
|
/** 经典 .s3mb 的 Worker 解析客户端;undefined = 尚未尝试创建,null = 不可用/已降级 */
|
|
416
484
|
private _workerClient: S3MWorkerClient | null | undefined; private readonly _useWorker: boolean;
|
|
@@ -431,6 +499,7 @@ export class S3MTileset {
|
|
|
431
499
|
// 渲染层可注入:Node 环境下不需要 three,也能跑 URL / 解析链路
|
|
432
500
|
this._buildTile = options.buildTile ?? null;
|
|
433
501
|
this._polygonOffset = options.polygonOffset;
|
|
502
|
+
this._materialQuality = options.materialQuality;
|
|
434
503
|
// 着色器共享 uniform,由 S3MLayer 持有并传进来
|
|
435
504
|
this._uniforms = options.uniforms ?? null;
|
|
436
505
|
this._useWorker = options.useWorker !== false;
|
|
@@ -439,6 +508,9 @@ export class S3MTileset {
|
|
|
439
508
|
this.maxConcurrent = options.maxConcurrent ?? 4;
|
|
440
509
|
this.maxTiles = options.maxTiles ?? 64;
|
|
441
510
|
this.maxTriangles = options.maxTriangles ?? Infinity;
|
|
511
|
+
this.maxMemory = Number.isFinite(options.maxMemory) && (options.maxMemory as number) > 0
|
|
512
|
+
? (options.maxMemory as number)
|
|
513
|
+
: Infinity;
|
|
442
514
|
this.maxImageCache = options.maxImageCache ?? 128;
|
|
443
515
|
// 硬上限 = 软上限 + 余量。淘汰只在「新瓦片已经落地并接管显示」之后做(make-before-break),
|
|
444
516
|
// 所以中间态允许临时超出 maxTiles;硬上限只用来挡住失控的请求量,不用于挤掉正在显示的内容。
|
|
@@ -651,14 +723,58 @@ export class S3MTileset {
|
|
|
651
723
|
this.maxTriangles = n > 0 ? n : Infinity;
|
|
652
724
|
}
|
|
653
725
|
|
|
726
|
+
/**
|
|
727
|
+
* 运行时调整显存/内存字节预算。`Infinity` = 不限制(默认)。
|
|
728
|
+
* 收紧后不会立刻掉内容,要等下一次 `_trimBudget`(下一帧 update)才生效。
|
|
729
|
+
*/
|
|
730
|
+
setMaxMemory(bytes: number): void {
|
|
731
|
+
this.maxMemory = Number.isFinite(bytes) && bytes > 0 ? bytes : Infinity;
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
/**
|
|
735
|
+
* 运行时改本数据集的光照模型档位。只影响**之后**构建的瓦片材质;
|
|
736
|
+
* 场上已有材质由 `S3MViewer.setMaterialQuality` 原位重建。
|
|
737
|
+
* `undefined` = 跟随模块级默认。
|
|
738
|
+
*/
|
|
739
|
+
setMaterialQuality(q: 'pbr' | 'lambert' | undefined): void {
|
|
740
|
+
this._materialQuality = q;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
/**
|
|
744
|
+
* 当前数据集驻留的显存与内存总字节数(几何缓冲精确大小 + 纹理显存估计)
|
|
745
|
+
*/
|
|
746
|
+
residentMemory(): number {
|
|
747
|
+
return this._residentGeometryBytes() + this._residentTextureBytes();
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
private _residentGeometryBytes(): number {
|
|
751
|
+
let total = 0;
|
|
752
|
+
for (const node of this.nodes.values()) {
|
|
753
|
+
if (node.stats && typeof node.stats.memory === 'number') {
|
|
754
|
+
total += node.stats.memory;
|
|
755
|
+
} else if (node.group) {
|
|
756
|
+
total += estimateObjectGeometryBytes(node.group);
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
return total;
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
private _residentTextureBytes(): number {
|
|
763
|
+
let total = 0;
|
|
764
|
+
for (const tex of this.textureCache.values()) {
|
|
765
|
+
total += estimateTextureBytes(tex);
|
|
766
|
+
}
|
|
767
|
+
return total;
|
|
768
|
+
}
|
|
769
|
+
|
|
654
770
|
/**
|
|
655
771
|
* 预算裁剪 —— 必须在可见性算完之后调用(make-before-break):
|
|
656
772
|
* 新瓦片已经落地、也已经决定由谁负责显示,这时候才把没人依赖的那块裁掉。
|
|
657
773
|
* 只踢「当前不显示」或「位置已被可见子瓦接手」的瓦片;挑不出安全候选时允许
|
|
658
774
|
* 暂时超出预算,等下一帧再裁 —— 宁可多占一会儿内存,也不在画面上开洞。
|
|
659
775
|
*
|
|
660
|
-
*
|
|
661
|
-
* `maxTriangles` 为 Infinity 时短路,行为与只有瓦片数预算时完全一致。
|
|
776
|
+
* 三条预算并行:瓦片数(`maxTiles`)、三角形总数(`maxTriangles`)与显存字节(`maxMemory`)。
|
|
777
|
+
* `maxTriangles` / `maxMemory` 为 Infinity 时短路,行为与只有瓦片数预算时完全一致。
|
|
662
778
|
*/
|
|
663
779
|
private _trimBudget(): boolean {
|
|
664
780
|
let removed = false;
|
|
@@ -667,9 +783,11 @@ export class S3MTileset {
|
|
|
667
783
|
const overTiles = () => this.nodes.size + this.pending.size > this.maxTiles;
|
|
668
784
|
const overTriangles = () =>
|
|
669
785
|
Number.isFinite(this.maxTriangles) && this._residentTriangles() > this.maxTriangles;
|
|
670
|
-
|
|
786
|
+
const overMemory = () =>
|
|
787
|
+
Number.isFinite(this.maxMemory) && this.residentMemory() > this.maxMemory;
|
|
788
|
+
// 预算生效时可能要连踢多块,迭代上限跟着驻留规模走;不生效时根本进不了循环
|
|
671
789
|
const iterationCap = this.nodes.size + this.maxTiles + 16;
|
|
672
|
-
while ((overTiles() || overTriangles()) && guard++ <= iterationCap) {
|
|
790
|
+
while ((overTiles() || overTriangles() || overMemory()) && guard++ <= iterationCap) {
|
|
673
791
|
if (!this._evictOne(this.nodes.size + this.pending.size > this.hardCap)) break;
|
|
674
792
|
removed = true;
|
|
675
793
|
}
|
|
@@ -1145,6 +1263,7 @@ export class S3MTileset {
|
|
|
1145
1263
|
uniforms: this._uniforms,
|
|
1146
1264
|
assembled,
|
|
1147
1265
|
polygonOffset: this._polygonOffset,
|
|
1266
|
+
materialQuality: this._materialQuality,
|
|
1148
1267
|
});
|
|
1149
1268
|
const { group, stats } = buildRes;
|
|
1150
1269
|
const texKeys = (buildRes as any).textureKeys ?? (group.userData?.textureKeys as string[] | undefined) ?? Object.keys(tile.textures ?? {});
|
|
@@ -1188,6 +1307,7 @@ export class S3MTileset {
|
|
|
1188
1307
|
meshes: stats.meshes ?? 0,
|
|
1189
1308
|
vertices: stats.vertices ?? 0,
|
|
1190
1309
|
triangles: stats.triangles ?? 0,
|
|
1310
|
+
memory: (stats as any).memory ?? estimateObjectGeometryBytes(group),
|
|
1191
1311
|
},
|
|
1192
1312
|
};
|
|
1193
1313
|
|