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.
This commit is contained in:
parent
a955d65ffa
commit
b35b9e5005
@ -213,7 +213,7 @@ impl Mesh {
|
|||||||
attribute: MeshVertexAttribute,
|
attribute: MeshVertexAttribute,
|
||||||
values: impl Into<VertexAttributeValues>,
|
values: impl Into<VertexAttributeValues>,
|
||||||
) {
|
) {
|
||||||
let mut values = values.into();
|
let values = values.into();
|
||||||
let values_format = VertexFormat::from(&values);
|
let values_format = VertexFormat::from(&values);
|
||||||
if values_format != attribute.format {
|
if values_format != attribute.format {
|
||||||
panic!(
|
panic!(
|
||||||
@ -222,17 +222,6 @@ impl Mesh {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// validate attributes
|
|
||||||
if attribute.id == Self::ATTRIBUTE_JOINT_WEIGHT.id {
|
|
||||||
let VertexAttributeValues::Float32x4(ref mut values) = values else {
|
|
||||||
unreachable!() // we confirmed the format above
|
|
||||||
};
|
|
||||||
for value in values.iter_mut().filter(|v| *v == &[0.0, 0.0, 0.0, 0.0]) {
|
|
||||||
// zero weights are invalid
|
|
||||||
value[0] = 1.0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.attributes
|
self.attributes
|
||||||
.insert(attribute.id, MeshAttributeData { attribute, values });
|
.insert(attribute.id, MeshAttributeData { attribute, values });
|
||||||
}
|
}
|
||||||
@ -630,6 +619,31 @@ impl Mesh {
|
|||||||
pub fn morph_target_names(&self) -> Option<&[String]> {
|
pub fn morph_target_names(&self) -> Option<&[String]> {
|
||||||
self.morph_target_names.as_deref()
|
self.morph_target_names.as_deref()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Normalize joint weights so they sum to 1.
|
||||||
|
pub fn normalize_joint_weights(&mut self) {
|
||||||
|
if let Some(joints) = self.attribute_mut(Self::ATTRIBUTE_JOINT_WEIGHT) {
|
||||||
|
let VertexAttributeValues::Float32x4(ref mut joints) = joints else {
|
||||||
|
panic!("unexpected joint weight format");
|
||||||
|
};
|
||||||
|
|
||||||
|
for weights in joints.iter_mut() {
|
||||||
|
// force negative weights to zero
|
||||||
|
weights.iter_mut().for_each(|w| *w = w.max(0.0));
|
||||||
|
|
||||||
|
let sum: f32 = weights.iter().sum();
|
||||||
|
if sum == 0.0 {
|
||||||
|
// all-zero weights are invalid
|
||||||
|
weights[0] = 1.0;
|
||||||
|
} else {
|
||||||
|
let recip = sum.recip();
|
||||||
|
for weight in weights.iter_mut() {
|
||||||
|
*weight *= recip;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user