Преглед изворни кода

Merge pull request #2724 from BabylonJS/master

Nightly
David Catuhe пре 8 година
родитељ
комит
ca998afbc2
52 измењених фајлова са 3060 додато и 2610 уклоњено
  1. 11 2
      Exporters/3ds Max/BabylonExport.Entities/BabylonCamera.cs
  2. 3 2
      Exporters/3ds Max/BabylonExport.Entities/BabylonExport.Entities.csproj
  3. 6 4
      Exporters/3ds Max/BabylonExport.Entities/BabylonScene.cs
  4. 12 29
      Exporters/3ds Max/BabylonExport.Entities/BabylonVector3.cs
  5. 1 1
      Exporters/3ds Max/BabylonExport.Entities/packages.config
  6. 10 1
      Exporters/3ds Max/GltfExport.Entities/GLTF.cs
  7. 25 0
      Exporters/3ds Max/GltfExport.Entities/GLTFCamera.cs
  8. 20 0
      Exporters/3ds Max/GltfExport.Entities/GLTFCameraOrthographic.cs
  9. 20 0
      Exporters/3ds Max/GltfExport.Entities/GLTFCameraPerspective.cs
  10. 3 0
      Exporters/3ds Max/GltfExport.Entities/GLTFExport.Entities.csproj
  11. 114 0
      Exporters/3ds Max/Max2Babylon/2017/Exporter/BabylonExporter.GLTFExporter.Camera.cs
  12. 49 0
      Exporters/3ds Max/Max2Babylon/2017/Exporter/BabylonExporter.GLTFExporter.Light.cs
  13. 23 24
      Exporters/3ds Max/Max2Babylon/2017/Exporter/BabylonExporter.GLTFExporter.Material.cs
  14. 273 188
      Exporters/3ds Max/Max2Babylon/2017/Exporter/BabylonExporter.GLTFExporter.Mesh.cs
  15. 4 4
      Exporters/3ds Max/Max2Babylon/2017/Exporter/BabylonExporter.GLTFExporter.Texture.cs
  16. 93 34
      Exporters/3ds Max/Max2Babylon/2017/Exporter/BabylonExporter.GLTFExporter.cs
  17. 42 0
      Exporters/3ds Max/Max2Babylon/2017/JsonTextWriterBounded.cs
  18. 3 0
      Exporters/3ds Max/Max2Babylon/2017/Max2Babylon2017.csproj
  19. 16 6
      Exporters/3ds Max/Max2Babylon/2017/Properties/Resources.Designer.cs
  20. 4 0
      Exporters/3ds Max/Max2Babylon/2017/Properties/Resources.resx
  21. BIN
      Exporters/3ds Max/Max2Babylon/2017/Resources/Logo_Exporter_v3.jpg
  22. 19 6
      Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Camera.cs
  23. 4 4
      Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Mesh.cs
  24. 1 1
      Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.cs
  25. 2 3
      Exporters/3ds Max/Max2Babylon/Forms/ExporterForm.Designer.cs
  26. 0 197
      Exporters/3ds Max/Max2Babylon/Forms/ExporterForm.resx
  27. 473 469
      dist/preview release/babylon.d.ts
  28. 40 40
      dist/preview release/babylon.js
  29. 73 16
      dist/preview release/babylon.max.js
  30. 473 469
      dist/preview release/babylon.module.d.ts
  31. 40 40
      dist/preview release/babylon.worker.js
  32. 502 498
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts
  33. 27 27
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js
  34. 69 12
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js
  35. 502 498
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.module.d.ts
  36. 2 1
      dist/preview release/gui/babylon.gui.js
  37. 3 3
      dist/preview release/gui/babylon.gui.min.js
  38. 1 1
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  39. 1 1
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  40. 1 1
      dist/preview release/loaders/babylon.glTFFileLoader.js
  41. 1 1
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  42. 1 0
      gui/src/advancedDynamicTexture.ts
  43. 1 1
      gui/src/controls/control.ts
  44. 1 1
      loaders/src/glTF/2.0/babylon.glTFLoader.ts
  45. 1 1
      src/Behaviors/Cameras/babylon.autoRotationBehavior.ts
  46. 5 5
      src/Cameras/babylon.freeCamera.ts
  47. 16 0
      src/Lights/Shadows/babylon.shadowGenerator.ts
  48. 14 0
      src/Materials/babylon.effect.ts
  49. 2 2
      src/Mesh/babylon.abstractMesh.ts
  50. 19 0
      src/PostProcess/babylon.postProcess.ts
  51. 24 17
      src/babylon.engine.ts
  52. 10 0
      src/babylon.scene.ts

+ 11 - 2
Exporters/3ds Max/BabylonExport.Entities/BabylonCamera.cs

@@ -5,6 +5,12 @@ namespace BabylonExport.Entities
     [DataContract]
     public class BabylonCamera : BabylonNode
     {
+        public enum CameraMode
+        {
+            PERSPECTIVE_CAMERA = 0,
+            ORTHOGRAPHIC_CAMERA = 1
+        }
+
         [DataMember]
         public string lockedTargetId { get; set; }
 
@@ -18,6 +24,9 @@ namespace BabylonExport.Entities
         public float[] rotation { get; set; }
 
         [DataMember]
+        public float[] rotationQuaternion { get; set; }
+
+        [DataMember]
         public float[] target { get; set; }
 
         [DataMember]
@@ -48,7 +57,7 @@ namespace BabylonExport.Entities
         public float[] ellipsoid { get; set; }
 
         [DataMember]
-        public int mode { get; set; }
+        public CameraMode mode { get; set; }
 
         [DataMember]
         public float? orthoLeft { get; set; }
@@ -84,7 +93,7 @@ namespace BabylonExport.Entities
             inertia = 0.9f;
             interaxialDistance = 0.0637f;
 
-            mode = 0;
+            mode = CameraMode.PERSPECTIVE_CAMERA;
             orthoLeft = null;
             orthoRight = null;
             orthoBottom = null;

+ 3 - 2
Exporters/3ds Max/BabylonExport.Entities/BabylonExport.Entities.csproj

@@ -9,7 +9,7 @@
     <AppDesignerFolder>Properties</AppDesignerFolder>
     <RootNamespace>BabylonExport.Entities</RootNamespace>
     <AssemblyName>BabylonExport.Entities</AssemblyName>
-    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
     <FileAlignment>512</FileAlignment>
     <SccProjectName>SAK</SccProjectName>
     <SccLocalPath>SAK</SccLocalPath>
@@ -91,13 +91,14 @@
     <None Include="packages.config" />
   </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!--
   <Import Project=".\packages\SharpDX.2.6.3\build\SharpDX.targets" Condition="Exists('.\packages\SharpDX.2.6.3\build\SharpDX.targets')" />
   <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
     <PropertyGroup>
       <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them.  For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText>
     </PropertyGroup>
     <Error Condition="!Exists('.\packages\SharpDX.2.6.3\build\SharpDX.targets')" Text="$([System.String]::Format('$(ErrorText)', '.\packages\SharpDX.2.6.3\build\SharpDX.targets'))" />
-  </Target>
+  </Target> -->
   <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
        Other similar extension points exist, see Microsoft.Common.targets.
   <Target Name="BeforeBuild">

+ 6 - 4
Exporters/3ds Max/BabylonExport.Entities/BabylonScene.cs

@@ -46,11 +46,11 @@ namespace BabylonExport.Entities
 
         [DataMember]
         public float[] physicsGravity { get; set; }
-
-        [DataMember]
+        
+        [DataMember(EmitDefaultValue = false)]
         public BabylonCamera[] cameras { get; set; }
-
-        [DataMember]
+        
+        [DataMember(EmitDefaultValue = false)]
         public string activeCameraID { get; set; }
 
         [DataMember]
@@ -142,6 +142,8 @@ namespace BabylonExport.Entities
             {
                 var camera = new BabylonCamera { name = "Default camera", id = Guid.NewGuid().ToString() };
 
+                // Default camera init gives infinit values
+                // Indeed, float.MaxValue - float.MinValue always leads to infinity
                 var distanceVector = MaxVector - MinVector;
                 var midPoint = MinVector + distanceVector / 2;
                 camera.target = midPoint.ToArray();

+ 12 - 29
Exporters/3ds Max/BabylonExport.Entities/BabylonVector3.cs

@@ -38,40 +38,23 @@ namespace BabylonExport.Entities
             return new BabylonVector3 { X = a.X * b, Y = a.Y * b, Z = a.Z * b };
         }
 
-        /**
-         * Returns a new Quaternion object, computed from the Vector3 coordinates.
-         */
-        public BabylonQuaternion toQuaternion()
+        public BabylonQuaternion toQuaternionGltf()
         {
-            var result = new BabylonQuaternion();
-
-            var cosxPlusz = Math.Cos((this.X + this.Z) * 0.5);
-            var sinxPlusz = Math.Sin((this.X + this.Z) * 0.5);
-            var coszMinusx = Math.Cos((this.Z - this.X) * 0.5);
-            var sinzMinusx = Math.Sin((this.Z - this.X) * 0.5);
-            var cosy = Math.Cos(this.Y * 0.5);
-            var siny = Math.Sin(this.Y * 0.5);
-
-            result.X = (float)(coszMinusx * siny);
-            result.Y = (float)(-sinzMinusx * siny);
-            result.Z = (float)(sinxPlusz * cosy);
-            result.W = (float)(cosxPlusz * cosy);
-            return result;
+            BabylonQuaternion babylonQuaternion = RotationYawPitchRollToRefBabylon(X, -Y, -Z);
+            // Doing following computation is ugly but works
+            // The goal is to switch from left to right handed coordinate system
+            // Swap X and Y
+            var tmp = babylonQuaternion.X;
+            babylonQuaternion.X = babylonQuaternion.Y;
+            babylonQuaternion.Y = tmp;
+            return babylonQuaternion;
         }
 
-        ///**
-        // * Returns a new Quaternion object, computed from the Vector3 coordinates.
-        // */
-        //public BabylonQuaternion toQuaternion()
-        //{
-        //    return RotationYawPitchRollToRef(Y,X,Z);
-        //}
-
-
         /**
+         * (Copy pasted from babylon)
          * Sets the passed quaternion "result" from the passed float Euler angles (y, x, z).  
          */
-        public BabylonQuaternion RotationYawPitchRollToRef(float yaw, float pitch, float roll)
+        private BabylonQuaternion RotationYawPitchRollToRefBabylon(float yaw, float pitch, float roll)
         {
             // Produces a quaternion from Euler angles in the z-y-x orientation (Tait-Bryan angles)
             var halfRoll = roll * 0.5;
@@ -92,5 +75,5 @@ namespace BabylonExport.Entities
             result.W = (float)((cosYaw * cosPitch * cosRoll) + (sinYaw * sinPitch * sinRoll));
             return result;
         }
-}
+    }
 }

+ 1 - 1
Exporters/3ds Max/BabylonExport.Entities/packages.config

@@ -1,4 +1,4 @@
 <?xml version="1.0" encoding="utf-8"?>
 <packages>
-  <package id="SharpDX" version="2.6.3" targetFramework="net35" />
+  <package id="SharpDX" version="2.6.3" targetFramework="net35" requireReinstallation="true" />
 </packages>

+ 10 - 1
Exporters/3ds Max/GltfExport.Entities/GLTF.cs

@@ -10,7 +10,7 @@ namespace GLTFExport.Entities
         public GLTFAsset asset { get; set; }
 
         [DataMember(EmitDefaultValue = false)]
-        public int scene { get; set; }
+        public int? scene { get; set; }
 
         [DataMember(EmitDefaultValue = false)]
         public GLTFScene[] scenes { get; set; }
@@ -19,6 +19,9 @@ namespace GLTFExport.Entities
         public GLTFNode[] nodes { get; set; }
 
         [DataMember(EmitDefaultValue = false)]
+        public GLTFCamera[] cameras { get; set; }
+
+        [DataMember(EmitDefaultValue = false)]
         public GLTFMesh[] meshes { get; set; }
 
         [DataMember(EmitDefaultValue = false)]
@@ -45,6 +48,7 @@ namespace GLTFExport.Entities
         public string OutputPath { get; private set; }
 
         public List<GLTFNode> NodesList { get; private set; }
+        public List<GLTFCamera> CamerasList { get; private set; }
         public List<GLTFBuffer> BuffersList { get; private set; }
         public List<GLTFBufferView> BufferViewsList { get; private set; }
         public List<GLTFAccessor> AccessorsList { get; private set; }
@@ -59,6 +63,7 @@ namespace GLTFExport.Entities
             OutputPath = outputPath;
 
             NodesList = new List<GLTFNode>();
+            CamerasList = new List<GLTFCamera>();
             BuffersList = new List<GLTFBuffer>();
             BufferViewsList = new List<GLTFBufferView>();
             AccessorsList = new List<GLTFAccessor>();
@@ -79,6 +84,10 @@ namespace GLTFExport.Entities
                 nodes = NodesList.ToArray();
                 NodesList.ForEach(node => node.Prepare());
             }
