Skip to content

GLTFLoader: Morph targets only work for matching accessor types #17608

@zeux

Description

@zeux

glTF files assume that morph target data is specified as relative adjustments, and three.js assumes that the data in morph target buffers is absolute.

This leads to a few obvious memory/performance caveats - the morph target data needs to be duplicated and modified during import - but also leads to inability to use a very narrow type for position deltas.

For example, when data is quantized with gltfpack (which makes the glTF files technically invalid right now but this will change soon: KhronosGroup/glTF#1673), the positions typically use UInt16 and morph target deltas use Int16. However, very frequently the morph target delta range is small enough to fit in Int8 - because three.js attempts to reconstruct the absolute position however, attempting to encode Int8 deltas leads to decoding issues on three.js side. Babylon.JS handles files like this perfectly.

I'd like to fix this - the obvious tactical fix is changing the morph target attribute cloning to assume the type of the base attribute, not morph target. However, I'd like to check - what are the thoughts of fixing this by adding support to three.js for relative morph target data?

In theory, the formulas are compatible to not require any shader code duplication - specifically, this equation that three.js currently uses:

basePosition
+ weight0 * ( morphPosition0 - basePosition )
+ weight1 * ( morphPosition1 - basePosition )

and this equation that glTF assumes:

basePosition
+ weight0 * glTFmorphPosition0
+ weight1 * glTFmorphPosition1

can be reformulated as:

weightBase * basePosition
+ weight0 * morphPosition0
+ weight1 * morphPosition1

After which for glTF style files the shader needs [1, weight0, weight1, ...] as an input, whereas normally you'd pass [1 - weight0 - weight1 - ..., weight0, weight1, ...] as an input. So by adding some sort of flag to three.js mesh (e.g. morphTargetsAreDeltas) and a bit of JS code to compute the weights correctly, we could support both with minimal cost.

Metadata

Metadata

Labels

No labels
No labels

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions