using System; using System.Collections.Generic; using Autodesk.Max; using BabylonExport.Entities; using SharpDX; namespace Max2Babylon { internal class BonePoseInfo { public IGMatrix AbsoluteTransform { get; set; } public IGMatrix LocalTransform { get; set; } } partial class BabylonExporter { readonly List skins = new List(); readonly List skinnedNodes = new List(); IGMatrix WithNoScale(IGMatrix mat) { var mat3 = mat.ExtractMatrix3(); mat3.NoScale(); return Loader.Global.GMatrix.Create(mat3); } private void ExportSkin( IIGameSkin skin, BabylonScene babylonScene) { var babylonSkeleton = new BabylonSkeleton { id = skins.IndexOf(skin) }; babylonSkeleton.name = "skeleton #" + babylonSkeleton.id; RaiseMessage(babylonSkeleton.name, 1); IGMatrix skinInitMatrix = Loader.Global.GMatrix.Create(Loader.Global.Matrix3.Create(true)); skin.GetInitSkinTM(skinInitMatrix); var skinIndex = skins.IndexOf(skin); var meshNode = skinnedNodes[skinIndex]; var meshInitMatrix = meshNode.GetObjectTM(0); var boneIds = skinSortedBones[skin]; var bones = new BabylonBone[boneIds.Count]; var gameBones = new IIGameNode[boneIds.Count]; var bindPoseInfos = new BonePoseInfo[boneIds.Count]; for (var unsortedIndex = 0; unsortedIndex < skin.TotalSkinBoneCount; unsortedIndex++) { var gameBone = skin.GetIGameBone(unsortedIndex, false); int index = gameBone == null ? boneIds.IndexOf(-2) : boneIds.IndexOf(gameBone.NodeID); if (gameBone == null) { gameBones[index]=null; bones[index] = new BabylonBone { index = index, name = "null-bone" }; bindPoseInfos[index] = new BonePoseInfo { }; } else { gameBones[index] = gameBone; bones[index] = new BabylonBone { index = index, name = gameBone.Name }; //IGMatrix boneInitMatrix = Loader.Global.GMatrix.Create(Loader.Global.Matrix3.Create(true)); var boneInitMatrix = gameBone.GetObjectTM(0); bindPoseInfos[index] = new BonePoseInfo { AbsoluteTransform = boneInitMatrix }; } } // fix hierarchy an generate animation keys for (var index = 0; index < skin.TotalSkinBoneCount; index++) { var gameBone = gameBones[index]; if (gameBone == null) { var babBone = bones[index]; bindPoseInfos[index].LocalTransform = Loader.Global.GMatrix.Create(Loader.Global.Matrix3.Create(true)); babBone.matrix = bindPoseInfos[index].LocalTransform.ToArray(); } else { var parent = gameBone.NodeParent; var babBone = bones[index]; if (parent != null) { babBone.parentBoneIndex = boneIds.IndexOf(parent.NodeID); } if (babBone.parentBoneIndex == -1) { bindPoseInfos[index].LocalTransform = bindPoseInfos[index].AbsoluteTransform.Multiply(meshInitMatrix.Inverse); } else { var parentBindPoseInfos = bindPoseInfos[babBone.parentBoneIndex]; bindPoseInfos[index].LocalTransform = bindPoseInfos[index].AbsoluteTransform.Multiply(parentBindPoseInfos.AbsoluteTransform.Inverse); } babBone.matrix = bindPoseInfos[index].LocalTransform.ToArray(); var babylonAnimation = new BabylonAnimation { name = gameBone.Name + "Animation", property = "_matrix", dataType = BabylonAnimation.DataType.Matrix, loopBehavior = BabylonAnimation.LoopBehavior.Cycle, framePerSecond = Loader.Global.FrameRate }; var start = Loader.Core.AnimRange.Start; var end = Loader.Core.AnimRange.End; float[] previous = null; var keys = new List(); for (var key = start; key <= end; key += Ticks) { var objectTM = gameBone.GetObjectTM(key); var parentNode = gameBone.NodeParent; IGMatrix mat; if (parentNode == null || babBone.parentBoneIndex == -1) { mat = objectTM.Multiply(meshNode.GetObjectTM(key).Inverse); } else { mat = objectTM.Multiply(parentNode.GetObjectTM(key).Inverse); } var current = mat.ToArray(); if (key == start || key == end || !(previous.IsEqualTo(current))) { keys.Add(new BabylonAnimationKey { frame = key / Ticks, values = current }); } previous = current; } babylonAnimation.keys = keys.ToArray(); babBone.animation = babylonAnimation; } } babylonSkeleton.bones = bones; babylonScene.SkeletonsList.Add(babylonSkeleton); } } }