|
@@ -1,128 +1,129 @@
|
|
|
-using System;
|
|
|
+using Autodesk.Max;
|
|
|
+using BabylonExport.Entities;
|
|
|
+using System;
|
|
|
using System.Collections.Generic;
|
|
|
using System.IO;
|
|
|
using System.Linq;
|
|
|
-using Autodesk.Max;
|
|
|
-using BabylonExport.Entities;
|
|
|
-using System.Runtime.InteropServices;
|
|
|
|
|
|
namespace Max2Babylon
|
|
|
{
|
|
|
partial class BabylonExporter
|
|
|
{
|
|
|
+ private int bonesCount;
|
|
|
+
|
|
|
readonly Dictionary<IIGameSkin, List<int>> skinSortedBones = new Dictionary<IIGameSkin, List<int>>();
|
|
|
- List<int> SortBones(IIGameSkin skin)
|
|
|
+
|
|
|
+ private bool IsMeshExportable(IIGameNode meshNode)
|
|
|
{
|
|
|
- var boneIds = new List<int>();
|
|
|
- var boneIndex = new Dictionary<int, IIGameNode>();
|
|
|
- for (var index = 0; index < skin.TotalSkinBoneCount; index++)
|
|
|
+ if (meshNode.MaxNode.GetBoolProperty("babylonjs_noexport"))
|
|
|
{
|
|
|
- var bone = skin.GetIGameBone(index, false);
|
|
|
- if (bone == null)
|
|
|
- {
|
|
|
- // non bone in skeletton
|
|
|
- boneIds.Add(-2);
|
|
|
-
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- boneIds.Add(bone.NodeID);
|
|
|
- boneIndex[bone.NodeID] = bone;
|
|
|
- }
|
|
|
+ return false;
|
|
|
}
|
|
|
- while (true)
|
|
|
+
|
|
|
+ if (!ExportHiddenObjects && meshNode.MaxNode.IsHidden(NodeHideFlags.None, false))
|
|
|
{
|
|
|
- bool foundMisMatch = false;
|
|
|
- for (int i = 0; i < boneIds.Count; ++i)
|
|
|
- {
|
|
|
- var id = boneIds[i];
|
|
|
- if (id == -2)
|
|
|
- {
|
|
|
- continue;
|
|
|
- }
|
|
|
- var parent = boneIndex[id].NodeParent;
|
|
|
- if (parent != null)
|
|
|
- {
|
|
|
- var parentId = parent.NodeID;
|
|
|
- if (boneIds.IndexOf(parentId) > i)
|
|
|
- {
|
|
|
- boneIds.RemoveAt(i);
|
|
|
- boneIds.Insert(boneIds.IndexOf(parentId) + 1, id);
|
|
|
- foundMisMatch = true;
|
|
|
- break;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- if (!foundMisMatch)
|
|
|
- {
|
|
|
- break;
|
|
|
- }
|
|
|
+ return false;
|
|
|
}
|
|
|
- return boneIds;
|
|
|
|
|
|
+ return true;
|
|
|
}
|
|
|
|
|
|
- private string GetParentID(IIGameNode parentNode, BabylonScene babylonScene, IIGameScene scene)
|
|
|
+ private BabylonNode ExportDummy(IIGameScene scene, IIGameNode meshNode, BabylonScene babylonScene)
|
|
|
{
|
|
|
- var parentType = parentNode.IGameObject.IGameType;
|
|
|
- var parentId = parentNode.MaxNode.GetGuid().ToString();
|
|
|
- switch (parentType)
|
|
|
- {
|
|
|
- case Autodesk.Max.IGameObject.ObjectTypes.Light:
|
|
|
- case Autodesk.Max.IGameObject.ObjectTypes.Mesh:
|
|
|
- case Autodesk.Max.IGameObject.ObjectTypes.Camera:
|
|
|
- break;
|
|
|
+ RaiseMessage(meshNode.Name, 1);
|
|
|
|
|
|
+ var gameMesh = meshNode.IGameObject.AsGameMesh();
|
|
|
+ bool initialized = gameMesh.InitializeData; // needed, the property is in fact a method initializing the exporter that has wrongly been auto
|
|
|
+ // translated into a property because it has no parameters
|
|
|
|
|
|
- default:
|
|
|
- if (babylonScene.MeshesList.All(m => m.id != parentId))
|
|
|
- {
|
|
|
- ExportMesh(scene, parentNode, babylonScene);
|
|
|
- }
|
|
|
- break;
|
|
|
- }
|
|
|
- return parentId;
|
|
|
- }
|
|
|
+ var babylonMesh = new BabylonMesh { name = meshNode.Name, id = meshNode.MaxNode.GetGuid().ToString() };
|
|
|
+ babylonMesh.isDummy = true;
|
|
|
|
|
|
- private float[] QuaternionToEulerAngles(IQuat rotation)
|
|
|
- {
|
|
|
- float rotx = 0, roty = 0, rotz = 0;
|
|
|
- unsafe
|
|
|
- {
|
|
|
- rotation.GetEuler(new IntPtr(&rotx), new IntPtr(&roty), new IntPtr(&rotz));
|
|
|
- }
|
|
|
- return new[] { rotx, roty, rotz };
|
|
|
+ // Position / rotation / scaling / hierarchy
|
|
|
+ exportNode(babylonMesh, meshNode, scene, babylonScene);
|
|
|
+
|
|
|
+ babylonScene.MeshesList.Add(babylonMesh);
|
|
|
+
|
|
|
+ return babylonMesh;
|
|
|
}
|
|
|
|
|
|
- private int bonesCount;
|
|
|
- private void ExportMesh(IIGameScene scene, IIGameNode meshNode, BabylonScene babylonScene)
|
|
|
+ private BabylonNode ExportMesh(IIGameScene scene, IIGameNode meshNode, BabylonScene babylonScene)
|
|
|
{
|
|
|
- if (meshNode.MaxNode.IsInstance())
|
|
|
+ if (IsMeshExportable(meshNode) == false)
|
|
|
{
|
|
|
- return;
|
|
|
+ return null;
|
|
|
}
|
|
|
|
|
|
- if (meshNode.MaxNode.GetBoolProperty("babylonjs_noexport"))
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
+ RaiseMessage(meshNode.Name, 1);
|
|
|
|
|
|
- if (!ExportHiddenObjects && meshNode.MaxNode.IsHidden(NodeHideFlags.None, false))
|
|
|
+ // Instances
|
|
|
+ var tabs = Loader.Global.NodeTab.Create();
|
|
|
+ Loader.Global.IInstanceMgr.InstanceMgr.GetInstances(meshNode.MaxNode, tabs);
|
|
|
+ if (tabs.Count > 1)
|
|
|
{
|
|
|
- return;
|
|
|
- }
|
|
|
+ // For a mesh with instances, we distinguish between master and instance meshes:
|
|
|
+ // - a master mesh stores all the info of the mesh (transform, hierarchy, animations + vertices, indices, materials, bones...)
|
|
|
+ // - an instance mesh only stores the info of the node (transform, hierarchy, animations)
|
|
|
|
|
|
- var gameMesh = meshNode.IGameObject.AsGameMesh();
|
|
|
- bool initialized = gameMesh.InitializeData; //needed, the property is in fact a method initializing the exporter that has wrongly been auto
|
|
|
- // translated into a property because it has no parameters
|
|
|
+ // Check if this mesh has already been exported
|
|
|
+ BabylonMesh babylonMasterMesh = null;
|
|
|
+ var index = 0;
|
|
|
+ while (babylonMasterMesh == null &&
|
|
|
+ index < tabs.Count)
|
|
|
+ {
|
|
|
+#if MAX2017
|
|
|
+ var indexer = index;
|
|
|
+#else
|
|
|
+ var indexer = new IntPtr(index);
|
|
|
+#endif
|
|
|
+ var tab = tabs[indexer];
|
|
|
|
|
|
- var babylonMesh = new BabylonMesh { name = meshNode.Name, id = meshNode.MaxNode.GetGuid().ToString() };
|
|
|
+ babylonMasterMesh = babylonScene.MeshesList.Find(_babylonMesh => {
|
|
|
+ // Same id
|
|
|
+ return _babylonMesh.id == tab.GetGuid().ToString() &&
|
|
|
+ // Mesh is not a dummy
|
|
|
+ _babylonMesh.isDummy == false;
|
|
|
+ });
|
|
|
|
|
|
- if (meshNode.NodeParent != null)
|
|
|
- {
|
|
|
- babylonMesh.parentId = GetParentID(meshNode.NodeParent, babylonScene, scene);
|
|
|
+ index++;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (babylonMasterMesh != null)
|
|
|
+ {
|
|
|
+ // Mesh already exported
|
|
|
+ // Export this node as instance
|
|
|
+
|
|
|
+ meshNode.MaxNode.MarkAsInstance();
|
|
|
+
|
|
|
+ var babylonInstanceMesh = new BabylonAbstractMesh { name = meshNode.Name, id = meshNode.MaxNode.GetGuid().ToString() };
|
|
|
+
|
|
|
+ // Add instance to master mesh
|
|
|
+ List<BabylonAbstractMesh> list = babylonMasterMesh.instances != null ? babylonMasterMesh.instances.ToList() : new List<BabylonAbstractMesh>();
|
|
|
+ list.Add(babylonInstanceMesh);
|
|
|
+ babylonMasterMesh.instances = list.ToArray();
|
|
|
+
|
|
|
+ // Export transform / hierarchy / animations
|
|
|
+ exportNode(babylonInstanceMesh, meshNode, scene, babylonScene);
|
|
|
+
|
|
|
+ // Animations
|
|
|
+ exportAnimation(babylonInstanceMesh, meshNode);
|
|
|
+
|
|
|
+ return babylonInstanceMesh;
|
|
|
+ }
|
|
|
}
|
|
|
+
|
|
|
+ var gameMesh = meshNode.IGameObject.AsGameMesh();
|
|
|
+ bool initialized = gameMesh.InitializeData; // needed, the property is in fact a method initializing the exporter that has wrongly been auto
|
|
|
+ // translated into a property because it has no parameters
|
|
|
+
|
|
|
+ var babylonMesh = new BabylonMesh { name = meshNode.Name, id = meshNode.MaxNode.GetGuid().ToString() };
|
|
|
+
|
|
|
+ // Position / rotation / scaling / hierarchy
|
|
|
+ exportNode(babylonMesh, meshNode, scene, babylonScene);
|
|
|
|
|
|
+ // Animations
|
|
|
+ exportAnimation(babylonMesh, meshNode);
|
|
|
+
|
|
|
// Sounds
|
|
|
var soundName = meshNode.MaxNode.GetStringProperty("babylonjs_sound_filename", "");
|
|
|
if (!string.IsNullOrEmpty(soundName))
|
|
@@ -205,34 +206,7 @@ namespace Max2Babylon
|
|
|
skinSortedBones[skin] = boneIds;
|
|
|
}
|
|
|
|
|
|
- // Position / rotation / scaling
|
|
|
- var localTM = meshNode.GetObjectTM(0);
|
|
|
- if (meshNode.NodeParent != null)
|
|
|
- {
|
|
|
- var parentWorld = meshNode.NodeParent.GetObjectTM(0);
|
|
|
- localTM.MultiplyBy(parentWorld.Inverse);
|
|
|
- }
|
|
|
-
|
|
|
- var meshTrans = localTM.Translation;
|
|
|
- var meshRotation = localTM.Rotation;
|
|
|
- var meshScale = localTM.Scaling;
|
|
|
- var exportQuaternions = Loader.Core.RootNode.GetBoolProperty("babylonjs_exportquaternions");
|
|
|
-
|
|
|
- babylonMesh.position = new[] { meshTrans.X, meshTrans.Y, meshTrans.Z };
|
|
|
-
|
|
|
- if (exportQuaternions)
|
|
|
- {
|
|
|
- babylonMesh.rotationQuaternion = new[] { meshRotation.X, meshRotation.Y, meshRotation.Z, -meshRotation.W };
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- babylonMesh.rotation = QuaternionToEulerAngles(meshRotation);
|
|
|
- }
|
|
|
-
|
|
|
- babylonMesh.scaling = new[] { meshScale.X, meshScale.Y, meshScale.Z };
|
|
|
-
|
|
|
// Mesh
|
|
|
- RaiseMessage(meshNode.Name, 1);
|
|
|
|
|
|
if (unskinnedMesh.IGameType == Autodesk.Max.IGameObject.ObjectTypes.Mesh && unskinnedMesh.MaxMesh != null)
|
|
|
{
|
|
@@ -437,96 +411,11 @@ namespace Max2Babylon
|
|
|
|
|
|
// Buffers - Indices
|
|
|
babylonMesh.indices = indices.ToArray();
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- // Instances
|
|
|
- var tabs = Loader.Global.NodeTab.Create();
|
|
|
-
|
|
|
- Loader.Global.IInstanceMgr.InstanceMgr.GetInstances(meshNode.MaxNode, tabs);
|
|
|
- var instances = new List<BabylonAbstractMesh>();
|
|
|
-
|
|
|
- for (var index = 0; index < tabs.Count; index++)
|
|
|
- {
|
|
|
-#if MAX2017
|
|
|
- var indexer = index;
|
|
|
-#else
|
|
|
- var indexer = new IntPtr(index);
|
|
|
-#endif
|
|
|
- var tab = tabs[indexer];
|
|
|
-
|
|
|
-#if !MAX2017
|
|
|
- Marshal.FreeHGlobal(indexer);
|
|
|
-#endif
|
|
|
-
|
|
|
- if (meshNode.MaxNode.GetGuid() == tab.GetGuid())
|
|
|
- {
|
|
|
- continue;
|
|
|
- }
|
|
|
- var instanceGameNode = scene.GetIGameNode(tab);
|
|
|
- if (instanceGameNode == null)
|
|
|
- {
|
|
|
- continue;
|
|
|
- }
|
|
|
- tab.MarkAsInstance();
|
|
|
-
|
|
|
- var instance = new BabylonAbstractMesh { name = tab.Name };
|
|
|
- {
|
|
|
- var instanceLocalTM = instanceGameNode.GetObjectTM(0);
|
|
|
-
|
|
|
- var instanceTrans = instanceLocalTM.Translation;
|
|
|
- var instanceRotation = instanceLocalTM.Rotation;
|
|
|
- var instanceScale = instanceLocalTM.Scaling;
|
|
|
-
|
|
|
- instance.id = instanceGameNode.MaxNode.GetGuid().ToString();
|
|
|
- instance.position = new[] { instanceTrans.X, instanceTrans.Y, instanceTrans.Z };
|
|
|
-
|
|
|
- if (exportQuaternions)
|
|
|
- {
|
|
|
- instance.rotationQuaternion = new[] { instanceRotation.X, instanceRotation.Y, instanceRotation.Z, -instanceRotation.W };
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- instance.rotation = QuaternionToEulerAngles(instanceRotation);
|
|
|
- }
|
|
|
-
|
|
|
- instance.scaling = new[] { instanceScale.X, instanceScale.Y, instanceScale.Z };
|
|
|
-
|
|
|
- if (instanceGameNode.NodeParent != null)
|
|
|
- {
|
|
|
- instance.parentId = GetParentID(instanceGameNode.NodeParent, babylonScene, scene);
|
|
|
- }
|
|
|
- }
|
|
|
- var instanceAnimations = new List<BabylonAnimation>();
|
|
|
- GenerateCoordinatesAnimations(meshNode, instanceAnimations);
|
|
|
- instance.animations = instanceAnimations.ToArray();
|
|
|
-
|
|
|
- instances.Add(instance);
|
|
|
- }
|
|
|
-
|
|
|
- babylonMesh.instances = instances.ToArray();
|
|
|
-
|
|
|
- // Animations
|
|
|
- var animations = new List<BabylonAnimation>();
|
|
|
-
|
|
|
- GenerateCoordinatesAnimations(meshNode, animations);
|
|
|
-
|
|
|
- if (!ExportFloatController(meshNode.MaxNode.VisController, "visibility", animations))
|
|
|
- {
|
|
|
- ExportFloatAnimation("visibility", animations, key => new[] { meshNode.MaxNode.GetVisibility(key, Tools.Forever) });
|
|
|
- }
|
|
|
-
|
|
|
- babylonMesh.animations = animations.ToArray();
|
|
|
-
|
|
|
- if (meshNode.MaxNode.GetBoolProperty("babylonjs_autoanimate", 1))
|
|
|
- {
|
|
|
- babylonMesh.autoAnimate = true;
|
|
|
- babylonMesh.autoAnimateFrom = (int)meshNode.MaxNode.GetFloatProperty("babylonjs_autoanimate_from");
|
|
|
- babylonMesh.autoAnimateTo = (int)meshNode.MaxNode.GetFloatProperty("babylonjs_autoanimate_to", 100);
|
|
|
- babylonMesh.autoAnimateLoop = meshNode.MaxNode.GetBoolProperty("babylonjs_autoanimateloop", 1);
|
|
|
}
|
|
|
|
|
|
babylonScene.MeshesList.Add(babylonMesh);
|
|
|
+
|
|
|
+ return babylonMesh;
|
|
|
}
|
|
|
|
|
|
private void ExtractFace(IIGameSkin skin, IIGameMesh unskinnedMesh, List<GlobalVertex> vertices, List<int> indices, bool hasUV, bool hasUV2, bool hasColor, bool hasAlpha, List<GlobalVertex>[] verticesAlreadyExported, ref int indexCount, ref int minVertexIndex, ref int maxVertexIndex, IFaceEx face, List<int> boneIds)
|
|
@@ -573,63 +462,56 @@ namespace Max2Babylon
|
|
|
CheckCancelled();
|
|
|
}
|
|
|
|
|
|
- public static void GenerateCoordinatesAnimations(IIGameNode meshNode, List<BabylonAnimation> animations)
|
|
|
+ List<int> SortBones(IIGameSkin skin)
|
|
|
{
|
|
|
- if (meshNode.IGameControl.IsAnimated(IGameControlType.Pos) ||
|
|
|
- meshNode.IGameControl.IsAnimated(IGameControlType.PosX) ||
|
|
|
- meshNode.IGameControl.IsAnimated(IGameControlType.PosY) ||
|
|
|
- meshNode.IGameControl.IsAnimated(IGameControlType.PosZ))
|
|
|
+ var boneIds = new List<int>();
|
|
|
+ var boneIndex = new Dictionary<int, IIGameNode>();
|
|
|
+ for (var index = 0; index < skin.TotalSkinBoneCount; index++)
|
|
|
{
|
|
|
- ExportVector3Animation("position", animations, key =>
|
|
|
+ var bone = skin.GetIGameBone(index, false);
|
|
|
+ if (bone == null)
|
|
|
{
|
|
|
- var worldMatrix = meshNode.GetObjectTM(key);
|
|
|
- if (meshNode.NodeParent != null)
|
|
|
- {
|
|
|
- var parentWorld = meshNode.NodeParent.GetObjectTM(key);
|
|
|
- worldMatrix.MultiplyBy(parentWorld.Inverse);
|
|
|
- }
|
|
|
- var trans = worldMatrix.Translation;
|
|
|
- return new[] { trans.X, trans.Y, trans.Z };
|
|
|
- });
|
|
|
- }
|
|
|
+ // non bone in skeletton
|
|
|
+ boneIds.Add(-2);
|
|
|
|
|
|
- if (meshNode.IGameControl.IsAnimated(IGameControlType.Rot) ||
|
|
|
- meshNode.IGameControl.IsAnimated(IGameControlType.EulerX) ||
|
|
|
- meshNode.IGameControl.IsAnimated(IGameControlType.EulerY) ||
|
|
|
- meshNode.IGameControl.IsAnimated(IGameControlType.EulerZ))
|
|
|
- {
|
|
|
- ExportQuaternionAnimation("rotationQuaternion", animations, key =>
|
|
|
+ }
|
|
|
+ else
|
|
|
{
|
|
|
- var worldMatrix = meshNode.GetObjectTM(key);
|
|
|
- if (meshNode.NodeParent != null)
|
|
|
- {
|
|
|
- var parentWorld = meshNode.NodeParent.GetObjectTM(key);
|
|
|
- worldMatrix.MultiplyBy(parentWorld.Inverse);
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- var rot = worldMatrix.Rotation;
|
|
|
- return new[] { rot.X, rot.Y, rot.Z, -rot.W };
|
|
|
- });
|
|
|
+ boneIds.Add(bone.NodeID);
|
|
|
+ boneIndex[bone.NodeID] = bone;
|
|
|
+ }
|
|
|
}
|
|
|
-
|
|
|
- if (meshNode.IGameControl.IsAnimated(IGameControlType.Scale))
|
|
|
+ while (true)
|
|
|
{
|
|
|
- ExportVector3Animation("scaling", animations, key =>
|
|
|
+ bool foundMisMatch = false;
|
|
|
+ for (int i = 0; i < boneIds.Count; ++i)
|
|
|
{
|
|
|
- var worldMatrix = meshNode.GetObjectTM(key);
|
|
|
- if (meshNode.NodeParent != null)
|
|
|
+ var id = boneIds[i];
|
|
|
+ if (id == -2)
|
|
|
{
|
|
|
- var parentWorld = meshNode.NodeParent.GetObjectTM(key);
|
|
|
- worldMatrix.MultiplyBy(parentWorld.Inverse);
|
|
|
+ continue;
|
|
|
}
|
|
|
- var scale = worldMatrix.Scaling;
|
|
|
-
|
|
|
- return new[] { scale.X, scale.Y, scale.Z };
|
|
|
- });
|
|
|
+ var parent = boneIndex[id].NodeParent;
|
|
|
+ if (parent != null)
|
|
|
+ {
|
|
|
+ var parentId = parent.NodeID;
|
|
|
+ if (boneIds.IndexOf(parentId) > i)
|
|
|
+ {
|
|
|
+ boneIds.RemoveAt(i);
|
|
|
+ boneIds.Insert(boneIds.IndexOf(parentId) + 1, id);
|
|
|
+ foundMisMatch = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!foundMisMatch)
|
|
|
+ {
|
|
|
+ break;
|
|
|
+ }
|
|
|
}
|
|
|
- }
|
|
|
+ return boneIds;
|
|
|
|
|
|
+ }
|
|
|
|
|
|
int CreateGlobalVertex(IIGameMesh mesh, IFaceEx face, int facePart, List<GlobalVertex> vertices, bool hasUV, bool hasUV2, bool hasColor, bool hasAlpha, List<GlobalVertex>[] verticesAlreadyExported, IIGameSkin skin, List<int> boneIds)
|
|
|
{
|
|
@@ -800,5 +682,107 @@ namespace Max2Babylon
|
|
|
|
|
|
return vertices.Count - 1;
|
|
|
}
|
|
|
+
|
|
|
+ private void exportNode(BabylonAbstractMesh babylonAbstractMesh, IIGameNode maxGameNode, IIGameScene maxGameScene, BabylonScene babylonScene)
|
|
|
+ {
|
|
|
+ // Position / rotation / scaling
|
|
|
+ exportTransform(babylonAbstractMesh, maxGameNode);
|
|
|
+
|
|
|
+ // Hierarchy
|
|
|
+ if (maxGameNode.NodeParent != null)
|
|
|
+ {
|
|
|
+ babylonAbstractMesh.parentId = maxGameNode.NodeParent.MaxNode.GetGuid().ToString();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private void exportTransform(BabylonAbstractMesh babylonAbstractMesh, IIGameNode maxGameNode)
|
|
|
+ {
|
|
|
+ // Position / rotation / scaling
|
|
|
+ var localTM = maxGameNode.GetObjectTM(0);
|
|
|
+ if (maxGameNode.NodeParent != null)
|
|
|
+ {
|
|
|
+ var parentWorld = maxGameNode.NodeParent.GetObjectTM(0);
|
|
|
+ localTM.MultiplyBy(parentWorld.Inverse);
|
|
|
+ }
|
|
|
+
|
|
|
+ var meshTrans = localTM.Translation;
|
|
|
+ var meshRotation = localTM.Rotation;
|
|
|
+ var meshScale = localTM.Scaling;
|
|
|
+
|
|
|
+ babylonAbstractMesh.position = new[] { meshTrans.X, meshTrans.Y, meshTrans.Z };
|
|
|
+
|
|
|
+ var rotationQuaternion = new BabylonQuaternion { X = meshRotation.X, Y = meshRotation.Y, Z = meshRotation.Z, W = -meshRotation.W };
|
|
|
+ if (ExportQuaternionsInsteadOfEulers)
|
|
|
+ {
|
|
|
+ babylonAbstractMesh.rotationQuaternion = rotationQuaternion.ToArray();
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ babylonAbstractMesh.rotation = rotationQuaternion.toEulerAngles().ToArray();
|
|
|
+ }
|
|
|
+
|
|
|
+ babylonAbstractMesh.scaling = new[] { meshScale.X, meshScale.Y, meshScale.Z };
|
|
|
+ }
|
|
|
+
|
|
|
+ private void exportAnimation(BabylonNode babylonNode, IIGameNode maxGameNode)
|
|
|
+ {
|
|
|
+ var animations = new List<BabylonAnimation>();
|
|
|
+
|
|
|
+ GenerateCoordinatesAnimations(maxGameNode, animations);
|
|
|
+
|
|
|
+ if (!ExportFloatController(maxGameNode.MaxNode.VisController, "visibility", animations))
|
|
|
+ {
|
|
|
+ ExportFloatAnimation("visibility", animations, key => new[] { maxGameNode.MaxNode.GetVisibility(key, Tools.Forever) });
|
|
|
+ }
|
|
|
+
|
|
|
+ babylonNode.animations = animations.ToArray();
|
|
|
+
|
|
|
+ if (maxGameNode.MaxNode.GetBoolProperty("babylonjs_autoanimate", 1))
|
|
|
+ {
|
|
|
+ babylonNode.autoAnimate = true;
|
|
|
+ babylonNode.autoAnimateFrom = (int)maxGameNode.MaxNode.GetFloatProperty("babylonjs_autoanimate_from");
|
|
|
+ babylonNode.autoAnimateTo = (int)maxGameNode.MaxNode.GetFloatProperty("babylonjs_autoanimate_to", 100);
|
|
|
+ babylonNode.autoAnimateLoop = maxGameNode.MaxNode.GetBoolProperty("babylonjs_autoanimateloop", 1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void GenerateCoordinatesAnimations(IIGameNode meshNode, List<BabylonAnimation> animations)
|
|
|
+ {
|
|
|
+ ExportVector3Animation("position", animations, key =>
|
|
|
+ {
|
|
|
+ var worldMatrix = meshNode.GetObjectTM(key);
|
|
|
+ if (meshNode.NodeParent != null)
|
|
|
+ {
|
|
|
+ var parentWorld = meshNode.NodeParent.GetObjectTM(key);
|
|
|
+ worldMatrix.MultiplyBy(parentWorld.Inverse);
|
|
|
+ }
|
|
|
+ var trans = worldMatrix.Translation;
|
|
|
+ return new[] { trans.X, trans.Y, trans.Z };
|
|
|
+ });
|
|
|
+
|
|
|
+ ExportQuaternionAnimation("rotationQuaternion", animations, key =>
|
|
|
+ {
|
|
|
+ var worldMatrix = meshNode.GetObjectTM(key);
|
|
|
+ if (meshNode.NodeParent != null)
|
|
|
+ {
|
|
|
+ var parentWorld = meshNode.NodeParent.GetObjectTM(key);
|
|
|
+ worldMatrix.MultiplyBy(parentWorld.Inverse);
|
|
|
+ }
|
|
|
+ var rot = worldMatrix.Rotation;
|
|
|
+ return new[] { rot.X, rot.Y, rot.Z, -rot.W };
|
|
|
+ });
|
|
|
+
|
|
|
+ ExportVector3Animation("scaling", animations, key =>
|
|
|
+ {
|
|
|
+ var worldMatrix = meshNode.GetObjectTM(key);
|
|
|
+ if (meshNode.NodeParent != null)
|
|
|
+ {
|
|
|
+ var parentWorld = meshNode.NodeParent.GetObjectTM(key);
|
|
|
+ worldMatrix.MultiplyBy(parentWorld.Inverse);
|
|
|
+ }
|
|
|
+ var scale = worldMatrix.Scaling;
|
|
|
+ return new[] { scale.X, scale.Y, scale.Z };
|
|
|
+ });
|
|
|
+ }
|
|
|
}
|
|
|
}
|