Explorar o código

Fixing performances and crashes issues

David Catuhe %!s(int64=11) %!d(string=hai) anos
pai
achega
e2278fa5ac

+ 5 - 0
Exporters/3ds Max/BabylonExport.Entities/BabylonBone.cs

@@ -19,5 +19,10 @@ namespace BabylonExport.Entities
 
         [DataMember]
         public BabylonAnimation animation { get; set; }
+
+        public BabylonBone()
+        {
+            parentBoneIndex = -1;
+        }
     }
 }

BIN=BIN
Exporters/3ds Max/Max2Babylon-0.4.8.zip


+ 84 - 11
Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Mesh.cs

@@ -1,7 +1,7 @@
 using System;
 using System.Collections.Generic;
 using System.Linq;
-using System.Threading;
+using System.Runtime.InteropServices;
 using Autodesk.Max;
 using BabylonExport.Entities;
 using MaxSharp;
@@ -10,7 +10,8 @@ namespace Max2Babylon
 {
     partial class BabylonExporter
     {
-        private void ExportMesh(Node meshNode, BabylonScene babylonScene, CancellationToken token)
+        private int bonesCount;
+        private void ExportMesh(Node meshNode, BabylonScene babylonScene)
         {
             if (meshNode._Node.GetBoolProperty("babylonjs_noexport"))
             {
@@ -37,6 +38,15 @@ namespace Max2Babylon
             // Collisions
             babylonMesh.checkCollisions = meshNode._Node.GetBoolProperty("babylonjs_checkcollisions");
 
+            // Skin
+            var skin = GetSkinModifier(meshNode._Node);
+
+            if (skin != null)
+            {
+                babylonMesh.skeletonId = skins.IndexOf(skin);
+                bonesCount = skin.NumBones;
+            }
+
             // Position / rotation / scaling
             var wm = meshNode.GetWorldMatrix(0, meshNode.HasParent());
             babylonMesh.position = wm.Trans.ToArraySwitched();
@@ -55,10 +65,10 @@ namespace Max2Babylon
             //Marshal.Copy(yPtr, rotate, 1, 1);
             //Marshal.Copy(zPtr, rotate, 2, 1);
 
-            //var temp = -rotate[1];
-            //rotate[0] = rotate[0] * parts.F;
+            //var temp = rotate[1];
+            //rotate[0] = -rotate[0] * parts.F;
             //rotate[1] = -rotate[2] * parts.F;
-            //rotate[2] = temp * parts.F;
+            //rotate[2] = -temp * parts.F;
 
             //babylonMesh.rotation = rotate;
 
@@ -141,6 +151,14 @@ namespace Max2Babylon
 
                 var optimizeVertices = meshNode._Node.GetBoolProperty("babylonjs_optimizevertices");
 
+                // Skin
+                IISkinContextData skinContext = null;
+
+                if (skin != null)
+                {
+                    skinContext = skin.GetContextInterface(meshNode._Node);
+                }
+
                 // Compute normals
                 VNormal[] vnorms = null;
                 List<GlobalVertex>[] verticesAlreadyExported = null;
@@ -156,11 +174,11 @@ namespace Max2Babylon
 
                 for (var face = 0; face < mesh.NumFaces; face++)
                 {
-                    indices.Add(CreateGlobalVertex(mesh, computedMesh, face, vx1, vertices, hasUV, hasUV2, vnorms, verticesAlreadyExported));
-                    indices.Add(CreateGlobalVertex(mesh, computedMesh, face, vx2, vertices, hasUV, hasUV2, vnorms, verticesAlreadyExported));
-                    indices.Add(CreateGlobalVertex(mesh, computedMesh, face, vx3, vertices, hasUV, hasUV2, vnorms, verticesAlreadyExported));
+                    indices.Add(CreateGlobalVertex(mesh, computedMesh, face, vx1, vertices, hasUV, hasUV2, vnorms, verticesAlreadyExported, skinContext));
+                    indices.Add(CreateGlobalVertex(mesh, computedMesh, face, vx2, vertices, hasUV, hasUV2, vnorms, verticesAlreadyExported, skinContext));
+                    indices.Add(CreateGlobalVertex(mesh, computedMesh, face, vx3, vertices, hasUV, hasUV2, vnorms, verticesAlreadyExported, skinContext));
                     matIDs.Add(mesh.Faces[face].MatID % multiMatsCount);
-                    if (token.IsCancellationRequested) token.ThrowIfCancellationRequested();
+                    CheckCancelled();
                 }
 
                 if (vertices.Count >= 65536)
@@ -187,6 +205,12 @@ namespace Max2Babylon
                     babylonMesh.uvs2 = vertices.SelectMany(v => v.UV2.ToArray()).ToArray();
                 }
 
+                if (skin != null)
+                {
+                    babylonMesh.matricesWeights = vertices.SelectMany(v => v.Weights.ToArray()).ToArray();
+                    babylonMesh.matricesIndices = vertices.Select(v => v.BonesIndices).ToArray();
+                }
+
                 // Submeshes
                 var sortedIndices = new List<int>();
                 var subMeshes = new List<BabylonSubMesh>();
@@ -256,7 +280,7 @@ namespace Max2Babylon
 
                         subMeshes.Add(subMesh);
                     }
-                    if (token.IsCancellationRequested) token.ThrowIfCancellationRequested();
+                    CheckCancelled();
                 }
                 babylonMesh.subMeshes = subMeshes.ToArray();
 
@@ -327,7 +351,7 @@ namespace Max2Babylon
             babylonScene.MeshesList.Add(babylonMesh);
         }
 
