@needle-tools/gltf-build-pipeline 1.1.0 → 1.1.2

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/CHANGELOG.md CHANGED
@@ -4,6 +4,12 @@ All notable changes to this package will be documented in this file.
4
4
  The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
5
5
  and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [1.1.2] - 2023-05-24
8
+ - fix: wasm out of memory error caused by starting to many compression processes at once
9
+
10
+ ## [1.1.1] - 2023-05-18
11
+ - fix: fix progressive texture processing for empty slots array, assume texture slot "baseColorTexture" (for custom shader support)
12
+
7
13
  ## [1.1.0] - 2023-05-06
8
14
  - add: support for per glb mesh compression selection (none, draco or meshopt)
9
15
 
@@ -23,12 +23,9 @@ function registerExtensions(io) {
23
23
  export async function make_progressive(opts) {
24
24
  console.log("INFO: Run progressive transform: " + opts.path);
25
25
  const file = opts.path;
26
- const tasks = [];
27
- foreachGLTF(file, f => {
28
- const prog = process(f, opts);
29
- tasks.push(prog);
26
+ return foreachGLTF(file, async (f) => {
27
+ await process(f, opts);
30
28
  });
31
- await Promise.all(tasks);
32
29
  }
33
30
  async function process(file, opts) {
34
31
  if (!file.endsWith(".glb") && !file.endsWith(".gltf")) {
@@ -50,7 +47,7 @@ async function process(file, opts) {
50
47
  console.log("WARN: \"" + err.message + "\" at \"" + file + "\"");
51
48
  }
52
49
  else
53
- console.log("ERR: \"" + err.message + "\" at \"" + file + "\"");
50
+ console.log("ERR: \"" + err.message + "\" at \"" + file + "\"\nStacktrace:\n" + err.stack);
54
51
  return;
55
52
  });
56
53
  if (document) {
@@ -76,7 +73,7 @@ async function process(file, opts) {
76
73
  }
77
74
  }
78
75
  catch (err) {
79
- console.log("ERR: failed to process file \"" + file + "\", Reason: " + err.message);
76
+ console.log("ERR: failed to process file \"" + file + "\", Reason: " + err.message, "\nStack:\n" + err.stack);
80
77
  }
81
78
  }
82
79
  // basic idea:
@@ -159,7 +156,10 @@ export function make_progressive_textures(filePath, _options = TEXTURE_RESIZE_DE
159
156
  }
160
157
  }
161
158
  await resizeTexture(options, texture, logger, uri || name, slots);
162
- addToCache(key, texture.getImage());
159
+ if (opts?.useCache === false) {
160
+ }
161
+ else
162
+ addToCache(key, texture.getImage());
163
163
  }
164
164
  logger.debug(`Progressive transform finished in ${((Date.now() - startTime) / 1000).toFixed(1)} sec.`);
165
165
  });
