Skip to content

GLTFExporter: Add EXT_texture_webp support.#33117

Merged
Mugen87 merged 5 commits intomrdoob:devfrom
BorisKourt:gltfexporter-ext-texture-webp
Mar 5, 2026
Merged

GLTFExporter: Add EXT_texture_webp support.#33117
Mugen87 merged 5 commits intomrdoob:devfrom
BorisKourt:gltfexporter-ext-texture-webp

Conversation

@BorisKourt
Copy link
Contributor

@BorisKourt BorisKourt commented Mar 4, 2026

Fixed #33116

In #23592 (r139), userData.mimeType was added so the exporter preserves
JPEG instead of inflating everything to PNG. WebP was deferred
to be handled via EXT_texture_webp: #23592 (comment)

We remove the image/webp → image/png guard in processTextureAsync
and register EXT_texture_webp in extensionsUsed when a WebP texture is
encountered.

@Mugen87 Mugen87 requested a review from donmccurdy March 4, 2026 14:10
@Mugen87 Mugen87 added this to the r184 milestone Mar 4, 2026
@Mugen87 Mugen87 changed the title GLTFExporter: add EXT_texture_webp export support (#33116) GLTFExporter: Add EXT_texture_webp export support. Mar 4, 2026
@Mugen87 Mugen87 changed the title GLTFExporter: Add EXT_texture_webp export support. GLTFExporter: Add EXT_texture_webp support. Mar 4, 2026
Copy link
Collaborator

@donmccurdy donmccurdy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @BorisKourt! I agree it'd be good to support EXT_texture_webp, but it won't be enough to append EXT_texture_webp to the extensionsUsed list. We also need to extend the texture definition, as shown in the "Using without a fallback" section of the spec:

https://github.com/KhronosGroup/glTF/tree/main/extensions/2.0/Vendor/EXT_texture_webp#using-without-a-fallback

I'd also recommend testing the output by exporting a file with WebP and then running it through https://github.khronos.org/glTF-Validator/ for validation.

@Mugen87
Copy link
Collaborator

Mugen87 commented Mar 4, 2026

@BorisKourt Updating processTextureAsync() like below should do the trick. Tested a round-rip with the following asset and it works as expected: https://github.khronos.org/glTF-Assets/model/SheenWoodLeatherSofa

async processTextureAsync( map ) {

	const writer = this;
	const options = writer.options;
	const cache = this.cache;
	const json = this.json;

	if ( cache.textures.has( map ) ) return cache.textures.get( map );

	if ( ! json.textures ) json.textures = [];

	// make non-readable textures (e.g. CompressedTexture) readable by blitting them into a new texture
	if ( map instanceof CompressedTexture ) {

		map = await this.decompressTextureAsync( map, options.maxTextureSize );

	}

	const mimeType = map.userData.mimeType;

	const imageIndex = this.processImage( map.image, map.format, map.flipY, mimeType );

	const textureDef = {
		sampler: this.processSampler( map )
	};

	if ( mimeType === 'image/webp' ) {

		textureDef.extensions = textureDef.extensions || {};
		textureDef.extensions[ 'EXT_texture_webp' ] = {
			source: imageIndex
		};

		this.extensionsUsed[ 'EXT_texture_webp' ] = true;
		this.extensionsRequired[ 'EXT_texture_webp' ] = true;

	} else {

		textureDef.source = imageIndex;

	}

	if ( map.name ) textureDef.name = map.name;

	await this._invokeAllAsync( async function ( ext ) {

		ext.writeTexture && await ext.writeTexture( map, textureDef );

	} );

	const index = json.textures.push( textureDef ) - 1;
	cache.textures.set( map, index );
	return index;

}

@BorisKourt
Copy link
Contributor Author

Thanks for catching this @donmccurdy and thanks for the sample @Mugen87! I already started noodling so let me know if I properly adapted everything. Attached is an exported file. Should I add an example directly to examples for this update or is it too small?

webp_test_synthetic.glb.zip


{
    "uri": "webp_test_synthetic.glb",
    "mimeType": "model/gltf-binary",
    "validatorVersion": "2.0.0-dev.3.10",
    "validatedAt": "2026-03-05T08:14:16.292Z",
    "issues": {
        "numErrors": 0,
        "numWarnings": 0,
        "numInfos": 0,
        "numHints": 0,
        "messages": [],
        "truncated": false
    },
    "info": {
        "version": "2.0",
        "generator": "three.js test",
        "extensionsUsed": [
            "EXT_texture_webp"
        ],
        "extensionsRequired": [
            "EXT_texture_webp"
        ],
        "resources": [
            {
                "pointer": "/buffers/0",
                "mimeType": "application/gltf-buffer",
                "storage": "glb",
                "byteLength": 104
            },
            {
                "pointer": "/images/0",
                "mimeType": "image/webp",
                "storage": "buffer-view",
                "image": {
                    "width": 1,
                    "height": 1,
                    "format": "rgb",
                    "primaries": "srgb",
                    "transfer": "srgb",
                    "bits": 8
                }
            }
        ],
        "animationCount": 0,
        "materialCount": 1,
        "hasMorphTargets": false,
        "hasSkins": false,
        "hasTextures": true,
        "hasDefaultScene": true,
        "drawCallCount": 1,
        "totalVertexCount": 3,
        "totalTriangleCount": 1,
        "maxUVs": 1,
        "maxInfluences": 0,
        "maxAttributes": 2
    }
}

@Mugen87
Copy link
Collaborator

Mugen87 commented Mar 5, 2026

There is no need to add a new glTF asset to the repository. Instead, can you please add a box mesh with a WebP texture to misc_exporter_gltf? You can place it next to the Coffeemat mesh. In this way, we have a mesh that goes through the new code path.

The idea is to add a new button "Export WebP Model" so we can easily verify the EXT_texture_webp support.

@BorisKourt
Copy link
Contributor Author

BorisKourt commented Mar 5, 2026

Will add what you suggest 👍 This was just an example export as per @donmccurdy's request, wasn't planning to add it to the repo!

@BorisKourt
Copy link
Contributor Author

Added it to the file and tested the exports in the Khronos validator also.

screenshot

@BorisKourt
Copy link
Contributor Author

Looks like screenshots need to be updated, should I do that as part of this pr?

@Mugen87
Copy link
Collaborator

Mugen87 commented Mar 5, 2026

That would be good. You can use below screenshot and replace it with the one in examples/screenshots.

misc_exporter_gltf.jpg.zip

@BorisKourt
Copy link
Contributor Author

Thanks, I have added it now.

@Mugen87
Copy link
Collaborator

Mugen87 commented Mar 5, 2026

Looking all good now. Thanks for your work on this!

@Mugen87 Mugen87 merged commit 192c265 into mrdoob:dev Mar 5, 2026
9 checks passed
@BorisKourt
Copy link
Contributor Author

Glad I could help!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

GLTFExporter silently converts WebP textures to PNG, preventing EXT_texture_webp export

3 participants