-
-
Notifications
You must be signed in to change notification settings - Fork 4.3k
Restructure morph target pipeline to reduce crate dependencies #18465
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
…t count more forgiving, just in case.
…eshMorphWeights`. This might smooth upgrades.
| pub fn clear_weights(&mut self) { | ||
| self.weights.clear(); | ||
| } | ||
| pub fn extend_weights(&mut self, weights: &[f32]) { | ||
| self.weights.extend(weights); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These were added so that MorphWeights supports everything that MeshMorphWeights did.
Personally I'd rather make MorphWeights members public and avoid the need for this interface.
crates/bevy_gltf/src/loader/mod.rs
Outdated
| // Create `MorphWeights`. The weights will be copied from `mesh.weights()` | ||
| // if present. If not then the weights are zero. | ||
| // | ||
| // The glTF spec says that all primitives must have the same number | ||
| // of morph targets, and `mesh.weights()` should be equal to that | ||
| // number if present. We're more forgiving and take whichever is | ||
| // biggest, leaving any unspecified weights at zero. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I played it safe here, to the point of accepting malformed glTFs. I wasn't sure if the importer is intended to be strict or permissive.
|
Changed from draft to ready for review. Documentation has been updated, and it now fully removes the |
|
Removed Contentious because I dont see why it would be contentious |
…0435 but accidentally added back by the last merge. Also removed `MorphPlugin` since it's now redundant.
|
PR has been updated to fix conflicts with #20472. |
Objective
bevy_animationandbevy_render.Summary
The morph target pipeline currently relies on copying morph target weights between components. This has three issues:
First, the copy requires a subtle system ordering dependency between
bevy_animationandbevy_render, via a system set declared inbevy_mesh.Second, the copy is arguably redundant - the weights will be copied again into render buffers.
Third, the copy requires certain entities to be children of other entities. This inflexibility is not a problem right now, but might be in future.
This PR removes the copy. Users who just import glTFs and use
bevy_animationare not affected. Users who make lower level changes might need to update their code.Background
The morph target pipeline lets main world entities set weights which are then automatically copied into per-mesh render buffers.
The current pipeline is:
bevy_animation::animate_targetsor user code sets weights on aMorphWeightscomponent (basically aVec<f32>).bevy_render::inherit_weightscopies weights fromMorphWeightsto anyMeshMorphWeightscomponents in child entities.MeshMorphWeightsis also aVec<f32>.bevy_render::extract_morphsfinds any entities with both aMesh3dandMeshMorphWeights, then copies the weights to per-mesh render buffers.The separation between
MorphWeightsandMeshMorphWeightsallows a singleMorphWeightscomponent in a parent entity to drive multiple meshes in child entities.Changes
In the new pipeline,
MeshMorphWeightsis not a copy ofMorphWeights. Instead it's a reference to the entity containingMorphWeights.inherit_weightsis no longer needed - insteadextract_morphsusesMeshMorphWeightsto find and copyMorphWeightsdirectly into render buffers.This is more flexible as the child entity requirement of
inherit_weightsis gone - aMeshMorphWeightscan point to any entity. Performance improves due to reduced copies and the child search becoming a direct entity lookup.Breakage
Changing
MeshMorphWeightsfrom a copy to a reference could affect some users.Unaffected: Users who import a glTF scene and drive the
MorphWeightscomponent themselves or viabevy_animation.Possibly Affected: Users who set up their own pipeline or modify the glTF pipeline. In particular, if they're manipulating
MeshMorphWeightsdirectly then they'll have to restructure to useMorphWeights.I did a github code search and found only one case that would break. They can fix this by rearranging the components.
Performance
Tested on
many_morph_targets(#18536):extract_morphsgoes from 42.5us to 48.9us (+6.4us).inherit_weightsgoes from 30.3us to zero.I expect a small memory saving due to one less copy of the weights per mesh.
There's room for further optimisation. The render buffers have a copy of the weights for each mesh, but multiple meshes could be sharing the same weights.
Testing
Also tested a few other glTFs, and hacked the glTF importer to simulate some valid and invalid combinations (missing weights, mismatched arrays).
Alternatives
The pipeline is a little awkward for someone who wants to put meshes and morph weights on the same entity - they have to add a
MorphWeightscomponent, and also aMeshMorphWeightscomponent that simply references its own entity.An alternative could be to make
MeshMorphWeightsan enum that's either a reference of an instance of weights:Now, the all-in-one entity just needs a
MeshMorphWeights::Instance- no need forMorphWeights.