+            if (CamerasList.Count > 0)
+            {
+                cameras = CamerasList.ToArray();
+            }
             if (BuffersList.Count > 0)
             {
                 buffers = BuffersList.ToArray();

+ 25 - 0
Exporters/3ds Max/GltfExport.Entities/GLTFCamera.cs

@@ -0,0 +1,25 @@
+using System.Runtime.Serialization;
+
+namespace GLTFExport.Entities
+{
+    [DataContract]
+    public class GLTFCamera : GLTFIndexedChildRootProperty
+    {
+        public enum CameraType
+        {
+            perspective,
+            orthographic
+        }
+
+        [DataMember(EmitDefaultValue = false)]
+        public GLTFCameraOrthographic orthographic { get; set; }
+
+        [DataMember(EmitDefaultValue = false)]
+        public GLTFCameraPerspective perspective { get; set; }
+
+        [DataMember(IsRequired = true)]
+        public string type { get; set; }
+
+        public GLTFNode gltfNode;
+    }
+}

+ 20 - 0
Exporters/3ds Max/GltfExport.Entities/GLTFCameraOrthographic.cs

@@ -0,0 +1,20 @@
+using System.Runtime.Serialization;
+
+namespace GLTFExport.Entities
+{
+    [DataContract]
+    public class GLTFCameraOrthographic : GLTFProperty
+    {
+        [DataMember(IsRequired = true)]
+        public float xmag { get; set; }
+
+        [DataMember(IsRequired = true)]
+        public float ymag { get; set; }
+
+        [DataMember(IsRequired = true)]
+        public float zfar { get; set; }
+
+        [DataMember(IsRequired = true)]
+        public float znear { get; set; }
+    }
+}

+ 20 - 0
Exporters/3ds Max/GltfExport.Entities/GLTFCameraPerspective.cs

@@ -0,0 +1,20 @@
+using System.Runtime.Serialization;
+
+namespace GLTFExport.Entities
+{
+    [DataContract]
+    public class GLTFCameraPerspective : GLTFProperty
+    {
+        [DataMember(EmitDefaultValue = false)]
+        public float? aspectRatio { get; set; }
+
+        [DataMember(IsRequired = true)]
+        public float yfov { get; set; }
+
+        [DataMember(EmitDefaultValue = false)]
+        public float? zfar { get; set; }
+
+        [DataMember(IsRequired = true)]
+        public float znear { get; set; }
+    }
+}

+ 3 - 0
Exporters/3ds Max/GltfExport.Entities/GLTFExport.Entities.csproj

@@ -44,6 +44,9 @@
     <Compile Include="GLTFAccessor.cs" />
     <Compile Include="GLTFBufferView.cs" />
     <Compile Include="GLTFBuffer.cs" />
+    <Compile Include="GLTFCameraPerspective.cs" />
+    <Compile Include="GLTFCameraOrthographic.cs" />
+    <Compile Include="GLTFCamera.cs" />
     <Compile Include="GLTFSampler.cs" />
     <Compile Include="GLTFIndexedChildRootProperty.cs" />
     <Compile Include="GLTFImage.cs" />

+ 114 - 0
Exporters/3ds Max/Max2Babylon/2017/Exporter/BabylonExporter.GLTFExporter.Camera.cs

@@ -0,0 +1,114 @@
+using BabylonExport.Entities;
+using GLTFExport.Entities;
+
+namespace Max2Babylon
+{
+    partial class BabylonExporter
+    {
+        // TODO - Test if ok with a gltf viewer working with custom camera (babylon loader/sandbox doesn't load them)
+        private GLTFCamera ExportCamera(BabylonCamera babylonCamera, GLTF gltf, GLTFNode gltfParentNode)
+        {
+            RaiseMessage("GLTFExporter.Camera | Export camera named: " + babylonCamera.name, 1);
+
+            // --------------------------
+            // ---------- Node ----------
+            // --------------------------
+
+            RaiseMessage("GLTFExporter.Camera | Node", 2);
+            // Node
+            var gltfNode = new GLTFNode();
+            gltfNode.name = babylonCamera.name;
+            gltfNode.index = gltf.NodesList.Count;
+            gltf.NodesList.Add(gltfNode);
+
+            // Hierarchy
+            if (gltfParentNode != null)
+            {
+                RaiseMessage("GLTFExporter.Camera | Add " + babylonCamera.name + " as child to " + gltfParentNode.name, 3);
+                gltfParentNode.ChildrenList.Add(gltfNode.index);
+            }
+            else
+            {
+                // It's a root node
+                // Only root nodes are listed in a gltf scene
+                RaiseMessage("GLTFExporter.Camera | Add " + babylonCamera.name + " as root node to scene", 3);
+                gltf.scenes[0].NodesList.Add(gltfNode.index);
+            }
+
+            // Transform
+            gltfNode.translation = babylonCamera.position;
+            // Switch from left to right handed coordinate system
+            //gltfNode.translation[0] *= -1;
+            if (babylonCamera.rotationQuaternion != null)
+            {
+                gltfNode.rotation = babylonCamera.rotationQuaternion;
+            }
+            else
+            {
+                // Convert rotation vector to quaternion
+                BabylonVector3 rotationVector3 = new BabylonVector3
+                {
+                    X = babylonCamera.rotation[0],
+                    Y = babylonCamera.rotation[1],
+                    Z = babylonCamera.rotation[2]
+                };
+                gltfNode.rotation = rotationVector3.toQuaternionGltf().ToArray();
+            }
+            // No scaling defined for babylon camera. Use identity instead.
+            gltfNode.scale = new float[3] { 1, 1, 1 };
+
+
+            // --- prints ---
+
+            RaiseMessage("GLTFExporter.Camera | babylonCamera data", 2);
+            RaiseMessage("GLTFExporter.Camera | babylonCamera.type=" + babylonCamera.type, 3);
+            RaiseMessage("GLTFExporter.Camera | babylonCamera.fov=" + babylonCamera.fov, 3);
+            RaiseMessage("GLTFExporter.Camera | babylonCamera.maxZ=" + babylonCamera.maxZ, 3);
+            RaiseMessage("GLTFExporter.Camera | babylonCamera.minZ=" + babylonCamera.minZ, 3);
+
+
+            // --------------------------
+            // ------- gltfCamera -------
+            // --------------------------
+
+            RaiseMessage("GLTFExporter.Camera | create gltfCamera", 2);
+
+            // Camera
+            var gltfCamera = new GLTFCamera { name = babylonCamera.name };
+            gltfCamera.index = gltf.CamerasList.Count;
+            gltf.CamerasList.Add(gltfCamera);
+            gltfNode.camera = gltfCamera.index;
+            gltfCamera.gltfNode = gltfNode;
+
+            // Camera type
+            switch (babylonCamera.mode)
+            {
+                case (BabylonCamera.CameraMode.ORTHOGRAPHIC_CAMERA):
+                    var gltfCameraOrthographic = new GLTFCameraOrthographic();
+                    gltfCameraOrthographic.xmag = 1; // TODO - How to retreive value from babylon? xmag:The floating-point horizontal magnification of the view
+                    gltfCameraOrthographic.ymag = 1; // TODO - How to retreive value from babylon? ymag:The floating-point vertical magnification of the view
+                    gltfCameraOrthographic.zfar = babylonCamera.maxZ;
+                    gltfCameraOrthographic.znear = babylonCamera.minZ;
+
+                    gltfCamera.type = GLTFCamera.CameraType.orthographic.ToString();
+                    gltfCamera.orthographic = gltfCameraOrthographic;
+                    break;
+                case (BabylonCamera.CameraMode.PERSPECTIVE_CAMERA):
+                    var gltfCameraPerspective = new GLTFCameraPerspective();
+                    gltfCameraPerspective.aspectRatio = null; // 0.8f; // TODO - How to retreive value from babylon? The aspect ratio in babylon is computed based on the engine rather than set on a camera (aspectRatio = _gl.drawingBufferWidth / _gl.drawingBufferHeight)
+                    gltfCameraPerspective.yfov = babylonCamera.fov; // WARNING - Babylon camera fov mode is assumed to be vertical (FOVMODE_VERTICAL_FIXED)
+                    gltfCameraPerspective.zfar = babylonCamera.maxZ;
+                    gltfCameraPerspective.znear = babylonCamera.minZ;
+
+                    gltfCamera.type = GLTFCamera.CameraType.perspective.ToString();
+                    gltfCamera.perspective = gltfCameraPerspective;
+                    break;
+                default:
+                    RaiseError("GLTFExporter.Camera | camera mode not found");
+                    break;
+            }
+            
+            return gltfCamera;
+        }
+    }
+}

+ 49 - 0
Exporters/3ds Max/Max2Babylon/2017/Exporter/BabylonExporter.GLTFExporter.Light.cs

@@ -0,0 +1,49 @@
+using BabylonExport.Entities;
+using GLTFExport.Entities;
+
+namespace Max2Babylon
+{
+    partial class BabylonExporter
+    {
+        private GLTFNode ExportLight(BabylonLight babylonLight, GLTF gltf, GLTFNode gltfParentNode)
+        {
+            RaiseMessage("GLTFExporter.Light | ExportLight babylonLight.name=" + babylonLight.name, 1);
+
+            // --------------------------
+            // ---------- Node ----------
+            // --------------------------
+
+            RaiseMessage("GLTFExporter.Light | Node", 2);
+            // Node
+            var gltfNode = new GLTFNode();
+            gltfNode.name = babylonLight.name;
+            gltfNode.index = gltf.NodesList.Count;
+            gltf.NodesList.Add(gltfNode);
+
+            // Hierarchy
+            if (gltfParentNode != null)
+            {
+                RaiseMessage("GLTFExporter.Light | Add " + babylonLight.name + " as child to " + gltfParentNode.name, 3);
+                gltfParentNode.ChildrenList.Add(gltfNode.index);
+            }
+            else
+            {
+                // It's a root node
+                // Only root nodes are listed in a gltf scene
+                RaiseMessage("GLTFExporter.Light | Add " + babylonLight.name + " as root node to scene", 3);
+                gltf.scenes[0].NodesList.Add(gltfNode.index);
+            }
+
+            // Transform
+            gltfNode.translation = babylonLight.position;
+            // Switch from left to right handed coordinate system
+            //gltfNode.translation[0] *= -1;
+            // No rotation defined for babylon light. Use identity instead.
+            gltfNode.rotation = new float[4] { 0, 0, 0, 1 };
+            // No scaling defined for babylon light. Use identity instead.
+            gltfNode.scale = new float[3] { 1, 1, 1 };
+
+            return gltfNode;
+        }
+    }
+}

+ 23 - 24
Exporters/3ds Max/Max2Babylon/2017/Exporter/BabylonExporter.GLTFExporter.Material.cs

@@ -5,73 +5,69 @@ namespace Max2Babylon
 {
     partial class BabylonExporter
     {
-        //readonly List<IIGameMaterial> referencedMaterials = new List<IIGameMaterial>();
-
         private void ExportMaterial(BabylonMaterial babylonMaterial, GLTF gltf)
         {
             var name = babylonMaterial.name;
             var id = babylonMaterial.id;
 
-            RaiseMessage("GLTFExporter.Material | ExportMaterial name=" + name, 1);
+            RaiseMessage("GLTFExporter.Material | Export material named: " + name, 1);
 
             if (babylonMaterial.GetType() == typeof(BabylonStandardMaterial))
             {
-                RaiseMessage("GLTFExporter.Material | babylonStandardMaterial != null", 1);
-
                 var babylonStandardMaterial = babylonMaterial as BabylonStandardMaterial;
 
 
                 // --- prints ---
 
-                RaiseMessage("GLTFExporter.Material | babylonMaterial data", 1);
-                RaiseMessage("GLTFExporter.Material | babylonMaterial.alpha=" + babylonMaterial.alpha, 2);
-                RaiseMessage("GLTFExporter.Material | babylonMaterial.backFaceCulling=" + babylonMaterial.backFaceCulling, 2);
-                RaiseMessage("GLTFExporter.Material | babylonMaterial.wireframe=" + babylonMaterial.wireframe, 2);
+                RaiseMessage("GLTFExporter.Material | babylonMaterial data", 2);
+                RaiseMessage("GLTFExporter.Material | babylonMaterial.alpha=" + babylonMaterial.alpha, 3);
+                RaiseMessage("GLTFExporter.Material | babylonMaterial.backFaceCulling=" + babylonMaterial.backFaceCulling, 3);
+                RaiseMessage("GLTFExporter.Material | babylonMaterial.wireframe=" + babylonMaterial.wireframe, 3);
 
                 // Ambient
                 for (int i = 0; i < babylonStandardMaterial.ambient.Length; i++)
                 {
-                    RaiseMessage("GLTFExporter.Material | babylonStandardMaterial.ambient[" + i + "]=" + babylonStandardMaterial.ambient[i], 2);
+                    RaiseMessage("GLTFExporter.Material | babylonStandardMaterial.ambient[" + i + "]=" + babylonStandardMaterial.ambient[i], 3);
                 }
 
                 // Diffuse
-                RaiseMessage("GLTFExporter.Material | babylonStandardMaterial.diffuse.Length=" + babylonStandardMaterial.diffuse.Length, 2);
+                RaiseMessage("GLTFExporter.Material | babylonStandardMaterial.diffuse.Length=" + babylonStandardMaterial.diffuse.Length, 3);
                 for (int i = 0; i < babylonStandardMaterial.diffuse.Length; i++)
                 {
-                    RaiseMessage("GLTFExporter.Material | babylonStandardMaterial.diffuse[" + i + "]=" + babylonStandardMaterial.diffuse[i], 2);
+                    RaiseMessage("GLTFExporter.Material | babylonStandardMaterial.diffuse[" + i + "]=" + babylonStandardMaterial.diffuse[i], 3);
                 }
                 if (babylonStandardMaterial.diffuseTexture == null)
                 {
-                    RaiseMessage("GLTFExporter.Material | babylonStandardMaterial.diffuseTexture=null", 2);
+                    RaiseMessage("GLTFExporter.Material | babylonStandardMaterial.diffuseTexture=null", 3);
                 }
 
                 // Normal / bump
                 if (babylonStandardMaterial.bumpTexture == null)
                 {
-                    RaiseMessage("GLTFExporter.Material | babylonStandardMaterial.bumpTexture=null", 2);
+                    RaiseMessage("GLTFExporter.Material | babylonStandardMaterial.bumpTexture=null", 3);
                 }
 
                 // Specular
                 for (int i = 0; i < babylonStandardMaterial.specular.Length; i++)
                 {
-                    RaiseMessage("GLTFExporter.Material | babylonStandardMaterial.specular[" + i + "]=" + babylonStandardMaterial.specular[i], 2);
+                    RaiseMessage("GLTFExporter.Material | babylonStandardMaterial.specular[" + i + "]=" + babylonStandardMaterial.specular[i], 3);
                 }
-                RaiseMessage("GLTFExporter.Material | babylonStandardMaterial.specularPower=" + babylonStandardMaterial.specularPower, 2);
+                RaiseMessage("GLTFExporter.Material | babylonStandardMaterial.specularPower=" + babylonStandardMaterial.specularPower, 3);
 
                 // Occlusion
                 if (babylonStandardMaterial.ambientTexture == null)
                 {
-                    RaiseMessage("GLTFExporter.Material | babylonStandardMaterial.ambientTexture=null", 2);
+                    RaiseMessage("GLTFExporter.Material | babylonStandardMaterial.ambientTexture=null", 3);
                 }
 
                 // Emissive
                 for (int i = 0; i < babylonStandardMaterial.emissive.Length; i++)
                 {
-                    RaiseMessage("GLTFExporter.Material | babylonStandardMaterial.emissive[" + i + "]=" + babylonStandardMaterial.emissive[i], 2);
+                    RaiseMessage("GLTFExporter.Material | babylonStandardMaterial.emissive[" + i + "]=" + babylonStandardMaterial.emissive[i], 3);
                 }
                 if (babylonStandardMaterial.emissiveTexture == null)
                 {
-                    RaiseMessage("GLTFExporter.Material | babylonStandardMaterial.emissiveTexture=null", 2);
+                    RaiseMessage("GLTFExporter.Material | babylonStandardMaterial.emissiveTexture=null", 3);
                 }
 
 
@@ -79,7 +75,7 @@ namespace Max2Babylon
                 // --------- gltfMaterial ---------
                 // --------------------------------
 
-                RaiseMessage("GLTFExporter.Material | create gltfMaterial", 1);
+                RaiseMessage("GLTFExporter.Material | create gltfMaterial", 2);
                 var gltfMaterial = new GLTFMaterial
                 {
                     name = name
@@ -113,10 +109,11 @@ namespace Max2Babylon
                 // --- gltfPbrMetallicRoughness ---
                 // --------------------------------
 
-                RaiseMessage("GLTFExporter.Material | create gltfPbrMetallicRoughness", 1);
+                RaiseMessage("GLTFExporter.Material | create gltfPbrMetallicRoughness", 2);
                 var gltfPbrMetallicRoughness = new GLTFPBRMetallicRoughness();
                 gltfMaterial.pbrMetallicRoughness = gltfPbrMetallicRoughness;
 
+                // TODO - Retreive diffuse or albedo?
                 // Base color
                 var babylonDiffuseColor = babylonStandardMaterial.diffuse;
                 gltfPbrMetallicRoughness.baseColorFactor = new float[4]
@@ -127,7 +124,7 @@ namespace Max2Babylon
                     babylonMaterial.alpha
                 };
                 gltfPbrMetallicRoughness.baseColorTexture = ExportTexture(babylonStandardMaterial.diffuseTexture, gltf);
-
+                 
                 // TODO - Metallic roughness
                 gltfPbrMetallicRoughness.metallicFactor = 0; // Non metal
                 // TODO - roughnessFactor
@@ -137,13 +134,15 @@ namespace Max2Babylon
 
         private void getAlphaMode(BabylonStandardMaterial babylonMaterial, out string alphaMode, out float? alphaCutoff)
         {
-            if (babylonMaterial.diffuseTexture.hasAlpha)
+            if (babylonMaterial.diffuseTexture != null && babylonMaterial.diffuseTexture.hasAlpha)
             {
+                // TODO - Babylon standard material is assumed to useAlphaFromDiffuseTexture. If not, the alpha mode is a mask.
                 alphaMode = GLTFMaterial.AlphaMode.BLEND.ToString();
             }
             else
             {
-                alphaMode = GLTFMaterial.AlphaMode.OPAQUE.ToString();
+                // glTF alpha mode default value is "OPAQUE"
+                alphaMode = null; // GLTFMaterial.AlphaMode.OPAQUE.ToString();
             }
             alphaCutoff = null;
         }

+ 273 - 188
Exporters/3ds Max/Max2Babylon/2017/Exporter/BabylonExporter.GLTFExporter.Mesh.cs

@@ -10,15 +10,15 @@ namespace Max2Babylon
 {
     partial class BabylonExporter
     {
-        private GLTFMesh ExportMesh(BabylonMesh babylonMesh, GLTF gltf, GLTFNode gltfParentNode)
+        private GLTFNode ExportMesh(BabylonMesh babylonMesh, GLTF gltf, GLTFNode gltfParentNode, BabylonScene babylonScene)
         {
-            RaiseMessage("GLTFExporter.Mesh | ExportMesh babylonMesh.name=" + babylonMesh.name, 1);
+            RaiseMessage("GLTFExporter.Mesh | Export mesh named: " + babylonMesh.name, 1);
 
             // --------------------------
             // ---------- Node ----------
             // --------------------------
 
-            RaiseMessage("GLTFExporter.Mesh | Node", 1);
+            RaiseMessage("GLTFExporter.Mesh | Node", 2);
             // Node
             var gltfNode = new GLTFNode();
             gltfNode.name = babylonMesh.name;
@@ -28,19 +28,22 @@ namespace Max2Babylon
             // Hierarchy
             if (gltfParentNode != null)
             {
-                RaiseMessage("GLTFExporter.Mesh | Add " + babylonMesh.name + " as child to " + gltfParentNode.name, 2);
+                RaiseMessage("GLTFExporter.Mesh | Add " + babylonMesh.name + " as child to " + gltfParentNode.name, 3);
                 gltfParentNode.ChildrenList.Add(gltfNode.index);
             }
             else
             {
                 // It's a root node
                 // Only root nodes are listed in a gltf scene
-                RaiseMessage("GLTFExporter.Mesh | Add " + babylonMesh.name + " as root node to scene", 2);
+                RaiseMessage("GLTFExporter.Mesh | Add " + babylonMesh.name + " as root node to scene", 3);
                 gltf.scenes[0].NodesList.Add(gltfNode.index);
             }
 
             // Transform
             gltfNode.translation = babylonMesh.position;
+            // TODO - Choose between this method and the extra root node
+            // Switch from left to right handed coordinate system
+            //gltfNode.translation[0] *= -1;
             if (babylonMesh.rotationQuaternion != null)
             {
                 gltfNode.rotation = babylonMesh.rotationQuaternion;
@@ -48,17 +51,13 @@ namespace Max2Babylon
             else
             {
                 // Convert rotation vector to quaternion
-                // TODO - Fix it
                 BabylonVector3 rotationVector3 = new BabylonVector3
                 {
                     X = babylonMesh.rotation[0],
                     Y = babylonMesh.rotation[1],
                     Z = babylonMesh.rotation[2]
                 };
-                gltfNode.rotation = rotationVector3.toQuaternion().ToArray();
-
-                RaiseMessage("GLTFExporter.Mesh | rotationVector3=[" + rotationVector3.X + "; " + rotationVector3.Y + "; " + rotationVector3.Z + "]", 2);
-                RaiseMessage("GLTFExporter.Mesh | gltfNode.rotation=[" + gltfNode.rotation[0] + "; " + gltfNode.rotation[1] + "; " + gltfNode.rotation[2] + "; " + gltfNode.rotation[3] + "]", 2);
+                gltfNode.rotation = rotationVector3.toQuaternionGltf().ToArray();
             }
             gltfNode.scale = babylonMesh.scaling;
 
@@ -67,64 +66,73 @@ namespace Max2Babylon
             // --- Mesh from babylon ----
             // --------------------------
 
-            RaiseMessage("GLTFExporter.Mesh | Mesh from babylon", 1);
+            if (babylonMesh.positions == null)
+            {
+                RaiseMessage("GLTFExporter.Mesh | Mesh is a dummy", 2);
+                return gltfNode;
+            }
+
+            RaiseMessage("GLTFExporter.Mesh | Mesh from babylon", 2);
             // Retreive general data from babylon mesh
             int nbVertices = babylonMesh.positions.Length / 3;
             bool hasUV = babylonMesh.uvs != null && babylonMesh.uvs.Length > 0;
             bool hasUV2 = babylonMesh.uvs2 != null && babylonMesh.uvs2.Length > 0;
             bool hasColor = babylonMesh.colors != null && babylonMesh.colors.Length > 0;
 
-            RaiseMessage("GLTFExporter.Mesh | nbVertices=" + nbVertices, 2);
-            RaiseMessage("GLTFExporter.Mesh | hasUV=" + hasUV, 2);
-            RaiseMessage("GLTFExporter.Mesh | hasUV2=" + hasUV2, 2);
-            RaiseMessage("GLTFExporter.Mesh | hasColor=" + hasColor, 2);
+            RaiseMessage("GLTFExporter.Mesh | nbVertices=" + nbVertices, 3);
+            RaiseMessage("GLTFExporter.Mesh | hasUV=" + hasUV, 3);
+            RaiseMessage("GLTFExporter.Mesh | hasUV2=" + hasUV2, 3);
+            RaiseMessage("GLTFExporter.Mesh | hasColor=" + hasColor, 3);
 
             // Retreive vertices data from babylon mesh
             List<GLTFGlobalVertex> globalVertices = new List<GLTFGlobalVertex>();
-            for (int i = 0; i < nbVertices; i++)
+            for (int indexVertex = 0; indexVertex < nbVertices; indexVertex++)
             {
                 GLTFGlobalVertex globalVertex = new GLTFGlobalVertex();
-                globalVertex.Position = createIPoint3(babylonMesh.positions, i);
-                globalVertex.Normal = createIPoint3(babylonMesh.normals, i);
+                globalVertex.Position = createIPoint3(babylonMesh.positions, indexVertex);
+                // Switch from left to right handed coordinate system
+                //globalVertex.Position.X *= -1;
+                globalVertex.Normal = createIPoint3(babylonMesh.normals, indexVertex);
                 if (hasUV)
                 {
-                    globalVertex.UV = createIPoint2(babylonMesh.uvs, i);
+                    globalVertex.UV = createIPoint2(babylonMesh.uvs, indexVertex);
                     // For glTF, the origin of the UV coordinates (0, 0) corresponds to the upper left corner of a texture image
                     // While for Babylon, it corresponds to the lower left corner of a texture image
                     globalVertex.UV.Y = 1 - globalVertex.UV.Y;
                 }
                 if (hasUV2)
                 {
-                    globalVertex.UV2 = createIPoint2(babylonMesh.uvs2, i);
+                    globalVertex.UV2 = createIPoint2(babylonMesh.uvs2, indexVertex);
                     // For glTF, the origin of the UV coordinates (0, 0) corresponds to the upper left corner of a texture image
                     // While for Babylon, it corresponds to the lower left corner of a texture image
                     globalVertex.UV2.Y = 1 - globalVertex.UV2.Y;
                 }
                 if (hasColor)
                 {
-                    globalVertex.Color = createIPoint4(babylonMesh.colors, i).ToArray();
+                    globalVertex.Color = createIPoint4(babylonMesh.colors, indexVertex).ToArray();
                 }
 
                 globalVertices.Add(globalVertex);
             }
 
             // Retreive indices from babylon mesh
-            List<ushort> indices = new List<ushort>();
-            indices = babylonMesh.indices.ToList().ConvertAll(new Converter<int, ushort>(n => (ushort)n));
+            List<ushort> babylonIndices = new List<ushort>();
+            babylonIndices = babylonMesh.indices.ToList().ConvertAll(new Converter<int, ushort>(n => (ushort)n));
+            // For triangle primitives in gltf, the front face has a counter-clockwise (CCW) winding order
             // Swap face side
-            for (int i = 0; i < indices.Count; i += 3)
-            { 
-                var tmp = indices[i];
-                indices[i] = indices[i + 2];
-                indices[i+2] = tmp;
-            }
+            //for (int i = 0; i < babylonIndices.Count; i += 3)
+            //{
+            //    var tmp = babylonIndices[i];
+            //    babylonIndices[i] = babylonIndices[i + 2];
+            //    babylonIndices[i + 2] = tmp;
+            //}
 
 
             // --------------------------
             // ------- Init glTF --------
             // --------------------------
 
-            RaiseMessage("GLTFExporter.Mesh | Init glTF", 1);
+            RaiseMessage("GLTFExporter.Mesh | Init glTF", 2);
             // Mesh
             var gltfMesh = new GLTFMesh { name = babylonMesh.name };
             gltfMesh.index = gltf.MeshesList.Count;
@@ -132,15 +140,6 @@ namespace Max2Babylon
             gltfNode.mesh = gltfMesh.index;
             gltfMesh.gltfNode = gltfNode;
 
-            // MeshPrimitive
-            var meshPrimitives = new List<GLTFMeshPrimitive>();
-            var meshPrimitive = new GLTFMeshPrimitive
-            {
-                attributes = new Dictionary<string, int>(),
-                mode = GLTFMeshPrimitive.FillMode.TRIANGLES // TODO reteive info from babylon material
-            };
-            meshPrimitives.Add(meshPrimitive);
-
             // Buffer
             var buffer = new GLTFBuffer
             {
@@ -171,51 +170,8 @@ namespace Max2Babylon
             bufferViewFloatVec3.index = gltf.BufferViewsList.Count;
             gltf.BufferViewsList.Add(bufferViewFloatVec3);
 
-            // Accessor - Indices
-            var accessorIndices = new GLTFAccessor
-            {
-                name = "accessorIndices",
-                bufferView = bufferViewScalar.index,
-                BufferView = bufferViewScalar,
-                componentType = GLTFAccessor.ComponentType.UNSIGNED_SHORT,
-                type = GLTFAccessor.TypeEnum.SCALAR.ToString()
-            };
-            accessorIndices.index = gltf.AccessorsList.Count;
-            gltf.AccessorsList.Add(accessorIndices);
-            meshPrimitive.indices = accessorIndices.index;
-
-            // Accessor - Positions
-            var accessorPositions = new GLTFAccessor
-            {
-                name = "accessorPositions",
-                bufferView = bufferViewFloatVec3.index,
-                BufferView = bufferViewFloatVec3,
-                componentType = GLTFAccessor.ComponentType.FLOAT,
-                type = GLTFAccessor.TypeEnum.VEC3.ToString(),
-                min = new float[] { float.MaxValue, float.MaxValue, float.MaxValue },
-                max = new float[] { float.MinValue, float.MinValue, float.MinValue }
-            };
-            accessorPositions.index = gltf.AccessorsList.Count;
-            gltf.AccessorsList.Add(accessorPositions);
-            meshPrimitive.attributes.Add(GLTFMeshPrimitive.Attribute.POSITION.ToString(), accessorPositions.index);
-
-            // Accessor - Normals
-            var accessorNormals = new GLTFAccessor
-            {
-                name = "accessorNormals",
-                bufferView = bufferViewFloatVec3.index,
-                BufferView = bufferViewFloatVec3,
-                componentType = GLTFAccessor.ComponentType.FLOAT,
-                type = GLTFAccessor.TypeEnum.VEC3.ToString()
-            };
-            accessorNormals.index = gltf.AccessorsList.Count;
-            gltf.AccessorsList.Add(accessorNormals);
-            meshPrimitive.attributes.Add(GLTFMeshPrimitive.Attribute.NORMAL.ToString(), accessorNormals.index);
-
             // BufferView - Vector4
             GLTFBufferView bufferViewFloatVec4 = null;
-            // Accessor - Colors
-            GLTFAccessor accessorColors = null;
             if (hasColor)
             {
                 bufferViewFloatVec4 = new GLTFBufferView
@@ -228,23 +184,11 @@ namespace Max2Babylon
                 };
                 bufferViewFloatVec4.index = gltf.BufferViewsList.Count;
                 gltf.BufferViewsList.Add(bufferViewFloatVec4);
-
-                accessorColors = new GLTFAccessor
-                {
-                    name = "accessorColors",
-                    bufferView = bufferViewFloatVec4.index,
-                    BufferView = bufferViewFloatVec4,
-                    componentType = GLTFAccessor.ComponentType.FLOAT,
-                    type = GLTFAccessor.TypeEnum.VEC4.ToString()
-                };
-                accessorColors.index = gltf.AccessorsList.Count;
-                gltf.AccessorsList.Add(accessorColors);
-                meshPrimitive.attributes.Add(GLTFMeshPrimitive.Attribute.COLOR_0.ToString(), accessorColors.index);
             }
 
             // BufferView - Vector2
             GLTFBufferView bufferViewFloatVec2 = null;
-            if (hasUV ||hasUV2)
+            if (hasUV || hasUV2)
             {
                 bufferViewFloatVec2 = new GLTFBufferView
                 {
@@ -257,142 +201,283 @@ namespace Max2Babylon
                 gltf.BufferViewsList.Add(bufferViewFloatVec2);
             }
 
-            // Accessor - UV
-            GLTFAccessor accessorUVs = null;
-            if (hasUV)
+            // --------------------------
+            // ---- glTF primitives -----
+            // --------------------------
+
+            RaiseMessage("GLTFExporter.Mesh | glTF primitives", 2);
+            var meshPrimitives = new List<GLTFMeshPrimitive>();
+
+            // Global vertices are sorted per submesh
+            var globalVerticesSubMeshes = new List<List<GLTFGlobalVertex>>();
+
+            // In gltf, indices of each mesh primitive are 0-based (ie: min value is 0)
+            // Thus, the gltf indices list is a concatenation of sub lists all 0-based
+            // Example for 2 triangles, each being a submesh:
+            //      babylonIndices = {0,1,2, 3,4,5} gives as result gltfIndicies = {0,1,2, 0,1,2}
+            var gltfIndices = new List<ushort>();
+            
+            foreach (BabylonSubMesh babylonSubMesh in babylonMesh.subMeshes)
             {
-                accessorUVs = new GLTFAccessor
+                // --------------------------
+                // ------ SubMesh data ------
+                // --------------------------
+
+                List<GLTFGlobalVertex> globalVerticesSubMesh = globalVertices.GetRange(babylonSubMesh.verticesStart, babylonSubMesh.verticesCount);
+                globalVerticesSubMeshes.Add(globalVerticesSubMesh);
+
+                List<ushort> _indices = babylonIndices.GetRange(babylonSubMesh.indexStart, babylonSubMesh.indexCount);
+                // Indices of this submesh / primitive are updated to be 0-based
+                var minIndiceValue = _indices.Min(); // Should be equal to babylonSubMesh.indexStart
+                for (int indexIndice = 0; indexIndice < _indices.Count; indexIndice++)
+                {
+                    _indices[indexIndice] -= minIndiceValue;
+                }
+                gltfIndices.AddRange(_indices);
+
+                // --------------------------
+                // -- Init glTF primitive ---
+                // --------------------------
+
+                // MeshPrimitive
+                var meshPrimitive = new GLTFMeshPrimitive
+                {
+                    attributes = new Dictionary<string, int>()
+                };
+                meshPrimitives.Add(meshPrimitive);
+
+                // Accessor - Indices
+                var accessorIndices = new GLTFAccessor
                 {
-                    name = "accessorUVs",
-                    bufferView = bufferViewFloatVec2.index,
-                    BufferView = bufferViewFloatVec2,
+                    name = "accessorIndices",
+                    bufferView = bufferViewScalar.index,
+                    BufferView = bufferViewScalar,
+                    componentType = GLTFAccessor.ComponentType.UNSIGNED_SHORT,
+                    type = GLTFAccessor.TypeEnum.SCALAR.ToString()
+                };
+                accessorIndices.index = gltf.AccessorsList.Count;
+                gltf.AccessorsList.Add(accessorIndices);
+                meshPrimitive.indices = accessorIndices.index;
+
+                // Accessor - Positions
+                var accessorPositions = new GLTFAccessor
+                {
+                    name = "accessorPositions",
+                    bufferView = bufferViewFloatVec3.index,
+                    BufferView = bufferViewFloatVec3,
                     componentType = GLTFAccessor.ComponentType.FLOAT,
-                    type = GLTFAccessor.TypeEnum.VEC2.ToString()
+                    type = GLTFAccessor.TypeEnum.VEC3.ToString(),
+                    min = new float[] { float.MaxValue, float.MaxValue, float.MaxValue },
+                    max = new float[] { float.MinValue, float.MinValue, float.MinValue }
                 };
-                accessorUVs.index = gltf.AccessorsList.Count;
-                gltf.AccessorsList.Add(accessorUVs);
-                meshPrimitive.attributes.Add(GLTFMeshPrimitive.Attribute.TEXCOORD_0.ToString(), accessorUVs.index);
-            }
+                accessorPositions.index = gltf.AccessorsList.Count;
+                gltf.AccessorsList.Add(accessorPositions);
+                meshPrimitive.attributes.Add(GLTFMeshPrimitive.Attribute.POSITION.ToString(), accessorPositions.index);
 
-            // Accessor - UV2
-            GLTFAccessor accessorUV2s = null;
-            if (hasUV2)
-            {
-                accessorUV2s = new GLTFAccessor
+                // Accessor - Normals
+                var accessorNormals = new GLTFAccessor
                 {
-                    name = "accessorUV2s",
-                    bufferView = bufferViewFloatVec2.index,
-                    BufferView = bufferViewFloatVec2,
+                    name = "accessorNormals",
+                    bufferView = bufferViewFloatVec3.index,
+                    BufferView = bufferViewFloatVec3,
                     componentType = GLTFAccessor.ComponentType.FLOAT,
-                    type = GLTFAccessor.TypeEnum.VEC2.ToString()
+                    type = GLTFAccessor.TypeEnum.VEC3.ToString()
                 };
-                accessorUV2s.index = gltf.AccessorsList.Count;
-                gltf.AccessorsList.Add(accessorUV2s);
-                meshPrimitive.attributes.Add(GLTFMeshPrimitive.Attribute.TEXCOORD_1.ToString(), accessorUV2s.index);
-            }
+                accessorNormals.index = gltf.AccessorsList.Count;
+                gltf.AccessorsList.Add(accessorNormals);
+                meshPrimitive.attributes.Add(GLTFMeshPrimitive.Attribute.NORMAL.ToString(), accessorNormals.index);
 
+                // Accessor - Colors
+                GLTFAccessor accessorColors = null;
+                if (hasColor)
+                {
+                    accessorColors = new GLTFAccessor
+                    {
+                        name = "accessorColors",
+                        bufferView = bufferViewFloatVec4.index,
+                        BufferView = bufferViewFloatVec4,
+                        componentType = GLTFAccessor.ComponentType.FLOAT,
+                        type = GLTFAccessor.TypeEnum.VEC4.ToString()
+                    };
+                    accessorColors.index = gltf.AccessorsList.Count;
+                    gltf.AccessorsList.Add(accessorColors);
+                    meshPrimitive.attributes.Add(GLTFMeshPrimitive.Attribute.COLOR_0.ToString(), accessorColors.index);
+                }
 
-            // --------------------------
-            // ------ Mesh as glTF ------
-            // --------------------------
+                // Accessor - UV
+                GLTFAccessor accessorUVs = null;
+                if (hasUV)
+                {
+                    accessorUVs = new GLTFAccessor
+                    {
+                        name = "accessorUVs",
+                        bufferView = bufferViewFloatVec2.index,
+                        BufferView = bufferViewFloatVec2,
+                        componentType = GLTFAccessor.ComponentType.FLOAT,
+                        type = GLTFAccessor.TypeEnum.VEC2.ToString()
+                    };
+                    accessorUVs.index = gltf.AccessorsList.Count;
+                    gltf.AccessorsList.Add(accessorUVs);
+                    meshPrimitive.attributes.Add(GLTFMeshPrimitive.Attribute.TEXCOORD_0.ToString(), accessorUVs.index);
+                }
 
-            RaiseMessage("GLTFExporter.Mesh | Mesh as glTF", 1);
-            // Material
-            //TODO - Handle multimaterials
-            GLTFMaterial gltfMaterial = gltf.MaterialsList.Find(material => material.id == babylonMesh.materialId);
-            if (gltfMaterial != null)
-            {
-                meshPrimitive.material = gltfMaterial.index;
-            }
+                // Accessor - UV2
+                GLTFAccessor accessorUV2s = null;
+                if (hasUV2)
+                {
+                    accessorUV2s = new GLTFAccessor
+                    {
+                        name = "accessorUV2s",
+                        bufferView = bufferViewFloatVec2.index,
+                        BufferView = bufferViewFloatVec2,
+                        componentType = GLTFAccessor.ComponentType.FLOAT,
+                        type = GLTFAccessor.TypeEnum.VEC2.ToString()
+                    };
+                    accessorUV2s.index = gltf.AccessorsList.Count;
+                    gltf.AccessorsList.Add(accessorUV2s);
+                    meshPrimitive.attributes.Add(GLTFMeshPrimitive.Attribute.TEXCOORD_1.ToString(), accessorUV2s.index);
+                }
 
-            // Update min and max vertex position for each component (X, Y, Z)
-            globalVertices.ForEach((globalVertex) =>
-            {
-                var positionArray = new float[] { globalVertex.Position.X, globalVertex.Position.Y, globalVertex.Position.Z };
-                for (int indexComponent = 0; indexComponent < positionArray.Length; indexComponent++)
+                
+                // --------------------------
+                // - Update glTF primitive --
+                // --------------------------
+
+                RaiseMessage("GLTFExporter.Mesh | Mesh as glTF", 3);
+
+                // Material
+                if (babylonMesh.materialId != null)
                 {
-                    if (positionArray[indexComponent] < accessorPositions.min[indexComponent])
+                    // Retreive the babylon material
+                    var babylonMaterialId = babylonMesh.materialId;
+                    var babylonMaterials = new List<BabylonMaterial>(babylonScene.materials);
+                    var babylonMaterial = babylonMaterials.Find(_babylonMaterial => _babylonMaterial.id == babylonMaterialId);
+                    if (babylonMaterial == null)
                     {
-                        accessorPositions.min[indexComponent] = positionArray[indexComponent];
+                        // It's a multi material
+                        var babylonMultiMaterials = new List<BabylonMultiMaterial>(babylonScene.multiMaterials);
+                        var babylonMultiMaterial = babylonMultiMaterials.Find(_babylonMultiMaterial => _babylonMultiMaterial.id == babylonMesh.materialId);
+                        babylonMaterialId = babylonMultiMaterial.materials[babylonSubMesh.materialIndex];
+                        babylonMaterial = babylonMaterials.Find(_babylonMaterial => _babylonMaterial.id == babylonMaterialId);
                     }
-                    if (positionArray[indexComponent] > accessorPositions.max[indexComponent])
+
+                    // Update primitive material index
+                    var indexMaterial = babylonMaterialsToExport.FindIndex(_babylonMaterial => _babylonMaterial == babylonMaterial);
+                    if (indexMaterial == -1)
                     {
-                        accessorPositions.max[indexComponent] = positionArray[indexComponent];
+                        // Store material for exportation
+                        indexMaterial = babylonMaterialsToExport.Count;
+                        babylonMaterialsToExport.Add(babylonMaterial);
                     }
-                }
-            });
+                    meshPrimitive.material = indexMaterial;
 
-            // Update byte length and count of accessors, bufferViews and buffers
-            // Scalar
-            AddElementsToAccessor(accessorIndices, indices.Count);
-            // Vector3
-            bufferViewFloatVec3.byteOffset = buffer.byteLength;
-            AddElementsToAccessor(accessorPositions, globalVertices.Count);
-            AddElementsToAccessor(accessorNormals, globalVertices.Count);
-            // Vector4
-            if (hasColor)
-            {
-                bufferViewFloatVec4.byteOffset = buffer.byteLength;
-                AddElementsToAccessor(accessorColors, globalVertices.Count);
-            }
-            // Vector2
-            if (hasUV || hasUV2)
-            {
-                bufferViewFloatVec2.byteOffset = buffer.byteLength;
+                    // TODO - Add and retreive info from babylon material
+                    meshPrimitive.mode = GLTFMeshPrimitive.FillMode.TRIANGLES;
+                }
 
+                // Update min and max vertex position for each component (X, Y, Z)
+                globalVerticesSubMesh.ForEach((globalVertex) =>
+                {
+                    var positionArray = new float[] { globalVertex.Position.X, globalVertex.Position.Y, globalVertex.Position.Z };
+                    for (int indexComponent = 0; indexComponent < positionArray.Length; indexComponent++)
+                    {
+                        if (positionArray[indexComponent] < accessorPositions.min[indexComponent])
+                        {
+                            accessorPositions.min[indexComponent] = positionArray[indexComponent];
+                        }
+                        if (positionArray[indexComponent] > accessorPositions.max[indexComponent])
+                        {
+                            accessorPositions.max[indexComponent] = positionArray[indexComponent];
+                        }
+                    }
+                });
+
+                // Update byte length and count of accessors, bufferViews and buffers
+                // Scalar
+                AddElementsToAccessor(accessorIndices, _indices.Count);
+                // Vector3
+                AddElementsToAccessor(accessorPositions, globalVerticesSubMesh.Count);
+                AddElementsToAccessor(accessorNormals, globalVerticesSubMesh.Count);
+                // Vector4
+                if (hasColor)
+                {
+                    AddElementsToAccessor(accessorColors, globalVerticesSubMesh.Count);
+                }
+                // Vector2
                 if (hasUV)
                 {
-                    AddElementsToAccessor(accessorUVs, globalVertices.Count);
+                    AddElementsToAccessor(accessorUVs, globalVerticesSubMesh.Count);
                 }
                 if (hasUV2)
                 {
-                    AddElementsToAccessor(accessorUV2s, globalVertices.Count);
+                    AddElementsToAccessor(accessorUV2s, globalVerticesSubMesh.Count);
                 }
             }
+            gltfMesh.primitives = meshPrimitives.ToArray();
+            
+            // Update byte offset of bufferViews
+            GLTFBufferView lastBufferView = null;
+            gltf.BufferViewsList.FindAll(bufferView => bufferView.buffer == buffer.index).ForEach(bufferView =>
+            {
+                if (lastBufferView != null)
+                {
+                    bufferView.byteOffset = lastBufferView.byteOffset + lastBufferView.byteLength;
+                }
+                lastBufferView = bufferView;
+            });
 
 
             // --------------------------
             // --------- Saving ---------
             // --------------------------
 
-            string outputBinaryFile = Path.Combine(gltf.OutputPath,  gltfMesh.name + ".bin");
-            RaiseMessage("GLTFExporter.Mesh | Saving " + outputBinaryFile, 1);
+            string outputBinaryFile = Path.Combine(gltf.OutputPath, gltfMesh.name + ".bin");
+            RaiseMessage("GLTFExporter.Mesh | Saving " + outputBinaryFile, 2);
 
+            // Write data to binary file
             using (BinaryWriter writer = new BinaryWriter(File.Open(outputBinaryFile, FileMode.Create)))
             {
-                // Binary arrays
-                List<float> vertices = globalVertices.SelectMany(v => new[] { v.Position.X, v.Position.Y, v.Position.Z }).ToList();
-                List<float> normals = globalVertices.SelectMany(v => new[] { v.Normal.X, v.Normal.Y, v.Normal.Z }).ToList();
+                // BufferView - Scalar
+                gltfIndices.ForEach(n => writer.Write(n));
 
-                List<float> colors = new List<float>();
-                if (hasColor)
+                // BufferView - Vector3
+                globalVerticesSubMeshes.ForEach(globalVerticesSubMesh =>
                 {
-                    colors = globalVertices.SelectMany(v => new[] { v.Color[0], v.Color[1], v.Color[2], v.Color[3] }).ToList();
-                }
+                    List<float> vertices = globalVerticesSubMesh.SelectMany(v => new[] { v.Position.X, v.Position.Y, v.Position.Z }).ToList();
+                    vertices.ForEach(n => writer.Write(n));
 
-                List<float> uvs = new List<float>();
-                if (hasUV)
-                {
-                    uvs = globalVertices.SelectMany(v => new[] { v.UV.X, v.UV.Y }).ToList(); // No symetry required to perform 3dsMax => gltf conversion
-                }
+                    List<float> normals = globalVerticesSubMesh.SelectMany(v => new[] { v.Normal.X, v.Normal.Y, v.Normal.Z }).ToList();
+                    normals.ForEach(n => writer.Write(n));
+                });
 
-                List<float> uvs2 = new List<float>();
-                if (hasUV2)
+                // BufferView - Vector4
+                globalVerticesSubMeshes.ForEach(globalVerticesSubMesh =>
                 {
-                    uvs2 = globalVertices.SelectMany(v => new[] { v.UV2.X, v.UV2.Y }).ToList(); // No symetry required to perform 3dsMax => gltf conversion
-                }
+                    if (hasColor)
+                    {
+                        List<float> colors = globalVerticesSubMesh.SelectMany(v => new[] { v.Color[0], v.Color[1], v.Color[2], v.Color[3] }).ToList();
+                        colors.ForEach(n => writer.Write(n));
+                    }
+                });
 
-                // Write data to binary file
-                indices.ForEach(n => writer.Write(n));
-                vertices.ForEach(n => writer.Write(n));
-                normals.ForEach(n => writer.Write(n));
-                colors.ForEach(n => writer.Write(n));
-                uvs.ForEach(n => writer.Write(n));
+                // BufferView - Vector2
+                globalVerticesSubMeshes.ForEach(globalVerticesSubMesh =>
+                {
+                    if (hasUV)
+                    {
+                        List<float> uvs = globalVerticesSubMesh.SelectMany(v => new[] { v.UV.X, v.UV.Y }).ToList();
+                        uvs.ForEach(n => writer.Write(n));
+                    }
+                    
+                    if (hasUV2)
+                    {
+                        List<float> uvs2 = globalVerticesSubMesh.SelectMany(v => new[] { v.UV2.X, v.UV2.Y }).ToList();
+                        uvs2.ForEach(n => writer.Write(n));
+                    }
+                });
             }
 
-            gltfMesh.primitives = meshPrimitives.ToArray();
-
-            return gltfMesh;
+            return gltfNode;
         }
 
         private IPoint2 createIPoint2(float[] array, int index)

+ 4 - 4
Exporters/3ds Max/Max2Babylon/2017/Exporter/BabylonExporter.GLTFExporter.Texture.cs

@@ -12,13 +12,13 @@ namespace Max2Babylon
                 return null;
             }
 
-            RaiseMessage("GLTFExporter.Texture | ExportTexture babylonTexture.name=" + babylonTexture.name, 1);
+            RaiseMessage("GLTFExporter.Texture | Export texture named: " + babylonTexture.name, 1);
 
             // --------------------------
             // -------- Sampler ---------
             // --------------------------
 
-            RaiseMessage("GLTFExporter.Texture | create sampler", 1);
+            RaiseMessage("GLTFExporter.Texture | create sampler", 2);
             GLTFSampler gltfSampler = new GLTFSampler();
             gltfSampler.index = gltf.SamplersList.Count;
             gltf.SamplersList.Add(gltfSampler);
@@ -39,7 +39,7 @@ namespace Max2Babylon
             // --------- Image ----------
             // --------------------------
 
-            RaiseMessage("GLTFExporter.Texture | create image", 1);
+            RaiseMessage("GLTFExporter.Texture | create image", 2);
             GLTFImage gltfImage = new GLTFImage
             {
                 uri = babylonTexture.name
@@ -53,7 +53,7 @@ namespace Max2Babylon
             // -------- Texture ---------
             // --------------------------
 
-            RaiseMessage("GLTFExporter.Texture | create texture", 1);
+            RaiseMessage("GLTFExporter.Texture | create texture", 2);
             var gltfTexture = new GLTFTexture
             {
                 name = babylonTexture.name,

+ 93 - 34
Exporters/3ds Max/Max2Babylon/2017/Exporter/BabylonExporter.GLTFExporter.cs

@@ -1,6 +1,7 @@
 using BabylonExport.Entities;
 using GLTFExport.Entities;
 using Newtonsoft.Json;
+using System;
 using System.Collections.Generic;
 using System.Globalization;
 using System.IO;
@@ -11,6 +12,9 @@ namespace Max2Babylon
 {
     internal partial class BabylonExporter
     {
+        List<BabylonMaterial> babylonMaterialsToExport;
+        GLTFNode gltfRootNode;
+
         public void ExportGltf(BabylonScene babylonScene, string outputFile, bool generateBinary)
         {
             RaiseMessage("GLTFExporter | Export outputFile=" + outputFile + " generateBinary=" + generateBinary);
@@ -36,30 +40,16 @@ namespace Max2Babylon
             GLTFScene[] scenes = { scene };
             gltf.scenes = scenes;
 
-            // Materials
-            RaiseMessage("GLTFExporter | Exporting materials");
-            ReportProgressChanged(10);
-            var babylonMaterials = babylonScene.MaterialsList;
-            babylonMaterials.ForEach((babylonMaterial) =>
-            {
-                ExportMaterial(babylonMaterial, gltf);
-                CheckCancelled();
-            });
-            // TODO - Handle multimaterials
-            RaiseMessage(string.Format("GLTFExporter | Total: {0}", gltf.MaterialsList.Count /*+ glTF.MultiMaterialsList.Count*/), Color.Gray, 1);
-
             // Nodes
-            List<BabylonNode> babylonNodes = new List<BabylonNode>();
-            babylonNodes.AddRange(babylonScene.meshes);
-            babylonNodes.AddRange(babylonScene.lights);
-            babylonNodes.AddRange(babylonScene.cameras);
+            List<BabylonNode> babylonNodes = getNodes(babylonScene);
 
             // Root nodes
-            RaiseMessage("GLTFExporter | Exporting root nodes");
+            RaiseMessage("GLTFExporter | Exporting nodes");
             List<BabylonNode> babylonRootNodes = babylonNodes.FindAll(node => node.parentId == null);
             var progressionStep = 80.0f / babylonRootNodes.Count;
-            var progression = 20.0f;
+            var progression = 10.0f;
             ReportProgressChanged((int)progression);
+            babylonMaterialsToExport = new List<BabylonMaterial>();
             babylonRootNodes.ForEach(babylonNode =>
             {
                 exportNodeRec(babylonNode, gltf, babylonScene);
@@ -68,15 +58,39 @@ namespace Max2Babylon
                 CheckCancelled();
             });
 
+            // TODO - Choose between this method and the reverse of X axis
+            // Switch from left to right handed coordinate system
+            var tmpNodesList = new List<int>(scene.NodesList);
+            var rootNode = new BabylonMesh
+            {
+                name = "root",
+                rotation = new float[] { 0, (float)Math.PI, 0 },
+                scaling = new float[] { 1, 1, -1 }
+            };
+            scene.NodesList.Clear();
+            gltfRootNode = ExportMesh(rootNode as BabylonMesh, gltf, null, babylonScene);
+            gltfRootNode.ChildrenList.AddRange(tmpNodesList);
+
+            // Materials
+            RaiseMessage("GLTFExporter | Exporting materials");
+            foreach (var babylonMaterial in babylonMaterialsToExport)
+            {
+                ExportMaterial(babylonMaterial, gltf);
+                CheckCancelled();
+            };
+            RaiseMessage(string.Format("GLTFExporter | Nb materials exported: {0}", gltf.MaterialsList.Count), Color.Gray, 1);
+
             // Output
             RaiseMessage("GLTFExporter | Saving to output file");
             // Cast lists to arrays
             gltf.Prepare();
-            var jsonSerializer = JsonSerializer.Create(new JsonSerializerSettings()); // Standard serializer, not the optimized one
+            var jsonSerializer = JsonSerializer.Create(new JsonSerializerSettings());
             var sb = new StringBuilder();
             var sw = new StringWriter(sb, CultureInfo.InvariantCulture);
 
-            using (var jsonWriter = new JsonTextWriter(sw))
+            // Do not use the optimized writer because it's not necessary to truncate values
+            // Use the bounded writer in case some values are infinity ()
+            using (var jsonWriter = new JsonTextWriterBounded(sw))
             {
                 jsonWriter.Formatting = Formatting.None;
                 jsonSerializer.Serialize(jsonWriter, gltf);
@@ -99,22 +113,25 @@ namespace Max2Babylon
             GLTFNode gltfNode = null; 
             if (babylonNode.GetType() == typeof(BabylonMesh))
             {
-                GLTFMesh gltfMesh = ExportMesh(babylonNode as BabylonMesh, gltf, gltfParentNode);
-                if (gltfMesh != null)
-                {
-                    gltfNode = gltfMesh.gltfNode;
-                }
+                gltfNode = ExportMesh(babylonNode as BabylonMesh, gltf, gltfParentNode, babylonScene);
             }
             else if (babylonNode.GetType() == typeof(BabylonCamera))
             {
-                // TODO - Export camera nodes
-                RaiseError($"TODO - Export camera node named {babylonNode.name}", 1);
+                GLTFCamera gltfCamera = ExportCamera(babylonNode as BabylonCamera, gltf, gltfParentNode);
+                gltfNode = gltfCamera.gltfNode;
             }
             else if (babylonNode.GetType() == typeof(BabylonLight))
             {
-                // TODO - Export light nodes as empty nodes (no lights in glTF 2.0 core)
-                RaiseError($"TODO - Export light node named {babylonNode.name}", 1);
-                RaiseWarning($"GLTFExporter.Node | Light named {babylonNode.name} has children but lights are not exported with glTF 2.0 core version. An empty node is used instead.", 1);
+                if (isNodeRelevantToExport(babylonNode, babylonScene))
+                {
+                    // Export light nodes as empty nodes (no lights in glTF 2.0 core)
+                    RaiseWarning($"GLTFExporter | Light named {babylonNode.name} has children but lights are not exported with glTF 2.0 core version. An empty node is used instead.", 1);
+                    gltfNode = ExportLight(babylonNode as BabylonLight, gltf, gltfParentNode);
+                }
+                else
+                {
+                    RaiseMessage($"GLTFExporter | Light named {babylonNode.name} is not relevant to export", 1);
+                }
             }
             else
             {
@@ -132,14 +149,56 @@ namespace Max2Babylon
             }
         }
 
-        private List<BabylonNode> getDescendants(BabylonNode babylonNode, BabylonScene babylonScene)
+        private List<BabylonNode> getNodes(BabylonScene babylonScene)
         {
             List<BabylonNode> babylonNodes = new List<BabylonNode>();
-            babylonNodes.AddRange(babylonScene.meshes);
-            babylonNodes.AddRange(babylonScene.lights);
-            babylonNodes.AddRange(babylonScene.cameras);
+            if (babylonScene.meshes != null)
+            {
+                babylonNodes.AddRange(babylonScene.meshes);
+            }
+            if (babylonScene.lights != null)
+            {
+                babylonNodes.AddRange(babylonScene.lights);
+            }
+            if (babylonScene.cameras != null)
+            {
+                babylonNodes.AddRange(babylonScene.cameras);
+            }
+            return babylonNodes;
+        }
 
+        private List<BabylonNode> getDescendants(BabylonNode babylonNode, BabylonScene babylonScene)
+        {
+            List<BabylonNode> babylonNodes = getNodes(babylonScene);
             return babylonNodes.FindAll(node => node.parentId == babylonNode.id);
         }
+
+        /// <summary>
+        /// Return true if node descendant hierarchy has any Mesh or Camera to export
+        /// </summary>
+        private bool isNodeRelevantToExport(BabylonNode babylonNode, BabylonScene babylonScene)
+        {
+            var type = babylonNode.GetType();
+            if (type == typeof(BabylonMesh) ||
+                type == typeof(BabylonCamera))
+            {
+                return true;
+            }
+
+            // Descandant recursivity
+            List<BabylonNode> babylonDescendants = getDescendants(babylonNode, babylonScene);
+            int indexDescendant = 0;
+            while (indexDescendant < babylonDescendants.Count) // while instead of for to stop as soon as a relevant node has been found
+            {
+                if (isNodeRelevantToExport(babylonDescendants[indexDescendant], babylonScene))
+                {
+                    return true;
+                }
+                indexDescendant++;
+            }
+
+            // No relevant node found in hierarchy
+            return false;
+        }
     }
 }

+ 42 - 0
Exporters/3ds Max/Max2Babylon/2017/JsonTextWriterBounded.cs

@@ -0,0 +1,42 @@
+using Newtonsoft.Json;
+using System.IO;
+
+namespace Max2Babylon
+{
+    class JsonTextWriterBounded : JsonTextWriter
+    {
+        public JsonTextWriterBounded(TextWriter textWriter)
+            : base(textWriter)
+        {
+        }
+
+        public override void WriteValue(float value)
+        {
+            if (float.IsNegativeInfinity(value))
+            {
+                value = float.MinValue;
+            }
+            else if (float.IsPositiveInfinity(value))
+            {
+                value = float.MaxValue;
+            }
+            base.WriteValue(value);
+        }
+
+        public override void WriteValue(float? value)
+        {
+            if (value.HasValue)
+            {
+                if (float.IsNegativeInfinity(value.Value))
+                {
+                    value = float.MinValue;
+                }
+                else if (float.IsPositiveInfinity(value.Value))
+                {
+                    value = float.MaxValue;
+                }
+            }
+            base.WriteValue(value);
+        }
+    }
+}

+ 3 - 0
Exporters/3ds Max/Max2Babylon/2017/Max2Babylon2017.csproj

@@ -191,11 +191,14 @@
     <Compile Include="..\Tools\WebServer.cs">
       <Link>Tools\WebServer.cs</Link>
     </Compile>
+    <Compile Include="Exporter\BabylonExporter.GLTFExporter.Light.cs" />
     <Compile Include="Exporter\BabylonExporter.GLTFExporter.Material.cs" />
+    <Compile Include="Exporter\BabylonExporter.GLTFExporter.Camera.cs" />
     <Compile Include="Exporter\BabylonExporter.GLTFExporter.Texture.cs" />
     <Compile Include="Exporter\BabylonExporter.GLTFExporter.Mesh.cs" />
     <Compile Include="Exporter\BabylonExporter.GLTFExporter.cs" />
     <Compile Include="Exporter\GLTFGlobalVertex.cs" />
+    <Compile Include="JsonTextWriterBounded.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Properties\Resources.Designer.cs">
       <AutoGen>True</AutoGen>

+ 16 - 6
Exporters/3ds Max/Max2Babylon/2017/Properties/Resources.Designer.cs

@@ -13,13 +13,13 @@ namespace Max2Babylon.Properties {
     
     
     /// <summary>
-    ///   A strongly-typed resource class, for looking up localized strings, etc.
+    ///   Une classe de ressource fortement typée destinée, entre autres, à la consultation des chaînes localisées.
     /// </summary>
-    // This class was auto-generated by the StronglyTypedResourceBuilder
-    // class via a tool like ResGen or Visual Studio.
-    // To add or remove a member, edit your .ResX file then rerun ResGen
-    // with the /str option, or rebuild your VS project.
-    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+    // Cette classe a été générée automatiquement par la classe StronglyTypedResourceBuilder
+    // à l'aide d'un outil, tel que ResGen ou Visual Studio.
+    // Pour ajouter ou supprimer un membre, modifiez votre fichier .ResX, puis réexécutez ResGen
+    // avec l'option /str ou régénérez votre projet VS.
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
     [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
     [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
     internal class Resources {
@@ -59,5 +59,15 @@ namespace Max2Babylon.Properties {
                 resourceCulture = value;
             }
         }
+        
+        /// <summary>
+        ///   Recherche une ressource localisée de type System.Drawing.Bitmap.
+        /// </summary>
+        internal static System.Drawing.Bitmap Logo_Exporter_v3 {
+            get {
+                object obj = ResourceManager.GetObject("Logo_Exporter_v3", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
     }
 }

+ 4 - 0
Exporters/3ds Max/Max2Babylon/2017/Properties/Resources.resx

@@ -117,4 +117,8 @@
   <resheader name="writer">
     <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
   </resheader>
+  <assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
+  <data name="Logo_Exporter_v3" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>..\Resources\Logo_Exporter_v3.jpg;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  </data>
 </root>

BIN
Exporters/3ds Max/Max2Babylon/2017/Resources/Logo_Exporter_v3.jpg


+ 19 - 6
Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Camera.cs

@@ -56,15 +56,28 @@ namespace Max2Babylon
             babylonCamera.applyGravity = cameraNode.MaxNode.GetBoolProperty("babylonjs_applygravity");
             babylonCamera.ellipsoid = cameraNode.MaxNode.GetVector3Property("babylonjs_ellipsoid");
 
-            // Position
-            var wm = cameraNode.GetLocalTM(0);
+            // Position / rotation
+            var localTM = cameraNode.GetObjectTM(0);
             if (cameraNode.NodeParent != null)
             {
                 var parentWorld = cameraNode.NodeParent.GetObjectTM(0);
-                wm.MultiplyBy(parentWorld.Inverse);
+                localTM.MultiplyBy(parentWorld.Inverse);
+            }
+
+            var position = localTM.Translation;
+            var rotation = localTM.Rotation;
+            var exportQuaternions = Loader.Core.RootNode.GetBoolProperty("babylonjs_exportquaternions");
+
+            babylonCamera.position = new[] { position.X, position.Y, position.Z };
+
+            if (exportQuaternions)
+            {
+                babylonCamera.rotationQuaternion = new[] { rotation.X, rotation.Y, rotation.Z, -rotation.W };
+            }
+            else
+            {
+                babylonCamera.rotation = QuaternionToEulerAngles(rotation);
             }
-            var position = wm.Translation;
-            babylonCamera.position = new [] { position.X, position.Y, position.Z };
 
             // Target
             var target = gameCamera.CameraTarget;
@@ -74,7 +87,7 @@ namespace Max2Babylon
             }
             else
             {
-                var dir = wm.GetRow(3);
+                var dir = localTM.GetRow(3);
                 babylonCamera.target = new [] { position.X - dir.X, position.Y - dir.Y, position.Z - dir.Z };
             }
 

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

@@ -84,14 +84,14 @@ namespace Max2Babylon
             return parentId;
         }
 
-        private void RotationToEulerAngles(BabylonAbstractMesh babylonMesh, IQuat rotation)
+        private float[] QuaternionToEulerAngles(IQuat rotation)
         {
             float rotx = 0, roty = 0, rotz = 0;
             unsafe
             {
                 rotation.GetEuler(new IntPtr(&rotx), new IntPtr(&roty), new IntPtr(&rotz));
             }
-            babylonMesh.rotation = new[] { rotx, roty, rotz };
+            return new[] { rotx, roty, rotz };
         }
 
         private int bonesCount;
@@ -226,7 +226,7 @@ namespace Max2Babylon
             }
             else
             {
-                RotationToEulerAngles(babylonMesh, meshRotation);
+                babylonMesh.rotation = QuaternionToEulerAngles(meshRotation);
             }
 
             babylonMesh.scaling = new[] { meshScale.X, meshScale.Y, meshScale.Z };
@@ -487,7 +487,7 @@ namespace Max2Babylon
                     }
                     else
                     {
-                        RotationToEulerAngles(instance, instanceRotation);
+                        instance.rotation = QuaternionToEulerAngles(instanceRotation);
                     }
 
                     instance.scaling = new[] { instanceScale.X, instanceScale.Y, instanceScale.Z };

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

@@ -309,7 +309,7 @@ namespace Max2Babylon
 
             // Output
             RaiseMessage("Saving to output file");
-            babylonScene.Prepare(false);
+            babylonScene.Prepare(false, false);
             var jsonSerializer = JsonSerializer.Create(new JsonSerializerSettings());
             var sb = new StringBuilder();
             var sw = new StringWriter(sb, CultureInfo.InvariantCulture);

+ 2 - 3
Exporters/3ds Max/Max2Babylon/Forms/ExporterForm.Designer.cs

@@ -28,7 +28,6 @@
         /// </summary>
         private void InitializeComponent()
         {
-            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ExporterForm));
             this.butExport = new System.Windows.Forms.Button();
             this.label1 = new System.Windows.Forms.Label();
             this.txtFilename = new System.Windows.Forms.TextBox();
@@ -138,7 +137,7 @@
             // pictureBox2
             // 
             this.pictureBox2.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
-            this.pictureBox2.Image = ((System.Drawing.Image)(resources.GetObject("pictureBox2.Image")));
+            this.pictureBox2.Image = global::Max2Babylon.Properties.Resources.Logo_Exporter_v3;
             this.pictureBox2.Location = new System.Drawing.Point(511, 12);
             this.pictureBox2.Name = "pictureBox2";
             this.pictureBox2.Size = new System.Drawing.Size(300, 130);
@@ -272,7 +271,7 @@
             this.chkGltf.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
             this.chkGltf.Location = new System.Drawing.Point(30, 133);
             this.chkGltf.Name = "chkGltf";
-            this.chkGltf.Size = new System.Drawing.Size(135, 17);
+            this.chkGltf.Size = new System.Drawing.Size(107, 17);
             this.chkGltf.TabIndex = 17;
             this.chkGltf.Text = "Generate glTF file";
             this.chkGltf.UseVisualStyleBackColor = true;

+ 0 - 197
Exporters/3ds Max/Max2Babylon/Forms/ExporterForm.resx

@@ -120,201 +120,4 @@
   <metadata name="saveFileDialog.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
     <value>17, 17</value>
   </metadata>
-  <assembly alias="System.Drawing" name="System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
-  <data name="pictureBox2.Image" type="System.Drawing.Bitmap, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
-    <value>
-        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
-</value>
-  </data>
 </root>

Разлика између датотеке није приказан због своје велике величине
+ 473 - 469
dist/preview release/babylon.d.ts


Разлика између датотеке није приказан због своје велике величине
+ 40 - 40
dist/preview release/babylon.js


+ 73 - 16
dist/preview release/babylon.max.js

@@ -7452,6 +7452,7 @@ var BABYLON;
             // To enable/disable IDB support and avoid XHR on .manifest
             this.enableOfflineSupport = false;
             this.scenes = new Array();
+            this.postProcesses = new Array();
             // Observables
             /**
              * Observable event triggered each time the rendering canvas is resized
@@ -8116,9 +8117,13 @@ var BABYLON;
                 scene._rebuildGeometries();
                 scene._rebuildTextures();
             }
+            for (var _b = 0, _c = this.postProcesses; _b < _c.length; _b++) {
+                var postprocess = _c[_b];
+                postprocess._rebuild();
+            }
             // Uniforms
-            for (var _b = 0, _c = this._uniformBuffers; _b < _c.length; _b++) {
-                var uniformBuffer = _c[_b];
+            for (var _d = 0, _e = this._uniformBuffers; _d < _e.length; _d++) {
+                var uniformBuffer = _e[_d];
                 uniformBuffer._rebuild();
             }
         };
@@ -8644,14 +8649,11 @@ var BABYLON;
         Engine.prototype._getVRDisplays = function () {
             var _this = this;
             var getWebVRDevices = function (devices) {
-                var size = devices.length;
-                var i = 0;
                 _this._vrDisplays = devices.filter(function (device) {
-                    return devices[i] instanceof VRDisplay;
+                    return device instanceof VRDisplay;
                 });
                 return _this._vrDisplays;
             };
-            //using a key due to typescript
             if (navigator.getVRDisplays) {
                 this.vrDisplaysPromise = navigator.getVRDisplays().then(getWebVRDevices);
             }
@@ -10853,6 +10855,10 @@ var BABYLON;
         Engine.prototype.dispose = function () {
             this.hideLoadingUI();
             this.stopRenderLoop();
+            // Release postProcesses
+            while (this.postProcesses.length) {
+                this.postProcesses[0].dispose();
+            }
             // Empty texture
             if (this._emptyTexture) {
                 this._releaseTexture(this._emptyTexture);
@@ -13338,7 +13344,7 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
-        AbstractMesh.prototype.moveWithCollisions = function (velocity) {
+        AbstractMesh.prototype.moveWithCollisions = function (direction) {
             var globalPosition = this.getAbsolutePosition();
             globalPosition.subtractFromFloatsToRef(0, this.ellipsoid.y, 0, this._oldPositionForCollisions);
             this._oldPositionForCollisions.addInPlace(this.ellipsoidOffset);
@@ -13346,7 +13352,7 @@ var BABYLON;
                 this._collider = new BABYLON.Collider();
             }
             this._collider.radius = this.ellipsoid;
-            this.getScene().collisionCoordinator.getNewPosition(this._oldPositionForCollisions, velocity, this._collider, 3, this, this._onCollisionPositionChange, this.uniqueId);
+            this.getScene().collisionCoordinator.getNewPosition(this._oldPositionForCollisions, direction, this._collider, 3, this, this._onCollisionPositionChange, this.uniqueId);
             return this;
         };
         // Submeshes octree
@@ -16471,6 +16477,7 @@ var BABYLON;
             /** Defines the gravity applied to this scene */
             this.gravity = new BABYLON.Vector3(0, -9.807, 0);
             // Postprocesses
+            this.postProcesses = new Array();
             this.postProcessesEnabled = true;
             // Customs render targets
             this.renderTargetsEnabled = true;
@@ -19065,6 +19072,10 @@ var BABYLON;
             while (this.spriteManagers.length) {
                 this.spriteManagers[0].dispose();
             }
+            // Release postProcesses
+            while (this.postProcesses.length) {
+                this.postProcesses[0].dispose();
+            }
             // Release layers
             while (this.layers.length) {
                 this.layers[0].dispose();
@@ -19390,8 +19401,12 @@ var BABYLON;
                 var mesh = _c[_b];
                 mesh._rebuild();
             }
-            for (var _d = 0, _e = this.layers; _d < _e.length; _d++) {
-                var layer = _e[_d];
+            for (var _d = 0, _e = this.postProcesses; _d < _e.length; _d++) {
+                var postprocess = _e[_d];
+                postprocess._rebuild();
+            }
+            for (var _f = 0, _g = this.layers; _f < _g.length; _f++) {
+                var layer = _g[_f];
                 layer._rebuild();
             }
         };
@@ -23979,6 +23994,9 @@ var BABYLON;
             this._currentRank = 32;
             this._maxRank = -1;
         }
+        EffectFallbacks.prototype.unBindMesh = function () {
+            this._mesh = null;
+        };
         EffectFallbacks.prototype.addFallback = function (rank, define) {
             if (!this._defines[rank]) {
                 if (rank < this._currentRank) {
@@ -24415,6 +24433,10 @@ var BABYLON;
                 }
                 this.onCompileObservable.notifyObservers(this);
                 this.onCompileObservable.clear();
+                // Unbind mesh reference in fallbacks
+                if (this._fallbacks) {
+                    this._fallbacks.unBindMesh();
+                }
             }
             catch (e) {
                 this._compilationError = e.message;
@@ -24439,6 +24461,10 @@ var BABYLON;
                     }
                     this.onErrorObservable.notifyObservers(this);
                     this.onErrorObservable.clear();
+                    // Unbind mesh reference in fallbacks
+                    if (this._fallbacks) {
+                        this._fallbacks.unBindMesh();
+                    }
                 }
             }
         };
@@ -34599,7 +34625,7 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
-        FreeCamera.prototype._collideWithWorld = function (velocity) {
+        FreeCamera.prototype._collideWithWorld = function (direction) {
             var globalPosition;
             if (this.parent) {
                 globalPosition = BABYLON.Vector3.TransformCoordinates(this.position, this.parent.getWorldMatrix());
@@ -34614,13 +34640,13 @@ var BABYLON;
             this._collider.radius = this.ellipsoid;
             this._collider.collisionMask = this._collisionMask;
             //no need for clone, as long as gravity is not on.
-            var actualVelocity = velocity;
-            //add gravity to the velocity to prevent the dual-collision checking
+            var actualDirection = direction;
+            //add gravity to the direction to prevent the dual-collision checking
             if (this.applyGravity) {
                 //this prevents mending with cameraDirection, a global variable of the free camera class.
-                actualVelocity = velocity.add(this.getScene().gravity);
+                actualDirection = direction.add(this.getScene().gravity);
             }
-            this.getScene().collisionCoordinator.getNewPosition(this._oldPosition, actualVelocity, this._collider, 3, null, this._onCollisionPositionChange, this.uniqueId);
+            this.getScene().collisionCoordinator.getNewPosition(this._oldPosition, actualDirection, this._collider, 3, null, this._onCollisionPositionChange, this.uniqueId);
         };
         FreeCamera.prototype._checkInputs = function () {
             if (!this._localDirection) {
@@ -46553,9 +46579,11 @@ var BABYLON;
                 this._scene = camera.getScene();
                 camera.attachPostProcess(this);
                 this._engine = this._scene.getEngine();
+                this._scene.postProcesses.push(this);
             }
             else {
                 this._engine = engine;
+                this._engine.postProcesses.push(this);
             }
             this._options = options;
             this.renderTargetSamplingMode = samplingMode ? samplingMode : BABYLON.Texture.NEAREST_SAMPLINGMODE;
@@ -46809,9 +46837,23 @@ var BABYLON;
             }
             this._textures.dispose();
         };
+        PostProcess.prototype._rebuild = function () {
+        };
         PostProcess.prototype.dispose = function (camera) {
             camera = camera || this._camera;
             this._disposeTextures();
+            if (this._scene) {
+                var index_1 = this._scene.postProcesses.indexOf(this);
+                if (index_1 !== -1) {
+                    this._scene.postProcesses.splice(index_1, 1);
+                }
+            }
+            else {
+                var index_2 = this._engine.postProcesses.indexOf(this);
+                if (index_2 !== -1) {
+                    this._engine.postProcesses.splice(index_2, 1);
+                }
+            }
             if (!camera) {
                 return;
             }
@@ -47068,6 +47110,9 @@ var BABYLON;
                 return this.filter === ShadowGenerator.FILTER_POISSONSAMPLING;
             },
             set: function (value) {
+                if (!value && this.filter !== ShadowGenerator.FILTER_POISSONSAMPLING) {
+                    return;
+                }
                 this.filter = (value ? ShadowGenerator.FILTER_POISSONSAMPLING : ShadowGenerator.FILTER_NONE);
             },
             enumerable: true,
@@ -47102,6 +47147,9 @@ var BABYLON;
                 return this.filter === ShadowGenerator.FILTER_EXPONENTIALSHADOWMAP;
             },
             set: function (value) {
+                if (!value && this.filter !== ShadowGenerator.FILTER_EXPONENTIALSHADOWMAP) {
+                    return;
+                }
                 this.filter = (value ? ShadowGenerator.FILTER_EXPONENTIALSHADOWMAP : ShadowGenerator.FILTER_NONE);
             },
             enumerable: true,
@@ -47112,6 +47160,9 @@ var BABYLON;
                 return this.filter === ShadowGenerator.FILTER_BLUREXPONENTIALSHADOWMAP;
             },
             set: function (value) {
+                if (!value && this.filter !== ShadowGenerator.FILTER_BLUREXPONENTIALSHADOWMAP) {
+                    return;
+                }
                 this.filter = (value ? ShadowGenerator.FILTER_BLUREXPONENTIALSHADOWMAP : ShadowGenerator.FILTER_NONE);
             },
             enumerable: true,
@@ -47122,6 +47173,9 @@ var BABYLON;
                 return this.filter === ShadowGenerator.FILTER_CLOSEEXPONENTIALSHADOWMAP;
             },
             set: function (value) {
+                if (!value && this.filter !== ShadowGenerator.FILTER_CLOSEEXPONENTIALSHADOWMAP) {
+                    return;
+                }
                 this.filter = (value ? ShadowGenerator.FILTER_CLOSEEXPONENTIALSHADOWMAP : ShadowGenerator.FILTER_NONE);
             },
             enumerable: true,
@@ -47132,6 +47186,9 @@ var BABYLON;
                 return this.filter === ShadowGenerator.FILTER_BLURCLOSEEXPONENTIALSHADOWMAP;
             },
             set: function (value) {
+                if (!value && this.filter !== ShadowGenerator.FILTER_BLURCLOSEEXPONENTIALSHADOWMAP) {
+                    return;
+                }
                 this.filter = (value ? ShadowGenerator.FILTER_BLURCLOSEEXPONENTIALSHADOWMAP : ShadowGenerator.FILTER_NONE);
             },
             enumerable: true,
@@ -71019,7 +71076,7 @@ var BABYLON;
             });
             this._onAfterCheckInputsObserver = camera.onAfterCheckInputsObservable.add(function () {
                 var now = BABYLON.Tools.Now;
-                var dt = 16;
+                var dt = 0;
                 if (_this._lastFrameTime != null) {
                     dt = now - _this._lastFrameTime;
                 }

Разлика између датотеке није приказан због своје велике величине
+ 473 - 469
dist/preview release/babylon.module.d.ts


Разлика између датотеке није приказан због своје велике величине
+ 40 - 40
dist/preview release/babylon.worker.js


Разлика између датотеке није приказан због своје велике величине
+ 502 - 498
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts


Разлика између датотеке није приказан због своје велике величине
+ 27 - 27
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js


+ 69 - 12
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js

@@ -7452,6 +7452,7 @@ var BABYLON;
             // To enable/disable IDB support and avoid XHR on .manifest
             this.enableOfflineSupport = false;
             this.scenes = new Array();
+            this.postProcesses = new Array();
             // Observables
             /**
              * Observable event triggered each time the rendering canvas is resized
@@ -8116,9 +8117,13 @@ var BABYLON;
                 scene._rebuildGeometries();
                 scene._rebuildTextures();
             }
+            for (var _b = 0, _c = this.postProcesses; _b < _c.length; _b++) {
+                var postprocess = _c[_b];
+                postprocess._rebuild();
+            }
             // Uniforms
-            for (var _b = 0, _c = this._uniformBuffers; _b < _c.length; _b++) {
-                var uniformBuffer = _c[_b];
+            for (var _d = 0, _e = this._uniformBuffers; _d < _e.length; _d++) {
+                var uniformBuffer = _e[_d];
                 uniformBuffer._rebuild();
             }
         };
@@ -8644,14 +8649,11 @@ var BABYLON;
         Engine.prototype._getVRDisplays = function () {
             var _this = this;
             var getWebVRDevices = function (devices) {
-                var size = devices.length;
-                var i = 0;
                 _this._vrDisplays = devices.filter(function (device) {
-                    return devices[i] instanceof VRDisplay;
+                    return device instanceof VRDisplay;
                 });
                 return _this._vrDisplays;
             };
-            //using a key due to typescript
             if (navigator.getVRDisplays) {
                 this.vrDisplaysPromise = navigator.getVRDisplays().then(getWebVRDevices);
             }
@@ -10853,6 +10855,10 @@ var BABYLON;
         Engine.prototype.dispose = function () {
             this.hideLoadingUI();
             this.stopRenderLoop();
+            // Release postProcesses
+            while (this.postProcesses.length) {
+                this.postProcesses[0].dispose();
+            }
             // Empty texture
             if (this._emptyTexture) {
                 this._releaseTexture(this._emptyTexture);
@@ -13338,7 +13344,7 @@ var BABYLON;
             enumerable: true,
             configurable: true
         });
-        AbstractMesh.prototype.moveWithCollisions = function (velocity) {
+        AbstractMesh.prototype.moveWithCollisions = function (direction) {
             var globalPosition = this.getAbsolutePosition();
             globalPosition.subtractFromFloatsToRef(0, this.ellipsoid.y, 0, this._oldPositionForCollisions);
             this._oldPositionForCollisions.addInPlace(this.ellipsoidOffset);
@@ -13346,7 +13352,7 @@ var BABYLON;
                 this._collider = new BABYLON.Collider();
             }
             this._collider.radius = this.ellipsoid;
-            this.getScene().collisionCoordinator.getNewPosition(this._oldPositionForCollisions, velocity, this._collider, 3, this, this._onCollisionPositionChange, this.uniqueId);
+            this.getScene().collisionCoordinator.getNewPosition(this._oldPositionForCollisions, direction, this._collider, 3, this, this._onCollisionPositionChange, this.uniqueId);
             return this;
         };
         // Submeshes octree
@@ -16471,6 +16477,7 @@ var BABYLON;
             /** Defines the gravity applied to this scene */
             this.gravity = new BABYLON.Vector3(0, -9.807, 0);
             // Postprocesses
+            this.postProcesses = new Array();
             this.postProcessesEnabled = true;
             // Customs render targets
             this.renderTargetsEnabled = true;
@@ -19065,6 +19072,10 @@ var BABYLON;
             while (this.spriteManagers.length) {
                 this.spriteManagers[0].dispose();
             }
+            // Release postProcesses
+            while (this.postProcesses.length) {
+                this.postProcesses[0].dispose();
+            }
             // Release layers
             while (this.layers.length) {
                 this.layers[0].dispose();
@@ -19390,8 +19401,12 @@ var BABYLON;
                 var mesh = _c[_b];
                 mesh._rebuild();
             }
-            for (var _d = 0, _e = this.layers; _d < _e.length; _d++) {
-                var layer = _e[_d];
+            for (var _d = 0, _e = this.postProcesses; _d < _e.length; _d++) {
+                var postprocess = _e[_d];
+                postprocess._rebuild();
+            }
+            for (var _f = 0, _g = this.layers; _f < _g.length; _f++) {
+                var layer = _g[_f];
                 layer._rebuild();
             }
         };
@@ -23979,6 +23994,9 @@ var BABYLON;
             this._currentRank = 32;
             this._maxRank = -1;
         }
+        EffectFallbacks.prototype.unBindMesh = function () {
+            this._mesh = null;
+        };
         EffectFallbacks.prototype.addFallback = function (rank, define) {
             if (!this._defines[rank]) {
                 if (rank < this._currentRank) {
@@ -24415,6 +24433,10 @@ var BABYLON;
                 }
                 this.onCompileObservable.notifyObservers(this);
                 this.onCompileObservable.clear();
+                // Unbind mesh reference in fallbacks
+                if (this._fallbacks) {
+                    this._fallbacks.unBindMesh();
+                }
             }
             catch (e) {
                 this._compilationError = e.message;
@@ -24439,6 +24461,10 @@ var BABYLON;
                     }
                     this.onErrorObservable.notifyObservers(this);
                     this.onErrorObservable.clear();
+                    // Unbind mesh reference in fallbacks
+                    if (this._fallbacks) {
+                        this._fallbacks.unBindMesh();
+                    }
                 }
             }
         };
