瀏覽代碼

Max2babylon:
- Light, mesh, camera animations
Babylon.js:
- Support for lights animation
- Fixing issue with missing quaternion.subtract function

David Catuhe 11 年之前
父節點
當前提交
0123dabf58

+ 13 - 0
Babylon/Loading/Plugins/babylon.babylonFileLoader.js

@@ -303,6 +303,19 @@ var BABYLON = BABYLON || {};
         if (parsedLight.excludedMeshesIds) {
             light._excludedMeshesIds = parsedLight.excludedMeshesIds;
         }
+
+        // Animations
+        if (parsedLight.animations) {
+            for (var animationIndex = 0; animationIndex < parsedLight.animations.length; animationIndex++) {
+                var parsedAnimation = parsedLight.animations[animationIndex];
+
+                light.animations.push(parseAnimation(parsedAnimation));
+            }
+        }
+
+        if (parsedLight.autoAnimate) {
+            scene.beginAnimation(light, parsedLight.autoAnimateFrom, parsedLight.autoAnimateTo, parsedLight.autoAnimateLoop, 1.0);
+        }
     };
 
     var parseCamera = function (parsedCamera, scene) {

+ 4 - 0
Babylon/Math/babylon.math.js

@@ -866,6 +866,10 @@
             return new Quaternion(this.x + other.x, this.y + other.y, this.z + other.z, this.w + other.w);
         };
 
+        Quaternion.prototype.subtract = function (other) {
+            return new Quaternion(this.x - other.x, this.y - other.y, this.z - other.z, this.w - other.w);
+        };
+
         Quaternion.prototype.scale = function (value) {
             return new Quaternion(this.x * value, this.y * value, this.z * value, this.w * value);
         };

+ 4 - 0
Babylon/Math/babylon.math.ts

@@ -831,6 +831,10 @@
             return new Quaternion(this.x + other.x, this.y + other.y, this.z + other.z, this.w + other.w);
         }
 
+        public subtract(other: Quaternion): Quaternion {
+            return new Quaternion(this.x - other.x, this.y - other.y, this.z - other.z, this.w - other.w);
+        }
+
         public scale(value: number): Quaternion {
             return new Quaternion(this.x * value, this.y * value, this.z * value, this.w * value);
         }

+ 1 - 1
Exporters/3ds Max/BabylonExport.Entities/BabylonAnimationKey.cs

@@ -6,7 +6,7 @@ namespace BabylonExport.Entities
     public class BabylonAnimationKey
     {
         [DataMember]
-        public float frame { get; set; }
+        public int frame { get; set; }
 
         [DataMember]
         public float[] values { get; set; }

+ 15 - 0
Exporters/3ds Max/BabylonExport.Entities/BabylonLight.cs

@@ -44,6 +44,21 @@ namespace BabylonExport.Entities
         [DataMember]
         public string[] excludedMeshesIds { get; set; }
 
+        [DataMember]
+        public bool autoAnimate { get; set; }
+
+        [DataMember]
+        public int autoAnimateFrom { get; set; }
+
+        [DataMember]
+        public int autoAnimateTo { get; set; }
+
+        [DataMember]
+        public bool autoAnimateLoop { get; set; }
+
+        [DataMember]
+        public BabylonAnimation[] animations { get; set; }
+
         public BabylonLight()
         {
             diffuse = new[] {1.0f, 1.0f, 1.0f};

二進制
Exporters/3ds Max/Max2Babylon-0.4.5.zip


+ 9 - 0
Exporters/3ds Max/Max2Babylon/BabylonPropertiesActionItem.cs

@@ -36,6 +36,15 @@ namespace Max2Babylon
                 }
             }
 
+            if (firstNode.ObjectRef != null && firstNode.ObjectRef.SuperClassID == SClass_ID.Light)
+            {
+                using (var frm = new LightPropertiesForm())
+                {
+                    frm.ShowDialog();
+                    return true;
+                }
+            }
+
             Loader.Core.PushPrompt("Selected entity does not have Babylon.js specific properties");
 
             return true;

+ 81 - 0
Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Animation.cs

@@ -0,0 +1,81 @@
+using System;
+using System.Collections.Generic;
+using BabylonExport.Entities;
+using MaxSharp;
+
+namespace Max2Babylon
+{
+    partial class BabylonExporter
+    {
+        private void ExportVector3Animation(string property, List<BabylonAnimation> animations,
+            Func<int, float[]> extractValueFunc)
+        {
+            ExportAnimation(property, animations, extractValueFunc, BabylonAnimation.DataType.Vector3);
+        }
+
+        private void ExportQuaternionAnimation(string property, List<BabylonAnimation> animations,
+            Func<int, float[]> extractValueFunc)
+        {
+            ExportAnimation(property, animations, extractValueFunc, BabylonAnimation.DataType.Quaternion);
+        }
+
+        private void ExportFloatAnimation(string property, List<BabylonAnimation> animations,
+            Func<int, float[]> extractValueFunc)
+        {
+            ExportAnimation(property, animations, extractValueFunc, BabylonAnimation.DataType.Float);
+        }
+
+        private void ExportAnimation(string property, List<BabylonAnimation> animations, Func<int, float[]> extractValueFunc, BabylonAnimation.DataType dataType)
+        {
+            const int ticks = 160;
+            var start = Loader.Core.AnimRange.Start;
+            var end = Loader.Core.AnimRange.End;
+
+            float[] previous = null;
+            var keys = new List<BabylonAnimationKey>();
+            for (var key = start; key <= end; key += ticks)
+            {
+                var current = extractValueFunc(key);
+
+                if (key == start || key == end || !(previous.IsEqualTo(current)))
+                {
+                    keys.Add(new BabylonAnimationKey()
+                    {
+                        frame = key / ticks,
+                        values = current
+                    });
+                }
+
+                previous = current;
+            }
+
+            if (keys.Count > 0)
+            {
+                var animationPresent = true;
+
+                if (keys.Count == 2)
+                {
+                    if (keys[0].values.IsEqualTo(keys[1].values))
+                    {
+                        animationPresent = false;
+                    }
+                }
+
+                if (animationPresent)
+                {
+                    var babylonAnimation = new BabylonAnimation
+                    {
+                        dataType = dataType,
+                        name = property + " animation",
+                        keys = keys.ToArray(),
+                        framePerSecond = Loader.Global.FrameRate,
+                        loopBehavior = BabylonAnimation.LoopBehavior.Relative,
+                        property = property
+                    };
+
+                    animations.Add(babylonAnimation);
+                }
+            }
+        }        
+    }
+}

+ 22 - 0
Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Camera.cs

@@ -1,4 +1,5 @@
 using System;
+using System.Collections.Generic;
 using BabylonExport.Entities;
 using MaxSharp;
 
@@ -54,6 +55,27 @@ namespace Max2Babylon
                 babylonCamera.target = dir.ToArraySwitched();
             }
 
