- Home /
How to Calculate BindPoses From My data?
I have Gltf Bone Skeleton Values in json format(PFA):
Bind_Matrix4x4
Bone_Inverses_Matrix4x4 [23]
Bone_Transforms [23]
(The uuid in bone array is just the bone object names i create in unity3d in runtime)
The documentation of this data tells me:
Bind matrix is the initial object world matrix so that if skeleton is offset from object during the time it is bound that relationship is preserved.
Inverse matrices are the inverses of bone world matrix.
In Unity3d i convert these gltf to unity space and while creating SkinnedMeshRenderer I do the following now.
Matrix4x4[23] bindposes;
foreach(Bone){
bindposes[curBoneId] = Bind_Mat4x4 * Bone_Inverses_Mat4x4[ curBoneId];
}
skinnedMeshRenderer.sharedMesh.bindposes = bindposes;
skinnedMeshRenderer.bones = boneTransforms;
skinnedMeshRenderer.rootBone = boneTransforms[0];
The way I create Bind Poses Are wrong i think(mesh is skewed).
Need Some Math Help here.
How to calculate Bindpose for each bone if bind matrix4x4 and bone Inverses are given separably like in the attached json?
Answer by Bunny83 · Jun 01, 2020 at 08:44 AM
Matrix multiplication is from right to left. So the incoming vertex first has to go though the Bind_Mat4x4 to convert from mesh local space to worldspace. After that you go through the inverse of the bone matrix to convert from worldspace to the local space of the bone. That's the bind pose. At runtime during skinning the last step is to use the current bone transform local to world matrix to calculate the final worldspace position.
So the bind pose has to look like this
bindposes[curBoneId] = Bone_Inverses_Mat4x4[ curBoneId] * Bind_Mat4x4;
There's a code example in the documentation. For reference here's my matrix crash course. If you're really want to dig into linear algebra I can highly recommend the 3B1B series "essence of linear algebra"
The mesh is still skewed. But if i do not use the given data and just calculate bindposes using the following
bindposes[currBoneIdx] = boneTransforms[currBoneIdx].worldToLocal$$anonymous$$atrix * boneTransforms[0].localToWorld$$anonymous$$atrix;
The mesh appears correct .
This is the code that i use to convert the data from gltf space to unity3d space.
public static readonly Vector3 CoordinateSpaceConversionScale = new Vector3(-1, 1, 1);
private static $$anonymous$$atrix4x4 ToUnity$$anonymous$$atrix4x4($$anonymous$$atrix4x4 gltf$$anonymous$$at4)
{
$$anonymous$$atrix4x4 convert = $$anonymous$$atrix4x4.Scale(CoordinateSpaceConversionScale);
$$anonymous$$atrix4x4 unity$$anonymous$$at = convert * gltf$$anonymous$$at4 * convert;
return unity$$anonymous$$at;
}
private static $$anonymous$$atrix4x4 CreateGltf$$anonymous$$atrix4x4(List<object> readFloatArray)
{//loading them in colum major format
$$anonymous$$atrix4x4 gltf$$anonymous$$at = new $$anonymous$$atrix4x4();
gltf$$anonymous$$at.m00 = (float)double.Parse(readFloatArray[0].ToString());
gltf$$anonymous$$at.m10 = (float)double.Parse(readFloatArray[1].ToString());
gltf$$anonymous$$at.m20 = (float)double.Parse(readFloatArray[2].ToString());
gltf$$anonymous$$at.m30 = (float)double.Parse(readFloatArray[3].ToString());
gltf$$anonymous$$at.m01 = (float)double.Parse(readFloatArray[4].ToString());
gltf$$anonymous$$at.m11 = (float)double.Parse(readFloatArray[5].ToString());
gltf$$anonymous$$at.m21 = (float)double.Parse(readFloatArray[6].ToString());
gltf$$anonymous$$at.m31 = (float)double.Parse(readFloatArray[7].ToString());
gltf$$anonymous$$at.m02 = (float)double.Parse(readFloatArray[8].ToString());
gltf$$anonymous$$at.m12 = (float)double.Parse(readFloatArray[9].ToString());
gltf$$anonymous$$at.m22 = (float)double.Parse(readFloatArray[10].ToString());
gltf$$anonymous$$at.m32 = (float)double.Parse(readFloatArray[11].ToString());
gltf$$anonymous$$at.m03 = (float)double.Parse(readFloatArray[12].ToString());
gltf$$anonymous$$at.m13 = (float)double.Parse(readFloatArray[13].ToString());
gltf$$anonymous$$at.m23 = (float)double.Parse(readFloatArray[14].ToString());
gltf$$anonymous$$at.m33 = (float)double.Parse(readFloatArray[15].ToString());
return gltf$$anonymous$$at;
}
https://docs.unity3d.com/ScriptReference/$$anonymous$$esh-boneWeights.html
"The bone weights should be in descending order (most significant first) and add up to 1." - In some cases this fails for the model that i load. PFA : 1.png,2.png
Could this be the problem?
Skinned$$anonymous$$eshRenderer does this right ? ![alt text][1] ![alt text][2] @Bunny83 Thanks for your help and time. [1]: /storage/temp/160981-1.jpg [2]: /storage/temp/160982-2.pngAt runtime during skinning the last step is to use the current bone transform local to world matrix to calculate the final worldspace position
Answer by Sudar-shan · Jun 02, 2020 at 06:55 PM
@Bunny83 Thanks that did the trick. But now The triangles are inverted like this. After id do this they appear correct:
skinnedMeshRenderer.sharedMesh.triangles = skinnedMeshRenderer.sharedMesh.triangles.Reverse().ToArray();
Your answer
Follow this Question
Related Questions
NullReferenceException using Matrix4x4? 2 Answers
Taking the user's screen resolution before running a GUI.matrix? 0 Answers
GUI Matrix problem 1 Answer
Detect GUI rotation degree 1 Answer
Unity Reload Bullets left 1 Answer