s3m-three 0.3.6 → 0.3.7

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 (43) hide show
  1. package/dist/browser/assets/{s3mWorker-hZY5KqWF.js → s3mWorker-D7AV6O30.js} +1 -1
  2. package/dist/browser/s3m-three.iife.ext-three.js +20 -20
  3. package/dist/browser/s3m-three.iife.js +20 -20
  4. package/dist/core/TextureDecode.d.ts +22 -1
  5. package/dist/core/TextureDecode.d.ts.map +1 -1
  6. package/dist/core/TextureDecode.js +47 -3
  7. package/dist/core/TextureDecode.js.map +1 -1
  8. package/dist/core/TileGeometry.d.ts +92 -0
  9. package/dist/core/TileGeometry.d.ts.map +1 -0
  10. package/dist/core/TileGeometry.js +607 -0
  11. package/dist/core/TileGeometry.js.map +1 -0
  12. package/dist/render/GeometryBuilder.d.ts +8 -10
  13. package/dist/render/GeometryBuilder.d.ts.map +1 -1
  14. package/dist/render/GeometryBuilder.js +77 -555
  15. package/dist/render/GeometryBuilder.js.map +1 -1
  16. package/dist/render/S3MViewer.d.ts +2 -0
  17. package/dist/render/S3MViewer.d.ts.map +1 -1
  18. package/dist/render/S3MViewer.js +9 -1
  19. package/dist/render/S3MViewer.js.map +1 -1
  20. package/dist/render/TextureFactory.d.ts +2 -1
  21. package/dist/render/TextureFactory.d.ts.map +1 -1
  22. package/dist/render/TextureFactory.js +30 -6
  23. package/dist/render/TextureFactory.js.map +1 -1
  24. package/dist/tileset/S3MTileset.d.ts +6 -2
  25. package/dist/tileset/S3MTileset.d.ts.map +1 -1
  26. package/dist/tileset/S3MTileset.js +14 -6
  27. package/dist/tileset/S3MTileset.js.map +1 -1
  28. package/dist/worker/S3MWorkerClient.d.ts +12 -4
  29. package/dist/worker/S3MWorkerClient.d.ts.map +1 -1
  30. package/dist/worker/S3MWorkerClient.js +12 -8
  31. package/dist/worker/S3MWorkerClient.js.map +1 -1
  32. package/dist/worker/s3mWorker.js +11 -3
  33. package/dist/worker/s3mWorker.js.map +1 -1
  34. package/docs/API.md +2 -0
  35. package/package.json +1 -1
  36. package/src/core/TextureDecode.ts +69 -3
  37. package/src/core/TileGeometry.ts +745 -0
  38. package/src/render/GeometryBuilder.ts +91 -617
  39. package/src/render/S3MViewer.ts +11 -3
  40. package/src/render/TextureFactory.ts +42 -8
  41. package/src/tileset/S3MTileset.ts +22 -8
  42. package/src/worker/S3MWorkerClient.ts +18 -9
  43. package/src/worker/s3mWorker.ts +24 -6
package/docs/API.md CHANGED
@@ -165,6 +165,8 @@ new S3MViewer(options?: S3MViewerOptions)
165
165
  | `maxConcurrent` | `number` | `4` | 每个数据集并发请求数 |
166
166
  | `useWorker` | `boolean` | `true` | 用 Web Worker 解析经典 `.s3mb` 瓦片(inflate / Draco / MeshOpt 全在 Worker 跑,主线程只做 fetch 与几何组装);Worker 不可用或崩溃时自动永久降级主线程。S3MBLOCK 路径仍主线程解析 |
167
167
  | (随 `useWorker`)纹理解码 | `boolean` | `true` | DXT / CRN / WEBP 纹理解码与 `.s3mb` 解析共用同一个 Worker(`core/TextureDecode.ts` 三方共用同一份实现,WEBP 走可 transfer 的 ImageBitmap);失败自动回主线程,产物逐字节一致 |