+            // Animations
+            var animations = new List<BabylonAnimation>();
+            ExportVector3Animation("position", animations, key =>
+            {
+                var worldMatrix = cameraNode.GetWorldMatrix(key, cameraNode.HasParent());
+                return worldMatrix.Trans.ToArraySwitched();
+            });
+
+            ExportFloatAnimation("fov", animations, key => new[] { Tools.ConvertFov(maxCamera.GetFOV(key, Interval.Forever._IInterval)) });
+
+
+            babylonCamera.animations = animations.ToArray();
+
+            if (cameraNode._Node.GetBoolProperty("babylonjs_autoanimate"))
+            {
+                babylonCamera.autoAnimate = true;
+                babylonCamera.autoAnimateFrom = (int)cameraNode._Node.GetFloatProperty("babylonjs_autoanimate_from");
+                babylonCamera.autoAnimateTo = (int)cameraNode._Node.GetFloatProperty("babylonjs_autoanimate_to");
+                babylonCamera.autoAnimateLoop = cameraNode._Node.GetBoolProperty("babylonjs_autoanimateloop");
+            }
+
             babylonScene.CamerasList.Add(babylonCamera);
             return babylonCamera;
         }

+ 37 - 0
Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Light.cs

@@ -106,6 +106,43 @@ namespace Max2Babylon
                 babylonLight.range = maxLight.GetAttenuation(0, 1, Interval.Forever);
             }
 
+            // Animations
+            var animations = new List<BabylonAnimation>();
+            ExportVector3Animation("position", animations, key =>
+            {
+                var worldMatrix = lightNode.GetWorldMatrix(key, lightNode.HasParent());
+                return worldMatrix.Trans.ToArraySwitched();
+            });
+
+            ExportVector3Animation("direction", animations, key =>
+            {
+                var targetNode = lightNode._Node.Target;
+                if (targetNode != null)
+                {
+                    var targetWm = target.GetObjTMBeforeWSM(0, Interval.Forever._IInterval);
+                    var targetPosition = targetWm.Trans;
+
+                    var direction = targetPosition.Subtract(position);
+                    return direction.ToArraySwitched();
+                }
+                
+                var dir = wm.GetRow(2).MultiplyBy(directionScale);
+                return dir.ToArraySwitched();
+            });
+
+            ExportFloatAnimation("intensity", animations, key => new[] { maxLight.GetIntensity(key, Interval.Forever) });
+
+
+            babylonLight.animations = animations.ToArray();
+
+            if (lightNode._Node.GetBoolProperty("babylonjs_autoanimate"))
+            {
+                babylonLight.autoAnimate = true;
+                babylonLight.autoAnimateFrom = (int)lightNode._Node.GetFloatProperty("babylonjs_autoanimate_from");
+                babylonLight.autoAnimateTo = (int)lightNode._Node.GetFloatProperty("babylonjs_autoanimate_to");
+                babylonLight.autoAnimateLoop = lightNode._Node.GetBoolProperty("babylonjs_autoanimateloop");
+            }
+
             babylonScene.LightsList.Add(babylonLight);
             return babylonLight;
         }

+ 34 - 31
Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Mesh.cs

@@ -238,43 +238,46 @@ namespace Max2Babylon
                 babylonMesh.indices = sortedIndices.ToArray();
             }
 
-            // Animations - Position
-            const int ticks = 160;
-            var start = Loader.Core.AnimRange.Start;
-            var end = Loader.Core.AnimRange.End;
-
-            IPoint3 previousPosition = null;
-            var keys = new List<BabylonAnimationKey>();
-            for (var key = start; key <= end; key += ticks)
+
+            // Animations
+            var animations = new List<BabylonAnimation>();
+            ExportVector3Animation("position", animations, key =>
             {
                 var worldMatrix = meshNode.GetWorldMatrix(key, meshNode.HasParent());
-                var currentPosition = worldMatrix.Trans;
+                return worldMatrix.Trans.ToArraySwitched();
+            });
 
-                if (key == start || key == end || (previousPosition.Equals(currentPosition, Tools.Epsilon) != 0))
-                {
-                    keys.Add(new BabylonAnimationKey()
-                    {
-                        frame = key,
-                        values = currentPosition.ToArraySwitched()
-                    });
-                }
+            ExportQuaternionAnimation("rotationQuaternion", animations, key =>
+            {
+                var worldMatrix = meshNode.GetWorldMatrix(key, meshNode.HasParent());
 
-                previousPosition = currentPosition;
-            }
+                var affineParts = Loader.Global.AffineParts.Create();
+                Loader.Global.DecompAffine(worldMatrix, affineParts);
 
-            if (keys.Count > 0)
+                return affineParts.Q.ToArray();
+            });
+
+            ExportVector3Animation("scaling", animations, key =>
             {
-                var babylonAnimation = new BabylonAnimation
-                {
-                    dataType = BabylonAnimation.DataType.Vector3,
-                    name = "Position animation",
-                    keys = keys.ToArray(),
-                    framePerSecond = Loader.Global.FrameRate,
-                    loopBehavior = BabylonAnimation.LoopBehavior.Relative,
-                    property = "position"
-                };
-
-                babylonMesh.animations = new[] {babylonAnimation};
+                var worldMatrix = meshNode.GetWorldMatrix(key, meshNode.HasParent());
+
+                var affineParts = Loader.Global.AffineParts.Create();
+                Loader.Global.DecompAffine(worldMatrix, affineParts);
+
+                return affineParts.K.ToArraySwitched();
+            });
+
+            ExportFloatAnimation("visibility", animations, key => new []{meshNode._Node.GetVisibility(key, Interval.Forever._IInterval)});
+
+
+            babylonMesh.animations = animations.ToArray();
+
+            if (meshNode._Node.GetBoolProperty("babylonjs_autoanimate"))
+            {
+                babylonMesh.autoAnimate = true;
+                babylonMesh.autoAnimateFrom = (int)meshNode._Node.GetFloatProperty("babylonjs_autoanimate_from");
+                babylonMesh.autoAnimateTo = (int)meshNode._Node.GetFloatProperty("babylonjs_autoanimate_to");
+                babylonMesh.autoAnimateLoop = meshNode._Node.GetBoolProperty("babylonjs_autoanimateloop");
             }
 
             babylonScene.MeshesList.Add(babylonMesh);

+ 140 - 20
Exporters/3ds Max/Max2Babylon/Forms/CameraPropertiesForm.Designer.cs

