Skip to content

Commit b35b9e5

Browse files
authored
normalize joint weights (#10539)
# Objective allow automatic fixing of bad joint weights. fix #10447 ## Solution - remove automatic normalization of vertexes with all zero joint weights. - add `Mesh::normalize_joint_weights` which fixes zero joint weights, and also ensures that all weights sum to 1. this is a manual call as it may be slow to apply to large skinned meshes, and is unnecessary if you have control over the source assets. note: this became a more significant problem with 0.12, as weights that are close to, but not exactly 1 now seem to use `Vec3::ZERO` for the unspecified weight, where previously they used the entity translation.
1 parent a955d65 commit b35b9e5

File tree

1 file changed

+26
-12
lines changed
  • crates/bevy_render/src/mesh/mesh

1 file changed

+26
-12
lines changed

crates/bevy_render/src/mesh/mesh/mod.rs

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ impl Mesh {
213213
attribute: MeshVertexAttribute,
214214
values: impl Into<VertexAttributeValues>,
215215
) {
216-
let mut values = values.into();
216+
let values = values.into();
217217
let values_format = VertexFormat::from(&values);
218218
if values_format != attribute.format {
219219
panic!(
@@ -222,17 +222,6 @@ impl Mesh {
222222
);
223223
}
224224

225-
// validate attributes
226-
if attribute.id == Self::ATTRIBUTE_JOINT_WEIGHT.id {
227-
let VertexAttributeValues::Float32x4(ref mut values) = values else {
228-
unreachable!() // we confirmed the format above
229-
};
230-
for value in values.iter_mut().filter(|v| *v == &[0.0, 0.0, 0.0, 0.0]) {
231-
// zero weights are invalid
232-
value[0] = 1.0;
233-
}
234-
}
235-
236225
self.attributes
237226
.insert(attribute.id, MeshAttributeData { attribute, values });
238227
}
@@ -630,6 +619,31 @@ impl Mesh {
630619
pub fn morph_target_names(&self) -> Option<&[String]> {
631620
self.morph_target_names.as_deref()
632621
}
622+
623+
/// Normalize joint weights so they sum to 1.
624+
pub fn normalize_joint_weights(&mut self) {
625+
if let Some(joints) = self.attribute_mut(Self::ATTRIBUTE_JOINT_WEIGHT) {
626+
let VertexAttributeValues::Float32x4(ref mut joints) = joints else {
627+
panic!("unexpected joint weight format");
628+
};
629+
630+
for weights in joints.iter_mut() {
631+
// force negative weights to zero
632+
weights.iter_mut().for_each(|w| *w = w.max(0.0));
633+
634+
let sum: f32 = weights.iter().sum();
635+
if sum == 0.0 {
636+
// all-zero weights are invalid
637+
weights[0] = 1.0;
638+
} else {
639+
let recip = sum.recip();
640+
for weight in weights.iter_mut() {
641+
*weight *= recip;
642+
}
643+
}
644+
}
645+
}
646+
}
633647
}
634648

635649
#[derive(Debug, Clone)]

0 commit comments

Comments
 (0)