GLTFLoader: Morph targets only work for matching accessor types
See original GitHub issueglTF 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: https://github.com/KhronosGroup/glTF/pull/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.
Issue Analytics
- State:
- Created 4 years ago
- Reactions:3
- Comments:10 (6 by maintainers)
Top GitHub Comments
Just to give a basic idea, here’s how first-class relative morph target support may look like: https://github.com/mrdoob/three.js/compare/dev...zeux:morph-relative
Yeah - definitely. This is why I mentioned the tactical fix as a possibility. However, with both GLTF and FBX storing deltas and having to reconstruct absolute positions at load time it seems like the core change may be more appropriate. This will also lead to being able to - eventually, conditional on something close to #17089 getting done at some point - directly load the buffer data for geometry buffers into large ArrayBuffers with no need for extra processing which is nice.