@@ -29,6 +29,8 @@
         private void InitializeComponent()
         {
             this.groupBox1 = new System.Windows.Forms.GroupBox();
+            this.ellipsoidControl = new Max2Babylon.Vector3Control();
+            this.label3 = new System.Windows.Forms.Label();
             this.chkGravity = new System.Windows.Forms.CheckBox();
             this.chkCollisions = new System.Windows.Forms.CheckBox();
             this.butOK = new System.Windows.Forms.Button();
@@ -38,12 +40,22 @@
             this.nupInertia = new System.Windows.Forms.NumericUpDown();
             this.label1 = new System.Windows.Forms.Label();
             this.nupSpeed = new System.Windows.Forms.NumericUpDown();
-            this.label3 = new System.Windows.Forms.Label();
-            this.ellipsoidControl = new Max2Babylon.Vector3Control();
+            this.groupBox3 = new System.Windows.Forms.GroupBox();
+            this.grpAutoAnimate = new System.Windows.Forms.GroupBox();
+            this.chkLoop = new System.Windows.Forms.CheckBox();
+            this.nupTo = new System.Windows.Forms.NumericUpDown();
+            this.label4 = new System.Windows.Forms.Label();
+            this.nupFrom = new System.Windows.Forms.NumericUpDown();
+            this.label5 = new System.Windows.Forms.Label();
+            this.chkAutoAnimate = new System.Windows.Forms.CheckBox();
             this.groupBox1.SuspendLayout();
             this.groupBox2.SuspendLayout();
             ((System.ComponentModel.ISupportInitialize)(this.nupInertia)).BeginInit();
             ((System.ComponentModel.ISupportInitialize)(this.nupSpeed)).BeginInit();
+            this.groupBox3.SuspendLayout();
+            this.grpAutoAnimate.SuspendLayout();
+            ((System.ComponentModel.ISupportInitialize)(this.nupTo)).BeginInit();
+            ((System.ComponentModel.ISupportInitialize)(this.nupFrom)).BeginInit();
             this.SuspendLayout();
             // 
             // groupBox1
@@ -60,6 +72,25 @@
             this.groupBox1.TabStop = false;
             this.groupBox1.Text = "Collisions";
             // 
+            // ellipsoidControl
+            // 
+            this.ellipsoidControl.Location = new System.Drawing.Point(21, 95);
+            this.ellipsoidControl.Name = "ellipsoidControl";
+            this.ellipsoidControl.Size = new System.Drawing.Size(294, 28);
+            this.ellipsoidControl.TabIndex = 3;
+            this.ellipsoidControl.X = 0F;
+            this.ellipsoidControl.Y = 0F;
+            this.ellipsoidControl.Z = 0F;
+            // 
+            // label3
+            // 
+            this.label3.AutoSize = true;
+            this.label3.Location = new System.Drawing.Point(18, 79);
+            this.label3.Name = "label3";
+            this.label3.Size = new System.Drawing.Size(48, 13);
+            this.label3.TabIndex = 2;
+            this.label3.Text = "Ellipsoid:";
+            // 
             // chkGravity
             // 
             this.chkGravity.AutoSize = true;
@@ -87,7 +118,7 @@
             this.butOK.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
             this.butOK.DialogResult = System.Windows.Forms.DialogResult.OK;
             this.butOK.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
-            this.butOK.Location = new System.Drawing.Point(93, 304);
+            this.butOK.Location = new System.Drawing.Point(93, 471);
             this.butOK.Name = "butOK";
             this.butOK.Size = new System.Drawing.Size(75, 23);
             this.butOK.TabIndex = 1;
@@ -100,7 +131,7 @@
             this.butCancel.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
             this.butCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
             this.butCancel.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
-            this.butCancel.Location = new System.Drawing.Point(174, 304);
+            this.butCancel.Location = new System.Drawing.Point(174, 471);
             this.butCancel.Name = "butCancel";
             this.butCancel.Size = new System.Drawing.Size(75, 23);
             this.butCancel.TabIndex = 2;
@@ -165,24 +196,98 @@
             0,
             0});
             // 
-            // label3
+            // groupBox3
             // 
-            this.label3.AutoSize = true;
-            this.label3.Location = new System.Drawing.Point(18, 79);
-            this.label3.Name = "label3";
-            this.label3.Size = new System.Drawing.Size(48, 13);
-            this.label3.TabIndex = 2;
-            this.label3.Text = "Ellipsoid:";
+            this.groupBox3.Controls.Add(this.grpAutoAnimate);
+            this.groupBox3.Controls.Add(this.chkAutoAnimate);
+            this.groupBox3.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.groupBox3.Location = new System.Drawing.Point(12, 302);
+            this.groupBox3.Name = "groupBox3";
+            this.groupBox3.Size = new System.Drawing.Size(319, 156);
+            this.groupBox3.TabIndex = 5;
+            this.groupBox3.TabStop = false;
+            this.groupBox3.Text = "Animations";
             // 
-            // ellipsoidControl
+            // grpAutoAnimate
             // 
-            this.ellipsoidControl.Location = new System.Drawing.Point(21, 95);
-            this.ellipsoidControl.Name = "ellipsoidControl";
-            this.ellipsoidControl.Size = new System.Drawing.Size(294, 28);
-            this.ellipsoidControl.TabIndex = 3;
-            this.ellipsoidControl.X = 0F;
-            this.ellipsoidControl.Y = 0F;
-            this.ellipsoidControl.Z = 0F;
+            this.grpAutoAnimate.Controls.Add(this.chkLoop);
+            this.grpAutoAnimate.Controls.Add(this.nupTo);
+            this.grpAutoAnimate.Controls.Add(this.label4);
+            this.grpAutoAnimate.Controls.Add(this.nupFrom);
+            this.grpAutoAnimate.Controls.Add(this.label5);
+            this.grpAutoAnimate.Enabled = false;
+            this.grpAutoAnimate.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.grpAutoAnimate.Location = new System.Drawing.Point(21, 51);
+            this.grpAutoAnimate.Name = "grpAutoAnimate";
+            this.grpAutoAnimate.Size = new System.Drawing.Size(292, 99);
+            this.grpAutoAnimate.TabIndex = 3;
+            this.grpAutoAnimate.TabStop = false;
+            // 
+            // chkLoop
+            // 
+            this.chkLoop.AutoSize = true;
+            this.chkLoop.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.chkLoop.Location = new System.Drawing.Point(9, 66);
+            this.chkLoop.Name = "chkLoop";
+            this.chkLoop.Size = new System.Drawing.Size(47, 17);
+            this.chkLoop.TabIndex = 5;
+            this.chkLoop.Text = "Loop";
+            this.chkLoop.ThreeState = true;
+            this.chkLoop.UseVisualStyleBackColor = true;
+            // 
+            // nupTo
+            // 
+            this.nupTo.Location = new System.Drawing.Point(47, 40);
+            this.nupTo.Maximum = new decimal(new int[] {
+            1000,
+            0,
+            0,
+            0});
+            this.nupTo.Name = "nupTo";
+            this.nupTo.Size = new System.Drawing.Size(120, 20);
+            this.nupTo.TabIndex = 3;
+            // 
+            // label4
+            // 
+            this.label4.AutoSize = true;
+            this.label4.Location = new System.Drawing.Point(6, 42);
+            this.label4.Name = "label4";
+            this.label4.Size = new System.Drawing.Size(23, 13);
+            this.label4.TabIndex = 4;
+            this.label4.Text = "To:";
+            // 
+            // nupFrom
+            // 
+            this.nupFrom.Location = new System.Drawing.Point(47, 14);
+            this.nupFrom.Maximum = new decimal(new int[] {
+            1000,
+            0,
+            0,
+            0});
+            this.nupFrom.Name = "nupFrom";
+            this.nupFrom.Size = new System.Drawing.Size(120, 20);
+            this.nupFrom.TabIndex = 1;
+            // 
+            // label5
+            // 
+            this.label5.AutoSize = true;
+            this.label5.Location = new System.Drawing.Point(6, 16);
+            this.label5.Name = "label5";
+            this.label5.Size = new System.Drawing.Size(33, 13);
+            this.label5.TabIndex = 2;
+            this.label5.Text = "From:";
+            // 
+            // chkAutoAnimate
+            // 
+            this.chkAutoAnimate.AutoSize = true;
+            this.chkAutoAnimate.Location = new System.Drawing.Point(21, 28);
+            this.chkAutoAnimate.Name = "chkAutoAnimate";
+            this.chkAutoAnimate.Size = new System.Drawing.Size(88, 17);
+            this.chkAutoAnimate.TabIndex = 0;
+            this.chkAutoAnimate.Text = "Auto animate";
+            this.chkAutoAnimate.ThreeState = true;
+            this.chkAutoAnimate.UseVisualStyleBackColor = true;
+            this.chkAutoAnimate.CheckedChanged += new System.EventHandler(this.chkAutoAnimate_CheckedChanged);
             // 
             // CameraPropertiesForm
             // 
