Skip to content

Commit

Permalink
fix: bindpose optimization may break mesh with bones with scale zero
Browse files Browse the repository at this point in the history
  • Loading branch information
anatawa12 committed Oct 17, 2023
1 parent 930aeda commit 82b7648
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 2 deletions.
4 changes: 4 additions & 0 deletions Editor/Math/Matrix3x3.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ struct Matrix3x3 : IEquatable<Matrix3x3>
public static Matrix3x3 zero = new Matrix3x3(0, 0, 0, 0, 0, 0, 0, 0, 0);
public static Matrix3x3 identity = new Matrix3x3(1, 0, 0, 0, 1, 0, 0, 0, 1);

public float determinant =>
(m00 * m11 * m22) + (m01 * m12 * m20) + (m02 * m10 * m21)
- (m00 * m12 * m21) - (m01 * m10 * m22) - (m02 * m11 * m20);

// @formatter:off
public float m00;
public float m10;
Expand Down
27 changes: 25 additions & 2 deletions Editor/Processors/MergeBoneProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ private void DoBoneMap2(MeshInfo2 meshInfo2, Dictionary<Transform, Transform> me
else
{
// we assume fist bone we find is the most natural bone.
if (!primaryBones.ContainsKey(bone.Transform))
if (!primaryBones.ContainsKey(bone.Transform) && ValidBindPose(bone.Bindpose))
primaryBones.Add(bone.Transform, bone);
}
}
Expand Down Expand Up @@ -161,7 +161,7 @@ private void DoBoneMap2(MeshInfo2 meshInfo2, Dictionary<Transform, Transform> me
vertex.Tangent = new Vector4(tangentVec3.x, tangentVec3.y, tangentVec3.z, vertex.Tangent.w);
foreach (var frames in vertex.BlendShapes.Values)
{
for (var i = 0; i < frames.Length; i++)
for (var i = 0; i < frames.Length; i++)
{
var frame = frames[i];
frames[i] = new Vertex.BlendShapeFrame(
Expand Down Expand Up @@ -204,6 +204,29 @@ private void DoBoneMap2(MeshInfo2 meshInfo2, Dictionary<Transform, Transform> me
}
}

private bool ValidBindPose(Matrix4x4 matrix)
{
const float SMALL = 0.001f;
const float BIG = 10000;

// if scaling part of bindpose is too small or too big, it can lead to invalid bind pose optimization
var scaling = Mathf.Abs(new Matrix3x3(matrix).determinant);

if (float.IsInfinity(scaling)) return false;
if (float.IsNaN(scaling)) return false;
if (scaling < SMALL) return false;
if (scaling > BIG) return false;

// if offset part of bindpose is too big, it may lead to invalid bind pose optimization

var offset = matrix.offset;
if (Mathf.Abs(offset.x) > BIG) return false;
if (Mathf.Abs(offset.y) > BIG) return false;
if (Mathf.Abs(offset.z) > BIG) return false;

return true;
}

private readonly struct BoneUniqKey : IEquatable<BoneUniqKey>
{
private readonly Matrix4x4 _bindPoseInfo;
Expand Down

0 comments on commit 82b7648

Please sign in to comment.