KHR_texture_basisu / EXT_texture_webp as a non-required extension #1407
-
Is there a way to use any of the provided image compression commands to create a compressed copy of the image (eg via KHR_texture_basisu extension), keep both images in the file, and have the texture reference both the original PNG/JPG as well as the compressed version via an extension? Note: this is not a feature request :) but I'm looking into supporting input files with KHR_texture_basisu extension in gltfpack and there are some annoying edge cases when input file is structured like the above, but I don't have test scenes that do this so I was wondering if gltf-transform can make a scene like this. If not I can edit the file by hand of course. |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment
-
Hi @zeux! As a design simplification I've merged glTF's Texture/Image concepts into one within this library, so there is no official support for representing fallback images as such. When reading a glTF file containing fallback images, the fallbacks are loaded as unused images, and removed if the application calls Unused images could be attached to the texture definitions as fallbacks with a bit of processing before writing the // compress-with-fallback.js
import { BufferUtils, NodeIO } from '@gltf-transform/core';
import { ALL_EXTENSIONS, EXTTextureWebP } from '@gltf-transform/extensions';
import { compressTexture } from '@gltf-transform/functions';
import { writeFile } from 'node:fs/promises';
import { join } from 'node:path';
import encoder from 'sharp';
const io = new NodeIO().registerExtensions(ALL_EXTENSIONS);
const document = await io.read('lamp/lamp.glb');
// Define EXT_texture_webp
document.createExtension(EXTTextureWebP).setRequired(false);
// Compress images and save fallbacks.
const fallbackMap = new Map();
const textures = document.getRoot().listTextures();
for (let dstIndex = 0; dstIndex < textures.length; dstIndex++) {
const dstTexture = textures[dstIndex];
const srcTexture = dstTexture.clone();
const srcIndex = document.getRoot().listTextures().length - 1;
await compressTexture(dstTexture, { encoder, targetFormat: 'webp' });
fallbackMap.set(dstIndex, srcIndex);
}
// Serialize.
const { json, resources } = await io.writeJSON(document);
// Attach fallbacks to associated textures.
for (const textureDef of json.textures) {
if (textureDef.extensions['EXT_texture_webp']) {
const srcIndex = textureDef.extensions['EXT_texture_webp'].source;
const dstIndex = fallbackMap.get(srcIndex);
textureDef.source = dstIndex;
}
}
// Write JSON and resources to disk.
await writeFile('lamp/lamp+fallback.gltf', BufferUtils.encodeText(JSON.stringify(json, null, 2)));
for (const resourceURI in resources) {
await writeFile(join('lamp', resourceURI), resources[resourceURI]);
} node ./compress-with-fallback.js This approach works for WebP or AVIF. For KTX2, because of the CLI dependency, some extra steps are required. |
Beta Was this translation helpful? Give feedback.
Hi @zeux! As a design simplification I've merged glTF's Texture/Image concepts into one within this library, so there is no official support for representing fallback images as such. When reading a glTF file containing fallback images, the fallbacks are loaded as unused images, and removed if the application calls
prune()
.Unused images could be attached to the texture definitions as fallbacks with a bit of processing before writing the
.gltf
and resources to disk. Since you are already very familiar with these extension definitions, I doubt this saves you time compared to modifying the JSON without using glTF Transform... but perhaps it's helpful to some future reader. 🙂// compress-with…