@@ -190,7 +295,8 @@
             this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
             this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
             this.CancelButton = this.butCancel;
-            this.ClientSize = new System.Drawing.Size(343, 339);
+            this.ClientSize = new System.Drawing.Size(343, 506);
+            this.Controls.Add(this.groupBox3);
             this.Controls.Add(this.groupBox2);
             this.Controls.Add(this.butCancel);
             this.Controls.Add(this.butOK);
@@ -206,6 +312,12 @@
             this.groupBox2.PerformLayout();
             ((System.ComponentModel.ISupportInitialize)(this.nupInertia)).EndInit();
             ((System.ComponentModel.ISupportInitialize)(this.nupSpeed)).EndInit();
+            this.groupBox3.ResumeLayout(false);
+            this.groupBox3.PerformLayout();
+            this.grpAutoAnimate.ResumeLayout(false);
+            this.grpAutoAnimate.PerformLayout();
+            ((System.ComponentModel.ISupportInitialize)(this.nupTo)).EndInit();
+            ((System.ComponentModel.ISupportInitialize)(this.nupFrom)).EndInit();
             this.ResumeLayout(false);
 
         }
@@ -224,5 +336,13 @@
         private System.Windows.Forms.NumericUpDown nupInertia;
         private System.Windows.Forms.Label label3;
         private Vector3Control ellipsoidControl;
+        private System.Windows.Forms.GroupBox groupBox3;
+        private System.Windows.Forms.GroupBox grpAutoAnimate;
+        private System.Windows.Forms.CheckBox chkLoop;
+        private System.Windows.Forms.NumericUpDown nupTo;
+        private System.Windows.Forms.Label label4;
+        private System.Windows.Forms.NumericUpDown nupFrom;
+        private System.Windows.Forms.Label label5;
+        private System.Windows.Forms.CheckBox chkAutoAnimate;
     }
 }

+ 15 - 0
Exporters/3ds Max/Max2Babylon/Forms/CameraPropertiesForm.cs

@@ -33,6 +33,11 @@ namespace Max2Babylon
             Tools.PrepareNumericUpDown(nupInertia, cameras, "babylonjs_inertia", 0.9f);
 
             Tools.PrepareVector3Control(ellipsoidControl, cameras[0], "babylonjs_ellipsoid", 0.5f, 1.0f, 0.5f);
+
+            Tools.PrepareCheckBox(chkAutoAnimate, cameras, "babylonjs_autoanimate");
+            Tools.PrepareCheckBox(chkLoop, cameras, "babylonjs_autoanimateloop");
+            Tools.PrepareNumericUpDown(nupFrom, cameras, "babylonjs_autoanimate_from");
+            Tools.PrepareNumericUpDown(nupTo, cameras, "babylonjs_autoanimate_to", 100.0f);
         }
 
         private void butOK_Click(object sender, EventArgs e)
@@ -44,6 +49,16 @@ namespace Max2Babylon
             Tools.UpdateNumericUpDown(nupInertia, cameras, "babylonjs_inertia");
 
             Tools.UpdateVector3Control(ellipsoidControl, cameras, "babylonjs_ellipsoid");
+
+            Tools.UpdateCheckBox(chkAutoAnimate, cameras, "babylonjs_autoanimate");
+            Tools.UpdateCheckBox(chkLoop, cameras, "babylonjs_autoanimateloop");
+            Tools.UpdateNumericUpDown(nupFrom, cameras, "babylonjs_autoanimate_from");
+            Tools.UpdateNumericUpDown(nupTo, cameras, "babylonjs_autoanimate_to");
+        }
+
+        private void chkAutoAnimate_CheckedChanged(object sender, EventArgs e)
+        {
+            grpAutoAnimate.Enabled = chkAutoAnimate.Checked;
         }
     }
 }

+ 203 - 0
Exporters/3ds Max/Max2Babylon/Forms/LightPropertiesForm.Designer.cs

