Skip to content

Commit 0ce3809

Browse files
authored
Merge pull request #274 from Unity-Technologies/UNI-35583-fix-skinning-weights
UNI-35583 fix skinning weights
2 parents 4ef5b41 + 3e1479b commit 0ce3809

File tree

5 files changed

+8494
-10
lines changed

5 files changed

+8494
-10
lines changed

Assets/FbxExporters/Editor/FbxExporter.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1025,8 +1025,17 @@ private bool ExportSkin (SkinnedMeshRenderer skinnedMesh,
10251025
/// </summary>
10261026
private void SetVertexWeights (MeshInfo meshInfo, Dictionary<int, FbxCluster> boneCluster)
10271027
{
1028+
HashSet<int> visitedVertices = new HashSet<int> ();
1029+
10281030
// set the vertex weights for each bone
10291031
for (int i = 0; i < meshInfo.BoneWeights.Length; i++) {
1032+
var actualIndex = ControlPointToIndex [meshInfo.Vertices [i]];
1033+
1034+
if (visitedVertices.Contains (actualIndex)) {
1035+
continue;
1036+
}
1037+
visitedVertices.Add (actualIndex);
1038+
10301039
var boneWeights = meshInfo.BoneWeights;
10311040
int[] indices = {
10321041
boneWeights [i].boneIndex0,
@@ -1048,7 +1057,8 @@ boneWeights [i].weight3
10481057
if (!boneCluster.ContainsKey (indices [j])) {
10491058
continue;
10501059
}
1051-
boneCluster [indices [j]].AddControlPointIndex (ControlPointToIndex[meshInfo.Vertices[i]], weights [j]);
1060+
// add vertex and weighting on vertex to this bone's cluster
1061+
boneCluster [indices [j]].AddControlPointIndex (actualIndex, weights [j]);
10521062
}
10531063
}
10541064
}

Assets/FbxExporters/Editor/UnitTests/ExporterTestBase.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,5 +261,21 @@ public static void AssertSameHierarchy (
261261
AssertSameHierarchy (expectedChild.gameObject, actualChild.gameObject);
262262
}
263263
}
264+
265+
/// <summary>
266+
/// Given the path to a file, find the file relative to
267+
/// the UnitTests folder.
268+
/// </summary>
269+
/// <returns>The path in unit tests.</returns>
270+
/// <param name="partialPath">Partial path.</param>
271+
protected static string FindPathInUnitTests(string partialPath){
272+
foreach (var dir in Directory.GetDirectories(Application.dataPath, "UnitTests", SearchOption.AllDirectories)) {
273+
var fullPath = Path.Combine (dir, partialPath);
274+
if (File.Exists (fullPath)) {
275+
return FbxExporters.EditorTools.ExportSettings.ConvertToAssetRelativePath (fullPath);
276+
}
277+
}
278+
return null;
279+
}
264280
}
265281
}

Assets/FbxExporters/Editor/UnitTests/ModelExporterTest.cs

Lines changed: 92 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -507,14 +507,9 @@ private void CompareMeshComponentAttributes(Mesh mesh, Mesh fbxMesh)
507507
Assert.AreEqual (mesh.tangents, fbxMesh.tangents);
508508
}
509509