-        int CreateGlobalVertex(IMesh mesh, Mesh computedMesh, int face, int facePart, List<GlobalVertex> vertices, bool hasUV, bool hasUV2, VNormal[] vnorms, List<GlobalVertex>[] verticesAlreadyExported)
+        int CreateGlobalVertex(IMesh mesh, Mesh computedMesh, int face, int facePart, List<GlobalVertex> vertices, bool hasUV, bool hasUV2, VNormal[] vnorms, List<GlobalVertex>[] verticesAlreadyExported, IISkinContextData skinContextData)
         {
             var faceObject = mesh.Faces[face];
             var vertexIndex = (int)faceObject.V[facePart];
@@ -351,6 +375,55 @@ namespace Max2Babylon
                 vertex.UV2 = Loader.Global.Point2.Create(mesh.MapVerts(2)[tvertexIndex].X, mesh.MapVerts(2)[tvertexIndex].Y);
             }
 
+            if (skinContextData != null)
+            {
+                float weight0 = 0;
+                float weight1 = 0;
+                float weight2 = 0;
+                int bone0 = bonesCount;
+                int bone1 = bonesCount;
+                int bone2 = bonesCount;
+                int bone3 = bonesCount;
+                int nbBones = skinContextData.GetNumAssignedBones(vertexIndex);
+
+                if (nbBones > 0)
+                {
+                    bone0 = skinContextData.GetAssignedBone(vertexIndex, 0);
+                    weight0 = skinContextData.GetBoneWeight(vertexIndex, 0);
+                }
+
+                if (nbBones > 1)
+                {
+                    bone1 = skinContextData.GetAssignedBone(vertexIndex, 1);
+                    weight1 = skinContextData.GetBoneWeight(vertexIndex, 1);
+                }
+
+                if (nbBones > 2)
+                {
+                    bone2 = skinContextData.GetAssignedBone(vertexIndex, 2);
+                    weight2 = skinContextData.GetBoneWeight(vertexIndex, 2);
+                }
+
+                if (nbBones > 3)
+                {
+                    bone3 = skinContextData.GetAssignedBone(vertexIndex, 3);
+                }
+
+                if (nbBones == 0)
+                {
+                    weight0 = 1.0f;
+                    bone0 = bonesCount;
+                }
+
+                if (nbBones > 4)
+                {
+                    RaiseError("Too many bones per vertex: " + nbBones);
+                }
+
+                vertex.Weights = Loader.Global.Point4.Create(weight0, weight1, weight2, 1.0 - weight0 - weight1 - weight2);
+                vertex.BonesIndices = (bone3 << 24) | (bone2 << 16) | (bone1 << 8) | bone0;
+            }
+
             if (verticesAlreadyExported != null)
             {
                 if (verticesAlreadyExported[vertexIndex] != null)

+ 30 - 5
Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.cs

@@ -5,6 +5,7 @@ using System.IO;
 using System.Linq;
 using System.Text;
 using System.Threading;
+using System.Windows.Forms;
 using Autodesk.Max;
 using BabylonExport.Entities;
 using MaxSharp;
@@ -23,6 +24,8 @@ namespace Max2Babylon
 
         readonly List<string> alreadyExportedTextures = new List<string>();
 
+        public bool IsCancelled { get; set; }
+
         void ReportProgressChanged(int progress)
         {
             if (OnImportProgressChanged != null)
@@ -60,8 +63,18 @@ namespace Max2Babylon
             }
         }
 
