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