@@ -34971,9 +34997,11 @@ var BABYLON;
                 this._scene = camera.getScene();
                 camera.attachPostProcess(this);
                 this._engine = this._scene.getEngine();
+                this._scene.postProcesses.push(this);
             }
             else {
                 this._engine = engine;
+                this._engine.postProcesses.push(this);
             }
             this._options = options;
             this.renderTargetSamplingMode = samplingMode ? samplingMode : BABYLON.Texture.NEAREST_SAMPLINGMODE;
@@ -35227,9 +35255,23 @@ var BABYLON;
             }
             this._textures.dispose();
         };
+        PostProcess.prototype._rebuild = function () {
+        };
         PostProcess.prototype.dispose = function (camera) {
             camera = camera || this._camera;
             this._disposeTextures();
+            if (this._scene) {
+                var index_1 = this._scene.postProcesses.indexOf(this);
+                if (index_1 !== -1) {
+                    this._scene.postProcesses.splice(index_1, 1);
+                }
+            }
+            else {
+                var index_2 = this._engine.postProcesses.indexOf(this);
+                if (index_2 !== -1) {
+                    this._engine.postProcesses.splice(index_2, 1);
+                }
+            }
             if (!camera) {
                 return;
             }
@@ -35486,6 +35528,9 @@ var BABYLON;
                 return this.filter === ShadowGenerator.FILTER_POISSONSAMPLING;
             },
             set: function (value) {
+                if (!value && this.filter !== ShadowGenerator.FILTER_POISSONSAMPLING) {
+                    return;
+                }
                 this.filter = (value ? ShadowGenerator.FILTER_POISSONSAMPLING : ShadowGenerator.FILTER_NONE);
             },
             enumerable: true,