-        public void Export(string outputFile, CancellationToken token)
+        void CheckCancelled()
+        {
+            Application.DoEvents();
+            if (IsCancelled)
+            {
+                throw new OperationCanceledException();
+            }
+        }
+
+        public void Export(string outputFile)
         {
+            IsCancelled = false;
             RaiseMessage("Exportation started");
             ReportProgressChanged(0);
             var babylonScene = new BabylonScene(Path.GetDirectoryName(outputFile));
@@ -75,6 +88,10 @@ namespace Max2Babylon
                 return;
             }
 
+            // Save scene
+            RaiseMessage("Saving 3ds max file");
+            var forceSave = Loader.Core.FileSave;
+
             // Global
             babylonScene.autoClear = true;
             babylonScene.clearColor = Loader.Core.GetBackGround(0, Interval.Forever._IInterval).ToArray();
@@ -135,13 +152,13 @@ namespace Max2Babylon
             foreach (var meshNode in meshes)
             {
                 Tools.PreparePipeline(meshNode._Node, true);
-                ExportMesh(meshNode, babylonScene, token);
+                ExportMesh(meshNode, babylonScene);
                 Tools.PreparePipeline(meshNode._Node, false);
 
                 progression += progressionStep;
                 ReportProgressChanged((int)progression);
 
-                if (token.IsCancellationRequested) token.ThrowIfCancellationRequested();
+                CheckCancelled();
             }
 
             // Materials
@@ -150,7 +167,7 @@ namespace Max2Babylon
             foreach (var mat in matsToExport)
             {
                 ExportMaterial(mat, babylonScene);
-                if (token.IsCancellationRequested) token.ThrowIfCancellationRequested();
+                CheckCancelled();
             }
 
             // Lights
@@ -158,7 +175,7 @@ namespace Max2Babylon
             foreach (var lightNode in maxScene.NodesListBySuperClass(SuperClassID.Light))
             {
                 ExportLight(lightNode, babylonScene);
-                if (token.IsCancellationRequested) token.ThrowIfCancellationRequested();
+                CheckCancelled();
             }
 
             if (babylonScene.LightsList.Count == 0)
@@ -166,6 +183,14 @@ namespace Max2Babylon
                 RaiseWarning("No light defined", true);
             }
 
+            // Skeletons
+            RaiseMessage("Exporting skeletons");
+            foreach (var skin in skins)
+            {
+                ExportSkin(skin, babylonScene);
+                skin.Dispose();
+            }
+
             // Output
             babylonScene.Prepare(false);
             var jsonSerializer = JsonSerializer.Create();

+ 8 - 1
Exporters/3ds Max/Max2Babylon/Exporter/GlobalVertex.cs

@@ -10,6 +10,8 @@ namespace Max2Babylon
         public IPoint3 Normal { get; set; }
         public IPoint2 UV { get; set; }
         public IPoint2 UV2 { get; set; }
+        public int BonesIndices { get; set; }
+        public IPoint4 Weights { get; set; }
 
         public override int GetHashCode()
         {
@@ -50,7 +52,12 @@ namespace Max2Babylon
                 return false;
             }
 
