@needle-tools/gltf-build-pipeline 2.2.1-alpha.6 → 2.2.1-alpha.7
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 +2 -1
- package/dist/extensions/NEEDLE_opaque/NEEDLE_opaque.js +6 -6
- package/dist/transforms/needle_progressive.js +10 -2
- package/dist/transforms/needle_texture_transform.js +7 -3
- package/dist/transforms/needle_toktx.js +5 -1
- package/dist/utils/texture.d.ts +3 -0
- package/dist/utils/texture.js +6 -0
- package/dist/utils/validate.js +3 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,8 +4,9 @@ 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.1-alpha.
|
|
7
|
+
## [2.2.1-alpha.7] - 2023-06-19
|
|
8
8
|
- fix: WARN if image validation can not run
|
|
9
|
+
- change: compress lightmap textures with webp
|
|
9
10
|
|
|
10
11
|
## [2.2.1-alpha.5] - 2023-06-18
|
|
11
12
|
- add: `stats` now includes json and animation size info
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Extension, ExtensionProperty, PropertyType, TextureChannel } from '@gltf-transform/core';
|
|
2
2
|
import { getTexture, tryGetInArray, writeExtension } from '../utils.js';
|
|
3
|
+
import { isLightmap } from '../../utils/texture.js';
|
|
3
4
|
const ALL_PROPERTY_TYPES = [];
|
|
4
5
|
for (const key in PropertyType) {
|
|
5
6
|
ALL_PROPERTY_TYPES.push(PropertyType[key]);
|
|
@@ -163,11 +164,11 @@ export function createOpaqueExtension(name, types, opts) {
|
|
|
163
164
|
continue;
|
|
164
165
|
const ext = sourceArray[EXTENSION_NAME];
|
|
165
166
|
if (ext) {
|
|
166
|
-
this.lightmapWorkaround(context);
|
|
167
167
|
const root = this.document.getRoot();
|
|
168
168
|
const prop = this.createExtension();
|
|
169
169
|
this.jsonPointerHandler.read(context, root, ext, prop);
|
|
170
170
|
root.setExtension(EXTENSION_NAME, prop);
|
|
171
|
+
this.lightmapWorkaround(context, prop, this.document.getLogger());
|
|
171
172
|
prop.add(ctx => {
|
|
172
173
|
ctx.jsonDoc.json.extensions = ctx.jsonDoc.json.extensions || {};
|
|
173
174
|
ctx.jsonDoc.json.extensions[EXTENSION_NAME] = ext;
|
|
@@ -180,7 +181,7 @@ export function createOpaqueExtension(name, types, opts) {
|
|
|
180
181
|
}
|
|
181
182
|
// this is temporarely here to prevent compression on textures named Lightmap
|
|
182
183
|
// until we have better control over the compression process
|
|
183
|
-
lightmapWorkaround(context) {
|
|
184
|
+
lightmapWorkaround(context, prop, logger) {
|
|
184
185
|
const textureDefinitions = context.jsonDoc.json.textures;
|
|
185
186
|
if (!textureDefinitions)
|
|
186
187
|
return;
|
|
@@ -189,10 +190,9 @@ export function createOpaqueExtension(name, types, opts) {
|
|
|
189
190
|
const tex = textures[i];
|
|
190
191
|
const texDef = textureDefinitions[i];
|
|
191
192
|
const name = texDef?.name;
|
|
192
|
-
if (
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
tex.setMimeType("image/lightmap");
|
|
193
|
+
if (isLightmap(tex) && tex.getMimeType() !== "image/exr") {
|
|
194
|
+
prop.setReference("lightmapTexture", tex, { channels: TextureChannel.R | TextureChannel.G | TextureChannel.B | TextureChannel.A });
|
|
195
|
+
logger.info(`Found lightmap texture ${name}: ${tex.getMimeType()} in ${EXTENSION_NAME}`);
|
|
196
196
|
}
|
|
197
197
|
}
|
|
198
198
|
}
|
|
@@ -7,7 +7,7 @@ import path, { basename, resolve } from 'path';
|
|
|
7
7
|
import { existsSync, readFileSync, rmSync, statSync, writeFileSync } from 'fs';
|
|
8
8
|
import { addMetaToCache, addToCache, getHash, getKey, tryGetFromCache, tryGetMetaFromCache } from '../cache/index.js';
|
|
9
9
|
import sharp from "sharp";
|
|
10
|
-
import { detectTextureCompressionMode, foreachGLTF, generateGuid, validateImageMimeType, writeNodeIO } from '../utils/index.js';
|
|
10
|
+
import { detectTextureCompressionMode, foreachGLTF, generateGuid, isLightmap, setLightmapName, validateImageMimeType, writeNodeIO } from '../utils/index.js';
|
|
11
11
|
import { needle_asset, writeNeedleAsset } from './needle_asset.js';
|
|
12
12
|
import { MeshoptDecoder, MeshoptSimplifier } from 'meshoptimizer';
|
|
13
13
|
import { compressPrimitive } from './needle_mesh_transform.js';
|
|
@@ -193,7 +193,9 @@ export function make_progressive_textures(filePath, _options = TEXTURE_RESIZE_DE
|
|
|
193
193
|
// generateLods ||= opts.config?.textures?.lods === true;
|
|
194
194
|
// // Ensure that texture lods are not disabled by { textures: { lods: false } }
|
|
195
195
|
// generateLods &&= opts.config?.textures?.lods !== false;
|
|
196
|
-
|
|
196
|
+
const _isLightmap = slots.includes("lightmapTexture") || isLightmap(texture);
|
|
197
|
+
// Lightmaps don't have multiple levels right now
|
|
198
|
+
if (generateLods && !_isLightmap) {
|
|
197
199
|
const LEVEL = 6;
|
|
198
200
|
let lastSize = currentSize;
|
|
199
201
|
for (let i = 1; i < LEVEL; i++) {
|
|
@@ -273,6 +275,7 @@ async function createTextureLod(args, opts) {
|
|
|
273
275
|
newTexture.setImage(img);
|
|
274
276
|
newTexture.setURI(texture.getURI());
|
|
275
277
|
newTexture.setMimeType(texture.getMimeType());
|
|
278
|
+
newTexture.setName(texture.getName() || ("LOD_" + textureIndex));
|
|
276
279
|
if (args.maxSize && args.maxSize >= 16) {
|
|
277
280
|
const currentSize = newTexture.getSize();
|
|
278
281
|
if (currentSize[0] > args.maxSize && currentSize[1] > args.maxSize) {
|
|
@@ -308,6 +311,10 @@ async function createTextureLod(args, opts) {
|
|
|
308
311
|
case "emissiveTexture":
|
|
309
312
|
newMaterial.setEmissiveTexture(newTexture);
|
|
310
313
|
break;
|
|
314
|
+
case "lightmapTexture":
|
|
315
|
+
newMaterial.setBaseColorTexture(newTexture);
|
|
316
|
+
setLightmapName(newTexture);
|
|
317
|
+
break;
|
|
311
318
|
default:
|
|
312
319
|
if (slot.startsWith("/textures/")) {
|
|
313
320
|
// Ensure the texture is using the alpha channel since we don't know what slots the original texture was used for
|
|
@@ -322,6 +329,7 @@ async function createTextureLod(args, opts) {
|
|
|
322
329
|
// Make sure the material is used
|
|
323
330
|
createMeshForMaterial(newDoc, newMaterial, slot_index++);
|
|
324
331
|
}
|
|
332
|
+
// Pass compression settings to the new texture
|
|
325
333
|
const compressionSettingsExt = texture.getExtension(NEEDLE_compression_texture.EXTENSION_NAME);
|
|
326
334
|
if (compressionSettingsExt !== undefined && compressionSettingsExt !== null && compressionSettingsExt.getExtensionDefinition) {
|
|
327
335
|
logger.info("> Pass compression extension to new texture");
|
|
@@ -4,10 +4,11 @@ import { NEEDLE_compression_texture } from '../extensions/index.js';
|
|
|
4
4
|
import { addToCache, getHash, getKey, tryGetFromCache } from "../cache/index.js";
|
|
5
5
|
import { NeedleWebPContext } from "./needle_webp.js";
|
|
6
6
|
import { NeedleToktxContext } from "./needle_toktx.js";
|
|
7
|
-
import { createTransform } from "@gltf-transform/functions";
|
|
7
|
+
import { createTransform, listTextureSlots } from "@gltf-transform/functions";
|
|
8
8
|
import { dirname } from "path";
|
|
9
9
|
import { existsSync, rmSync } from "fs";
|
|
10
10
|
import { validateImageMimeType } from "../utils/validate.js";
|
|
11
|
+
import { isLightmap } from "../utils/texture.js";
|
|
11
12
|
export async function resizeTextureIfNecessary(texture) {
|
|
12
13
|
const ext = texture.getExtension(NEEDLE_compression_texture.EXTENSION_NAME);
|
|
13
14
|
if (ext?.model) {
|
|
@@ -84,7 +85,7 @@ export const needle_texture_transform = function (options) {
|
|
|
84
85
|
async function processTexture(texture, index, document, logger, context) {
|
|
85
86
|
const validationResult = validateImageMimeType(texture.getMimeType(), texture.getImage());
|
|
86
87
|
if (validationResult?.error) {
|
|
87
|
-
logger.warn(`Texture ${texture.getName()} [${index}] has an incorrect mime type
|
|
88
|
+
logger.warn(`WARN: Texture ${texture.getName()} [${index}] has an incorrect mime type \"${texture.getMimeType()}\" → auto-correcting to ${validationResult.mimeType}`);
|
|
88
89
|
texture.setMimeType(validationResult.mimeType);
|
|
89
90
|
}
|
|
90
91
|
const originalMimeType = texture.getMimeType();
|
|
@@ -142,13 +143,16 @@ async function processTexture(texture, index, document, logger, context) {
|
|
|
142
143
|
}
|
|
143
144
|
else {
|
|
144
145
|
let mimeType = "image/ktx2";
|
|
145
|
-
|
|
146
|
+
const slots = listTextureSlots(texture);
|
|
146
147
|
// if (slots.includes("metallicRoughnessTexture"))
|
|
147
148
|
// mimeType = "image/webp";
|
|
148
149
|
const isVRM = context.file?.toLowerCase().endsWith(".vrm");
|
|
149
150
|
if (context.config?.usecase === "product") {
|
|
150
151
|
mimeType = "image/webp";
|
|
151
152
|
}
|
|
153
|
+
else if (slots.includes("lightmapTexture") || isLightmap(texture)) {
|
|
154
|
+
mimeType = "image/webp";
|
|
155
|
+
}
|
|
152
156
|
// TODO: need to make this into a function
|
|
153
157
|
// const webpThreshold = 256; // this is the default threshold in progressive textures (needle_progressive.ts)
|
|
154
158
|
// console.log(context.file, isVRM);
|
|
@@ -10,7 +10,7 @@ import os from 'os';
|
|
|
10
10
|
import tmp from 'tmp';
|
|
11
11
|
import pLimit from 'p-limit';
|
|
12
12
|
import { replaceExtension } from "../utils/fileutils.js";
|
|
13
|
-
import { ceilMultipleOfFour, isMultipleOfFour } from "../utils/index.js";
|
|
13
|
+
import { ceilMultipleOfFour, isLightmap, isMultipleOfFour } from "../utils/index.js";
|
|
14
14
|
import sharp from "sharp";
|
|
15
15
|
const NUM_CPUS = os.cpus().length || 1; // microsoft/vscode#112122
|
|
16
16
|
let didLogEnvironmentInfo = false;
|
|
@@ -175,6 +175,10 @@ export class NeedleToktxContext {
|
|
|
175
175
|
quality = 255;
|
|
176
176
|
compression = 4;
|
|
177
177
|
}
|
|
178
|
+
else if (slots.includes("lightmapTexture") || isLightmap(texture)) {
|
|
179
|
+
quality = 255;
|
|
180
|
+
compression = 4;
|
|
181
|
+
}
|
|
178
182
|
}
|
|
179
183
|
const defaults = mode === Mode.ETC1S ? ETC1S_DEFAULTS : UASTC_DEFAULTS;
|
|
180
184
|
// TODO: should we ensure that the texture is using all channels? Unused channels are discarded anyways. The issue we have here is that textures that are solely used from pointers have unknown channels. We register them with RGBA when generating progressive assets as well as assign texture json pointers /textures/ to
|
package/dist/utils/texture.d.ts
CHANGED
|
@@ -1,2 +1,5 @@
|
|
|
1
|
+
import { Texture } from "@gltf-transform/core";
|
|
1
2
|
export declare function isMultipleOfFour(value: number): boolean;
|
|
2
3
|
export declare function ceilMultipleOfFour(value: number): number;
|
|
4
|
+
export declare function isLightmap(texture: Texture): boolean;
|
|
5
|
+
export declare function setLightmapName(texture: Texture): void;
|
package/dist/utils/texture.js
CHANGED
|
@@ -6,3 +6,9 @@ export function ceilMultipleOfFour(value) {
|
|
|
6
6
|
return 4;
|
|
7
7
|
return value % 4 ? value + 4 - (value % 4) : value;
|
|
8
8
|
}
|
|
9
|
+
export function isLightmap(texture) {
|
|
10
|
+
return texture.getName()?.startsWith("Lightmap");
|
|
11
|
+
}
|
|
12
|
+
export function setLightmapName(texture) {
|
|
13
|
+
texture.setName("Lightmap");
|
|
14
|
+
}
|
package/dist/utils/validate.js
CHANGED
|
@@ -2,10 +2,11 @@ import { ImageUtils } from "@gltf-transform/core";
|
|
|
2
2
|
export function validateImageMimeType(mimetype, image) {
|
|
3
3
|
const actualMimeType = ImageUtils.getMimeType(image);
|
|
4
4
|
if (actualMimeType != null && actualMimeType != mimetype) {
|
|
5
|
-
|
|
5
|
+
const msg = `Image reported wrong mime type \"${mimetype}\" but is actually \"${actualMimeType}\"`;
|
|
6
|
+
console.error(`WARN: ${msg}`);
|
|
6
7
|
return {
|
|
7
8
|
error: true,
|
|
8
|
-
message:
|
|
9
|
+
message: msg,
|
|
9
10
|
mimeType: actualMimeType
|
|
10
11
|
};
|
|
11
12
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@needle-tools/gltf-build-pipeline",
|
|
3
|
-
"version": "2.2.1-alpha.
|
|
3
|
+
"version": "2.2.1-alpha.7",
|
|
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",
|