@@ -35520,6 +35565,9 @@ var BABYLON;
                 return this.filter === ShadowGenerator.FILTER_EXPONENTIALSHADOWMAP;
             },
             set: function (value) {
+                if (!value && this.filter !== ShadowGenerator.FILTER_EXPONENTIALSHADOWMAP) {
+                    return;
+                }
                 this.filter = (value ? ShadowGenerator.FILTER_EXPONENTIALSHADOWMAP : ShadowGenerator.FILTER_NONE);
             },
             enumerable: true,
@@ -35530,6 +35578,9 @@ var BABYLON;
                 return this.filter === ShadowGenerator.FILTER_BLUREXPONENTIALSHADOWMAP;
             },
             set: function (value) {
+                if (!value && this.filter !== ShadowGenerator.FILTER_BLUREXPONENTIALSHADOWMAP) {
+                    return;
+                }
                 this.filter = (value ? ShadowGenerator.FILTER_BLUREXPONENTIALSHADOWMAP : ShadowGenerator.FILTER_NONE);
             },
             enumerable: true,
@@ -35540,6 +35591,9 @@ var BABYLON;
                 return this.filter === ShadowGenerator.FILTER_CLOSEEXPONENTIALSHADOWMAP;
             },
             set: function (value) {
+                if (!value && this.filter !== ShadowGenerator.FILTER_CLOSEEXPONENTIALSHADOWMAP) {
+                    return;
+                }
                 this.filter = (value ? ShadowGenerator.FILTER_CLOSEEXPONENTIALSHADOWMAP : ShadowGenerator.FILTER_NONE);
             },
             enumerable: true,