@@ -0,0 +1,203 @@
+namespace Max2Babylon
+{
+    partial class LightPropertiesForm
+    {
+        /// <summary>
+        /// Required designer variable.
+        /// </summary>
+        private System.ComponentModel.IContainer components = null;
+
+        /// <summary>
+        /// Clean up any resources being used.
+        /// </summary>
+        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Windows Form Designer generated code
+
+        /// <summary>
+        /// Required method for Designer support - do not modify
+        /// the contents of this method with the code editor.
+        /// </summary>
+        private void InitializeComponent()
+        {
+            this.butOK = new System.Windows.Forms.Button();
+            this.butCancel = new System.Windows.Forms.Button();
+            this.groupBox3 = new System.Windows.Forms.GroupBox();
+            this.grpAutoAnimate = new System.Windows.Forms.GroupBox();
+            this.chkLoop = new System.Windows.Forms.CheckBox();
+            this.nupTo = new System.Windows.Forms.NumericUpDown();
+            this.label4 = new System.Windows.Forms.Label();
+            this.nupFrom = new System.Windows.Forms.NumericUpDown();
+            this.label5 = new System.Windows.Forms.Label();
+            this.chkAutoAnimate = new System.Windows.Forms.CheckBox();
+            this.groupBox3.SuspendLayout();
+            this.grpAutoAnimate.SuspendLayout();
+            ((System.ComponentModel.ISupportInitialize)(this.nupTo)).BeginInit();
+            ((System.ComponentModel.ISupportInitialize)(this.nupFrom)).BeginInit();
+            this.SuspendLayout();
+            // 
+            // butOK
+            // 
+            this.butOK.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
+            this.butOK.DialogResult = System.Windows.Forms.DialogResult.OK;
+            this.butOK.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.butOK.Location = new System.Drawing.Point(93, 179);
+            this.butOK.Name = "butOK";
+            this.butOK.Size = new System.Drawing.Size(75, 23);
+            this.butOK.TabIndex = 1;
+            this.butOK.Text = "OK";
+            this.butOK.UseVisualStyleBackColor = true;
+            this.butOK.Click += new System.EventHandler(this.butOK_Click);
+            // 
+            // butCancel
+            // 
+            this.butCancel.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
+            this.butCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
+            this.butCancel.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.butCancel.Location = new System.Drawing.Point(174, 179);
+            this.butCancel.Name = "butCancel";
+            this.butCancel.Size = new System.Drawing.Size(75, 23);
+            this.butCancel.TabIndex = 2;
+            this.butCancel.Text = "Cancel";
+            this.butCancel.UseVisualStyleBackColor = true;
+            // 
+            // groupBox3
+            // 
+            this.groupBox3.Controls.Add(this.grpAutoAnimate);
+            this.groupBox3.Controls.Add(this.chkAutoAnimate);
+            this.groupBox3.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.groupBox3.Location = new System.Drawing.Point(12, 12);
+            this.groupBox3.Name = "groupBox3";
+            this.groupBox3.Size = new System.Drawing.Size(319, 156);
+            this.groupBox3.TabIndex = 5;
+            this.groupBox3.TabStop = false;
+            this.groupBox3.Text = "Animations";
+            // 
+            // grpAutoAnimate
+            // 
+            this.grpAutoAnimate.Controls.Add(this.chkLoop);
+            this.grpAutoAnimate.Controls.Add(this.nupTo);
+            this.grpAutoAnimate.Controls.Add(this.label4);
+            this.grpAutoAnimate.Controls.Add(this.nupFrom);
+            this.grpAutoAnimate.Controls.Add(this.label5);
+            this.grpAutoAnimate.Enabled = false;
+            this.grpAutoAnimate.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.grpAutoAnimate.Location = new System.Drawing.Point(21, 51);
+            this.grpAutoAnimate.Name = "grpAutoAnimate";
+            this.grpAutoAnimate.Size = new System.Drawing.Size(292, 99);
+            this.grpAutoAnimate.TabIndex = 3;
+            this.grpAutoAnimate.TabStop = false;
+            // 
+            // chkLoop
+            // 
+            this.chkLoop.AutoSize = true;
+            this.chkLoop.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.chkLoop.Location = new System.Drawing.Point(9, 66);
+            this.chkLoop.Name = "chkLoop";
+            this.chkLoop.Size = new System.Drawing.Size(47, 17);
+            this.chkLoop.TabIndex = 5;
+            this.chkLoop.Text = "Loop";
+            this.chkLoop.ThreeState = true;
+            this.chkLoop.UseVisualStyleBackColor = true;
+            // 
+            // nupTo
+            // 
+            this.nupTo.Location = new System.Drawing.Point(47, 40);
+            this.nupTo.Maximum = new decimal(new int[] {
+            1000,
+            0,
+            0,
+            0});
+            this.nupTo.Name = "nupTo";
+            this.nupTo.Size = new System.Drawing.Size(120, 20);
+            this.nupTo.TabIndex = 3;
+            // 
+            // label4
+            // 
+            this.label4.AutoSize = true;
+            this.label4.Location = new System.Drawing.Point(6, 42);
+            this.label4.Name = "label4";
+            this.label4.Size = new System.Drawing.Size(23, 13);
+            this.label4.TabIndex = 4;
+            this.label4.Text = "To:";
+            // 
+            // nupFrom
+            // 
+            this.nupFrom.Location = new System.Drawing.Point(47, 14);
+            this.nupFrom.Maximum = new decimal(new int[] {
+            1000,
+            0,
+            0,
+            0});
+            this.nupFrom.Name = "nupFrom";
+            this.nupFrom.Size = new System.Drawing.Size(120, 20);
+            this.nupFrom.TabIndex = 1;
+            // 
+            // label5
+            // 
+            this.label5.AutoSize = true;
+            this.label5.Location = new System.Drawing.Point(6, 16);
+            this.label5.Name = "label5";
+            this.label5.Size = new System.Drawing.Size(33, 13);
+            this.label5.TabIndex = 2;
+            this.label5.Text = "From:";
+            // 
+            // chkAutoAnimate
+            // 
+            this.chkAutoAnimate.AutoSize = true;
+            this.chkAutoAnimate.Location = new System.Drawing.Point(21, 28);
+            this.chkAutoAnimate.Name = "chkAutoAnimate";
+            this.chkAutoAnimate.Size = new System.Drawing.Size(88, 17);
+            this.chkAutoAnimate.TabIndex = 0;
+            this.chkAutoAnimate.Text = "Auto animate";
+            this.chkAutoAnimate.ThreeState = true;
+            this.chkAutoAnimate.UseVisualStyleBackColor = true;
+            this.chkAutoAnimate.CheckedChanged += new System.EventHandler(this.chkAutoAnimate_CheckedChanged);
+            // 
+            // LightPropertiesForm
+            // 
+            this.AcceptButton = this.butOK;
+            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+            this.CancelButton = this.butCancel;
+            this.ClientSize = new System.Drawing.Size(343, 214);
+            this.Controls.Add(this.groupBox3);
+            this.Controls.Add(this.butCancel);
+            this.Controls.Add(this.butOK);
+            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
+            this.Name = "LightPropertiesForm";
+            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
+            this.Text = "Babylon.js - Light Properties";
+            this.Load += new System.EventHandler(this.LightPropertiesForm_Load);
+            this.groupBox3.ResumeLayout(false);
+            this.groupBox3.PerformLayout();
+            this.grpAutoAnimate.ResumeLayout(false);
+            this.grpAutoAnimate.PerformLayout();
+            ((System.ComponentModel.ISupportInitialize)(this.nupTo)).EndInit();
+            ((System.ComponentModel.ISupportInitialize)(this.nupFrom)).EndInit();
+            this.ResumeLayout(false);
+
+        }
+
+        #endregion
+
+        private System.Windows.Forms.Button butOK;
+        private System.Windows.Forms.Button butCancel;
+        private System.Windows.Forms.GroupBox groupBox3;
+        private System.Windows.Forms.GroupBox grpAutoAnimate;
+        private System.Windows.Forms.CheckBox chkLoop;
+        private System.Windows.Forms.NumericUpDown nupTo;
+        private System.Windows.Forms.Label label4;
+        private System.Windows.Forms.NumericUpDown nupFrom;
+        private System.Windows.Forms.Label label5;
+        private System.Windows.Forms.CheckBox chkAutoAnimate;
+    }
+}

