s3m-three 0.4.19 → 0.4.21

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.
Files changed (87) hide show
  1. package/dist/browser/assets/{s3mWorker-4iTAmWIu.js → s3mWorker-DvAUA8NJ.js} +1 -1
  2. package/dist/browser/s3m-three.iife.ext-three.js +243 -243
  3. package/dist/browser/s3m-three.iife.js +227 -227
  4. package/dist/core/Draco.d.ts.map +1 -1
  5. package/dist/core/Draco.js +0 -1
  6. package/dist/core/Draco.js.map +1 -1
  7. package/dist/core/S3MBlockParser.d.ts.map +1 -1
  8. package/dist/core/S3MBlockParser.js +27 -14
  9. package/dist/core/S3MBlockParser.js.map +1 -1
  10. package/dist/core/SplatSort.d.ts +14 -1
  11. package/dist/core/SplatSort.d.ts.map +1 -1
  12. package/dist/core/SplatSort.js +51 -4
  13. package/dist/core/SplatSort.js.map +1 -1
  14. package/dist/core/TileGeometry.d.ts +10 -0
  15. package/dist/core/TileGeometry.d.ts.map +1 -1
  16. package/dist/core/TileGeometry.js +17 -14
  17. package/dist/core/TileGeometry.js.map +1 -1
  18. package/dist/render/DatasetManager.d.ts +3 -1
  19. package/dist/render/DatasetManager.d.ts.map +1 -1
  20. package/dist/render/DatasetManager.js +2 -1
  21. package/dist/render/DatasetManager.js.map +1 -1
  22. package/dist/render/FeatureStyleManager.d.ts.map +1 -1
  23. package/dist/render/GeometryBuilder.d.ts +8 -0
  24. package/dist/render/GeometryBuilder.d.ts.map +1 -1
  25. package/dist/render/GeometryBuilder.js +62 -7
  26. package/dist/render/GeometryBuilder.js.map +1 -1
  27. package/dist/render/S3MViewer.d.ts +106 -440
  28. package/dist/render/S3MViewer.d.ts.map +1 -1
  29. package/dist/render/S3MViewer.js +297 -1653
  30. package/dist/render/S3MViewer.js.map +1 -1
  31. package/dist/render/SplatSorter.d.ts.map +1 -1
  32. package/dist/render/SplatSorter.js +8 -1
  33. package/dist/render/SplatSorter.js.map +1 -1
  34. package/dist/render/viewer/EdgeDecorator.d.ts +206 -0
  35. package/dist/render/viewer/EdgeDecorator.d.ts.map +1 -0
  36. package/dist/render/viewer/EdgeDecorator.js +628 -0
  37. package/dist/render/viewer/EdgeDecorator.js.map +1 -0
  38. package/dist/render/viewer/HeightIndex.d.ts +36 -0
  39. package/dist/render/viewer/HeightIndex.d.ts.map +1 -0
  40. package/dist/render/viewer/HeightIndex.js +98 -0
  41. package/dist/render/viewer/HeightIndex.js.map +1 -0
  42. package/dist/render/viewer/LightRig.d.ts +88 -0
  43. package/dist/render/viewer/LightRig.d.ts.map +1 -0
  44. package/dist/render/viewer/LightRig.js +229 -0
  45. package/dist/render/viewer/LightRig.js.map +1 -0
  46. package/dist/render/viewer/PickService.d.ts +109 -0
  47. package/dist/render/viewer/PickService.d.ts.map +1 -0
  48. package/dist/render/viewer/PickService.js +591 -0
  49. package/dist/render/viewer/PickService.js.map +1 -0
  50. package/dist/render/viewer/SelectionDecorator.d.ts +84 -0
  51. package/dist/render/viewer/SelectionDecorator.d.ts.map +1 -0
  52. package/dist/render/viewer/SelectionDecorator.js +339 -0
  53. package/dist/render/viewer/SelectionDecorator.js.map +1 -0
  54. package/dist/render/viewer/SplatLayer.d.ts +26 -0
  55. package/dist/render/viewer/SplatLayer.d.ts.map +1 -0
  56. package/dist/render/viewer/SplatLayer.js +44 -0
  57. package/dist/render/viewer/SplatLayer.js.map +1 -0
  58. package/dist/render/viewer/types.d.ts +256 -0
  59. package/dist/render/viewer/types.d.ts.map +1 -0
  60. package/dist/render/viewer/types.js +3 -0
  61. package/dist/render/viewer/types.js.map +1 -0
  62. package/dist/tileset/S3MTileset.d.ts +30 -3
  63. package/dist/tileset/S3MTileset.d.ts.map +1 -1
  64. package/dist/tileset/S3MTileset.js +99 -5
  65. package/dist/tileset/S3MTileset.js.map +1 -1
  66. package/dist/worker/s3mWorker.js +1 -1
  67. package/dist/worker/s3mWorker.js.map +1 -1
  68. package/docs/API.md +9 -28
  69. package/docs/FORMAT-NOTES.md +38 -14
  70. package/package.json +1 -1
  71. package/src/core/Draco.ts +1 -2
  72. package/src/core/S3MBlockParser.ts +27 -16
  73. package/src/core/SplatSort.ts +67 -5
  74. package/src/core/TileGeometry.ts +24 -11
  75. package/src/render/DatasetManager.ts +5 -1
  76. package/src/render/FeatureStyleManager.ts +1 -1
  77. package/src/render/GeometryBuilder.ts +59 -7
  78. package/src/render/S3MViewer.ts +327 -1916
  79. package/src/render/SplatSorter.ts +8 -1
  80. package/src/render/viewer/EdgeDecorator.ts +722 -0
  81. package/src/render/viewer/HeightIndex.ts +94 -0
  82. package/src/render/viewer/LightRig.ts +267 -0
  83. package/src/render/viewer/PickService.ts +651 -0
  84. package/src/render/viewer/SelectionDecorator.ts +377 -0
  85. package/src/render/viewer/SplatLayer.ts +44 -0
  86. package/src/render/viewer/types.ts +264 -0
  87. package/src/tileset/S3MTileset.ts +106 -6
