BabylonExporter.Skeleton.cs 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. using System;
  2. using System.Collections.Generic;
  3. using Autodesk.Max;
  4. using BabylonExport.Entities;
  5. using SharpDX;
  6. namespace Max2Babylon
  7. {
  8. internal class BonePoseInfo
  9. {
  10. public IGMatrix AbsoluteTransform { get; set; }
  11. public IGMatrix LocalTransform { get; set; }
  12. }
  13. partial class BabylonExporter
  14. {
  15. readonly List<IIGameSkin> skins = new List<IIGameSkin>();
  16. readonly List<IIGameNode> skinnedNodes = new List<IIGameNode>();
  17. IGMatrix WithNoScale(IGMatrix mat)
  18. {
  19. var mat3 = mat.ExtractMatrix3();
  20. mat3.NoScale();
  21. return Loader.Global.GMatrix.Create(mat3);
  22. }
  23. private void ExportSkin(IIGameSkin skin, BabylonScene babylonScene)
  24. {
  25. var babylonSkeleton = new BabylonSkeleton { id = skins.IndexOf(skin) };
  26. babylonSkeleton.name = "skeleton #" + babylonSkeleton.id;
  27. RaiseMessage(babylonSkeleton.name, 1);
  28. var skinIndex = skins.IndexOf(skin);
  29. var meshNode = skinnedNodes[skinIndex];
  30. var skinInitMatrix = meshNode.GetObjectTM(0);
  31. var bones = new List<BabylonBone>();
  32. var gameBones = new List<IIGameNode>();
  33. var boneIds = new List<int>();
  34. var bindPoseInfos = new List<BonePoseInfo>();
  35. for(int i = 0; i < skin.TotalSkinBoneCount; ++i)
  36. {
  37. bones.Add(null);
  38. gameBones.Add(null);
  39. boneIds.Add(-1);
  40. bindPoseInfos.Add(null);
  41. }
  42. for (var index = 0; index < skin.TotalSkinBoneCount; index++)
  43. {
  44. var gameBone = skin.GetIGameBone(index, false);
  45. var sortedIndex = skinSortedBones[skin].IndexOf(gameBone.NodeID);
  46. gameBones[sortedIndex] = (gameBone);
  47. boneIds[sortedIndex] =(gameBone.NodeID);
  48. bones[sortedIndex]=(new BabylonBone { index = sortedIndex, name = gameBone.Name });
  49. var boneInitMatrix = gameBone.GetObjectTM(0);
  50. bindPoseInfos[sortedIndex] = (new BonePoseInfo { AbsoluteTransform = boneInitMatrix });
  51. }
  52. // fix hierarchy an generate animation keys
  53. var exportNonOptimizedAnimations = Loader.Core.RootNode.GetBoolProperty("babylonjs_exportnonoptimizedanimations");
  54. for (var index = 0; index < skin.TotalSkinBoneCount; index++)
  55. {
  56. var gameBone = gameBones[index];
  57. var parent = gameBone.NodeParent;
  58. var babBone = bones[index];
  59. if (parent != null)
  60. {
  61. babBone.parentBoneIndex = boneIds.IndexOf(parent.NodeID);
  62. }
  63. if (babBone.parentBoneIndex == -1)
  64. {
  65. bindPoseInfos[index].LocalTransform = bindPoseInfos[index].AbsoluteTransform.Multiply(skinInitMatrix.Inverse);
  66. }
  67. else
  68. {
  69. var parentBindPoseInfos = bindPoseInfos[babBone.parentBoneIndex];
  70. bindPoseInfos[index].LocalTransform = bindPoseInfos[index].AbsoluteTransform.Multiply(parentBindPoseInfos.AbsoluteTransform.Inverse);
  71. }
  72. babBone.matrix = bindPoseInfos[index].LocalTransform.ToArray();
  73. var babylonAnimation = new BabylonAnimation
  74. {
  75. name = gameBone.Name + "Animation",
  76. property = "_matrix",
  77. dataType = (int)BabylonAnimation.DataType.Matrix,
  78. loopBehavior = (int)BabylonAnimation.LoopBehavior.Cycle,
  79. framePerSecond = Loader.Global.FrameRate
  80. };
  81. var start = Loader.Core.AnimRange.Start;
  82. var end = Loader.Core.AnimRange.End;
  83. float[] previous = null;
  84. var keys = new List<BabylonAnimationKey>();
  85. for (var key = start; key <= end; key += Ticks)
  86. {
  87. var objectTM = gameBone.GetObjectTM(key);
  88. var parentNode = gameBone.NodeParent;
  89. IGMatrix mat;
  90. if (parentNode == null || babBone.parentBoneIndex == -1)
  91. {
  92. mat = objectTM.Multiply(meshNode.GetObjectTM(key).Inverse);
  93. }
  94. else
  95. {
  96. mat = objectTM.Multiply(parentNode.GetObjectTM(key).Inverse);
  97. }
  98. var current = mat.ToArray();
  99. if (key == start || key == end || exportNonOptimizedAnimations || !(previous.IsEqualTo(current)))
  100. {
  101. keys.Add(new BabylonAnimationKey
  102. {
  103. frame = key / Ticks,
  104. values = current
  105. });
  106. }
  107. previous = current;
  108. }
  109. babylonAnimation.keys = keys.ToArray();
  110. babBone.animation = babylonAnimation;
  111. }
  112. babylonSkeleton.bones = bones.ToArray();
  113. babylonScene.SkeletonsList.Add(babylonSkeleton);
  114. }
  115. }
  116. }