@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 +6 -0
- package/dist/transforms/needle_progressive.js +12 -8
- package/dist/utils/fileutils.d.ts +1 -1
- package/dist/utils/fileutils.js +11 -8
- package/pack-gltf.mjs +17 -6
- package/package.json +1 -1
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
|
-
|
|
27
|
-
|
|
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
|
-
|
|
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>;
|
package/dist/utils/fileutils.js
CHANGED
|
@@ -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
|
|
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 → ${
|
|
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.
|
|
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",
|