-            return true;
+            if (Weights != null && !other.Weights.IsAlmostEqualTo(Weights, Tools.Epsilon))
+            {
+                return false;
+            }
+
+            return other.BonesIndices == BonesIndices;
         }
     }
 }

+ 24 - 22
Exporters/3ds Max/Max2Babylon/Forms/ExporterForm.cs

@@ -1,6 +1,4 @@
 using System;
-using System.Threading;
-using System.Threading.Tasks;
 using System.Windows.Forms;
 using MaxCustomControls;
 using MaxSharp;
@@ -11,7 +9,7 @@ namespace Max2Babylon
     public partial class ExporterForm : MaxForm
     {
         private readonly BabylonExportActionItem babylonExportAction;
-        private CancellationTokenSource cancellationToken;
+        private BabylonExporter exporter;
 
         public ExporterForm(BabylonExportActionItem babylonExportAction)
         {
@@ -33,45 +31,47 @@ namespace Max2Babylon
             }
         }
 
-        private async void butExport_Click(object sender, EventArgs e)
+        private void butExport_Click(object sender, EventArgs e)
         {
             Kernel.Scene.RootNode.SetLocalData(txtFilename.Text);
 
-            var exporter = new BabylonExporter();
+            exporter = new BabylonExporter();
             TreeNode currentNode = null;
             TreeNode previousNode = null;
 
             treeView.Nodes.Clear();
 
-            exporter.OnImportProgressChanged += progress => BeginInvoke(new Action(() =>
+            exporter.OnImportProgressChanged += progress => 
             {
                 progressBar.Value = progress;
-            }));
+                Application.DoEvents();
+            };
 
-            exporter.OnWarning += (warning, asChild) => BeginInvoke(new Action(() =>
+            exporter.OnWarning += (warning, asChild) => 
             {
                 previousNode = new TreeNode(warning) { ForeColor = Color.Orange };
 
                 currentNode = CreateTreeNode(asChild, currentNode, previousNode);
 
                 previousNode.EnsureVisible();
-            }));
+                Application.DoEvents();
+            };
 
-            exporter.OnError += (error, asChild) => BeginInvoke(new Action(() =>
+            exporter.OnError += (error, asChild) =>
             {
                 previousNode = new TreeNode(error) { ForeColor = Color.Red };
 
                 currentNode = CreateTreeNode(asChild, currentNode, previousNode);
 
                 previousNode.EnsureVisible();
-            }));
+                Application.DoEvents();
+            };
 
-            exporter.OnMessage += (message, asChild, emphasis, embed, color) => BeginInvoke(new Action(() =>
+            exporter.OnMessage += (message, asChild, emphasis, embed, color) => 
             {
                 var oldPrevious = previousNode;
 
-                previousNode = new TreeNode(message);
-                previousNode.ForeColor = color;
+                previousNode = new TreeNode(message) {ForeColor = color};
 
                 if (emphasis)
                 {
@@ -84,21 +84,23 @@ namespace Max2Babylon
                 {
                     previousNode.EnsureVisible();
                 }
-            }));
+                Application.DoEvents();
+            };
 
             butExport.Enabled = false;
             butCancel.Enabled = true;
 
-            cancellationToken = new CancellationTokenSource();
-            var token = cancellationToken.Token;
-
             try
             {
-                await Task.Run(() => exporter.Export(txtFilename.Text, token), token);
+                exporter.Export(txtFilename.Text);
+            }
+            catch (OperationCanceledException)
+            {
+                progressBar.Value = 0;                
             }
-            catch
+            catch (Exception ex)
             {
-                previousNode = new TreeNode("Exportation cancelled") { ForeColor = Color.Red };
+                previousNode = new TreeNode("Exportation cancelled: " + ex.Message) { ForeColor = Color.Red };
 
                 currentNode = CreateTreeNode(false, currentNode, previousNode);
 
@@ -140,7 +142,7 @@ namespace Max2Babylon
 
         private void butCancel_Click(object sender, EventArgs e)
         {
-            cancellationToken.Cancel();
+            exporter.IsCancelled = true;
         }
     }
 }

