Skip to content

Commit

Permalink
[#D3D-2966] Updates skin serialization (2.0)
Browse files Browse the repository at this point in the history
  • Loading branch information
AurL committed Jun 20, 2017
1 parent 7fb5480 commit 779342e
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 52 deletions.
4 changes: 2 additions & 2 deletions GlTF_Attributes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -131,12 +131,12 @@ public override void Write ()
if (jointAccessor != null)
{
CommaNL();
Indent(); jsonWriter.Write("\"JOINT\": " + GlTF_Writer.accessors.IndexOf(jointAccessor));
Indent(); jsonWriter.Write("\"JOINTS_0\": " + GlTF_Writer.accessors.IndexOf(jointAccessor));
}
if (weightAccessor != null)
{
CommaNL();
Indent(); jsonWriter.Write("\"WEIGHT\": " + GlTF_Writer.accessors.IndexOf(weightAccessor));
Indent(); jsonWriter.Write("\"WEIGHTS_0\": " + GlTF_Writer.accessors.IndexOf(weightAccessor));
}
if (tangentAccessor != null)
{
Expand Down
26 changes: 2 additions & 24 deletions GlTF_Node.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ public class GlTF_Node : GlTF_Writer {
public GlTF_Translation translation;
public int skinIndex = -1;
public List<string> skeletons = new List<string>();
public string jointName = "";
public bool additionalProperties = false;

public static string GetNameFromObject(Object o)
Expand All @@ -35,7 +34,7 @@ public override void Write ()
IndentIn();
Indent();
CommaNL();
jsonWriter.Write ("\"name\": \""+ id + "\"");
jsonWriter.Write ("\"name\": \"" + id + "\"");
if (cameraName != null)
{
CommaNL();
Expand Down Expand Up @@ -70,12 +69,6 @@ public override void Write ()
Indent(); jsonWriter.Write ("]");
}

if (jointName.Length > 0)
{
CommaNL();
Indent(); jsonWriter.Write("\"jointName\": \"" + jointName + "\"");
}

if (matrix != null)
{
CommaNL();
Expand All @@ -100,23 +93,8 @@ public override void Write ()
}
}
jsonWriter.Write("\n");
if(skeletons.Count > 0)
{
CommaNL();
Indent(); jsonWriter.Write("\"skeletons\": [\n");
IndentIn();
if(skeletons.Count > 0)
foreach(string s in skeletons)
{
CommaNL();
Indent(); jsonWriter.Write("" + GlTF_Writer.nodeNames.IndexOf(s) + "\n");
}

IndentOut();
Indent(); jsonWriter.Write("]");
}

if(skinIndex > -1)
if (skinIndex > -1)
{
CommaNL();
Indent(); jsonWriter.Write("\"skin\": " + skinIndex + "\n");
Expand Down
103 changes: 82 additions & 21 deletions GlTF_Skin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ public class GlTF_Skin : GlTF_Writer {
public Matrix4x4[] invBindMatrices;
public int invBindMatricesAccessorIndex;
public Transform node;
public string[] jointNames;
public List<Transform> joints;
public List<Transform> jointNames;
public Transform mesh;
public Transform rootBone;

public GlTF_Skin() { }

Expand All @@ -28,35 +30,42 @@ public void Populate (Transform m, ref GlTF_Accessor invBindMatricesAccessor, in
// In this case we also make this matrix relative to the root
// So that we can move the root game object around freely
Mesh mesh = skinMesh.sharedMesh;
Matrix4x4[] invBindMatrices = new Matrix4x4[skinMesh.sharedMesh.bindposes.Length];
joints = new List<Transform>();
//Collect all bones from skin object. Order should be kept here since bones are referenced in the mesh
foreach(Transform t in skinMesh.bones)
{
joints.Add(t);
}

// glTF expects a single hierarchy of bones, but Unity skips all the nodes that are not used.
// Find the common ancestor of all used bones in order to get a valid bone herarchy
rootBone = rebuildBoneHierarchy(skinMesh, ref joints);

for(int i=0;i<invBindMatrices.Length;++i)
Matrix4x4[] invBindMatrices = new Matrix4x4[joints.Count];

for (int i = 0; i < invBindMatrices.Length; ++i)
{
// Generates inverseWorldMatrix in right-handed coordinate system
// Manually converts world translation and rotation from left to right handed coordinates systems
Vector3 pos = skinMesh.bones[i].position;
Quaternion rot = skinMesh.bones[i].rotation;
Vector3 pos = joints[i].position;
Quaternion rot = joints[i].rotation;
convertQuatLeftToRightHandedness(ref rot);
convertVector3LeftToRightHandedness(ref pos);

invBindMatrices[i] = Matrix4x4.TRS(pos, rot, skinMesh.bones[i].lossyScale).inverse * sceneRootMatrix.inverse;
invBindMatrices[i] = Matrix4x4.TRS(pos, rot, joints[i].lossyScale).inverse * sceneRootMatrix.inverse;
}

invBindMatricesAccessor.Populate(invBindMatrices, m);
invBindMatricesAccessorIndex = invBindAccessorIndex;

// Fill jointNames
jointNames = new string[skinMesh.bones.Length];
for(int i=0; i< skinMesh.bones.Length; ++i)
{
jointNames[i] = GlTF_Node.GetNameFromObject(skinMesh.bones[i]);
}
}

public static List<string> findRootSkeletons(SkinnedMeshRenderer skin)
// Rebuild hierarchy and returns root bone
public Transform rebuildBoneHierarchy(SkinnedMeshRenderer skin, ref List<Transform> joints)
{
List<string> skeletons = new List<string>();
List<Transform> tbones = new List<Transform>();
List<Transform> traversed = new List<Transform>(); // Will be returned and contain all the nodes that are in the hierarchy but not used as bones (that need to be converted)
Transform computedRoot = null;
// Get bones
foreach (Transform bone in skin.bones)
{
Expand All @@ -83,10 +92,60 @@ public static List<string> findRootSkeletons(SkinnedMeshRenderer skin)
{
tbones.Remove(b);
}
foreach (Transform t in tbones)
skeletons.Add(GlTF_Node.GetNameFromObject(t));

return skeletons;
// if more than one root, find common ancestor
if (tbones.Count > 1)
{
Transform rootSkeleton = null; //Will get the final root node
List<Transform> visited = new List<Transform>(tbones); // internal list to detect parenting
List<Transform> evol = new List<Transform>(tbones); // used to increment on each node
// Get the parent of each bone
while (evol.Count > 1)
{
for (int i = 0; i < evol.Count; ++i)
{
evol[i] = evol[i].parent;
if (evol[i] != null)
{
if(!traversed.Contains(evol[i]))
{
traversed.Add(evol[i]);
}

if (visited.Contains(evol[i]))
{
rootSkeleton = evol[i];
evol[i] = null;
}
else
{
visited.Add(evol[i]);
}
}
}

List<Transform> clean = new List<Transform>();
foreach (Transform t in evol)
{
if (t)
clean.Add(t);
}

evol = new List<Transform>(clean);
}

skeletons.Add(GlTF_Node.GetNameFromObject(rootSkeleton));
computedRoot = rootSkeleton;
}
else if (tbones.Count == 1)
{
skeletons.Add(GlTF_Node.GetNameFromObject(tbones[0]));
computedRoot = tbones[0];
}

joints.AddRange(traversed);

return computedRoot;
}

public override void Write ()
Expand All @@ -95,18 +154,20 @@ public override void Write ()
IndentIn();

Indent(); jsonWriter.Write("\"inverseBindMatrices\": "+ invBindMatricesAccessorIndex + ",\n");
Indent(); jsonWriter.Write ("\"jointNames\": [\n");
Indent(); jsonWriter.Write ("\"joints\": [\n");

IndentIn();
foreach (string j in jointNames)
foreach (Transform j in joints)
{
CommaNL();
Indent(); jsonWriter.Write ("\""+ j + "\"");
Indent(); jsonWriter.Write ("" + GlTF_Writer.nodeNames.IndexOf(GlTF_Node.GetNameFromObject(j)));
}

IndentOut();
jsonWriter.WriteLine();
Indent(); jsonWriter.Write ("],\n");
Indent(); jsonWriter.Write("\"name\": \"" + name + "\"\n");
Indent(); jsonWriter.Write("\"name\": \"" + name + "\",\n");
Indent(); jsonWriter.Write("\"skeleton\": " + GlTF_Writer.nodeNames.IndexOf(GlTF_Node.GetNameFromObject(rootBone)) + "\n");
IndentOut();
Indent(); jsonWriter.Write ("}");
}
Expand Down
5 changes: 0 additions & 5 deletions SceneToGlTFWiz.cs
Original file line number Diff line number Diff line change
Expand Up @@ -559,7 +559,6 @@ public IEnumerator Export(string path, Preset presetAsset, bool buildZip, bool e
SkinnedMeshRenderer skinMesh = tr.GetComponent<SkinnedMeshRenderer>();
if (exportAnimation && skinMesh != null && skinMesh.enabled && checkSkinValidity(skinMesh, trs) && skinMesh.rootBone != null)
{
node.skeletons = GlTF_Skin.findRootSkeletons(skinMesh);
GlTF_Skin skin = new GlTF_Skin();

skin.name = GlTF_Writer.cleanNonAlphanumeric(skinMesh.rootBone.name) + "_skeleton_" + GlTF_Writer.cleanNonAlphanumeric(node.name) + tr.GetInstanceID();
Expand All @@ -575,10 +574,6 @@ public IEnumerator Export(string path, Preset presetAsset, bool buildZip, bool e
node.skinIndex = GlTF_Writer.skins.IndexOf(skin);
}

// The node is a bone?
if (exportAnimation && bones.Contains(tr))
node.jointName = GlTF_Node.GetNameFromObject(tr);

foreach (Transform t in tr.transform)
{
if(t.gameObject.activeInHierarchy)
Expand Down

0 comments on commit 779342e

Please sign in to comment.