@needle-tools/gltf-build-pipeline 2.2.0-alpha.4 → 2.2.0-alpha.6
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 +5 -1
- package/dist/cache/cache.js +3 -1
- package/dist/cli/index.js +4 -2
- package/dist/transforms/needle_progressive.d.ts +1 -1
- package/dist/transforms/needle_progressive.js +17 -5
- package/dist/transforms/needle_texture_transform.js +7 -3
- package/dist/transforms/needle_toktx.js +2 -2
- package/dist/transforms/toktx.d.ts +1 -0
- package/dist/transforms/toktx.js +2 -2
- package/dist/utils/mesh.d.ts +6 -1
- package/dist/utils/mesh.js +15 -9
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,7 +4,10 @@ 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
|
-
## [2.2.0-alpha.
|
|
7
|
+
## [2.2.0-alpha.6] - 2023-06-13
|
|
8
|
+
- fix: progressive transform of converted GLB files where meshes don't have indicies
|
|
9
|
+
|
|
10
|
+
## [2.2.0-alpha.5] - 2023-06-06
|
|
8
11
|
- add: CLI `--progressive` option to `transform` command (default is true)
|
|
9
12
|
- add: CLI `--compress` option to `transform` command (default is true)
|
|
10
13
|
- add: config `meshes: { lods: boolean }` option
|
|
@@ -12,6 +15,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|
|
12
15
|
- change: enable texture LODs by default
|
|
13
16
|
- fix: `--config` path can now point to a directory or a `needle.config.json` file as well
|
|
14
17
|
- fix: mesh LOD regression caused by change in gltf-transform `weld` behaviour
|
|
18
|
+
- fix: KTX SOFTWARE >= 4.3.0 is installed
|
|
15
19
|
|
|
16
20
|
## [2.1.0-alpha.6] - 2023-06-04
|
|
17
21
|
- fix: errors when invoking npm scripts caused by the cli program
|
package/dist/cache/cache.js
CHANGED
|
@@ -19,6 +19,7 @@ import { getVersion } from "../utils/version.js";
|
|
|
19
19
|
// return 0;
|
|
20
20
|
// }
|
|
21
21
|
const buildPipelineVersion = getVersion(false);
|
|
22
|
+
const debugLogs = process.argv.includes("--debug");
|
|
22
23
|
/**
|
|
23
24
|
* Clear the cache.
|
|
24
25
|
* This will remove all files in the cache directory.
|
|
@@ -86,7 +87,8 @@ export function limitCacheSize(maxSizeMB = cacheSizeLimit) {
|
|
|
86
87
|
export function addToCache(key, bytes) {
|
|
87
88
|
const dir = getCacheDirectory();
|
|
88
89
|
const path = `${dir}/${key}.bin`;
|
|
89
|
-
|
|
90
|
+
if (debugLogs)
|
|
91
|
+
console.log(`Added ${(bytes.byteLength / 1024).toFixed(1)} KB to cache at \"${path}\"`);
|
|
90
92
|
fs.writeFileSync(path, bytes);
|
|
91
93
|
}
|
|
92
94
|
/**
|
package/dist/cli/index.js
CHANGED
|
@@ -77,7 +77,7 @@ Each version will be compressed and written to the output directory.
|
|
|
77
77
|
logger.info("→ Transform " + file);
|
|
78
78
|
const progressive_results = new Array();
|
|
79
79
|
if (options.progressive === true) {
|
|
80
|
-
await make_progressive({
|
|
80
|
+
if (await make_progressive({
|
|
81
81
|
path: file,
|
|
82
82
|
results: progressive_results,
|
|
83
83
|
config,
|
|
@@ -86,7 +86,9 @@ Each version will be compressed and written to the output directory.
|
|
|
86
86
|
}).catch(err => {
|
|
87
87
|
logger.error(err);
|
|
88
88
|
process.exit(ERROR_CODES.PROGRESSIVE_FAILED);
|
|
89
|
-
})
|
|
89
|
+
}) === false) {
|
|
90
|
+
process.exit(ERROR_CODES.PROGRESSIVE_FAILED);
|
|
91
|
+
}
|
|
90
92
|
}
|
|
91
93
|
if (options.compress === true) {
|
|
92
94
|
const opts = {
|
|
@@ -7,7 +7,7 @@ declare interface ProgressiveOptions {
|
|
|
7
7
|
debug?: boolean;
|
|
8
8
|
useCache?: boolean;
|
|
9
9
|
}
|
|
10
|
-
export declare function make_progressive(opts: ProgressiveOptions): Promise<
|
|
10
|
+
export declare function make_progressive(opts: ProgressiveOptions): Promise<boolean>;
|
|
11
11
|
export declare function createTransform(name: string, fn: Transform): Transform;
|
|
12
12
|
export declare function make_progressive_textures(filePath: string, _options: TextureResizeOptions, opts: ProgressiveOptions): Transform;
|
|
13
13
|
/** Options for the {@link textureResize} function. */
|
|
@@ -14,14 +14,22 @@ import { compressPrimitive } from './needle_mesh_transform.js';
|
|
|
14
14
|
import { calculateMeshDensity, getMeshInformation } from "../utils/mesh.js";
|
|
15
15
|
export async function make_progressive(opts) {
|
|
16
16
|
const file = opts.path;
|
|
17
|
-
|
|
17
|
+
let success = true;
|
|
18
|
+
await foreachGLTF(file, async (f) => {
|
|
19
|
+
// Should we stop if one file fails?
|
|
20
|
+
if (!success) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
18
23
|
// Don't re-process files that are already LODs
|
|
19
24
|
if (isMeshLOD(f) || isImageLOD(f)) {
|
|
20
25
|
console.log(`Progressive Transform: Ignore existing LOD file at ${f}`);
|
|
21
26
|
return;
|
|
22
27
|
}
|
|
23
|
-
await onProcess(f, opts);
|
|
28
|
+
const res = await onProcess(f, opts);
|
|
29
|
+
if (!res)
|
|
30
|
+
success = false;
|
|
24
31
|
});
|
|
32
|
+
return success;
|
|
25
33
|
}
|
|
26
34
|
function registerExtensions(io) {
|
|
27
35
|
registerDefaultExtensions(io);
|
|
@@ -39,10 +47,11 @@ function registerExtensions(io) {
|
|
|
39
47
|
async function onProcess(file, opts) {
|
|
40
48
|
if (!file.endsWith(".glb") && !file.endsWith(".gltf") && !file.endsWith(".vrm")) {
|
|
41
49
|
console.log("ERR: file is not gltf/glb");
|
|
42
|
-
return;
|
|
50
|
+
return false;
|
|
43
51
|
}
|
|
44
52
|
if (!existsSync(file)) {
|
|
45
53
|
console.log("ERR: file does not exist: " + file);
|
|
54
|
+
return false;
|
|
46
55
|
}
|
|
47
56
|
try {
|
|
48
57
|
const io = new NodeIO();
|
|
@@ -85,7 +94,9 @@ async function onProcess(file, opts) {
|
|
|
85
94
|
}
|
|
86
95
|
catch (err) {
|
|
87
96
|
console.log("ERR: failed to process file \"" + file + "\", Reason: " + err.message, "\nStack:\n" + err.stack);
|
|
97
|
+
return false;
|
|
88
98
|
}
|
|
99
|
+
return true;
|
|
89
100
|
}
|
|
90
101
|
// basic idea:
|
|
91
102
|
// 1. iterate all images that have an extension marking them to be progressively loaded
|
|
@@ -688,7 +699,8 @@ function clonePrimitiveData(prim, logger) {
|
|
|
688
699
|
if (semantics.some(s => s.includes("JOINTS"))) {
|
|
689
700
|
return null;
|
|
690
701
|
}
|
|
691
|
-
const
|
|
702
|
+
const prevIndices = prim.getIndices();
|
|
703
|
+
const indices = !prevIndices ? null : new Uint32Array(prevIndices.getArray());
|
|
692
704
|
const attributes = {};
|
|
693
705
|
for (const attr of semantics) {
|
|
694
706
|
logger.info(`[${NAME}] Clone attribute ${attr}`);
|
|
@@ -753,7 +765,7 @@ async function createMeshLod(doc, basePath, level, mesh, meshInfo, guid, lodLeve
|
|
|
753
765
|
newNode.setName("LOD " + level + "_" + guid);
|
|
754
766
|
newNode.setTranslation([0, 0, 0]);
|
|
755
767
|
const newMesh = newDoc.createMesh();
|
|
756
|
-
newMesh.setName(mesh.getName() + " LOD " + level);
|
|
768
|
+
newMesh.setName((mesh.getName() || "Unnamed") + " LOD " + level);
|
|
757
769
|
newNode.setMesh(newMesh);
|
|
758
770
|
const newMat = newDoc.createMaterial();
|
|
759
771
|
const weights = mesh.getWeights();
|
|
@@ -39,8 +39,12 @@ export const needle_texture_transform = function (options) {
|
|
|
39
39
|
};
|
|
40
40
|
return createTransform("needle_texture_transform", async (document) => {
|
|
41
41
|
await webPContext.prepare(document);
|
|
42
|
-
if (context.noToktx !== true)
|
|
43
|
-
await toktxContext.prepare(document);
|
|
42
|
+
if (context.noToktx !== true) {
|
|
43
|
+
const validToktx = await toktxContext.prepare(document);
|
|
44
|
+
if (!validToktx) {
|
|
45
|
+
context.noToktx = true;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
44
48
|
try {
|
|
45
49
|
const logger = document.getLogger();
|
|
46
50
|
const textures = document.getRoot().listTextures();
|
|
@@ -168,7 +172,7 @@ async function processTexture(texture, index, document, logger, context) {
|
|
|
168
172
|
successFullyProcessed = await context.toktxContext.process(index, texture, options, context);
|
|
169
173
|
}
|
|
170
174
|
else {
|
|
171
|
-
console.log("Toktx not found: Skipping texture compression
|
|
175
|
+
console.log("Toktx not found: Skipping texture compression: " + originalMimeType);
|
|
172
176
|
}
|
|
173
177
|
}
|
|
174
178
|
if (context.useCache && successFullyProcessed && key) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { BufferUtils, FileUtils, ImageUtils, uuid } from "@gltf-transform/core";
|
|
2
2
|
import { listTextureSlots, getTextureChannelMask, fitPowerOfTwo, TextureResizeFilter } from "@gltf-transform/functions";
|
|
3
3
|
import { KHRTextureBasisu } from "@gltf-transform/extensions";
|
|
4
|
-
import { checkKTXSoftware, createParams, Mode } from "./toktx.js";
|
|
4
|
+
import { checkKTXSoftware, createParams, KTX_SOFTWARE_VERSION_MIN, Mode } from "./toktx.js";
|
|
5
5
|
import { existsSync, mkdirSync } from "fs";
|
|
6
6
|
import { formatBytes, spawn, waitExit } from './util.js';
|
|
7
7
|
import { ETC1S_DEFAULTS, UASTC_DEFAULTS } from "./toktx_types.js";
|
|
@@ -70,7 +70,7 @@ export class NeedleToktxContext {
|
|
|
70
70
|
const logger = document.getLogger();
|
|
71
71
|
this.version = await checkKTXSoftware(logger, this.env);
|
|
72
72
|
if (this.version === null) {
|
|
73
|
-
|
|
73
|
+
logger.warn(`WARN: toktx not found, skipping texture compression. Please install KTX-Software >= ${KTX_SOFTWARE_VERSION_MIN}`);
|
|
74
74
|
this._prepareFailed = true;
|
|
75
75
|
return false;
|
|
76
76
|
}
|
package/dist/transforms/toktx.js
CHANGED
|
@@ -10,8 +10,7 @@ import { TextureResizeFilter, getTextureColorSpace } from '@gltf-transform/funct
|
|
|
10
10
|
import { ETC1S_DEFAULTS, UASTC_DEFAULTS } from './toktx_types.js';
|
|
11
11
|
tmp.setGracefulCleanup();
|
|
12
12
|
const NUM_CPUS = os.cpus().length || 1; // microsoft/vscode#112122
|
|
13
|
-
const KTX_SOFTWARE_VERSION_MIN = '4.
|
|
14
|
-
const KTX_SOFTWARE_VERSION_ACTIVE = '4.1.0-rc1';
|
|
13
|
+
export const KTX_SOFTWARE_VERSION_MIN = '4.3.0';
|
|
15
14
|
export const Filter = {
|
|
16
15
|
BOX: 'box',
|
|
17
16
|
TENT: 'tent',
|
|
@@ -167,6 +166,7 @@ export async function checkKTXSoftware(logger, env) {
|
|
|
167
166
|
}
|
|
168
167
|
else if (semver.lt(semver.clean(version), KTX_SOFTWARE_VERSION_MIN)) {
|
|
169
168
|
logger.warn(`toktx: Expected KTX-Software >= v${KTX_SOFTWARE_VERSION_MIN}, found ${version}.`);
|
|
169
|
+
return null;
|
|
170
170
|
}
|
|
171
171
|
else {
|
|
172
172
|
if (!didLogToktxVersion)
|
package/dist/utils/mesh.d.ts
CHANGED
|
@@ -5,4 +5,9 @@ export declare type MeshInformation = {
|
|
|
5
5
|
readonly totalIndexCount: number;
|
|
6
6
|
};
|
|
7
7
|
export declare function getMeshInformation(mesh: Mesh): MeshInformation;
|
|
8
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Calculate the density of a mesh.
|
|
10
|
+
* @param prim - The primitive to calculate the density for.
|
|
11
|
+
* @returns The density of the mesh or -1 if the mesh is not indexed.
|
|
12
|
+
*/
|
|
13
|
+
export declare function calculateMeshDensity(prim: Primitive): number | -1;
|
package/dist/utils/mesh.js
CHANGED
|
@@ -14,6 +14,11 @@ export function getMeshInformation(mesh) {
|
|
|
14
14
|
totalIndexCount,
|
|
15
15
|
};
|
|
16
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* Calculate the density of a mesh.
|
|
19
|
+
* @param prim - The primitive to calculate the density for.
|
|
20
|
+
* @returns The density of the mesh or -1 if the mesh is not indexed.
|
|
21
|
+
*/
|
|
17
22
|
export function calculateMeshDensity(prim) {
|
|
18
23
|
const bounds = {
|
|
19
24
|
min: [Infinity, Infinity, Infinity],
|
|
@@ -71,16 +76,17 @@ export function calculateMeshDensity(prim) {
|
|
|
71
76
|
// Add the area (half the magnitude of the cross product) to the total
|
|
72
77
|
area += Math.sqrt(cross[0] * cross[0] + cross[1] * cross[1] + cross[2] * cross[2]) / 2;
|
|
73
78
|
}
|
|
79
|
+
const count = indices.getCount() / 3;
|
|
80
|
+
const density = count / area;
|
|
81
|
+
// const size = [0, 0, 0] as vec3;
|
|
82
|
+
// size[0] = bounds.max[0] - bounds.min[0];
|
|
83
|
+
// size[1] = bounds.max[1] - bounds.min[1];
|
|
84
|
+
// size[2] = bounds.max[2] - bounds.min[2];
|
|
85
|
+
// const volume = size[0] * size[1] * size[2];
|
|
86
|
+
// const density = count / volume;
|
|
87
|
+
return density;
|
|
74
88
|
}
|
|
75
|
-
|
|
76
|
-
const density = count / area;
|
|
77
|
-
// const size = [0, 0, 0] as vec3;
|
|
78
|
-
// size[0] = bounds.max[0] - bounds.min[0];
|
|
79
|
-
// size[1] = bounds.max[1] - bounds.min[1];
|
|
80
|
-
// size[2] = bounds.max[2] - bounds.min[2];
|
|
81
|
-
// const volume = size[0] * size[1] * size[2];
|
|
82
|
-
// const density = count / volume;
|
|
83
|
-
return density;
|
|
89
|
+
return -1;
|
|
84
90
|
function expandBounds(point, target) {
|
|
85
91
|
for (let i = 0; i < 3; i++) {
|
|
86
92
|
target.min[i] = Math.min(point[i], target.min[i]);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@needle-tools/gltf-build-pipeline",
|
|
3
|
-
"version": "2.2.0-alpha.
|
|
3
|
+
"version": "2.2.0-alpha.6",
|
|
4
4
|
"description": "Pipeline and tools for optimizing gltf files using gltf-transform and compression settings within glTF extensions",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|