@needle-tools/gltf-build-pipeline 1.4.0-beta → 1.4.1-beta.1
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,11 @@ 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.4.1-beta] - 2023-03-13
|
|
8
|
+
- change: update gltf-transform to `^3.10.0`
|
|
9
|
+
- change: progressive mesh transform does now set ratio for LODs (see [simplifier issue 661 on github](https://github.com/zeux/meshoptimizer/issues/661))
|
|
10
|
+
- fix: issue where progressive meshes were not generated if a mesh was multiple times in the glTF
|
|
11
|
+
|
|
7
12
|
## [1.4.0-beta] - 2023-03-12
|
|
8
13
|
- add: progressive mesh transform to automatically generate mesh LOD levels (currently we only generate one low poly version)
|
|
9
14
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Extension, ExtensionProperty, Graph, IProperty, Property, PropertyType, ReaderContext, WriterContext } from "@gltf-transform/core";
|
|
2
2
|
export declare const NEEDLE_PROGRESSIVE_EXTENSION_NAME = "NEEDLE_progressive";
|
|
3
3
|
export declare interface IProgressiveTextureInfo {
|
|
4
|
-
uri?: string;
|
|
5
4
|
guid: string;
|
|
5
|
+
uri?: string | Array<string>;
|
|
6
6
|
}
|
|
7
7
|
export declare function generateGuid(): string;
|
|
8
8
|
export declare class NEEDLE_progressive extends Extension {
|
|
@@ -9,31 +9,16 @@ export class NEEDLE_progressive_mesh_settings extends Extension {
|
|
|
9
9
|
return this;
|
|
10
10
|
const root = this.document.getRoot();
|
|
11
11
|
const meshes = root.listMeshes();
|
|
12
|
-
/**
|
|
13
|
-
* If a mesh is used in multiple objects it only appears once in the gltf-transform list
|
|
14
|
-
* So we have to store the key and the index of the mesh in the list
|
|
15
|
-
*/
|
|
16
|
-
const map = new Map();
|
|
17
|
-
let offset = 0;
|
|
18
12
|
for (let i = 0; i < definitions.length; i++) {
|
|
19
13
|
const def = definitions[i];
|
|
20
14
|
if (def.extensions && def.extensions[EXTENSION_NAME]) {
|
|
21
15
|
const ext = def.extensions[EXTENSION_NAME];
|
|
22
16
|
const prop = new NEEDLE_progressive_mesh_settings_property(this.document.getGraph(), "");
|
|
23
17
|
Object.assign(prop, ext);
|
|
24
|
-
let index = i
|
|
25
|
-
const
|
|
26
|
-
if (
|
|
27
|
-
|
|
28
|
-
console.log(`INFO: Progressive mesh extension was ${i} already found...`);
|
|
29
|
-
continue;
|
|
30
|
-
}
|
|
31
|
-
else {
|
|
32
|
-
map.set(key, index);
|
|
33
|
-
}
|
|
34
|
-
const tex = meshes[index];
|
|
35
|
-
if (tex)
|
|
36
|
-
tex.setExtension(EXTENSION_NAME, prop);
|
|
18
|
+
let index = i;
|
|
19
|
+
const mesh = meshes[index];
|
|
20
|
+
if (mesh)
|
|
21
|
+
mesh.setExtension(EXTENSION_NAME, prop);
|
|
37
22
|
else {
|
|
38
23
|
console.warn(`WARN: Progressive mesh at index ${i} was not found in the glTF file. This might result in falsely loaded textures for ${ext.guid} / name \"${def.name}\"`);
|
|
39
24
|
}
|
|
@@ -150,8 +150,8 @@ export function make_progressive_textures(filePath, _options = TEXTURE_RESIZE_DE
|
|
|
150
150
|
const relName = path.relative(directory, outPath);
|
|
151
151
|
// TODO: this path should be added to the NEEDLE dependencies extension
|
|
152
152
|
texture.setExtension(NEEDLE_PROGRESSIVE_EXTENSION_NAME, progressiveExt.create({
|
|
153
|
-
uri: relName,
|
|
154
153
|
guid: textureGuid,
|
|
154
|
+
uri: relName,
|
|
155
155
|
}));
|
|
156
156
|
const key = getKey(texture);
|
|
157
157
|
if (opts.useCache) {
|
|
@@ -300,51 +300,68 @@ export function make_progressive_meshes(filePath, _options, opts) {
|
|
|
300
300
|
}
|
|
301
301
|
const logger = doc.getLogger();
|
|
302
302
|
const filename = path.basename(filePath);
|
|
303
|
-
console.log("Progressive Mesh Transform: " + filename);
|
|
303
|
+
console.log("> Progressive Mesh Transform: " + filename);
|
|
304
304
|
let index = 0;
|
|
305
305
|
// the lowest LOD (last entry) will be saved in the original file
|
|
306
306
|
const LODS = [
|
|
307
307
|
{ error: 0 },
|
|
308
|
-
|
|
309
|
-
{
|
|
308
|
+
{ ratio: 0.5, error: 1 },
|
|
309
|
+
{ ratio: 0.25, error: 1 },
|
|
310
310
|
];
|
|
311
|
-
|
|
311
|
+
/** Map of visited GUID -> extension */
|
|
312
|
+
const visited = new Map();
|
|
313
|
+
const meshes = doc.getRoot().listMeshes();
|
|
314
|
+
for (const mesh of meshes) {
|
|
312
315
|
// TODO: skip meshes that are already below a certain threshold (E.g. just 4 vertices)
|
|
313
316
|
const settings = mesh.getExtension(NEEDLE_progressive_mesh_settings.EXTENSION_NAME);
|
|
314
317
|
if (!settings) {
|
|
315
|
-
logger.debug(`${NAME}: no ${NEEDLE_progressive_mesh_settings.EXTENSION_NAME} found for mesh at index ${index}`);
|
|
318
|
+
logger.debug(`${NAME}: no ${NEEDLE_progressive_mesh_settings.EXTENSION_NAME} found for mesh at index ${index++}`);
|
|
316
319
|
continue;
|
|
317
320
|
}
|
|
318
321
|
const progressiveExt = doc.createExtension(NEEDLE_progressive);
|
|
319
322
|
if (!progressiveExt || !progressiveExt.create) {
|
|
320
|
-
logger.debug(`${NAME}: Skipping because progressive extension is not available. ${index}`);
|
|
323
|
+
logger.debug(`${NAME}: Skipping because progressive extension is not available. ${index++}`);
|
|
321
324
|
continue;
|
|
322
325
|
}
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
326
|
+
// check if we have already produced LODs for this mesh
|
|
327
|
+
let needsToGenerateLODs = true;
|
|
328
|
+
const generatedLODs = new Array();
|
|
329
|
+
if (visited.has(settings.guid)) {
|
|
330
|
+
// we can not just set the extension here...
|
|
331
|
+
logger.debug(`${NAME}: Mesh has already been processed ${index} - will use previously generated LODs`);
|
|
332
|
+
needsToGenerateLODs = false;
|
|
333
|
+
const existingPaths = visited.get(settings.guid).paths;
|
|
334
|
+
generatedLODs.push(...existingPaths);
|
|
335
|
+
}
|
|
336
|
+
if (needsToGenerateLODs) {
|
|
337
|
+
// produce LODS, skip the last level because it will be saved in the original file
|
|
338
|
+
for (let level = 0; level < LODS.length - 1; level++) {
|
|
339
|
+
const lod = LODS[level];
|
|
340
|
+
console.log(`${NAME}: Generate LOD ${level}`);
|
|
341
|
+
const guid = settings.guid;
|
|
342
|
+
const lodPath = createMeshLod(doc, outputDirectory, level, mesh, guid, lod);
|
|
343
|
+
generatedLODs.push(lodPath);
|
|
344
|
+
}
|
|
334
345
|
}
|
|
335
346
|
for (const prim of mesh.listPrimitives()) {
|
|
336
347
|
const lastLod = LODS[LODS.length - 1];
|
|
337
|
-
|
|
348
|
+
console.log(`${NAME}: ${filename} LOD ${LODS.length - 1}`);
|
|
349
|
+
simplifyMesh(doc, mesh, prim, lastLod);
|
|
338
350
|
}
|
|
351
|
+
const model = progressiveExt.create({
|
|
352
|
+
guid: settings.guid,
|
|
353
|
+
uri: generatedLODs.map(l => l),
|
|
354
|
+
});
|
|
355
|
+
mesh.setExtension(NEEDLE_PROGRESSIVE_EXTENSION_NAME, model);
|
|
339
356
|
index++;
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
}));
|
|
357
|
+
if (!visited.has(settings.guid)) {
|
|
358
|
+
visited.set(settings.guid, {
|
|
359
|
+
model: model,
|
|
360
|
+
paths: generatedLODs,
|
|
361
|
+
});
|
|
362
|
+
}
|
|
347
363
|
}
|
|
364
|
+
console.log("< Progressive Mesh Transform: finished");
|
|
348
365
|
});
|
|
349
366
|
}
|
|
350
367
|
/**
|
|
@@ -354,7 +371,7 @@ export function make_progressive_meshes(filePath, _options, opts) {
|
|
|
354
371
|
* @param guid a unique identifier for the mesh
|
|
355
372
|
* @param error the error to use for simplification. Higher means more simplification
|
|
356
373
|
*/
|
|
357
|
-
function createMeshLod(doc, basePath, level, mesh, guid,
|
|
374
|
+
function createMeshLod(doc, basePath, level, mesh, guid, lodLevel) {
|
|
358
375
|
const newDoc = new Document();
|
|
359
376
|
const newScene = newDoc.createScene();
|
|
360
377
|
newDoc.createBuffer();
|
|
@@ -399,9 +416,9 @@ function createMeshLod(doc, basePath, level, mesh, guid, error) {
|
|
|
399
416
|
newPrim.setExtension(name, copy);
|
|
400
417
|
}
|
|
401
418
|
}
|
|
402
|
-
if (error
|
|
419
|
+
if (lodLevel.error != undefined || lodLevel.ratio != undefined) {
|
|
403
420
|
for (const prim of newMesh.listPrimitives()) {
|
|
404
|
-
simplifyMesh(newDoc, newMesh, prim,
|
|
421
|
+
simplifyMesh(newDoc, newMesh, prim, lodLevel);
|
|
405
422
|
}
|
|
406
423
|
}
|
|
407
424
|
const progressiveExt = newDoc.createExtension(NEEDLE_progressive);
|
|
@@ -427,11 +444,11 @@ function createMeshLod(doc, basePath, level, mesh, guid, error) {
|
|
|
427
444
|
const name = "mesh_lod_" + level + "_" + guid;
|
|
428
445
|
const filename = name + ext;
|
|
429
446
|
const outName = basePath + filename;
|
|
430
|
-
console.log(`${NAME}: Write mesh LOD ${level} to \"${filename}\" with
|
|
447
|
+
console.log(`${NAME}: Write mesh LOD ${level} to \"${filename}\" with: ${JSON.stringify(lodLevel)}`);
|
|
431
448
|
newIo.write(outName, newDoc);
|
|
432
449
|
return filename;
|
|
433
450
|
}
|
|
434
|
-
function simplifyMesh(doc, mesh, prim,
|
|
451
|
+
function simplifyMesh(doc, mesh, prim, lodinfo) {
|
|
435
452
|
const weldOptions = {
|
|
436
453
|
...WELD_DEFAULTS,
|
|
437
454
|
overwrite: true,
|
|
@@ -439,8 +456,10 @@ function simplifyMesh(doc, mesh, prim, error) {
|
|
|
439
456
|
const simplifyOptions = {
|
|
440
457
|
...SIMPLIFY_DEFAULTS, simplifier: MeshoptSimplifier,
|
|
441
458
|
};
|
|
442
|
-
if (error != undefined)
|
|
443
|
-
simplifyOptions.error = error;
|
|
459
|
+
if (lodinfo.error != undefined)
|
|
460
|
+
simplifyOptions.error = lodinfo.error;
|
|
461
|
+
if (lodinfo.ratio != undefined)
|
|
462
|
+
simplifyOptions.ratio = lodinfo.ratio;
|
|
444
463
|
compressPrimitive(doc, mesh, prim, weldOptions, simplifyOptions);
|
|
445
464
|
}
|
|
446
465
|
function isMeshLOD(filepath) {
|
package/dist/utils/fileutils.js
CHANGED
|
@@ -62,7 +62,7 @@ async function testEntry(entry, callback, context) {
|
|
|
62
62
|
// Try resolve potential relative path
|
|
63
63
|
const newPath = context.baseDirectory + "/" + entry;
|
|
64
64
|
if (existsSync(newPath) === false) {
|
|
65
|
-
console.log(`INFO: Resolved path failed: ${entry} -> ${newPath}`);
|
|
65
|
+
console.log(`INFO: Resolved path failed: ${entry} -> ${newPath} (doesnt exist or is locked by another process)`);
|
|
66
66
|
return;
|
|
67
67
|
}
|
|
68
68
|
else {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@needle-tools/gltf-build-pipeline",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.1-beta.1",
|
|
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",
|
|
@@ -16,9 +16,9 @@
|
|
|
16
16
|
"compile": "tsc || exit 1"
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@gltf-transform/core": "^3.
|
|
20
|
-
"@gltf-transform/extensions": "^3.
|
|
21
|
-
"@gltf-transform/functions": "^3.
|
|
19
|
+
"@gltf-transform/core": "^3.10.0",
|
|
20
|
+
"@gltf-transform/extensions": "^3.10.0",
|
|
21
|
+
"@gltf-transform/functions": "^3.10.0",
|
|
22
22
|
"command-exists": "^1.2.9",
|
|
23
23
|
"command-line-args": "^5.2.1",
|
|
24
24
|
"draco3dgltf": "^1.5.3",
|