+ 48 - 0
Exporters/3ds Max/Max2Babylon/Forms/LightPropertiesForm.cs

@@ -0,0 +1,48 @@
+using System;
+using System.Collections.Generic;
+using System.Windows.Forms;
+using Autodesk.Max;
+
+namespace Max2Babylon
+{
+    public partial class LightPropertiesForm : Form
+    {
+        private readonly List<IINode> lights = new List<IINode>();
+
+        public LightPropertiesForm()
+        {
+            InitializeComponent();
+        }
+
+        private void LightPropertiesForm_Load(object sender, EventArgs e)
+        {
+            for (var index = 0; index < Loader.Core.SelNodeCount; index++)
+            {
+                var node = Loader.Core.GetSelNode(index);
+
+                if (node.ObjectRef != null && node.ObjectRef.SuperClassID == SClass_ID.Light)
+                {
+                    lights.Add(node);
+                }
+            }
+
+            Tools.PrepareCheckBox(chkAutoAnimate, lights, "babylonjs_autoanimate");
+            Tools.PrepareCheckBox(chkLoop, lights, "babylonjs_autoanimateloop");
+            Tools.PrepareNumericUpDown(nupFrom, lights, "babylonjs_autoanimate_from");
+            Tools.PrepareNumericUpDown(nupTo, lights, "babylonjs_autoanimate_to", 100.0f);
+        }
+
+        private void butOK_Click(object sender, EventArgs e)
+        {
+            Tools.UpdateCheckBox(chkAutoAnimate, lights, "babylonjs_autoanimate");
+            Tools.UpdateCheckBox(chkLoop, lights, "babylonjs_autoanimateloop");
+            Tools.UpdateNumericUpDown(nupFrom, lights, "babylonjs_autoanimate_from");
+            Tools.UpdateNumericUpDown(nupTo, lights, "babylonjs_autoanimate_to");
+        }
+
+        private void chkAutoAnimate_CheckedChanged(object sender, EventArgs e)
+        {
+            grpAutoAnimate.Enabled = chkAutoAnimate.Checked;
+        }
+    }
+}

+ 120 - 0
Exporters/3ds Max/Max2Babylon/Forms/LightPropertiesForm.resx

@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+</root>

+ 151 - 26
Exporters/3ds Max/Max2Babylon/Forms/ObjectPropertiesForm.Designer.cs

@@ -33,12 +33,24 @@
             this.butCancel = new System.Windows.Forms.Button();
             this.butOK = new System.Windows.Forms.Button();
             this.groupBox2 = new System.Windows.Forms.GroupBox();
+            this.chkShowSubMeshesBoundingBox = new System.Windows.Forms.CheckBox();
+            this.chkShowBoundingBox = new System.Windows.Forms.CheckBox();
             this.chkNoOptimize = new System.Windows.Forms.CheckBox();
             this.chkPickable = new System.Windows.Forms.CheckBox();
-            this.chkShowBoundingBox = new System.Windows.Forms.CheckBox();
-            this.chkShowSubMeshesBoundingBox = new System.Windows.Forms.CheckBox();
+            this.groupBox3 = new System.Windows.Forms.GroupBox();
+            this.grpAutoAnimate = new System.Windows.Forms.GroupBox();
+            this.chkLoop = new System.Windows.Forms.CheckBox();
+            this.nupTo = new System.Windows.Forms.NumericUpDown();
+            this.label2 = new System.Windows.Forms.Label();
+            this.nupFrom = new System.Windows.Forms.NumericUpDown();
+            this.label1 = new System.Windows.Forms.Label();
+            this.chkAutoAnimate = new System.Windows.Forms.CheckBox();
             this.groupBox1.SuspendLayout();
             this.groupBox2.SuspendLayout();
+            this.groupBox3.SuspendLayout();
+            this.grpAutoAnimate.SuspendLayout();
+            ((System.ComponentModel.ISupportInitialize)(this.nupTo)).BeginInit();
+            ((System.ComponentModel.ISupportInitialize)(this.nupFrom)).BeginInit();
             this.SuspendLayout();
             // 
             // groupBox1
@@ -55,9 +67,10 @@
             // chkCollisions
             // 
             this.chkCollisions.AutoSize = true;
+            this.chkCollisions.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
             this.chkCollisions.Location = new System.Drawing.Point(21, 28);
             this.chkCollisions.Name = "chkCollisions";
-            this.chkCollisions.Size = new System.Drawing.Size(102, 17);
+            this.chkCollisions.Size = new System.Drawing.Size(99, 17);
             this.chkCollisions.TabIndex = 0;
             this.chkCollisions.Text = "Check collisions";
             this.chkCollisions.ThreeState = true;
@@ -68,7 +81,7 @@
             this.butCancel.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
             this.butCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
             this.butCancel.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
-            this.butCancel.Location = new System.Drawing.Point(174, 226);
+            this.butCancel.Location = new System.Drawing.Point(174, 509);
             this.butCancel.Name = "butCancel";
             this.butCancel.Size = new System.Drawing.Size(75, 23);
             this.butCancel.TabIndex = 6;
@@ -80,7 +93,7 @@
             this.butOK.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
             this.butOK.DialogResult = System.Windows.Forms.DialogResult.OK;
             this.butOK.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
-            this.butOK.Location = new System.Drawing.Point(93, 226);
+            this.butOK.Location = new System.Drawing.Point(93, 509);
             this.butOK.Name = "butOK";
             this.butOK.Size = new System.Drawing.Size(75, 23);
             this.butOK.TabIndex = 5;
@@ -102,12 +115,37 @@
             this.groupBox2.TabStop = false;
             this.groupBox2.Text = "Misc.";
             // 