@@ -35550,6 +35604,9 @@ var BABYLON;
                 return this.filter === ShadowGenerator.FILTER_BLURCLOSEEXPONENTIALSHADOWMAP;
             },
             set: function (value) {
+                if (!value && this.filter !== ShadowGenerator.FILTER_BLURCLOSEEXPONENTIALSHADOWMAP) {
+                    return;
+                }
                 this.filter = (value ? ShadowGenerator.FILTER_BLURCLOSEEXPONENTIALSHADOWMAP : ShadowGenerator.FILTER_NONE);
             },
             enumerable: true,
@@ -50935,7 +50992,7 @@ var BABYLON;
             });
             this._onAfterCheckInputsObserver = camera.onAfterCheckInputsObservable.add(function () {
                 var now = BABYLON.Tools.Now;
-                var dt = 16;
+                var dt = 0;
                 if (_this._lastFrameTime != null) {
                     dt = now - _this._lastFrameTime;
                 }
@@ -54784,7 +54841,7 @@ var BABYLON;
                 if (material.normalTexture) {
                     babylonMaterial.bumpTexture = this.loadTexture(material.normalTexture);
                     babylonMaterial.invertNormalMapX = true;
-                    babylonMaterial.invertNormalMapY = true;
+                    babylonMaterial.invertNormalMapY = false;
                     if (material.normalTexture.scale !== undefined) {
                         babylonMaterial.bumpTexture.level = material.normalTexture.scale;
                     }

Разлика између датотеке није приказан због своје велике величине
+ 502 - 498
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.module.d.ts


+ 2 - 1
dist/preview release/gui/babylon.gui.js

@@ -238,6 +238,7 @@ var BABYLON;
                 }
                 // Render
                 context.font = "18px Arial";
+                context.strokeStyle = "white";
                 var measure = new GUI.Measure(0, 0, renderWidth, renderHeight);
                 this._rootContainer._draw(measure, context);
             };
@@ -663,7 +664,7 @@ var BABYLON;
                 this._fontSize = new GUI.ValueAndUnit(18, GUI.ValueAndUnit.UNITMODE_PIXEL, false);
                 this._width = new GUI.ValueAndUnit(1, GUI.ValueAndUnit.UNITMODE_PERCENTAGE, false);
                 this._height = new GUI.ValueAndUnit(1, GUI.ValueAndUnit.UNITMODE_PERCENTAGE, false);
-                this._color = "white";
+                this._color = "";
                 this._horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_CENTER;
                 this._verticalAlignment = Control.VERTICAL_ALIGNMENT_CENTER;
                 this._isDirty = true;

Разлика између датотеке није приказан због своје велике величине
+ 3 - 3
dist/preview release/gui/babylon.gui.min.js


+ 1 - 1
dist/preview release/loaders/babylon.glTF2FileLoader.js

@@ -1182,7 +1182,7 @@ var BABYLON;
                 if (material.normalTexture) {
                     babylonMaterial.bumpTexture = this.loadTexture(material.normalTexture);
                     babylonMaterial.invertNormalMapX = true;
-                    babylonMaterial.invertNormalMapY = true;
+                    babylonMaterial.invertNormalMapY = false;
                     if (material.normalTexture.scale !== undefined) {
                         babylonMaterial.bumpTexture.level = material.normalTexture.scale;
                     }

Разлика између датотеке није приказан због своје велике величине
+ 1 - 1
dist/preview release/loaders/babylon.glTF2FileLoader.min.js


+ 1 - 1
dist/preview release/loaders/babylon.glTFFileLoader.js

@@ -3340,7 +3340,7 @@ var BABYLON;
                 if (material.normalTexture) {
                     babylonMaterial.bumpTexture = this.loadTexture(material.normalTexture);
                     babylonMaterial.invertNormalMapX = true;
-                    babylonMaterial.invertNormalMapY = true;
+                    babylonMaterial.invertNormalMapY = false;
                     if (material.normalTexture.scale !== undefined) {
                         babylonMaterial.bumpTexture.level = material.normalTexture.scale;
                     }

Разлика између датотеке није приказан због своје велике величине
+ 1 - 1
dist/preview release/loaders/babylon.glTFFileLoader.min.js


+ 1 - 0
gui/src/advancedDynamicTexture.ts

@@ -256,6 +256,7 @@ module BABYLON.GUI {
 
             // Render
             context.font = "18px Arial";
+            context.strokeStyle = "white";
             var measure = new Measure(0, 0, renderWidth, renderHeight);
             this._rootContainer._draw(measure, context);
         }

+ 1 - 1
gui/src/controls/control.ts

@@ -15,7 +15,7 @@ module BABYLON.GUI {
         public _height = new ValueAndUnit(1, ValueAndUnit.UNITMODE_PERCENTAGE, false);
         private _lastMeasuredFont: string;
         protected _fontOffset: {ascent: number, height: number, descent: number};
-        private _color = "white";
+        private _color = "";
         protected _horizontalAlignment = Control.HORIZONTAL_ALIGNMENT_CENTER;
         protected _verticalAlignment = Control.VERTICAL_ALIGNMENT_CENTER;
         private _isDirty = true;

+ 1 - 1
loaders/src/glTF/2.0/babylon.glTFLoader.ts

@@ -996,7 +996,7 @@ module BABYLON.GLTF2 {
             if (material.normalTexture) {
                 babylonMaterial.bumpTexture = this.loadTexture(material.normalTexture);
                 babylonMaterial.invertNormalMapX = true;
-                babylonMaterial.invertNormalMapY = true;
+                babylonMaterial.invertNormalMapY = false;
                 if (material.normalTexture.scale !== undefined) {
                     babylonMaterial.bumpTexture.level = material.normalTexture.scale;
                 }

+ 1 - 1
src/Behaviors/Cameras/babylon.autoRotationBehavior.ts

@@ -98,7 +98,7 @@ module BABYLON {
 
             this._onAfterCheckInputsObserver = camera.onAfterCheckInputsObservable.add(() => {      
                 let now = Tools.Now;
-                let dt = 16;
+                let dt = 0;
                 if (this._lastFrameTime != null) {
                     dt =  now - this._lastFrameTime;
                 }

+ 5 - 5
src/Cameras/babylon.freeCamera.ts

@@ -114,7 +114,7 @@
             this._collisionMask = !isNaN(mask) ? mask : -1;
         }
 	 
-        public _collideWithWorld(velocity: Vector3): void {
+        public _collideWithWorld(direction: Vector3): void {
             var globalPosition: Vector3;
 
             if (this.parent) {
@@ -133,15 +133,15 @@
             this._collider.collisionMask = this._collisionMask;
 		
             //no need for clone, as long as gravity is not on.
-            var actualVelocity = velocity;
+            var actualDirection = direction;
 			
-            //add gravity to the velocity to prevent the dual-collision checking
+            //add gravity to the direction to prevent the dual-collision checking
             if (this.applyGravity) {
                 //this prevents mending with cameraDirection, a global variable of the free camera class.
-                actualVelocity = velocity.add(this.getScene().gravity);
+                actualDirection = direction.add(this.getScene().gravity);
             }
 
-            this.getScene().collisionCoordinator.getNewPosition(this._oldPosition, actualVelocity, this._collider, 3, null, this._onCollisionPositionChange, this.uniqueId);
+            this.getScene().collisionCoordinator.getNewPosition(this._oldPosition, actualDirection, this._collider, 3, null, this._onCollisionPositionChange, this.uniqueId);
 
         }
 

+ 16 - 0
src/Lights/Shadows/babylon.shadowGenerator.ts

@@ -154,6 +154,10 @@
         }
 
         public set usePoissonSampling(value: boolean) {
+            if (!value && this.filter!== ShadowGenerator.FILTER_POISSONSAMPLING) {
+                return;
+            }    
+
             this.filter = (value ? ShadowGenerator.FILTER_POISSONSAMPLING : ShadowGenerator.FILTER_NONE);
         }
 
@@ -179,6 +183,9 @@
             return this.filter === ShadowGenerator.FILTER_EXPONENTIALSHADOWMAP;
         }
         public set useExponentialShadowMap(value: boolean) {
+            if (!value && this.filter!== ShadowGenerator.FILTER_EXPONENTIALSHADOWMAP) {
+                return;
+            }
             this.filter = (value ? ShadowGenerator.FILTER_EXPONENTIALSHADOWMAP : ShadowGenerator.FILTER_NONE);
         }
 
@@ -186,6 +193,9 @@
             return this.filter === ShadowGenerator.FILTER_BLUREXPONENTIALSHADOWMAP;
         }
         public set useBlurExponentialShadowMap(value: boolean) {
+            if (!value && this.filter!== ShadowGenerator.FILTER_BLUREXPONENTIALSHADOWMAP) {
+                return;
+            }            
             this.filter = (value ? ShadowGenerator.FILTER_BLUREXPONENTIALSHADOWMAP : ShadowGenerator.FILTER_NONE);
         }
 
@@ -193,6 +203,9 @@
             return this.filter === ShadowGenerator.FILTER_CLOSEEXPONENTIALSHADOWMAP;
         }
         public set useCloseExponentialShadowMap(value: boolean) {
+            if (!value && this.filter!== ShadowGenerator.FILTER_CLOSEEXPONENTIALSHADOWMAP) {
+                return;
+            }                   
             this.filter = (value ? ShadowGenerator.FILTER_CLOSEEXPONENTIALSHADOWMAP : ShadowGenerator.FILTER_NONE);
         }
 
@@ -200,6 +213,9 @@
             return this.filter === ShadowGenerator.FILTER_BLURCLOSEEXPONENTIALSHADOWMAP;
         }
         public set useBlurCloseExponentialShadowMap(value: boolean) {
+            if (!value && this.filter!== ShadowGenerator.FILTER_BLURCLOSEEXPONENTIALSHADOWMAP) {
+                return;
+            }                  
             this.filter = (value ? ShadowGenerator.FILTER_BLURCLOSEEXPONENTIALSHADOWMAP : ShadowGenerator.FILTER_NONE);
         }
 

+ 14 - 0
src/Materials/babylon.effect.ts

@@ -8,6 +8,10 @@
         private _mesh: AbstractMesh;
         private _meshRank: number;
 
+        public unBindMesh() {
+            this._mesh = null;
+        }
+
         public addFallback(rank: number, define: string): void {
             if (!this._defines[rank]) {
                 if (rank < this._currentRank) {
@@ -539,6 +543,11 @@
                 }
                 this.onCompileObservable.notifyObservers(this);
                 this.onCompileObservable.clear();
+
+                // Unbind mesh reference in fallbacks
+                if (this._fallbacks) {
+                    this._fallbacks.unBindMesh();
+                }
             } catch (e) {
                 this._compilationError = e.message;
 
@@ -564,6 +573,11 @@
                     }
                     this.onErrorObservable.notifyObservers(this);
                     this.onErrorObservable.clear();
+
+                    // Unbind mesh reference in fallbacks
+                    if (this._fallbacks) {
+                        this._fallbacks.unBindMesh();
+                    }
                 }
             }            
         }

+ 2 - 2
src/Mesh/babylon.abstractMesh.ts

@@ -1529,7 +1529,7 @@
             }
         }
 
-        public moveWithCollisions(velocity: Vector3): AbstractMesh {
+        public moveWithCollisions(direction: Vector3): AbstractMesh {
             var globalPosition = this.getAbsolutePosition();
 
             globalPosition.subtractFromFloatsToRef(0, this.ellipsoid.y, 0, this._oldPositionForCollisions);
@@ -1541,7 +1541,7 @@
 
             this._collider.radius = this.ellipsoid;
 
-            this.getScene().collisionCoordinator.getNewPosition(this._oldPositionForCollisions, velocity, this._collider, 3, this, this._onCollisionPositionChange, this.uniqueId);
+            this.getScene().collisionCoordinator.getNewPosition(this._oldPositionForCollisions, direction, this._collider, 3, this, this._onCollisionPositionChange, this.uniqueId);
             return this;
         }
 

+ 19 - 0
src/PostProcess/babylon.postProcess.ts

@@ -142,9 +142,12 @@
                 this._scene = camera.getScene();
                 camera.attachPostProcess(this);
                 this._engine = this._scene.getEngine();
+
+                this._scene.postProcesses.push(this);
             }
             else {
                 this._engine = engine;
+                this._engine.postProcesses.push(this);
             }
 
             this._options = options;
@@ -366,11 +369,27 @@
             this._textures.dispose();
         }
 
