@needle-tools/gltf-build-pipeline 2.1.0-alpha.6 → 2.2.0-alpha.10
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 +17 -0
- package/dist/{src/cache → cache}/cache.js +3 -1
- package/dist/cli/index.js +127 -0
- package/dist/{src/config → config}/index.d.ts +8 -2
- package/dist/{src/config → config}/index.js +31 -15
- package/dist/{src/extensions → extensions}/NEEDLE_mesh_compression/NEEDLE_mesh_compression.js +1 -1
- package/dist/functions/weld.3.d.ts +76 -0
- package/dist/functions/weld.3.js +414 -0
- package/dist/{src/transforms → transforms}/needle_mesh_transform.js +4 -2
- package/dist/{src/transforms → transforms}/needle_progressive.d.ts +1 -1
- package/dist/{src/transforms → transforms}/needle_progressive.js +73 -55
- package/dist/{src/transforms → transforms}/needle_texture_transform.js +7 -3
- package/dist/{src/transforms → transforms}/needle_toktx.js +3 -3
- package/dist/{src/transforms → transforms}/toktx.d.ts +2 -1
- package/dist/{src/transforms → transforms}/toktx.js +4 -8
- package/dist/transforms/toktx_types.d.ts +78 -0
- package/dist/transforms/toktx_types.js +62 -0
- package/dist/{src/utils → utils}/mesh.d.ts +6 -1
- package/dist/{src/utils → utils}/mesh.js +26 -9
- package/dist/{src/utils → utils}/stats.js +1 -1
- package/dist/{src/utils → utils}/version.js +1 -1
- package/package.json +10 -9
- package/scripts/clear-caches.mjs +1 -1
- package/scripts/defaults.mjs +2 -2
- package/scripts/fileutils.mjs +1 -1
- package/scripts/index.mjs +1 -1
- package/scripts/limit-caches.mjs +1 -1
- package/scripts/make-progressive.mjs +2 -2
- package/scripts/pack-gltf.mjs +2 -2
- package/tsconfig.json +7 -3
- package/dist/___config.json +0 -3
- package/dist/package.json +0 -75
- package/dist/src/cli/index.js +0 -192
- /package/dist/{src/cache → cache}/cache.d.ts +0 -0
- /package/dist/{src/cache → cache}/index.d.ts +0 -0
- /package/dist/{src/cache → cache}/index.js +0 -0
- /package/dist/{src/cli → cli}/index.d.ts +0 -0
- /package/dist/{src/constants.d.ts → constants.d.ts} +0 -0
- /package/dist/{src/constants.js → constants.js} +0 -0
- /package/dist/{src/extensions → extensions}/NEEDLE_compression_texture/NEEDLE_compression_texture.d.ts +0 -0
- /package/dist/{src/extensions → extensions}/NEEDLE_compression_texture/NEEDLE_compression_texture.js +0 -0
- /package/dist/{src/extensions → extensions}/NEEDLE_compression_texture/index.d.ts +0 -0
- /package/dist/{src/extensions → extensions}/NEEDLE_compression_texture/index.js +0 -0
- /package/dist/{src/extensions → extensions}/NEEDLE_mesh_compression/NEEDLE_mesh_compression.d.ts +0 -0
- /package/dist/{src/extensions → extensions}/NEEDLE_mesh_compression/index.d.ts +0 -0
- /package/dist/{src/extensions → extensions}/NEEDLE_mesh_compression/index.js +0 -0
- /package/dist/{src/extensions → extensions}/NEEDLE_opaque/NEEDLE_opaque.d.ts +0 -0
- /package/dist/{src/extensions → extensions}/NEEDLE_opaque/NEEDLE_opaque.js +0 -0
- /package/dist/{src/extensions → extensions}/NEEDLE_opaque/index.d.ts +0 -0
- /package/dist/{src/extensions → extensions}/NEEDLE_opaque/index.js +0 -0
- /package/dist/{src/extensions → extensions}/NEEDLE_progressive/NEEDLE_progressive.d.ts +0 -0
- /package/dist/{src/extensions → extensions}/NEEDLE_progressive/NEEDLE_progressive.js +0 -0
- /package/dist/{src/extensions → extensions}/NEEDLE_progressive/index.d.ts +0 -0
- /package/dist/{src/extensions → extensions}/NEEDLE_progressive/index.js +0 -0
- /package/dist/{src/extensions → extensions}/NEEDLE_progressive_mesh_settings/index.d.ts +0 -0
- /package/dist/{src/extensions → extensions}/NEEDLE_progressive_mesh_settings/index.js +0 -0
- /package/dist/{src/extensions → extensions}/NEEDLE_progressive_texture_settings/index.d.ts +0 -0
- /package/dist/{src/extensions → extensions}/NEEDLE_progressive_texture_settings/index.js +0 -0
- /package/dist/{src/extensions → extensions}/index.d.ts +0 -0
- /package/dist/{src/extensions → extensions}/index.js +0 -0
- /package/dist/{src/extensions → extensions}/utils.d.ts +0 -0
- /package/dist/{src/extensions → extensions}/utils.js +0 -0
- /package/dist/{src/index.d.ts → index.d.ts} +0 -0
- /package/dist/{src/index.js → index.js} +0 -0
- /package/dist/{src/scripts → scripts}/index.d.ts +0 -0
- /package/dist/{src/scripts → scripts}/index.js +0 -0
- /package/dist/{src/scripts → scripts}/pack-gltf.d.ts +0 -0
- /package/dist/{src/scripts → scripts}/pack-gltf.js +0 -0
- /package/dist/{src/transforms → transforms}/index.d.ts +0 -0
- /package/dist/{src/transforms → transforms}/index.js +0 -0
- /package/dist/{src/transforms → transforms}/needle_animation_transform.d.ts +0 -0
- /package/dist/{src/transforms → transforms}/needle_animation_transform.js +0 -0
- /package/dist/{src/transforms → transforms}/needle_asset.d.ts +0 -0
- /package/dist/{src/transforms → transforms}/needle_asset.js +0 -0
- /package/dist/{src/transforms → transforms}/needle_common.d.ts +0 -0
- /package/dist/{src/transforms → transforms}/needle_common.js +0 -0
- /package/dist/{src/transforms → transforms}/needle_mesh_transform.d.ts +0 -0
- /package/dist/{src/transforms → transforms}/needle_texture_transform.d.ts +0 -0
- /package/dist/{src/transforms → transforms}/needle_toktx.d.ts +0 -0
- /package/dist/{src/transforms → transforms}/needle_webp.d.ts +0 -0
- /package/dist/{src/transforms → transforms}/needle_webp.js +0 -0
- /package/dist/{src/transforms → transforms}/util.d.ts +0 -0
- /package/dist/{src/transforms → transforms}/util.js +0 -0
- /package/dist/{src/utils → utils}/compression_utils.d.ts +0 -0
- /package/dist/{src/utils → utils}/compression_utils.js +0 -0
- /package/dist/{src/utils → utils}/fileutils.d.ts +0 -0
- /package/dist/{src/utils → utils}/fileutils.js +0 -0
- /package/dist/{src/utils → utils}/guid.d.ts +0 -0
- /package/dist/{src/utils → utils}/guid.js +0 -0
- /package/dist/{src/utils → utils}/index.d.ts +0 -0
- /package/dist/{src/utils → utils}/index.js +0 -0
- /package/dist/{src/utils → utils}/nodeio.d.ts +0 -0
- /package/dist/{src/utils → utils}/nodeio.js +0 -0
- /package/dist/{src/utils → utils}/stats.d.ts +0 -0
- /package/dist/{src/utils → utils}/texture.d.ts +0 -0
- /package/dist/{src/utils → utils}/texture.js +0 -0
- /package/dist/{src/utils → utils}/version.d.ts +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,23 @@ 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.10] - 2023-06-13
|
|
8
|
+
- fix: progressive transform of converted GLB files where meshes don't have indicies
|
|
9
|
+
- fix: skip progressive texture generation for textures for textures that already match the lowest LOD size
|
|
10
|
+
- fix: if compression is set to None the LOD textures should respect that setting and also not be compressed
|
|
11
|
+
- fix: fallback mesh density calculation for meshes that aren't indexed
|
|
12
|
+
- fix: NEEDLE_mesh_compression extension falsely overriding primitive extensions
|
|
13
|
+
|
|
14
|
+
## [2.2.0-alpha.5] - 2023-06-06
|
|
15
|
+
- add: CLI `--progressive` option to `transform` command (default is true)
|
|
16
|
+
- add: CLI `--compress` option to `transform` command (default is true)
|
|
17
|
+
- add: config `meshes: { lods: boolean }` option
|
|
18
|
+
- remove: CLI "compress" command
|
|
19
|
+
- change: enable texture LODs by default
|
|
20
|
+
- fix: `--config` path can now point to a directory or a `needle.config.json` file as well
|
|
21
|
+
- fix: mesh LOD regression caused by change in gltf-transform `weld` behaviour
|
|
22
|
+
- fix: KTX SOFTWARE >= 4.3.0 is installed
|
|
23
|
+
|
|
7
24
|
## [2.1.0-alpha.6] - 2023-06-04
|
|
8
25
|
- fix: errors when invoking npm scripts caused by the cli program
|
|
9
26
|
- fix: remove cache directory error
|
|
@@ -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
|
/**
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
#! /usr/bin/env node
|
|
2
|
+
import { program } from '@donmccurdy/caporal';
|
|
3
|
+
import { packGLTF } from "../scripts/index.js";
|
|
4
|
+
import { printStats, writeFileStatsToFile } from '../utils/stats.js';
|
|
5
|
+
import { getVersion } from '../utils/version.js';
|
|
6
|
+
import { UsecaseOptions, createConfig, getConfig } from '../config/index.js';
|
|
7
|
+
import { make_progressive } from '../transforms/needle_progressive.js';
|
|
8
|
+
import { cacheSizeLimit, clearCache } from '../cache/cache.js';
|
|
9
|
+
import { statSync } from 'fs';
|
|
10
|
+
import { foreachGLTF, getDirName } from '../utils/fileutils.js';
|
|
11
|
+
import path, { dirname } from 'path';
|
|
12
|
+
import { ERROR_CODES } from '../constants.js';
|
|
13
|
+
// For testing / dev you can run `npm link` in the package directory
|
|
14
|
+
// For removing the link run `npm rm --global @needle-tools/gltf-build-pipeline`
|
|
15
|
+
program
|
|
16
|
+
.command("version", "Print current verison")
|
|
17
|
+
.action(async ({ logger }) => {
|
|
18
|
+
logger.info(getVersion());
|
|
19
|
+
})
|
|
20
|
+
.command("clear-caches", "Clear all caches")
|
|
21
|
+
.help(`Clears all cached files
|
|
22
|
+
Caches are limited to ${cacheSizeLimit} MB disc space by default.
|
|
23
|
+
`)
|
|
24
|
+
.action(async ({ logger }) => {
|
|
25
|
+
logger.info("Clearing caches");
|
|
26
|
+
clearCache(logger);
|
|
27
|
+
})
|
|
28
|
+
.command("transform", "Transform (progressive loading) and compress glTF, GLB or VRM files")
|
|
29
|
+
.help(`
|
|
30
|
+
This will produce multiple versions of the input file, each with a different level of optimization.
|
|
31
|
+
Each version will be compressed and written to the output directory.
|
|
32
|
+
`)
|
|
33
|
+
.argument('<input>', "The input glTF, GLB or VRM file that should be compressed OR a directory that contains files to be compressed")
|
|
34
|
+
// .argument('<output>', "The output file. If not provided, the input file will be overwritten.", { default: "" })
|
|
35
|
+
.option("--compress", `When enabled files will be compressed`, { validator: program.BOOLEAN, default: true })
|
|
36
|
+
.option("--progressive", `When enabled files will processed to be progressively loaded`, { validator: program.BOOLEAN, default: true })
|
|
37
|
+
.option("--usecase <usecase>", `The usecase for the compression. This will set the compression settings. Possible options: [${UsecaseOptions.join(", ")}]`, { validator: program.STRING })
|
|
38
|
+
.option("--config <config>", "The path to a JSON file containing the compression settings. This can also be a needle.config.json file with a \"compression\" object or usecase string.", { validator: program.STRING })
|
|
39
|
+
.option("--stats", "Output a stats file next to input file (or inside the input directory). It will be named as the input file/directory \"<input>.needle.stats.json\"", { validator: program.BOOLEAN, default: false })
|
|
40
|
+
.option("--cache", "Use \"--cache False\" to disable caching.\nWhen caching is enabled then previously processed files will be detected and loaded from disc cache instead of being processed again if settings or the file contents have not changed.", { validator: program.BOOLEAN, default: true })
|
|
41
|
+
.option("--debug", "Enable for more verbose outout with \"--debug True\"", { validator: program.BOOLEAN, default: false })
|
|
42
|
+
.action(async ({ logger, args, options }) => {
|
|
43
|
+
if (options.compress === false && options.progressive === false) {
|
|
44
|
+
logger.error("You need to enable at least one of the options: --compress or --progressive");
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
logger.info("Transforming glTF file: " + args.input);
|
|
48
|
+
const stats = {
|
|
49
|
+
startTime: Date.now(),
|
|
50
|
+
totalGPUMemoryInMB: 0,
|
|
51
|
+
totalFilesProcessed: 0,
|
|
52
|
+
totalFileSizeInMB: 0,
|
|
53
|
+
totalFileSizeInMBBefore: 0,
|
|
54
|
+
};
|
|
55
|
+
const file = args.input.toString();
|
|
56
|
+
let config = getConfig(options.config?.toString(), file, {
|
|
57
|
+
logger
|
|
58
|
+
});
|
|
59
|
+
if (options.usecase) {
|
|
60
|
+
logger.info("Using usecase: " + options.usecase);
|
|
61
|
+
config = { ...createConfig(options.usecase.toString()), ...config, };
|
|
62
|
+
if (config.usecase != "default" && config.usecase != options.usecase.toString()) {
|
|
63
|
+
logger.warn(`Conflicting usecase. Your specific config at \"${options.config}\" has a different usecase than the one provided by the CLI: \"${options.usecase}\". Using the usecase from the config file.`);
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
config.usecase = options.usecase.toString();
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
const output = options.output?.toString() || file;
|
|
70
|
+
const outputIsDirectory = statSync(output).isDirectory();
|
|
71
|
+
const outDir = outputIsDirectory ? output : dirname(output);
|
|
72
|
+
const file_stats = [];
|
|
73
|
+
const set = new Set();
|
|
74
|
+
const useCache = options.cache !== false;
|
|
75
|
+
const debug = options.debug === true;
|
|
76
|
+
await foreachGLTF(file, async (file) => {
|
|
77
|
+
logger.info("→ Transform " + file);
|
|
78
|
+
const progressive_results = new Array();
|
|
79
|
+
if (options.progressive === true) {
|
|
80
|
+
if (await make_progressive({
|
|
81
|
+
path: file,
|
|
82
|
+
results: progressive_results,
|
|
83
|
+
config,
|
|
84
|
+
debug,
|
|
85
|
+
useCache,
|
|
86
|
+
}).catch(err => {
|
|
87
|
+
logger.error(err);
|
|
88
|
+
process.exit(ERROR_CODES.PROGRESSIVE_FAILED);
|
|
89
|
+
}) === false) {
|
|
90
|
+
process.exit(ERROR_CODES.PROGRESSIVE_FAILED);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
if (options.compress === true) {
|
|
94
|
+
const opts = {
|
|
95
|
+
config,
|
|
96
|
+
stats,
|
|
97
|
+
packedFiles: set,
|
|
98
|
+
debug,
|
|
99
|
+
useCache,
|
|
100
|
+
logger: logger,
|
|
101
|
+
file_stats,
|
|
102
|
+
};
|
|
103
|
+
for (const res of progressive_results) {
|
|
104
|
+
if (await packGLTF(res, res, opts) === false) {
|
|
105
|
+
process.exit(ERROR_CODES.PACKING_FAILED);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (await packGLTF(file, file, opts) === false) {
|
|
109
|
+
process.exit(ERROR_CODES.PACKING_FAILED);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
printStats(stats, logger, config);
|
|
114
|
+
if (options.stats) {
|
|
115
|
+
const statsFile = (outputIsDirectory ? (path.join(file, getDirName(file))) : file) + ".needle.stats.json";
|
|
116
|
+
writeFileStatsToFile(config, file_stats, statsFile);
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
program.run().catch(err => {
|
|
120
|
+
// Since we still invoke this package with paths when running npm scripts we need to ignore this error
|
|
121
|
+
// We might want to move this code here into an extra package.
|
|
122
|
+
if (err.message.includes("Unknown command") && !err.message.includes("Did you mean")) {
|
|
123
|
+
// ignore
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
throw err;
|
|
127
|
+
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ILogger } from "@gltf-transform/core";
|
|
1
2
|
declare type Usecase = "default" | "product" | "world";
|
|
2
3
|
export declare const UsecaseOptions: string[];
|
|
3
4
|
/**
|
|
@@ -9,6 +10,9 @@ export type Config = {
|
|
|
9
10
|
textures?: {
|
|
10
11
|
lods: boolean;
|
|
11
12
|
};
|
|
13
|
+
meshes?: {
|
|
14
|
+
lods: boolean;
|
|
15
|
+
};
|
|
12
16
|
};
|
|
13
17
|
/**
|
|
14
18
|
* Create a config object with the given usecase.
|
|
@@ -42,6 +46,8 @@ export declare function createConfig(usecase: string): {
|
|
|
42
46
|
*
|
|
43
47
|
*
|
|
44
48
|
*/
|
|
45
|
-
export declare function getConfig(configPath?: string, fallbackSearchDirectory?: string
|
|
46
|
-
|
|
49
|
+
export declare function getConfig(configPath?: string, fallbackSearchDirectory?: string, opts?: {
|
|
50
|
+
logger: ILogger;
|
|
51
|
+
}): Config;
|
|
52
|
+
export declare function searchConfig(directory: string, logger: ILogger): Config | null;
|
|
47
53
|
export {};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { Logger, Verbosity } from "@gltf-transform/core";
|
|
1
2
|
import { existsSync, readFileSync, statSync } from "fs";
|
|
2
|
-
import path, { dirname } from "path";
|
|
3
|
+
import path, { dirname, resolve } from "path";
|
|
3
4
|
export const UsecaseOptions = ["product", "world"];
|
|
4
5
|
const defaultConfig = {
|
|
5
6
|
usecase: "default",
|
|
@@ -41,12 +42,27 @@ export function createConfig(usecase) {
|
|
|
41
42
|
*
|
|
42
43
|
*
|
|
43
44
|
*/
|
|
44
|
-
export function getConfig(configPath, fallbackSearchDirectory) {
|
|
45
|
+
export function getConfig(configPath, fallbackSearchDirectory, opts) {
|
|
46
|
+
let logger = opts?.logger;
|
|
47
|
+
if (!logger) {
|
|
48
|
+
logger = new Logger(Verbosity.WARN);
|
|
49
|
+
}
|
|
45
50
|
if (configPath != null) {
|
|
51
|
+
configPath = resolve(process.cwd(), configPath);
|
|
46
52
|
if (!existsSync(configPath)) {
|
|
47
53
|
throw new Error(`No config found at \"${configPath}\"`);
|
|
48
54
|
}
|
|
49
|
-
const
|
|
55
|
+
const isDirectory = statSync(configPath).isDirectory();
|
|
56
|
+
if (isDirectory) {
|
|
57
|
+
const res = searchConfig(configPath, logger);
|
|
58
|
+
if (res) {
|
|
59
|
+
return res;
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
throw new Error(`No config found in directory \"${configPath}\"`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const res = resolveConfig(configPath, readFileSync(configPath, "utf8"), logger);
|
|
50
66
|
if (res) {
|
|
51
67
|
return res;
|
|
52
68
|
}
|
|
@@ -60,21 +76,21 @@ export function getConfig(configPath, fallbackSearchDirectory) {
|
|
|
60
76
|
// Resolve the config once and cache it
|
|
61
77
|
// Check if a needle.config.json exists in the directory from which the script is run (or any parent directory)
|
|
62
78
|
if (fallbackSearchDirectory) {
|
|
63
|
-
const result = searchConfig(fallbackSearchDirectory);
|
|
79
|
+
const result = searchConfig(fallbackSearchDirectory, logger);
|
|
64
80
|
if (result) {
|
|
65
81
|
_cachedConfig = { ...defaultConfig, ...result };
|
|
66
|
-
|
|
82
|
+
logger.info("Using config with usecase: " + _cachedConfig.usecase);
|
|
67
83
|
}
|
|
68
84
|
}
|
|
69
85
|
// If no config was found, use the default config
|
|
70
86
|
if (!_cachedConfig) {
|
|
71
|
-
|
|
87
|
+
logger.info("No config found. Using default config.");
|
|
72
88
|
_cachedConfig = defaultConfig;
|
|
73
89
|
}
|
|
74
90
|
return _cachedConfig;
|
|
75
91
|
}
|
|
76
92
|
let _cachedConfig = undefined;
|
|
77
|
-
export function searchConfig(directory) {
|
|
93
|
+
export function searchConfig(directory, logger) {
|
|
78
94
|
if (statSync(directory).isFile()) {
|
|
79
95
|
directory = dirname(directory);
|
|
80
96
|
}
|
|
@@ -83,7 +99,7 @@ export function searchConfig(directory) {
|
|
|
83
99
|
const configPath = path.join(directory, "needle.config.json");
|
|
84
100
|
if (existsSync(configPath)) {
|
|
85
101
|
const content = readFileSync(configPath, "utf8");
|
|
86
|
-
const config = resolveConfig(configPath, content);
|
|
102
|
+
const config = resolveConfig(configPath, content, logger);
|
|
87
103
|
if (config) {
|
|
88
104
|
return config;
|
|
89
105
|
}
|
|
@@ -96,13 +112,13 @@ export function searchConfig(directory) {
|
|
|
96
112
|
}
|
|
97
113
|
return null;
|
|
98
114
|
}
|
|
99
|
-
function resolveConfig(filename, content) {
|
|
115
|
+
function resolveConfig(filename, content, logger) {
|
|
100
116
|
// Handle config being part of `needle.config.json`
|
|
101
117
|
if (filename.endsWith("needle.config.json")) {
|
|
102
118
|
try {
|
|
103
119
|
const config = JSON.parse(content);
|
|
104
120
|
if (config.gltf) {
|
|
105
|
-
|
|
121
|
+
logger.info("Found \"gltf\" config at \"" + filename + "\".");
|
|
106
122
|
// If the optimization config is a string, it's the usecase
|
|
107
123
|
if (typeof config.gltf === "string") {
|
|
108
124
|
return createConfig(config.gltf);
|
|
@@ -110,12 +126,12 @@ function resolveConfig(filename, content) {
|
|
|
110
126
|
return config.gltf;
|
|
111
127
|
}
|
|
112
128
|
else {
|
|
113
|
-
|
|
129
|
+
logger.info("No \"gltf\" config found in needle.config.json. Using default config.");
|
|
114
130
|
return null;
|
|
115
131
|
}
|
|
116
132
|
}
|
|
117
133
|
catch (err) {
|
|
118
|
-
|
|
134
|
+
logger.error(`Failed parsing config \"${err.message}\" at ${filename}`);
|
|
119
135
|
}
|
|
120
136
|
}
|
|
121
137
|
// Handle config being the content of the file
|
|
@@ -125,12 +141,12 @@ function resolveConfig(filename, content) {
|
|
|
125
141
|
}
|
|
126
142
|
catch (err) {
|
|
127
143
|
if (err instanceof Error)
|
|
128
|
-
|
|
144
|
+
logger.error(`Failed parsing config \"${err.message}\" at ${filename}`);
|
|
129
145
|
else
|
|
130
|
-
|
|
146
|
+
logger.error(`Failed parsing config \"${err}\" at ${filename}`);
|
|
131
147
|
}
|
|
132
148
|
}
|
|
133
149
|
else {
|
|
134
|
-
|
|
150
|
+
logger.error("Invalid config file format. Expected JSON object at " + filename);
|
|
135
151
|
}
|
|
136
152
|
}
|
package/dist/{src/extensions → extensions}/NEEDLE_mesh_compression/NEEDLE_mesh_compression.js
RENAMED
|
@@ -62,7 +62,7 @@ export class NEEDLE_mesh_compression extends Extension {
|
|
|
62
62
|
if (ext) {
|
|
63
63
|
const prim = meshDef.primitives[i];
|
|
64
64
|
if (prim) {
|
|
65
|
-
prim.extensions =
|
|
65
|
+
prim.extensions = prim.extensions || {};
|
|
66
66
|
prim.extensions[EXTENSION_NAME] = ext.model;
|
|
67
67
|
}
|
|
68
68
|
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { Document, Primitive, Transform } from '@gltf-transform/core';
|
|
2
|
+
/** @hidden */
|
|
3
|
+
export declare function createIndices(count: number, maxIndex?: number): Uint16Array | Uint32Array;
|
|
4
|
+
export declare function formatLong(x: number): string;
|
|
5
|
+
export declare function formatDelta(a: number, b: number, decimals?: number): string;
|
|
6
|
+
export declare function formatDeltaOp(a: number, b: number): string;
|
|
7
|
+
export declare function cleanPrimitive(prim: Primitive): void;
|
|
8
|
+
/** Options for the {@link weld} function. */
|
|
9
|
+
export interface WeldOptions {
|
|
10
|
+
/** Tolerance for vertex positions, as a fraction of primitive AABB. */
|
|
11
|
+
tolerance?: number;
|
|
12
|
+
/** Tolerance for vertex normals, in radians. */
|
|
13
|
+
toleranceNormal?: number;
|
|
14
|
+
/** Whether to overwrite existing indices. */
|
|
15
|
+
overwrite?: boolean;
|
|
16
|
+
/** Enables a more thorough, but slower, search for vertices to weld. */
|
|
17
|
+
exhaustive?: boolean;
|
|
18
|
+
}
|
|
19
|
+
export declare const WELD_DEFAULTS: Required<WeldOptions>;
|
|
20
|
+
/**
|
|
21
|
+
* Index {@link Primitive Primitives} and (optionally) merge similar vertices. When merged
|
|
22
|
+
* and indexed, data is shared more efficiently between vertices. File size can
|
|
23
|
+
* be reduced, and the GPU can sometimes use the vertex cache more efficiently.
|
|
24
|
+
*
|
|
25
|
+
* When welding, the 'tolerance' threshold determines which vertices qualify for
|
|
26
|
+
* welding based on distance between the vertices as a fraction of the primitive's
|
|
27
|
+
* bounding box (AABB). For example, tolerance=0.01 welds vertices within +/-1%
|
|
28
|
+
* of the AABB's longest dimension. Other vertex attributes are also compared
|
|
29
|
+
* during welding, with attribute-specific thresholds. For `tolerance=0`, geometry
|
|
30
|
+
* is indexed in place, without merging.
|
|
31
|
+
*
|
|
32
|
+
* To preserve visual appearance consistently, use low `toleranceNormal` thresholds
|
|
33
|
+
* around 0.1 (±3º). To pre-processing a scene before simplification or LOD creation,
|
|
34
|
+
* use higher thresholds around 0.5 (±30º).
|
|
35
|
+
*
|
|
36
|
+
* Example:
|
|
37
|
+
*
|
|
38
|
+
* ```javascript
|
|
39
|
+
* import { weld } from '@gltf-transform/functions';
|
|
40
|
+
*
|
|
41
|
+
* await document.transform(
|
|
42
|
+
* weld({ tolerance: 0.001, toleranceNormal: 0.5 })
|
|
43
|
+
* );
|
|
44
|
+
* ```
|
|
45
|
+
*
|
|
46
|
+
* @category Transforms
|
|
47
|
+
*/
|
|
48
|
+
export declare function weld(_options?: WeldOptions): Transform;
|
|
49
|
+
/**
|
|
50
|
+
* Index a {@link Primitive} and (optionally) weld similar vertices. When merged
|
|
51
|
+
* and indexed, data is shared more efficiently between vertices. File size can
|
|
52
|
+
* be reduced, and the GPU can sometimes use the vertex cache more efficiently.
|
|
53
|
+
*
|
|
54
|
+
* When welding, the 'tolerance' threshold determines which vertices qualify for
|
|
55
|
+
* welding based on distance between the vertices as a fraction of the primitive's
|
|
56
|
+
* bounding box (AABB). For example, tolerance=0.01 welds vertices within +/-1%
|
|
57
|
+
* of the AABB's longest dimension. Other vertex attributes are also compared
|
|
58
|
+
* during welding, with attribute-specific thresholds. For tolerance=0, geometry
|
|
59
|
+
* is indexed in place, without merging.
|
|
60
|
+
*
|
|
61
|
+
* Example:
|
|
62
|
+
*
|
|
63
|
+
* ```javascript
|
|
64
|
+
* import { weldPrimitive } from '@gltf-transform/functions';
|
|
65
|
+
*
|
|
66
|
+
* const mesh = document.getRoot().listMeshes()
|
|
67
|
+
* .find((mesh) => mesh.getName() === 'Gizmo');
|
|
68
|
+
*
|
|
69
|
+
* for (const prim of mesh.listPrimitives()) {
|
|
70
|
+
* weldPrimitive(prim, {tolerance: 0.0001});
|
|
71
|
+
* }
|
|
72
|
+
* ```
|
|
73
|
+
*
|
|
74
|
+
* @privateRemarks TODO(v4): Remove the "Document" parameter.
|
|
75
|
+
*/
|
|
76
|
+
export declare function weldPrimitive(a: Document | Primitive, b?: Primitive | WeldOptions, c?: Required<WeldOptions>): void;
|