+            // chkShowSubMeshesBoundingBox
+            // 
+            this.chkShowSubMeshesBoundingBox.AutoSize = true;
+            this.chkShowSubMeshesBoundingBox.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.chkShowSubMeshesBoundingBox.Location = new System.Drawing.Point(21, 97);
+            this.chkShowSubMeshesBoundingBox.Name = "chkShowSubMeshesBoundingBox";
+            this.chkShowSubMeshesBoundingBox.Size = new System.Drawing.Size(184, 17);
+            this.chkShowSubMeshesBoundingBox.TabIndex = 3;
+            this.chkShowSubMeshesBoundingBox.Text = "Show submeshes bounding boxes";
+            this.chkShowSubMeshesBoundingBox.ThreeState = true;
+            this.chkShowSubMeshesBoundingBox.UseVisualStyleBackColor = true;
+            // 
+            // chkShowBoundingBox
+            // 
+            this.chkShowBoundingBox.AutoSize = true;
+            this.chkShowBoundingBox.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.chkShowBoundingBox.Location = new System.Drawing.Point(21, 74);
+            this.chkShowBoundingBox.Name = "chkShowBoundingBox";
+            this.chkShowBoundingBox.Size = new System.Drawing.Size(117, 17);
+            this.chkShowBoundingBox.TabIndex = 2;
+            this.chkShowBoundingBox.Text = "Show bounding box";
+            this.chkShowBoundingBox.ThreeState = true;
+            this.chkShowBoundingBox.UseVisualStyleBackColor = true;
+            // 
             // chkNoOptimize
             // 
             this.chkNoOptimize.AutoSize = true;
+            this.chkNoOptimize.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
             this.chkNoOptimize.Location = new System.Drawing.Point(21, 51);
             this.chkNoOptimize.Name = "chkNoOptimize";
-            this.chkNoOptimize.Size = new System.Drawing.Size(165, 17);
+            this.chkNoOptimize.Size = new System.Drawing.Size(162, 17);
             this.chkNoOptimize.TabIndex = 1;
             this.chkNoOptimize.Text = "Do not try to optimize vertices";
             this.chkNoOptimize.ThreeState = true;
@@ -116,35 +154,107 @@
             // chkPickable
             // 
             this.chkPickable.AutoSize = true;
+            this.chkPickable.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
             this.chkPickable.Location = new System.Drawing.Point(21, 28);
             this.chkPickable.Name = "chkPickable";
-            this.chkPickable.Size = new System.Drawing.Size(67, 17);
+            this.chkPickable.Size = new System.Drawing.Size(64, 17);
             this.chkPickable.TabIndex = 0;
             this.chkPickable.Text = "Pickable";
             this.chkPickable.ThreeState = true;
             this.chkPickable.UseVisualStyleBackColor = true;
             // 
-            // chkShowBoundingBox
+            // groupBox3
             // 
-            this.chkShowBoundingBox.AutoSize = true;
-            this.chkShowBoundingBox.Location = new System.Drawing.Point(21, 74);
-            this.chkShowBoundingBox.Name = "chkShowBoundingBox";
-            this.chkShowBoundingBox.Size = new System.Drawing.Size(120, 17);
-            this.chkShowBoundingBox.TabIndex = 2;
-            this.chkShowBoundingBox.Text = "Show bounding box";
-            this.chkShowBoundingBox.ThreeState = true;
-            this.chkShowBoundingBox.UseVisualStyleBackColor = true;
+            this.groupBox3.Controls.Add(this.grpAutoAnimate);
+            this.groupBox3.Controls.Add(this.chkAutoAnimate);
+            this.groupBox3.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.groupBox3.Location = new System.Drawing.Point(12, 226);
+            this.groupBox3.Name = "groupBox3";
+            this.groupBox3.Size = new System.Drawing.Size(319, 156);
+            this.groupBox3.TabIndex = 4;
+            this.groupBox3.TabStop = false;
+            this.groupBox3.Text = "Animations";
             // 
-            // chkShowSubMeshesBoundingBox
+            // grpAutoAnimate
             // 
-            this.chkShowSubMeshesBoundingBox.AutoSize = true;
-            this.chkShowSubMeshesBoundingBox.Location = new System.Drawing.Point(21, 97);
-            this.chkShowSubMeshesBoundingBox.Name = "chkShowSubMeshesBoundingBox";
-            this.chkShowSubMeshesBoundingBox.Size = new System.Drawing.Size(187, 17);
-            this.chkShowSubMeshesBoundingBox.TabIndex = 3;
-            this.chkShowSubMeshesBoundingBox.Text = "Show submeshes bounding boxes";
-            this.chkShowSubMeshesBoundingBox.ThreeState = true;
-            this.chkShowSubMeshesBoundingBox.UseVisualStyleBackColor = true;
+            this.grpAutoAnimate.Controls.Add(this.chkLoop);
+            this.grpAutoAnimate.Controls.Add(this.nupTo);
+            this.grpAutoAnimate.Controls.Add(this.label2);
+            this.grpAutoAnimate.Controls.Add(this.nupFrom);
+            this.grpAutoAnimate.Controls.Add(this.label1);
+            this.grpAutoAnimate.Enabled = false;
+            this.grpAutoAnimate.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.grpAutoAnimate.Location = new System.Drawing.Point(21, 51);
+            this.grpAutoAnimate.Name = "grpAutoAnimate";
+            this.grpAutoAnimate.Size = new System.Drawing.Size(292, 99);
+            this.grpAutoAnimate.TabIndex = 3;
+            this.grpAutoAnimate.TabStop = false;
+            // 
+            // chkLoop
+            // 
+            this.chkLoop.AutoSize = true;
+            this.chkLoop.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.chkLoop.Location = new System.Drawing.Point(9, 66);
+            this.chkLoop.Name = "chkLoop";
+            this.chkLoop.Size = new System.Drawing.Size(47, 17);
+            this.chkLoop.TabIndex = 5;
+            this.chkLoop.Text = "Loop";
+            this.chkLoop.ThreeState = true;
+            this.chkLoop.UseVisualStyleBackColor = true;
+            // 
+            // nupTo
+            // 
+            this.nupTo.Location = new System.Drawing.Point(47, 40);
+            this.nupTo.Maximum = new decimal(new int[] {
+            1000,
+            0,
+            0,
+            0});
+            this.nupTo.Name = "nupTo";
+            this.nupTo.Size = new System.Drawing.Size(120, 20);
+            this.nupTo.TabIndex = 3;
+            // 
+            // label2
+            // 
+            this.label2.AutoSize = true;
+            this.label2.Location = new System.Drawing.Point(6, 42);
+            this.label2.Name = "label2";
+            this.label2.Size = new System.Drawing.Size(23, 13);
+            this.label2.TabIndex = 4;
+            this.label2.Text = "To:";
+            // 
+            // nupFrom
+            // 
+            this.nupFrom.Location = new System.Drawing.Point(47, 14);
+            this.nupFrom.Maximum = new decimal(new int[] {
+            1000,
+            0,
+            0,
+            0});
+            this.nupFrom.Name = "nupFrom";
+            this.nupFrom.Size = new System.Drawing.Size(120, 20);
+            this.nupFrom.TabIndex = 1;
+            // 
+            // label1
+            // 
+            this.label1.AutoSize = true;
+            this.label1.Location = new System.Drawing.Point(6, 16);
+            this.label1.Name = "label1";
+            this.label1.Size = new System.Drawing.Size(33, 13);
+            this.label1.TabIndex = 2;
+            this.label1.Text = "From:";
+            // 
+            // chkAutoAnimate
+            // 
+            this.chkAutoAnimate.AutoSize = true;
+            this.chkAutoAnimate.Location = new System.Drawing.Point(21, 28);
+            this.chkAutoAnimate.Name = "chkAutoAnimate";
+            this.chkAutoAnimate.Size = new System.Drawing.Size(88, 17);
+            this.chkAutoAnimate.TabIndex = 0;
+            this.chkAutoAnimate.Text = "Auto animate";
+            this.chkAutoAnimate.ThreeState = true;
+            this.chkAutoAnimate.UseVisualStyleBackColor = true;
+            this.chkAutoAnimate.CheckedChanged += new System.EventHandler(this.chkAutoAnimate_CheckedChanged);
             // 
             // ObjectPropertiesForm
             // 
