Updating The Difference Matrix

Yo @bghgary or @Deltakosh … It turns out i am still having issues with creating native babylon skeletons in Unity using the Babylon Entities.

In the 3DSMax its seems you are NOT actually calculating the bone.matrix from the bind poses… But instead just set the bone local transform matrix and set needInitialSkinMatrix = true

But in Unity it we build the bone matrix using the bindpose inverse matrix (multiplied by parent bone matrix if has one).

I think those approach is MISSING the update difference matrix part because this way is not taking into account the bone’s local transform matrix… Some some animation get rotated when they should not be.

In GLTF… @bghgary … this is how you are dealing with this:


 private _updateBoneMatrices(babylonSkeleton: Skeleton, inverseBindMatricesData: Nullable<Float32Array>): void {
        for (const babylonBone of babylonSkeleton.bones) {
            let baseMatrix = Matrix.Identity();
            const boneIndex = babylonBone._index!;
            if (inverseBindMatricesData && boneIndex !== -1) {
                Matrix.FromArrayToRef(inverseBindMatricesData, boneIndex * 16, baseMatrix);
                baseMatrix.invertToRef(baseMatrix);
            }

            const babylonParentBone = babylonBone.getParent();
            if (babylonParentBone) {
                baseMatrix.multiplyToRef(babylonParentBone.getInvertedAbsoluteTransform(), baseMatrix);
            }

            babylonBone.updateMatrix(baseMatrix, false, false);
            babylonBone._updateDifferenceMatrix(undefined, false);
        }
    }

In Unity C#… This is how i am creating the skeleton:


        public static BabylonSkeleton CreateBabylonSkeleton(SkinnedMeshRenderer skin, bool switchHandedness = false)
        {
            Transform root = skin.rootBone;
            Transform[] bones = skin.bones;
            BabylonSkeleton babylonSkeleton = new BabylonSkeleton();
            babylonSkeleton.id = Math.Abs(UnityTools.GetID(root).GetHashCode());
            babylonSkeleton.name = (skin.transform.parent != null) ? skin.transform.parent.name : skin.transform.name;
            babylonSkeleton.needInitialSkinMatrix = false;

            Matrix4x4[] bindPoses = skin.sharedMesh.bindposes;
            var transformToBoneMap = new Dictionary<Transform, BabylonBone>();
            for (var i = 0; i < bones.Length; i++)
            {
                Transform unityBone = bones[i];
                string boneTranformId = UnityTools.GetID(unityBone);
                Dictionary<string, object> boneMetaData = new Dictionary<string, object>();
                boneMetaData["path"] = UnityTools.FormatTransformPath(unityBone, root, true);
                var babylonBone = new BabylonBone();
                babylonBone.id = ("bone_" + boneTranformId);
                babylonBone.name = unityBone.name;
                babylonBone.index = i;
                babylonBone.metadata = boneMetaData;
                babylonBone.linkedTransformNodeId = (CanvasToolsInfo.Instance.BoneExportSystem == (int)EditorBoneTransform.Linked) ? boneTranformId : null;
                transformToBoneMap[unityBone] = babylonBone;
            }
            // ..
            // Attaches parent bone indexs and bind poses
            // ..
            for (var i = 0; i < bones.Length; i++)
            {
                var unityBone = bones[i];
                var babylonBone = transformToBoneMap[unityBone];
                var poseMatrix = Matrix4x4.identity;
                var localMatrix = Matrix4x4.TRS(unityBone.localPosition, unityBone.localRotation, unityBone.localScale);
                
                if (transformToBoneMap.ContainsKey(unityBone.parent))
                {
                    var babylonParentBone = transformToBoneMap[unityBone.parent];
                    babylonBone.parentBoneIndex = babylonParentBone.index;
                    poseMatrix = bindPoses[babylonBone.parentBoneIndex] * bindPoses[i].inverse;
                }
                else
                {
                    babylonBone.parentBoneIndex = -1;
                    poseMatrix = bindPoses[i].inverse;
                }

                babylonBone.matrix = UnityTools.GenerateMatrixFloats(new Matrix4x4[]{ poseMatrix }, switchHandedness);
            }
            // Reorder skeleton bones
            babylonSkeleton.bones = transformToBoneMap.Values.OrderBy(b => b.index).ToArray();
            return babylonSkeleton;
        }


as you can see here:


                if (transformToBoneMap.ContainsKey(unityBone.parent))
                {
                    var babylonParentBone = transformToBoneMap[unityBone.parent];
                    babylonBone.parentBoneIndex = babylonParentBone.index;
                    poseMatrix = bindPoses[babylonBone.parentBoneIndex] * bindPoses[i].inverse;
                }
                else
                {
                    babylonBone.parentBoneIndex = -1;
                    poseMatrix = bindPoses[i].inverse;
                }

This is where i am doing the same thing in your _updateBoneMatrices… Which is basically taking the inverted bindpose matrix and multiply with parent inverse bindpose.

The thing you have have is the call to _updateDifferenceMatrix

I am assuming this is the piece i am missing from the C# code to create a matrix for the bone that gets serialized in the BabylonBone.cs (Using Babylon.Entities)

Can you please tell me how apply the difference to the C# code above: poseMatrix

_updateDifferenceMatrix is an optimization to avoid recalculating a bunch of matrices and should have nothing to do with what you are doing. It’s hard for me to figure out without being able to debug the code, but it doesn’t look like you are taking the bone’s local matrix into account anywhere (localMatrix isn’t referenced). In the glTF loader, this is accounted for in getInvertedAbsoluteTransform(). Some day I should write up how all the maths work.

I thought so… I have the localMatrix but I don’t know the maths to apply the localMatrix to the poseMatrix… how would I do that in c# using Matrix4x4 ???

Yo @Deltakosh you think you could help with this… I’m not sure the maths to take into account the local matrix with the poseMatrix. I tried multiply using the local matrix of the parent bone… but that’s obviously not it . I wanna put this as the fix for the current edition of the toolkit that I now call the Classic Edition

Or Anybody Else that knows how to apply the bone’s local matrix in the skeleton… ???

I tried multiply the bone’s actual local matrix with the calculated inverse bind poses (if not root bone)… But it get even worse… So if anyone know what the deal is with creating Babylon Skeleton using the entities and calculating the bone local matrix property…

Please help so i can fix the LONG STANDING issue with the Unity Exporter and native babylon skeletons :frowning:

on my phone now but did you check the math directly in the skeleton class? this is where we compute the final matrices

Yeah I did … but still can’t get working right.

All the different codes I seen for doing this use a different approach for handling the initial bone matrix.

The Babylon entities use Autodesk API to get the local bone matrix only and set that to bone.matrix and use the needInitialSkinWeights to true

While I Unity we set need initial skin to false and actually TRY and compute the final bone matrix using the actual bind poses from unity mesh. But what I am missing is WHEN, WHERE and HOW to apply the bone local matrix with the bind pose matrix to get that final pose matrix to store on the Babylon entities bone.matrix

So @Deltakosh can you explain to me how to apply that local matrix to the bind pose matrix… I tried multiply bone local matrix with pose matrix for parent bones… I tried for each bone… I can’t figure out WHERE to multiply the local bone matrix

Anybody… got anything on this ?

I really need to fix this issue.