+ 60 - 15
Exporters/3ds Max/Max2Babylon/Tools/Tools.cs

@@ -33,17 +33,17 @@ namespace Max2Babylon
             {
                 var modifier = derivedObject.GetModifier(index);
 
-                if (modifier.ClassID.PartA == 9815843 && modifier.ClassID.PartB == 87654) // Skin
-                {
-                    if (deactivate)
-                    {
-                        modifier.DisableMod();
-                    }
-                    else
-                    {
-                        modifier.EnableMod();
-                    }
-                }
+                //if (modifier.ClassID.PartA == 9815843 && modifier.ClassID.PartB == 87654) // Skin
+                //{
+                //    if (deactivate)
+                //    {
+                //        modifier.DisableMod();
+                //    }
+                //    else
+                //    {
+                //        modifier.EnableMod();
+                //    }
+                //}
             }
         }
 
@@ -136,6 +136,11 @@ namespace Max2Babylon
             return new[] { value.r, value.g, value.b };
         }
 
+        public static float[] ToArray(this IPoint4 value)
+        {
+            return new[] { value.X, value.Y, value.Z, value.W };
+        }
+
         public static float[] ToArray(this IPoint3 value)
         {
             return new[] { value.X, value.Y, value.Z };
@@ -236,15 +241,18 @@ namespace Max2Babylon
 
         public static IMatrix3 GetWorldMatrix(this Node node, TimeValue t, bool parent)
         {
-            var innerNode = node._Node;
+            return node._Node.GetWorldMatrix(t, parent);
+        }
 
-            var tm = innerNode.GetNodeTM(t, Interval.Forever._IInterval);
-            var ptm = innerNode.ParentNode.GetNodeTM(t, Interval.Forever._IInterval);
+        public static IMatrix3 GetWorldMatrix(this IINode node, TimeValue t, bool parent)
+        {
+            var tm = node.GetNodeTM(t, Interval.Forever._IInterval);
+            var ptm = node.ParentNode.GetNodeTM(t, Interval.Forever._IInterval);
 
             if (!parent)
                 return tm;
 
-            if (innerNode.ParentNode.SuperClassID == SuperClassID.Camera)
+            if (node.ParentNode.SuperClassID == SuperClassID.Camera)
             {
                 var r = ptm.GetRow(3);
                 ptm.IdentityMatrix();
@@ -255,6 +263,18 @@ namespace Max2Babylon
             return tm.Multiply(ptm);
         }
 
+        public static IMatrix3 GetWorldMatrixComplete(this IINode node, TimeValue t, bool parent)
+        {
+            var tm = node.GetObjTMAfterWSM(t, Interval.Forever._IInterval);
+            var ptm = node.ParentNode.GetObjTMAfterWSM(t, Interval.Forever._IInterval);
+
+            if (!parent)
+                return tm;
+
+            ptm.Invert();
+            return tm.Multiply(ptm);
+        }
+
         public static ITriObject GetMesh(this IObject obj, out bool mustBeDeleted)
         {
             mustBeDeleted = false;
@@ -268,6 +288,31 @@ namespace Max2Babylon
             return tri;
         }
 
+        public static bool IsAlmostEqualTo(this IPoint4 current, IPoint4 other, float epsilon)
+        {
+            if (Math.Abs(current.X - other.X) > epsilon)
+            {
+                return false;
+            }
+
+            if (Math.Abs(current.Y - other.Y) > epsilon)
+            {
+                return false;
+            }
+
+            if (Math.Abs(current.Z - other.Z) > epsilon)
+            {
+                return false;
+            }
+
+            if (Math.Abs(current.W - other.W) > epsilon)
+            {
+                return false;
+            }
+
+            return true;
+        }
+
         public static bool IsAlmostEqualTo(this IPoint3 current, IPoint3 other, float epsilon)
         {
             if (Math.Abs(current.X - other.X) > epsilon)