168
+ | (随 `useWorker`)几何组装 | `boolean` | `true` | 顶点解交错 / 法线计算 / 同材质合批合并(`core/TileGeometry.ts`)随解析在 Worker 完成,主线程只做 three 对象包装;Worker 不可用时主线程跑同一份实现,产物一致 |
169
+ | (随 `useWorker`)DXT 压缩直传 | 自动 | 自动 | 宿主 GL 同时支持 `WEBGL_compressed_texture_s3tc`(+srgb) 时,dxt1/dxt5(含 CRN 转码产物)不解码直接 `CompressedTexture` 上传,显存与上传带宽降为 1/4~1/8;块长与 4×4 对齐公式不符、flipY 图集、移动端无扩展时自动回退 RGBA 解码 |
168
170
  | `lodRangeScale` | `number` | `1.0` | LOD 切换距离缩放系数,> 1 更倾向保留粗模,< 1 提前细化 |
169
171
  | `buildTile` | `BuildTileFn \| null` | — | 自定义瓦片构建器(测试 / 服务端渲染时注入) |
170
172
  | `attributes` | `AttributeQueryOptions` | — | 业务属性查询配置,配了才能 `colorByField()`,见[按业务字段着色](#按业务字段着色) |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "s3m-three",
3
- "version": "0.3.6",
3
+ "version": "0.3.7",
4
4
  "description": "SuperMap S3M 三维模型格式的 three.js 渲染内核:浏览器内直接解析 .s3mb 瓦片,无需转 3D Tiles,支持 LOD 调度、白膜/按高度/按单体/动态扫描着色、单体级 GPU 拾取。宿主无关,可单独用于任意 three 场景。",
5
5
  "type": "module",
6
6
  "repository": {
@@ -26,10 +26,25 @@ export interface DecodedTextureData {
26
26
  /** WEBP 路径的解码结果(ImageBitmap 可 transfer,主线程直接 new THREE.Texture 包) */
27
27
  bitmap: ImageBitmap | null;
28
28
  hasAlpha: boolean;
29
+ /**
30
+ * 压缩直传模式(decodeTextureData 的 compressed 选项):不解码,原样返回 DXT 块,
31
+ * 主线程用 CompressedTexture 硬件解压上传。与 rgba 互斥。
32
+ */
33
+ blocks?: Uint8Array;
34
+ blockFormat?: 'dxt1' | 'dxt5';
29
35
  /** CRN 转码失败时的原始错误(渲染层负责打 warn) */
30
36
  error?: string;
31
37
  }
32
38
 
39
+ export interface DecodeOptions {
40
+ /**
41
+ * 压缩直传:dxt1/dxt5(含 CRN 转码产物)不解码,原样返回 DXT 块。
42
+ * 仅在宿主支持 WEBGL_compressed_texture_s3tc(+srgb) 时开启;
43
+ * flipY 纹理走不了压缩上传(WebGL 对压缩纹理忽略 UNPACK_FLIP_Y),自动回退解码。
44
+ */
45
+ compressed?: boolean;
46
+ }
47
+
33
48
  /** 行序翻转(原地)。S3MBLOCK 图集按 GL 方向存储(v=0 在最后一行),解码后要翻一次行 */
34
49
  function flipRows(rgba: Uint8Array, width: number, height: number): void {
35
50
  const row = width * 4;
@@ -92,8 +107,23 @@ function rawRGBA(tex: S3MTexture): { rgba: Uint8Array; hasAlpha: boolean } {
92
107
  return { rgba: out, hasAlpha: hasAlphaChannel(pixelFormat) };
93
108
  }
94
109
 
110
+ /**
111
+ * DXT 块数据的期望字节数:4×4 对齐块 × 每块字节(DXT1=8,DXT5=16)。
112
+ * S3M 纹理宽高不总是 4 的倍数,驱动按声明尺寸算期望大小——对不上就是
113
+ * GL_INVALID_VALUE: glCompressedTexSubImage2D: The <imageSize> does not match。
114
+ * 压缩直传前必须用这个函数把关,不匹配就回退 RGBA 解码。
115
+ */
116
+ export function expectedDxtByteLength(width: number, height: number, format: 'dxt1' | 'dxt5'): number {
117
+ const bw = (width + 3) >> 2;
118
+ const bh = (height + 3) >> 2;
119
+ return bw * bh * (format === 'dxt1' ? 8 : 16);
120
+ }
121
+
95
122
  /** 主线程 / Worker 共用的解码入口。不抛错:失败与不支持都体现在返回值里 */
96
- export async function decodeTextureData(tex: S3MTexture): Promise<DecodedTextureData> {
123
+ export async function decodeTextureData(
124
+ tex: S3MTexture,
125
+ options: DecodeOptions = {}
126
+ ): Promise<DecodedTextureData> {
97
127
  const empty: DecodedTextureData = {
98
128
  kind: 'unsupported(0/0)',
99
129
  width: 0,
@@ -106,13 +136,35 @@ export async function decodeTextureData(tex: S3MTexture): Promise<DecodedTexture
106
136
 
107
137
  const kind = resolveTextureKind(tex.compressType ?? 0, tex.pixelFormat);
108
138
 
139
+ // 压缩直传的公共前提:不是 GL 翻行图集(压缩上传无法 flipY)
140
+ const canCompress = options.compressed === true && !tex.flipY;
141
+
142
+ /** 块数据字节数与 4×4 对齐公式一致才允许直传,否则回退解码 */
143
+ const compressible = (data: Uint8Array, w: number, h: number, format: 'dxt1' | 'dxt5'): boolean =>
144
+ data.byteLength === expectedDxtByteLength(w, h, format);
145
+
109
146
  if (kind === 'crn') {
110
147
  try {
111
148
  const crn = await transcodeCRN(tex.data);
149
+ const pf = crn.dxtFormat === 1 ? PixelFormat.DXT1 : PixelFormat.DXT5;
150
+ const fmt = crn.dxtFormat === 1 ? 'dxt1' : 'dxt5';
151
+ if (canCompress && compressible(crn.data, crn.width, crn.height, fmt)) {
152
+ // CRN→DXT 的转码免不了(wasm),但后续的 DXT→RGBA 解块省掉,块数据直传 GPU
153
+ return {
154
+ kind: `crn->dxt${crn.dxtFormat}(c)`,
155
+ width: crn.width,
156
+ height: crn.height,
157
+ rgba: null,
158
+ bitmap: null,
159
+ hasAlpha: pf === PixelFormat.DXT5,
160
+ blocks: crn.data,
161
+ blockFormat: fmt,
162
+ };
163
+ }
112
164
  const decoded = decodeDXT({
113
165
  width: crn.width,
114
166
  height: crn.height,
115
- pixelFormat: crn.dxtFormat === 1 ? PixelFormat.DXT1 : PixelFormat.DXT5,
167
+ pixelFormat: pf,
116
168
  data: crn.data,
117
169
  });
118
170
  return {
@@ -138,7 +190,21 @@ export async function decodeTextureData(tex: S3MTexture): Promise<DecodedTexture
138
190
  }
139
191
 
140
192
  if (kind === 'dxt1' || kind === 'dxt3' || kind === 'dxt4' || kind === 'dxt5') {
141
- const decoded = decodeDXT({ ...tex, pixelFormat: dxtPixelFormatOf(kind) });
193
+ const pf = dxtPixelFormatOf(kind);
194
+ // dxt3/dxt4 少见,不进直传白名单;块长与 4×4 对齐公式不符的也回退解码
195
+ if (canCompress && (kind === 'dxt1' || kind === 'dxt5') && compressible(tex.data, tex.width, tex.height, kind)) {
196
+ return {
197
+ kind: `${kind}(c)`,
198
+ width: tex.width,
199
+ height: tex.height,
200
+ rgba: null,
201
+ bitmap: null,
202
+ hasAlpha: kind === 'dxt5',
203
+ blocks: tex.data,
204
+ blockFormat: kind,
205
+ };
206
+ }
207
+ const decoded = decodeDXT({ ...tex, pixelFormat: pf });
142
208
  return { kind, width: tex.width, height: tex.height, rgba: decoded.rgba, bitmap: null, hasAlpha: decoded.hasAlpha };
143
209
  }
144
210