streaming-gltf 1.0.1 → 1.0.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "streaming-gltf",
3
- "version": "1.0.1",
3
+ "version": "1.0.3",
4
4
  "description": "Streaming progressive glTF LOD renderer (BatchedMesh/InstancedMesh tiers, network-lazy GPU-eager LOD streaming, on-GPU position lerping) plus the local bake/convert + streaming-download pipeline (tools/bake-*.mjs).",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -9,7 +9,8 @@
9
9
  "exports": {
10
10
  ".": "./index.js",
11
11
  "./model-pool": "./examples/local-progressive/model-pool.js",
12
- "./batched-far-tier": "./examples/local-progressive/batched-far-tier.js"
12
+ "./batched-far-tier": "./examples/local-progressive/batched-far-tier.js",
13
+ "./bake": "./tools/bake-progressive.mjs"
13
14
  },
14
15
  "files": [
15
16
  "index.js",
@@ -35,6 +36,14 @@
35
36
  "three": ">= 0.160.0",
36
37
  "@pixiv/three-vrm": ">= 3.0.0"
37
38
  },
39
+ "optionalDependencies": {
40
+ "@gltf-transform/core": "^4.3.0",
41
+ "@gltf-transform/extensions": "^4.3.0",
42
+ "@gltf-transform/functions": "^4.3.0",
43
+ "draco3dgltf": "^1.5.7",
44
+ "meshoptimizer": "^1.1.1",
45
+ "sharp": "^0.34.5"
46
+ },
38
47
  "devDependencies": {
39
48
  "@gltf-transform/core": "^4.3.0",
40
49
  "@gltf-transform/extensions": "^4.3.0",
@@ -13,7 +13,7 @@ import draco3dgltf from 'draco3dgltf';
13
13
  import sharp from 'sharp';
14
14
  import { mkdir, writeFile, rm, stat, readFile } from 'node:fs/promises';
15
15
  import path from 'node:path';
16
- import { fileURLToPath } from 'node:url';
16
+ import { fileURLToPath, pathToFileURL } from 'node:url';
17
17
 
18
18
  // Read a GLB and return its JSON chunk as a parsed object plus the original
19
19
  // binary chunk bytes. Used to round-trip extensions gltf-transform doesn't
@@ -207,16 +207,6 @@ async function rewriteGlbJson(filePath, mutator) {
207
207
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
208
208
  const repoRoot = path.resolve(__dirname, '..');
209
209
 
210
- const INPUT = process.argv[2] || path.join(repoRoot, 'model.glb');
211
- // Default output dir is named after the input basename so multiple models
212
- // can be baked into examples/local-progressive/ side by side.
213
- const inputBase = path.basename(INPUT, path.extname(INPUT));
214
- const DEFAULT_OUT = path.join(
215
- repoRoot,
216
- 'examples/local-progressive',
217
- inputBase === 'model' ? 'output' : `output_${inputBase}`,
218
- );
219
- const OUT_DIR = process.argv[3] || DEFAULT_OUT;
220
210
  const LODS_SUBDIR = 'lods';
221
211
 
222
212
  // LOD recipes from highest to lowest detail. Each entry: { ratio, kind }
@@ -232,7 +222,14 @@ const EXTRA_LOD_STAGES = [
232
222
  ];
233
223
  const TEX_LOD_SIZES = [2048, 1024, 512, 256, 128];
234
224
 
235
- async function main() {
225
+ // Bake a single source GLB into the progressive LOD format consumed by
226
+ // ModelPool: writes `<outDir>/model.progressive.glb` (lowest LOD inline + a
227
+ // LOCAL_progressive extension) plus sibling LOD/texture files under
228
+ // `<outDir>/lods/`. Exported so a server can bake on demand without shelling
229
+ // out to the CLI; the CLI entry below is a thin wrapper around it.
230
+ export async function bakeProgressive(INPUT, OUT_DIR) {
231
+ if (!INPUT) throw new Error('bakeProgressive: input path required');
232
+ if (!OUT_DIR) throw new Error('bakeProgressive: output dir required');
236
233
  console.log(`[bake] input : ${INPUT}`);
237
234
  console.log(`[bake] output : ${OUT_DIR}`);
238
235
 
@@ -426,9 +423,20 @@ async function main() {
426
423
  let target = Math.min(FAR_TRI_CAP * 3, u32.length);
427
424
  target -= target % 3;
428
425
  target = Math.max(96, target); // >=32 tris
429
- const res = MeshoptSimplifier.simplifySloppy(u32, f32, 3, null, target, 1e9);
430
- const out = Array.isArray(res) ? res[0] : res;
431
- idxAcc.setArray(out instanceof Uint32Array ? out : new Uint32Array(out));
426
+ // simplifySloppy asserts on some inputs (degenerate / tiny / non-
427
+ // manifold index buffers). The unskinned LOD is an optimization,
428
+ // not a correctness requirement: on failure keep the meshopt-
429
+ // decoded indices as-is (a heavier-but-correct far dot) rather
430
+ // than aborting the whole bake.
431
+ try {
432
+ const res = MeshoptSimplifier.simplifySloppy(u32, f32, 3, null, target, 1e9);
433
+ const out = Array.isArray(res) ? res[0] : res;
434
+ if (out && out.length >= 3) {
435
+ idxAcc.setArray(out instanceof Uint32Array ? out : new Uint32Array(out));
436
+ }
437
+ } catch (e) {
438
+ console.warn(`[bake] simplifySloppy skipped for unskinned LOD (${u32.length / 3} tris): ${e.message}`);
439
+ }
432
440
  }
433
441
  } else {
434
442
  await cloneDoc.transform(
@@ -660,4 +668,16 @@ async function main() {
660
668
  console.log(`[bake] saving on initial load: ${(100 - (rootSize/origSize)*100).toFixed(1)}%`);
661
669
  }
662
670
 
663
- main().catch((e) => { console.error(e); process.exit(1); });
671
+ // CLI entry: only run when invoked directly (`node tools/bake-progressive.mjs
672
+ // <in> <out>`), not when imported for the on-demand server bake path.
673
+ if (import.meta.url === pathToFileURL(process.argv[1] || '').href) {
674
+ const INPUT = process.argv[2] || path.join(repoRoot, 'model.glb');
675
+ const inputBase = path.basename(INPUT, path.extname(INPUT));
676
+ const DEFAULT_OUT = path.join(
677
+ repoRoot,
678
+ 'examples/local-progressive',
679
+ inputBase === 'model' ? 'output' : `output_${inputBase}`,
680
+ );
681
+ const OUT_DIR = process.argv[3] || DEFAULT_OUT;
682
+ bakeProgressive(INPUT, OUT_DIR).catch((e) => { console.error(e); process.exit(1); });
683
+ }