@@ -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) */
@@ -287,6 +287,14 @@ export interface S3MTilesetOptions {
287
287
  * 不传 = 不限制,行为与旧版完全一致。运行时可用 `setMaxTriangles()` 调整。
288
288
  */
289
289
  maxTriangles?: number;
290
+ /**
291
+ * 本数据集**驻留显存/内存字节数**的软上限(默认不限制)。
292
+ * 包含几何顶点缓冲(精确字节)与纹理显存估计。超限时按同一套 make-before-break
293
+ * 主动淘汰非显示瓦片及其独占纹理。
294
+ *
295
+ * 不传 = 不限制(Infinity),行为与旧版完全一致。运行时可用 `setMaxMemory()` 调整。
296
+ */
297
+ maxMemory?: number;
290
298
  /**
291
299
  * 是否请求 `.texblock` 子图集(S3MBLOCK 根图集的清晰版)。**默认关**。
292
300
  *
@@ -315,6 +323,54 @@ export interface S3MTilesetOptions {
315
323
  unsupported?: UnsupportedPolicy;
316
324
  }
317
325
 
326
+ /** 估算单个纹理占用的显存字节数 */
327
+ export function estimateTextureBytes(tex: any): number {
328
+ if (!tex) return 0;
329
+ if (Array.isArray(tex.mipmaps) && tex.mipmaps.length > 0) {
330
+ let bytes = 0;
331
+ for (const m of tex.mipmaps) {
332
+ if (m?.data?.byteLength) bytes += m.data.byteLength;
333
+ }
334
+ if (bytes > 0) return bytes;
335
+ }
336
+ const img = tex.image;
337
+ if (!img) return 0;
338
+ if (img.data && typeof img.data.byteLength === 'number') {
339
+ return img.data.byteLength;
340
+ }
341
+ const w = img.width ?? 0;
342
+ const h = img.height ?? 0;
343
+ if (w > 0 && h > 0) {
344
+ const factor = tex.generateMipmaps ? 1.3333333333333333 : 1;
345
+ return Math.round(w * h * 4 * factor);
346
+ }
347
+ return 0;
348
+ }
349
+
350
+ /** 估算三维对象树中包含的几何缓冲字节数 */
351
+ export function estimateObjectGeometryBytes(obj: any): number {
352
+ let bytes = 0;
353
+ if (!obj) return 0;
354
+ obj.traverse?.((child: any) => {
355
+ const geo = child.geometry;
356
+ if (geo) {
357
+ if (geo.attributes) {
358
+ for (const attr of Object.values(geo.attributes) as any[]) {
359
+ if (attr?.array?.byteLength) bytes += attr.array.byteLength;
360
+ }
361
+ }
362
+ if (geo.index?.array?.byteLength) {
363
+ bytes += geo.index.array.byteLength;
364
+ }
365
+ }
366
+ if (child.isInstancedMesh) {
367
+ if (child.instanceMatrix?.array?.byteLength) bytes += child.instanceMatrix.array.byteLength;
368
+ if (child.instanceColor?.array?.byteLength) bytes += child.instanceColor.array.byteLength;
369
+ }
370
+ });
371
+ return bytes;
372
+ }
373
+
318
374
  export class S3MTileset {
319
375
  configUrl: string;
320
376
  config: Record<string, unknown> | null = null;
@@ -377,6 +433,10 @@ export class S3MTileset {
377
433
  * 判据与旧版逐字一致,不会多算一次面数。
378
434
  */
379
435
  maxTriangles: number;
436
+ /**
437
+ * 驻留显存/内存字节数的软上限。`Infinity` = 不限制(默认)。
438
+ */
439
+ maxMemory: number;
380
440
  lodRangeScale: number;
381
441
 
382
442
  /** 数据集配置声明的高度范围(米),若配置未声明则返回 null */
@@ -403,7 +463,6 @@ export class S3MTileset {
403
463
  /** 子瓦片 URL → 父瓦片 URL,用于淘汰后补洞 */
404
464
  private readonly _parentOf = new Map<string, string>();
405
465
  private _frame = 0;
406
- private _lodDbgOnce = false;
407
466
  /** 格式类永久错误只向上报一次,避免整棵瓦片树刷同样的日志 */
408
467
  private _permanentReported = false;
409
468
  /** 请求量的硬上限(软上限 maxTiles 的超额余量),见构造函数注释 */
@@ -440,6 +499,9 @@ export class S3MTileset {
440
499
  this.maxConcurrent = options.maxConcurrent ?? 4;
441
500
  this.maxTiles = options.maxTiles ?? 64;
442
501
  this.maxTriangles = options.maxTriangles ?? Infinity;
502
+ this.maxMemory = Number.isFinite(options.maxMemory) && (options.maxMemory as number) > 0
503
+ ? (options.maxMemory as number)
504
+ : Infinity;
443
505
  this.maxImageCache = options.maxImageCache ?? 128;
444
506
  // 硬上限 = 软上限 + 余量。淘汰只在「新瓦片已经落地并接管显示」之后做(make-before-break),
445
507
  // 所以中间态允许临时超出 maxTiles;硬上限只用来挡住失控的请求量,不用于挤掉正在显示的内容。
@@ -652,14 +714,49 @@ export class S3MTileset {
652
714
  this.maxTriangles = n > 0 ? n : Infinity;
653
715
  }
654
716
 
717
+ /**
718
+ * 运行时调整显存/内存字节预算。`Infinity` = 不限制(默认)。
719
+ * 收紧后不会立刻掉内容,要等下一次 `_trimBudget`(下一帧 update)才生效。
720
+ */
721
+ setMaxMemory(bytes: number): void {
722
+ this.maxMemory = Number.isFinite(bytes) && bytes > 0 ? bytes : Infinity;
723
+ }
724
+
725
+ /**
726
+ * 当前数据集驻留的显存与内存总字节数(几何缓冲精确大小 + 纹理显存估计)
727
+ */
728
+ residentMemory(): number {
729
+ return this._residentGeometryBytes() + this._residentTextureBytes();
730
+ }
731
+
732
+ private _residentGeometryBytes(): number {
733
+ let total = 0;
734
+ for (const node of this.nodes.values()) {
735
+ if (node.stats && typeof node.stats.memory === 'number') {
736
+ total += node.stats.memory;
737
+ } else if (node.group) {
738
+ total += estimateObjectGeometryBytes(node.group);
739
+ }
740
+ }
741
+ return total;
742
+ }
743
+
744
+ private _residentTextureBytes(): number {
745
+ let total = 0;
746
+ for (const tex of this.textureCache.values()) {
747
+ total += estimateTextureBytes(tex);
748
+ }
749
+ return total;
750
+ }
751
+
655
752
  /**
656
753
  * 预算裁剪 —— 必须在可见性算完之后调用(make-before-break):
657
754
  * 新瓦片已经落地、也已经决定由谁负责显示,这时候才把没人依赖的那块裁掉。
658
755
  * 只踢「当前不显示」或「位置已被可见子瓦接手」的瓦片;挑不出安全候选时允许
659
756
  * 暂时超出预算,等下一帧再裁 —— 宁可多占一会儿内存,也不在画面上开洞。
660
757
  *
661
- * 两条预算并行:瓦片数(`maxTiles`)与三角形总数(`maxTriangles`,默认不限制)。
662
- * `maxTriangles` 为 Infinity 时短路,行为与只有瓦片数预算时完全一致。
758
+ * 三条预算并行:瓦片数(`maxTiles`)、三角形总数(`maxTriangles`)与显存字节(`maxMemory`)。
759
+ * `maxTriangles` / `maxMemory` 为 Infinity 时短路,行为与只有瓦片数预算时完全一致。
663
760
  */
664
761
  private _trimBudget(): boolean {
665
762
  let removed = false;
@@ -668,9 +765,11 @@ export class S3MTileset {
668
765
  const overTiles = () => this.nodes.size + this.pending.size > this.maxTiles;
669
766
  const overTriangles = () =>
670
767
  Number.isFinite(this.maxTriangles) && this._residentTriangles() > this.maxTriangles;
671
- // 面数预算生效时可能要连踢多块,迭代上限跟着驻留规模走;不生效时根本进不了循环
768
+ const overMemory = () =>
769
+ Number.isFinite(this.maxMemory) && this.residentMemory() > this.maxMemory;
770
+ // 预算生效时可能要连踢多块,迭代上限跟着驻留规模走;不生效时根本进不了循环
672
771
  const iterationCap = this.nodes.size + this.maxTiles + 16;
673
- while ((overTiles() || overTriangles()) && guard++ <= iterationCap) {
772
+ while ((overTiles() || overTriangles() || overMemory()) && guard++ <= iterationCap) {
674
773
  if (!this._evictOne(this.nodes.size + this.pending.size > this.hardCap)) break;
675
774
  removed = true;
676
775
  }
@@ -1189,6 +1288,7 @@ export class S3MTileset {
1189
1288
  meshes: stats.meshes ?? 0,
1190
1289
  vertices: stats.vertices ?? 0,
1191
1290
  triangles: stats.triangles ?? 0,
1291
+ memory: (stats as any).memory ?? estimateObjectGeometryBytes(group),
1192
1292
  },
1193
1293
  };
1194
1294