+        public _rebuild(): void {
+            
+        }
+
         public dispose(camera?: Camera): void {
             camera = camera || this._camera;            
 
             this._disposeTextures();
 
+            if (this._scene) {
+                let index = this._scene.postProcesses.indexOf(this);
+                if (index !== -1) {
+                    this._scene.postProcesses.splice(index, 1);
+                }                
+            } else {
+                let index = this._engine.postProcesses.indexOf(this);
+                if (index !== -1) {
+                    this._engine.postProcesses.splice(index, 1);
+                }         
+            }
+
             if (!camera) {
                 return;
             }

+ 24 - 17
src/babylon.engine.ts

@@ -529,6 +529,7 @@
         // To enable/disable IDB support and avoid XHR on .manifest
         public enableOfflineSupport = false;
         public scenes = new Array<Scene>();
+        public postProcesses = new Array<PostProcess>();
 
         // Observables
 
@@ -584,7 +585,7 @@
         private _onFocus: () => void;
         private _onFullscreenChange: () => void;
         private _onPointerLockChange: () => void;
-        
+
         private _onVRDisplayPointerRestricted: () => void;
         private _onVRDisplayPointerUnrestricted: () => void;
 
@@ -827,26 +828,26 @@
 
                     // Rebuild buffers
                     this._rebuildBuffers();
-                    
+
                     // Cache
                     this.wipeCaches(true);
 
                     Tools.Warn("WebGL context successfully restored.");
-                
+
                     this._contextWasLost = false;
                 };
 
                 canvas.addEventListener("webglcontextlost", this._onContextLost, false);
                 canvas.addEventListener("webglcontextrestored", this._onContextRestored, false);
             }