@@ -181,6 +181,10 @@ function createTextureLod(basePath, level, texture, slots, guid, textureIndex) {
181
181
  newTexture.setImage(img);
182
182
  newTexture.setURI(texture.getURI());
183
183
  newTexture.setMimeType(texture.getMimeType());
184
+ if (!slots?.length) {
185
+ console.warn(`WARN: No material slots found for texture at index ${textureIndex} (name: \"${texture.getName()}\") → will assume slot \"baseColorTexture\"`);
186
+ slots = ["baseColorTexture"];
187
+ }
184
188
  // create material adding the texture to the same slot
185
189
  for (const slot of slots) {
186
190
  const newMaterial = newDoc.createMaterial();
@@ -1,2 +1,2 @@
1
1
  export declare type GLTFFileCallback = (file: string) => void | Promise<void>;
2
- export declare function foreachGLTF(args: string | string[], callback: GLTFFileCallback): void;
2
+ export declare function foreachGLTF(args: string | string[], callback: GLTFFileCallback): Promise<void>;
@@ -1,6 +1,6 @@
1
1
  import { existsSync, statSync, readdirSync, readFileSync } from 'fs';
2
2
  import { isAbsolute } from 'path';
3
- export function foreachGLTF(args, callback) {
3
+ export async function foreachGLTF(args, callback) {
4
4
  // get original directory this run was invoked from
5
5
  const initDir = process.env.INIT_CWD;
6
6
  const context = {
@@ -10,11 +10,11 @@ export function foreachGLTF(args, callback) {
10
10
  // traverse recursively through all files and directories
11
11
  if (Array.isArray(args)) {
12
12
  for (const arg of args) {
13
- testEntry(arg, callback, context);
13
+ await testEntry(arg, callback, context);
14
14
  }
15
15
  }
16
16
  else if (typeof args === "string") {
17
- testEntry(args, callback, context);
17
+ await testEntry(args, callback, context);
18
18
  }
19
19
  // try to run with needle config
20
20
  if (context.filesFound <= 0 && context.baseDirectory) {
@@ -26,13 +26,13 @@ export function foreachGLTF(args, callback) {
26
26
  // If it's an absolute path
27
27
  if (existsSync(buildDirectory)) {
28
28
  console.log("INFO: Using build directory from needle.config.json: " + buildDirectory);
29
- testEntry(buildDirectory, callback, context);
29
+ await testEntry(buildDirectory, callback, context);
30
30
  }
31
31
  else { // if its a relative path
32
32
  const newPath = context.baseDirectory + "/" + buildDirectory;
33
33
  if (existsSync(newPath)) {
34
34
  console.log("INFO: Using build directory from needle.config.json: " + newPath);
35
- testEntry(newPath, callback, context);
35
+ await testEntry(newPath, callback, context);
36
36
  }
37
37
  }
38
38
  }
@@ -42,7 +42,7 @@ export function foreachGLTF(args, callback) {
42
42
  console.log("WARN: No glTF files found. Make sure to invoke with a valid path to a glTF file or directory. This path may be relative to " + initDir);
43
43
  }
44
44
  }
45
- function testEntry(entry, callback, context) {
45
+ async function testEntry(entry, callback, context) {
46
46
  if (entry === "." || entry === "./") {
47
47
  if (context.baseDirectory) {
48
48
  entry = context.baseDirectory;
@@ -82,7 +82,10 @@ function testEntry(entry, callback, context) {
82
82
  }
83
83
  if (entry.endsWith(".glb") || entry.endsWith(".gltf")) {
84
84
  context.filesFound += 1;
85
- callback(entry);
85
+ const res = callback(entry);
86
+ if (res instanceof Promise) {
87
+ await res;
88
+ }
86
89
  }
87
90
  else {
88
91
  const stat = statSync(entry);
@@ -93,7 +96,7 @@ function testEntry(entry, callback, context) {
93
96
  }
94
97
  const files = readdirSync(entry);
95
98
  for (const file of files) {
96
- testEntry(entry + "/" + file, callback, context);
99
+ await testEntry(entry + "/" + file, callback, context);
97
100
  }
98
101
  }
99
102
  else {
package/pack-gltf.mjs CHANGED
@@ -69,6 +69,9 @@ if (noToktx)
69
69
  console.log("Using toktx is disabled");
70
70
 
71
71
  const packedFiles = new Set();
72
+ let totalGPUMemoryInMB = 0;
73
+ let totalFilesProcessed = 0;
74
+ let totalFileSizeInMB = 0;
72
75
 
73
76
  async function packFile(file) {
74
77
  if (!existsSync(file)) {
@@ -105,8 +108,8 @@ async function packFile(file) {
105
108
  await document.transform(
106
109
  needle_asset(),
107
110
  needle_texture_transform({
108
- useCache: allowCaching,
109
- noToktx: noToktx,
111
+ useCache: allowCaching,
112
+ noToktx: noToktx,
110
113
  debug: debug,
111
114
  reportGPUMemory: val => totalGPUTextureMemmory += val
112
115
  }),
@@ -117,10 +120,14 @@ async function packFile(file) {
117
120
  if (debug) file += ".debug.glb";
118
121
  await io.write(file, document);
119
122
  const duration = Date.now() - startTime;
120
- const sizeInBytes = statSync(file).size;
123
+ const sizeInMB = statSync(file).size / 1024 / 1024;
121
124
  const filename = path.basename(file);
122
125
  const gpuMemoryInMB = totalGPUTextureMemmory / 1024 / 1024;
123
- console.log(`← Compressing done in ${(duration / 1000).toFixed(1)} sec, ${(prevSize / 1024 / 1024).toFixed(1)} MB → ${(sizeInBytes / 1024 / 1024).toFixed(1)} MB (GPU: ${gpuMemoryInMB.toFixed(1)} MB textures): ${filename} at ${file}`);
126
+ console.log(`← Compressing done in ${(duration / 1000).toFixed(1)} sec, ${(prevSize / 1024 / 1024).toFixed(1)} MB → ${sizeInMB.toFixed(1)} MB (GPU: ${gpuMemoryInMB.toFixed(1)} MB textures): ${filename} at ${file}`);
127
+
128
+ totalFilesProcessed++;
129
+ totalFileSizeInMB += sizeInMB;
130
+ totalGPUMemoryInMB += gpuMemoryInMB;
124
131
  return true;
125
132
  }
126
133
  catch (err) {
@@ -130,7 +137,11 @@ async function packFile(file) {
130
137
  }
131
138
  }
132
139
 
133
-
140
+ let startTime = Date.now();
134
141
  foreachGLTF(process.argv, async (file) => {
135
142
  await packFile(file);
136
- });
143
+ }).then(() => {
144
+ const duration = Date.now() - startTime;
145
+ const durationInMinutes = duration / 1000 / 60;
146
+ console.log(`Finished packing ${totalFilesProcessed} files in ${durationInMinutes.toFixed(1)} minutes; total size: ${totalFileSizeInMB.toFixed(1)} MB, total GPU memory: ${totalGPUMemoryInMB.toFixed(1)} MB`);
147
+ })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@needle-tools/gltf-build-pipeline",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
4
4
  "description": "Pipeline and tools for optimizing gltf files using gltf-transform and compression settings within glTF extensions",
5
5
  "main": "index.mjs",
6
6
  "type": "module",