-
-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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.
crates/bevy_mesh/src/morph.rs
Outdated
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_animation
andbevy_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_animation
andbevy_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_animation
are 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_targets
or user code sets weights on aMorphWeights
component (basically aVec<f32>
).bevy_render::inherit_weights
copies weights fromMorphWeights
to anyMeshMorphWeights
components in child entities.MeshMorphWeights
is also aVec<f32>
.bevy_render::extract_morphs
finds any entities with both aMesh3d
andMeshMorphWeights
, then copies the weights to per-mesh render buffers.The separation between
MorphWeights
andMeshMorphWeights
allows a singleMorphWeights
component in a parent entity to drive multiple meshes in child entities.Changes
In the new pipeline,
MeshMorphWeights
is not a copy ofMorphWeights
. Instead it's a reference to the entity containingMorphWeights
.inherit_weights
is no longer needed - insteadextract_morphs
usesMeshMorphWeights
to find and copyMorphWeights
directly into render buffers.This is more flexible as the child entity requirement of
inherit_weights
is gone - aMeshMorphWeights
can point to any entity. Performance improves due to reduced copies and the child search becoming a direct entity lookup.Breakage
Changing
MeshMorphWeights
from a copy to a reference could affect some users.Unaffected: Users who import a glTF scene and drive the
MorphWeights
component themselves or viabevy_animation
.Possibly Affected: Users who set up their own pipeline or modify the glTF pipeline. In particular, if they're manipulating
MeshMorphWeights
directly 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_morphs
goes from 42.5us to 48.9us (+6.4us).inherit_weights
goes 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
MorphWeights
component, and also aMeshMorphWeights
component that simply references its own entity.An alternative could be to make
MeshMorphWeights
an 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
.