-            
+
             // Viewport
             var limitDeviceRatio = options.limitDeviceRatio || window.devicePixelRatio || 1.0;
             this._hardwareScalingLevel = adaptToDeviceRatio ? 1.0 / Math.min(limitDeviceRatio, window.devicePixelRatio || 1.0) : 1.0;
             this.resize();
 
             this._isStencilEnable = options.stencil;
-            this._initGLContext();            
+            this._initGLContext();
 
             if (canvas) {
                 // Fullscreen
@@ -902,7 +903,7 @@
                 }
 
                 window.addEventListener('vrdisplaypointerrestricted', this._onVRDisplayPointerRestricted, false);
-                window.addEventListener('vrdisplaypointerunrestricted', this._onVRDisplayPointerUnrestricted, false);  
+                window.addEventListener('vrdisplaypointerunrestricted', this._onVRDisplayPointerUnrestricted, false);
             }
 
             if (options.audioEngine && AudioEngine && !Engine.audioEngine) {
@@ -956,13 +957,17 @@
                 scene._rebuildTextures();
             }
 
+            for (var postprocess of this.postProcesses) {
+                postprocess._rebuild();
+            }
+
             // Uniforms
             for (var uniformBuffer of this._uniformBuffers) {
                 uniformBuffer._rebuild();
             }
         }
 
