Explorar o código

Fix instantiation

noalak %!s(int64=8) %!d(string=hai) anos
pai
achega
ff01f8f2eb
Modificáronse 1 ficheiros con 145 adicións e 162 borrados
  1. 145 162
      Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Mesh.cs

+ 145 - 162
Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Mesh.cs

@@ -75,6 +75,7 @@ namespace Max2Babylon
 
 
                 default:
+                    // Create a dummy (empty mesh) when the type of parent node is not exportable (spline, xref...)
                     if (babylonScene.MeshesList.All(m => m.id != parentId))
                     {
                         ExportMesh(scene, parentNode, babylonScene);
@@ -97,10 +98,6 @@ namespace Max2Babylon
         private int bonesCount;
         private void ExportMesh(IIGameScene scene, IIGameNode meshNode, BabylonScene babylonScene)
         {
-            if (meshNode.MaxNode.IsInstance())
-            {
-                return;
-            }
 
             if (meshNode.MaxNode.GetBoolProperty("babylonjs_noexport"))
             {
@@ -112,17 +109,61 @@ namespace Max2Babylon
                 return;
             }
 
+            RaiseMessage(meshNode.Name, 1);
+
+            // Instances
+            var tabs = Loader.Global.NodeTab.Create();
+            Loader.Global.IInstanceMgr.InstanceMgr.GetInstances(meshNode.MaxNode, tabs);
+            if (tabs.Count > 1)
+            {
+                // 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)
+
+                // Check if this mesh has already been exported
+                BabylonMesh babylonMasterMesh = null;
+                for (var index = 0; index < tabs.Count; index++)
+                {
+#if MAX2017
+                    var indexer = index;
+#else
+                    var indexer = new IntPtr(index);
+#endif
+                    var tab = tabs[indexer];
+
+                    babylonMasterMesh = babylonScene.MeshesList.Find(_babylonMesh => _babylonMesh.id == tab.GetGuid().ToString());
+                }
+
+                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;
+                }
+            }
+            
             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() };
 
-            if (meshNode.NodeParent != null)
-            {
-                babylonMesh.parentId = GetParentID(meshNode.NodeParent, babylonScene, scene);
-            }
-
             // Sounds
             var soundName = meshNode.MaxNode.GetStringProperty("babylonjs_sound_filename", "");
             if (!string.IsNullOrEmpty(soundName))
@@ -205,34 +246,10 @@ 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 };
+            // Position / rotation / scaling / hierarchy
+            exportNode(babylonMesh, meshNode, scene, babylonScene);
 
             // Mesh
-            RaiseMessage(meshNode.Name, 1);
 
             if (unskinnedMesh.IGameType == Autodesk.Max.IGameObject.ObjectTypes.Mesh && unskinnedMesh.MaxMesh != null)
             {
@@ -440,91 +457,8 @@ namespace Max2Babylon
 
             }
 
-            // 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);
-            }
+            exportAnimation(babylonMesh, meshNode);
 
             babylonScene.MeshesList.Add(babylonMesh);
         }
@@ -573,61 +507,46 @@ namespace Max2Babylon
             CheckCancelled();
         }
 
-        public static void GenerateCoordinatesAnimations(IIGameNode meshNode, List<BabylonAnimation> animations)
+        public void GenerateCoordinatesAnimations(IIGameNode meshNode, List<BabylonAnimation> animations)
         {
-            if (meshNode.IGameControl.IsAnimated(IGameControlType.Pos) ||
-                meshNode.IGameControl.IsAnimated(IGameControlType.PosX) ||
-                meshNode.IGameControl.IsAnimated(IGameControlType.PosY) ||
-                meshNode.IGameControl.IsAnimated(IGameControlType.PosZ))
+            ExportVector3Animation("position", animations, key =>
             {
-                ExportVector3Animation("position", animations, key =>
+                var worldMatrix = meshNode.GetObjectTM(key);
+                if (meshNode.NodeParent != 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 };
-                });
-            }
+                    var parentWorld = meshNode.NodeParent.GetObjectTM(key);
+                    worldMatrix.MultiplyBy(parentWorld.Inverse);
+                }
+                var trans = worldMatrix.Translation;
+                return new[] { trans.X, trans.Y, trans.Z };
+            });
 
-            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 =>
             {
-                ExportQuaternionAnimation("rotationQuaternion", animations, key =>
+                var worldMatrix = meshNode.GetObjectTM(key);
+                if (meshNode.NodeParent != null)
                 {
-                    var worldMatrix = meshNode.GetObjectTM(key);
-                    if (meshNode.NodeParent != null)
-                    {
-                        var parentWorld = meshNode.NodeParent.GetObjectTM(key);
-                        worldMatrix.MultiplyBy(parentWorld.Inverse);
-                    }
+                    var parentWorld = meshNode.NodeParent.GetObjectTM(key);
+                    worldMatrix.MultiplyBy(parentWorld.Inverse);
+                }
 
 
-                    var rot = worldMatrix.Rotation;
-                    return new[] { rot.X, rot.Y, rot.Z, -rot.W };
-                });
-            }
+                var rot = worldMatrix.Rotation;
+                return new[] { rot.X, rot.Y, rot.Z, -rot.W };
+            });
 
-            if (meshNode.IGameControl.IsAnimated(IGameControlType.Scale))
+            ExportVector3Animation("scaling", animations, key =>
             {
-                ExportVector3Animation("scaling", animations, key =>
+                var worldMatrix = meshNode.GetObjectTM(key);
+                if (meshNode.NodeParent != null)
                 {
-                    var worldMatrix = meshNode.GetObjectTM(key);
-                    if (meshNode.NodeParent != null)
-                    {
-                        var parentWorld = meshNode.NodeParent.GetObjectTM(key);
-                        worldMatrix.MultiplyBy(parentWorld.Inverse);
-                    }
-                    var scale = worldMatrix.Scaling;
+                    var parentWorld = meshNode.NodeParent.GetObjectTM(key);
+                    worldMatrix.MultiplyBy(parentWorld.Inverse);
+                }
+                var scale = worldMatrix.Scaling;
 
-                    return new[] { scale.X, scale.Y, scale.Z };
-                });
-            }
+                return new[] { scale.X, scale.Y, scale.Z };
+            });
         }
 
 
@@ -800,5 +719,69 @@ 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 = GetParentID(maxGameNode.NodeParent, babylonScene, maxGameScene);
+            }
+        }
+
+        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;
+            var exportQuaternions = Loader.Core.RootNode.GetBoolProperty("babylonjs_exportquaternions");
+            
+            babylonAbstractMesh.position = new[] { meshTrans.X, meshTrans.Y, meshTrans.Z };
+
+            if (exportQuaternions)
+            {
+                babylonAbstractMesh.rotationQuaternion = new[] { meshRotation.X, meshRotation.Y, meshRotation.Z, -meshRotation.W };
+            }
+            else
+            {
+                babylonAbstractMesh.rotation = QuaternionToEulerAngles(meshRotation);
+            }
+
+            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);
+            }
+        }
     }
 }