@@ -152,7 +262,8 @@
             this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
             this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
             this.CancelButton = this.butCancel;
-            this.ClientSize = new System.Drawing.Size(343, 261);
+            this.ClientSize = new System.Drawing.Size(343, 544);
+            this.Controls.Add(this.groupBox3);
             this.Controls.Add(this.groupBox2);
             this.Controls.Add(this.butCancel);
             this.Controls.Add(this.butOK);
@@ -166,6 +277,12 @@
             this.groupBox1.PerformLayout();
             this.groupBox2.ResumeLayout(false);
             this.groupBox2.PerformLayout();
+            this.groupBox3.ResumeLayout(false);
+            this.groupBox3.PerformLayout();
+            this.grpAutoAnimate.ResumeLayout(false);
+            this.grpAutoAnimate.PerformLayout();
+            ((System.ComponentModel.ISupportInitialize)(this.nupTo)).EndInit();
+            ((System.ComponentModel.ISupportInitialize)(this.nupFrom)).EndInit();
             this.ResumeLayout(false);
 
         }
@@ -181,5 +298,13 @@
         private System.Windows.Forms.CheckBox chkNoOptimize;
         private System.Windows.Forms.CheckBox chkShowSubMeshesBoundingBox;
         private System.Windows.Forms.CheckBox chkShowBoundingBox;
+        private System.Windows.Forms.GroupBox groupBox3;
+        private System.Windows.Forms.GroupBox grpAutoAnimate;
+        private System.Windows.Forms.CheckBox chkLoop;
+        private System.Windows.Forms.NumericUpDown nupTo;
+        private System.Windows.Forms.Label label2;
+        private System.Windows.Forms.NumericUpDown nupFrom;
+        private System.Windows.Forms.Label label1;
+        private System.Windows.Forms.CheckBox chkAutoAnimate;
     }
 }

+ 15 - 0
Exporters/3ds Max/Max2Babylon/Forms/ObjectPropertiesForm.cs

@@ -21,6 +21,11 @@ namespace Max2Babylon
             Tools.UpdateCheckBox(chkNoOptimize, objects, "babylonjs_nooptimize");
             Tools.UpdateCheckBox(chkShowBoundingBox, objects, "babylonjs_showboundingbox");
             Tools.UpdateCheckBox(chkShowSubMeshesBoundingBox, objects, "babylonjs_showsubmeshesboundingbox");
+
+            Tools.UpdateCheckBox(chkAutoAnimate, objects, "babylonjs_autoanimate");
+            Tools.UpdateCheckBox(chkLoop, objects, "babylonjs_autoanimateloop");
+            Tools.UpdateNumericUpDown(nupFrom, objects, "babylonjs_autoanimate_from");
+            Tools.UpdateNumericUpDown(nupTo, objects, "babylonjs_autoanimate_to");
         }
 
         private void ObjectPropertiesForm_Load(object sender, EventArgs e)
@@ -40,6 +45,16 @@ namespace Max2Babylon
             Tools.PrepareCheckBox(chkNoOptimize, objects, "babylonjs_nooptimize");
             Tools.PrepareCheckBox(chkShowBoundingBox, objects, "babylonjs_showboundingbox");
             Tools.PrepareCheckBox(chkShowSubMeshesBoundingBox, objects, "babylonjs_showsubmeshesboundingbox");
+
+            Tools.PrepareCheckBox(chkAutoAnimate, objects, "babylonjs_autoanimate");
+            Tools.PrepareCheckBox(chkLoop, objects, "babylonjs_autoanimateloop");
+            Tools.PrepareNumericUpDown(nupFrom, objects, "babylonjs_autoanimate_from");
+            Tools.PrepareNumericUpDown(nupTo, objects, "babylonjs_autoanimate_to", 100.0f);
+        }
+
+        private void chkAutoAnimate_CheckedChanged(object sender, EventArgs e)
+        {
+            grpAutoAnimate.Enabled = chkAutoAnimate.Checked;
         }
     }
 }

+ 11 - 1
Exporters/3ds Max/Max2Babylon/Tools.cs

@@ -3,7 +3,6 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Windows.Forms;
 using Autodesk.Max;
-using Autodesk.Max.IMXSDebugger;
 using MaxSharp;
 using SharpDX;
 using Color = MaxSharp.Color;
@@ -13,6 +12,17 @@ namespace Max2Babylon
     public static class Tools
     {
         public const float Epsilon = 0.001f;
+
+        public static bool IsEqualTo(this float[] value, float[] other)
+        {
+            if (value.Length != other.Length)
+            {
+                return false;
+            }
+
+            return !value.Where((t, i) => Math.Abs(t - other[i]) > Epsilon).Any();
+        }
+
         public static float[] ToArray(this IMatrix3 value)
         {
             var row0 = value.GetRow(0).ToArraySwitched();

+ 3 - 0
Exporters/3ds Max/readme.md

@@ -17,6 +17,7 @@ This exporter is designed for 3ds Max 2013+. You just have to unzip the content
  - Collisions (*)
  - Position
  - Target / Rotation
+ - Animations: Position, Fov
 - *Lights*
  - Omni / spot / directional / Ambient(Hemispheric)
  - Shadows maps for directional lights
@@ -25,6 +26,7 @@ This exporter is designed for 3ds Max 2013+. You just have to unzip the content
  - Intensity
  - Diffuse
  - Specular
+ - Animations: Position, Direction, intensity 
 - *Meshes*
  - Visibility
  - Renderable
@@ -33,6 +35,7 @@ This exporter is designed for 3ds Max 2013+. You just have to unzip the content
  - Pickable (*)
  - Position / rotation / scaling
  - Geometry (position, normal, texture coordinates (2 channels))
+ - Animations: Position, scaling, rotation, visibility
 - *Materials*
  - Multi-materials
  - Alpha

File diff suppressed because it is too large
+ 7 - 7
babylon.1.12-beta.js