-        private _initGLContext(): void {            
+        private _initGLContext(): void {
             // Caps
             this._caps = new EngineCapabilities();
             this._caps.maxTexturesImageUnits = this._gl.getParameter(this._gl.MAX_TEXTURE_IMAGE_UNITS);
@@ -1576,17 +1581,14 @@
 
         private _getVRDisplays() {
             var getWebVRDevices = (devices: Array<any>) => {
-                var size = devices.length;
-                var i = 0;
 
                 this._vrDisplays = devices.filter(function (device) {
-                    return devices[i] instanceof VRDisplay;
+                    return device instanceof VRDisplay;
                 });
 
                 return this._vrDisplays;
             }
 
-            //using a key due to typescript
             if (navigator.getVRDisplays) {
                 this.vrDisplaysPromise = navigator.getVRDisplays().then(getWebVRDevices);
             }
@@ -2785,10 +2787,10 @@
                     if (buffer instanceof HTMLImageElement) {
                         onload(buffer);
                     } else {
-                        Tools.LoadImage(url, onload, onerror, scene ? scene.database: null);
+                        Tools.LoadImage(url, onload, onerror, scene ? scene.database : null);
                     }
                 else if (buffer instanceof Array || typeof buffer === "string")
-                    Tools.LoadImage(buffer, onload, onerror, scene ? scene.database: null);
+                    Tools.LoadImage(buffer, onload, onerror, scene ? scene.database : null);
                 else
                     onload(buffer);
             }
@@ -2895,7 +2897,7 @@
             texture.samplingMode = samplingMode;
             texture.invertY = invertY;
             texture._compression = compression;
-            
+
             if (!this._doNotHandleContextLost) {
                 texture._bufferView = data;
             }
@@ -3042,7 +3044,7 @@
                 fullOptions.generateMipMaps = options.generateMipMaps;
                 fullOptions.generateDepthBuffer = options.generateDepthBuffer === undefined ? true : options.generateDepthBuffer;
                 fullOptions.generateStencilBuffer = fullOptions.generateDepthBuffer && options.generateStencilBuffer;
-                fullOptions.type = options.type === undefined ? Engine.TEXTURETYPE_UNSIGNED_INT : options.type ;
+                fullOptions.type = options.type === undefined ? Engine.TEXTURETYPE_UNSIGNED_INT : options.type;
                 fullOptions.samplingMode = options.samplingMode === undefined ? Texture.TRILINEAR_SAMPLINGMODE : options.samplingMode;
             } else {
                 fullOptions.generateMipMaps = <boolean>options;
@@ -4250,6 +4252,11 @@
 
             this.stopRenderLoop();
 
+            // Release postProcesses
+            while (this.postProcesses.length) {
+                this.postProcesses[0].dispose();
+            }
+
             // Empty texture
             if (this._emptyTexture) {
                 this._releaseTexture(this._emptyTexture);
@@ -4294,12 +4301,12 @@
             window.removeEventListener("blur", this._onBlur);
             window.removeEventListener("focus", this._onFocus);
             window.removeEventListener('vrdisplaypointerrestricted', this._onVRDisplayPointerRestricted);
-            window.removeEventListener('vrdisplaypointerunrestricted', this._onVRDisplayPointerUnrestricted);              
+            window.removeEventListener('vrdisplaypointerunrestricted', this._onVRDisplayPointerUnrestricted);
             this._renderingCanvas.removeEventListener("pointerout", this._onCanvasBlur);
 
             if (!this._doNotHandleContextLost) {
                 this._renderingCanvas.removeEventListener("webglcontextlost", this._onContextLost);
-                this._renderingCanvas.removeEventListener("webglcontextrestored", this._onContextRestored);            
+                this._renderingCanvas.removeEventListener("webglcontextrestored", this._onContextRestored);
             }
             document.removeEventListener("fullscreenchange", this._onFullscreenChange);
             document.removeEventListener("mozfullscreenchange", this._onFullscreenChange);

+ 10 - 0
src/babylon.scene.ts

@@ -694,6 +694,7 @@
         public gravity = new Vector3(0, -9.807, 0);
 
         // Postprocesses
+        public postProcesses = new Array<PostProcess>();
         public postProcessesEnabled = true;
         public postProcessManager: PostProcessManager;
         private _postProcessRenderPipelineManager: PostProcessRenderPipelineManager
@@ -3449,6 +3450,11 @@
                 this.spriteManagers[0].dispose();
             }
 
+            // Release postProcesses
+            while (this.postProcesses.length) {
+                this.postProcesses[0].dispose();
+            }
+
             // Release layers
             while (this.layers.length) {
                 this.layers[0].dispose();
@@ -3840,6 +3846,10 @@
                 mesh._rebuild();
             }
 
+            for (var postprocess of this.postProcesses) {
+                postprocess._rebuild();
+            }            
+
             for (var layer of this.layers) {
                 layer._rebuild();
             }