510-
[Test]
511-
public void TestSkinnedMeshExport(){
512-
// for now use this cowboy taken from the asset store as the test file
513-
// TODO: find a better/simpler test file
514-
var fbxPath = "FbxExporters/Editor/UnitTests/Models/Cowboy/cowboyMidPoly(riged).fbx";
515-
510+
private void ExportSkinnedMesh(string fileToExport, out SkinnedMeshRenderer originalSkinnedMesh, out SkinnedMeshRenderer exportedSkinnedMesh){
516511
// add fbx to scene
517-
GameObject originalFbxObj = AssetDatabase.LoadMainAssetAtPath("Assets/" + fbxPath) as GameObject;
512+
GameObject originalFbxObj = AssetDatabase.LoadMainAssetAtPath("Assets/" + fileToExport) as GameObject;
518513
Assert.IsNotNull (originalFbxObj);
519514
GameObject originalGO = GameObject.Instantiate (originalFbxObj);
520515
Assert.IsTrue (originalGO);
@@ -526,11 +521,36 @@ public void TestSkinnedMeshExport(){
526521
GameObject fbxObj = AssetDatabase.LoadMainAssetAtPath(filename) as GameObject;
527522
Assert.IsTrue (fbxObj);
528523

529-
var originalSkinnedMesh = originalGO.GetComponentInChildren<SkinnedMeshRenderer> ();
524+
originalSkinnedMesh = originalGO.GetComponentInChildren<SkinnedMeshRenderer> ();
530525
Assert.IsNotNull (originalSkinnedMesh);
531526

532-
var exportedSkinnedMesh = fbxObj.GetComponentInChildren<SkinnedMeshRenderer> ();
527+
exportedSkinnedMesh = fbxObj.GetComponentInChildren<SkinnedMeshRenderer> ();
533528
Assert.IsNotNull (exportedSkinnedMesh);
529+
}
530+
531+
public class SkinnedMeshTestDataClass
532+
{
533+
public static System.Collections.IEnumerable TestCases1 {
534+
get {
535+
// for now use this cowboy taken from the asset store as the test file
536+
// TODO: find a better/simpler test file
537+
yield return "Models/Cowboy/cowboyMidPoly(riged).fbx";
538+
}
539+
}
540+
public static System.Collections.IEnumerable TestCases2 {
541+
get {
542+
yield return "Models/SimpleMan/SimpleMan.fbx";
543+
}
544+
}
545+
}
546+
547+
[Test, TestCaseSource(typeof(SkinnedMeshTestDataClass), "TestCases1")]
548+
public void TestSkinnedMeshExport(string fbxPath){
549+
fbxPath = FindPathInUnitTests (fbxPath);
550+
Assert.That (fbxPath, Is.Not.Null);
551+
552+
SkinnedMeshRenderer originalSkinnedMesh, exportedSkinnedMesh;
553+
ExportSkinnedMesh (fbxPath, out originalSkinnedMesh, out exportedSkinnedMesh);
534554

535555
Assert.IsTrue (originalSkinnedMesh.name == exportedSkinnedMesh.name ||
536556
(originalSkinnedMesh.transform.parent == null && exportedSkinnedMesh.transform.parent == null));
@@ -594,5 +614,68 @@ public void TestSkinnedMeshExport(){
594614
var expWeights = exportedMesh.boneWeights;
595615
Assert.IsNotNull (expWeights);
596616
}
617+
618+
[Test, TestCaseSource(typeof(SkinnedMeshTestDataClass), "TestCases2")]
619+
public void TestBoneWeightExport(string fbxPath){
620+
fbxPath = FindPathInUnitTests (fbxPath);
621+
Assert.That (fbxPath, Is.Not.Null);
622+
623+
SkinnedMeshRenderer originalSkinnedMesh, exportedSkinnedMesh;
624+
ExportSkinnedMesh (fbxPath, out originalSkinnedMesh, out exportedSkinnedMesh);
625+
626+
var origVerts = originalSkinnedMesh.sharedMesh.vertices;
627+
Assert.That (origVerts, Is.Not.Null);
628+
629+
var expVerts = exportedSkinnedMesh.sharedMesh.vertices;
630+
Assert.That (expVerts, Is.Not.Null);
631+
632+
var origBoneWeights = originalSkinnedMesh.sharedMesh.boneWeights;
633+
Assert.That (origBoneWeights, Is.Not.Null);
634+
Assert.That (origBoneWeights.Length, Is.GreaterThan (0));
635+
636+
var expBoneWeights = exportedSkinnedMesh.sharedMesh.boneWeights;
637+
Assert.That (expBoneWeights, Is.Not.Null);
638+
Assert.That (expBoneWeights.Length, Is.GreaterThan (0));
639+
640+
var origBones = originalSkinnedMesh.bones;
641+
var expBones = exportedSkinnedMesh.bones;
642+
643+
int comparisonCount = 0;
644+
int minVertCount = Mathf.Min (origVerts.Length, expVerts.Length);
645+
for(int i = 0; i < minVertCount; i++){
646+
for (int j = 0; j < minVertCount; j++) {
647+
if (origVerts [i] == expVerts [j]) {
648+
// compare bone weights
649+
var origBw = origBoneWeights[i];
650+
var expBw = expBoneWeights [j];
651+
652+
var indexMsg = "Bone index {0} doesn't match";
653+
var nameMsg = "bone names don't match";
654+
655+
Assert.That (expBw.boneIndex0, Is.EqualTo (origBw.boneIndex0), string.Format(indexMsg, 0));
656+
Assert.That (expBones[expBw.boneIndex0].name, Is.EqualTo (origBones[origBw.boneIndex0].name), nameMsg);
657+
658+
Assert.That (expBw.boneIndex1, Is.EqualTo (origBw.boneIndex1), string.Format(indexMsg, 1));
659+
Assert.That (expBones[expBw.boneIndex1].name, Is.EqualTo (origBones[origBw.boneIndex1].name), nameMsg);
660+
661+
Assert.That (expBw.boneIndex2, Is.EqualTo (origBw.boneIndex2), string.Format(indexMsg, 2));
662+
Assert.That (expBones[expBw.boneIndex2].name, Is.EqualTo (origBones[origBw.boneIndex2].name), nameMsg);
663+
664+
Assert.That (expBw.boneIndex3, Is.EqualTo (origBw.boneIndex3), string.Format(indexMsg, 3));
665+
Assert.That (expBones[expBw.boneIndex3].name, Is.EqualTo (origBones[origBw.boneIndex3].name), nameMsg);
666+
667+
var message = "Bone weight {0} doesn't match";
668+
Assert.That (expBw.weight0, Is.EqualTo (origBw.weight0).Within(0.001f), string.Format(message, 0));
669+
Assert.That (expBw.weight1, Is.EqualTo (origBw.weight1).Within(0.001f), string.Format(message, 1));
670+
Assert.That (expBw.weight2, Is.EqualTo (origBw.weight2).Within(0.001f), string.Format(message, 2));
671+
Assert.That (expBw.weight3, Is.EqualTo (origBw.weight3).Within(0.001f), string.Format(message, 3));
672+
673+
comparisonCount++;
674+
break;
675+
}
676+
}
677+
}
678+
Debug.LogWarningFormat ("Compared {0} out of a possible {1} bone weights", comparisonCount, minVertCount);
679+
}
597680
}
598681
}

0 commit comments

Comments
 (0)