-
-
Notifications
You must be signed in to change notification settings - Fork 3.9k
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 |
Objective
bevy_animation
independent ofbevy_render
by rearranging the morph target pipeline.bevy_pbr
inbevy_animation
#16392.Summary
I want to make
bevy_animation
independent ofbevy_render
(see also #18543, #18437). I'm assuming this is good for compile times and alternative renderers.The final dependency is a system ordering that ensures morph target weights are written by
bevy_animation
before they're read bybevy_render
:This PR removes the dependency by eliminating
inherit_weights
. The changes are also an optimisation and make the pipeline more flexible.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
.Any code that writes
MorphWeights
is unchanged.inherit_weights
disappears - insteadextract_morphs
usesMeshMorphWeights
to find and copyMorphWeights
directly into render buffers.In theory this is more flexible as meshes are not required to be a child of the entity with
MorphWeights
- although in practice I'd guess that's a niche requirement. 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 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 still feels a little awkward, particularly the case where
MeshMorphWeights
might reference aMorphWeights
on the same entity.Some alternatives:
MeshMorphWeights
an enum that's either an entity reference or aVec<f32>
of weights.MeshMorphWeights
, changeMorphWeights
to be an enum that's either an entity reference or aVec<f32>
of weights.MorphWeights
interface, which means breaking more user code.MorphWeights::first_mesh
variable.I kinda like 2, but will be controversial. Maybe something for a follow up PR.