Przeglądaj źródła

Merge branch 'master' of https://github.com/BabylonJS/Babylon.js

David Rousset 8 lat temu
rodzic
commit
bb3505e86b
36 zmienionych plików z 18389 dodań i 17100 usunięć
  1. 1 0
      Exporters/3ds Max/BabylonExport.Entities/BabylonExport.Entities.csproj
  2. 76 0
      Exporters/3ds Max/BabylonExport.Entities/BabylonPBRMetallicRoughnessMaterial.cs
  3. 12 2
      Exporters/3ds Max/GltfExport.Entities/GLTF.cs
  4. 4 1
      Exporters/3ds Max/GltfExport.Entities/GLTFBuffer.cs
  5. 3 1
      Exporters/3ds Max/GltfExport.Entities/GLTFBufferView.cs
  6. 2 0
      Exporters/3ds Max/GltfExport.Entities/GLTFImage.cs
  7. BIN
      Exporters/3ds Max/Max2Babylon-0.15.0.zip
  8. BIN
      Exporters/3ds Max/Max2Babylon-0.16.0.zip
  9. 177 22
      Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.GLTFExporter.Material.cs
  10. 103 75
      Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.GLTFExporter.Mesh.cs
  11. 12 2
      Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.GLTFExporter.Texture.cs
  12. 167 16
      Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.GLTFExporter.cs
  13. 173 18
      Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Material.cs
  14. 324 82
      Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Texture.cs
  15. 2 11
      Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.cs
  16. 15 0
      Exporters/3ds Max/Max2Babylon/Forms/ExporterForm.Designer.cs
  17. 8 1
      Exporters/3ds Max/Max2Babylon/Forms/ExporterForm.cs
  18. 47 116
      Exporters/3ds Max/Max2Babylon/Tools/Tools.cs
  19. 2 2
      Playground/frame.html
  20. 0 1
      Playground/js/frame.js
  21. 7880 7860
      dist/preview release/babylon.d.ts
  22. 21 21
      dist/preview release/babylon.js
  23. 162 32
      dist/preview release/babylon.max.js
  24. 7880 7860
      dist/preview release/babylon.module.d.ts
  25. 21 21
      dist/preview release/babylon.worker.js
  26. 449 429
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts
  27. 23 23
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js
  28. 162 32
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js
  29. 449 429
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.module.d.ts
  30. 1 0
      dist/preview release/what's new.md
  31. 2 2
      package.json
  32. 2 3
      src/Mesh/babylon.meshBuilder.ts
  33. 55 0
      src/Particles/babylon.particle.ts
  34. 128 21
      src/Particles/babylon.particleSystem.ts
  35. 13 16
      src/Particles/babylon.solidParticleSystem.ts
  36. 13 1
      src/Shaders/particles.vertex.fx

+ 1 - 0
Exporters/3ds Max/BabylonExport.Entities/BabylonExport.Entities.csproj

@@ -56,6 +56,7 @@
   <ItemGroup>
     <Compile Include="BabylonActions.cs" />
     <Compile Include="BabylonAnimation.cs" />
+    <Compile Include="BabylonPBRMetallicRoughnessMaterial.cs" />
     <Compile Include="BabylonAnimationKey.cs" />
     <Compile Include="BabylonBone.cs" />
     <Compile Include="BabylonCamera.cs" />

+ 76 - 0
Exporters/3ds Max/BabylonExport.Entities/BabylonPBRMetallicRoughnessMaterial.cs

@@ -0,0 +1,76 @@
+using System.Runtime.Serialization;
+
+namespace BabylonExport.Entities
+{
+    [DataContract]
+    public class BabylonPBRMetallicRoughnessMaterial : BabylonMaterial
+    {
+        [DataMember]
+        public string customType { get; private set; }
+
+        [DataMember]
+        public float[] baseColor { get; set; }
+
+        [DataMember]
+        public BabylonTexture baseTexture { get; set; }
+
+        [DataMember]
+        public float metallic { get; set; }
+
+        [DataMember]
+        public float roughness { get; set; }
+
+        [DataMember]
+        public BabylonTexture metallicRoughnessTexture { get; set; }
+
+        [DataMember]
+        public int maxSimultaneousLights { get; set; }
+
+        [DataMember]
+        public bool disableLighting { get; set; }
+
+        [DataMember]
+        public BabylonTexture environmentTexture { get; set; }
+
+        [DataMember]
+        public bool invertNormalMapX { get; set; }
+
+        [DataMember]
+        public bool invertNormalMapY { get; set; }
+
+        [DataMember]
+        public BabylonTexture normalTexture { get; set; }
+
+        [DataMember]
+        public float[] emissiveColor { get; set; }
+
+        [DataMember]
+        public BabylonTexture emissiveTexture { get; set; }
+
+        [DataMember]
+        public float occlusionStrength { get; set; }
+
+        [DataMember]
+        public BabylonTexture occlusionTexture { get; set; }
+
+        [DataMember]
+        public float alphaCutOff { get; set; }
+
+        [DataMember]
+        public int transparencyMode { get; set; }
+
+        [DataMember]
+        public bool doubleSided { get; set; }
+
+        public BabylonPBRMetallicRoughnessMaterial() : base()
+        {
+            customType = "BABYLON.PBRMetallicRoughnessMaterial";
+
+            maxSimultaneousLights = 4;
+            emissiveColor = new[] { 0f, 0f, 0f };
+            occlusionStrength = 1.0f;
+            alphaCutOff = 0.4f;
+            transparencyMode = 0;
+        }
+    }
+}

+ 12 - 2
Exporters/3ds Max/GltfExport.Entities/GLTF.cs

@@ -1,4 +1,5 @@
 using System.Collections.Generic;
+using System.IO;
 using System.Runtime.Serialization;
 
 namespace GLTFExport.Entities
@@ -45,7 +46,8 @@ namespace GLTFExport.Entities
         [DataMember(EmitDefaultValue = false)]
         public GLTFSampler[] samplers { get; set; }
 
-        public string OutputPath { get; private set; }
+        public string OutputFolder { get; private set; }
+        public string OutputFile { get; private set; }
 
         public List<GLTFNode> NodesList { get; private set; }
         public List<GLTFCamera> CamerasList { get; private set; }
@@ -58,9 +60,17 @@ namespace GLTFExport.Entities
         public List<GLTFImage> ImagesList { get; private set; }
         public List<GLTFSampler> SamplersList { get; private set; }
 
+        public GLTFBuffer buffer;
+        public GLTFBufferView bufferViewScalar;
+        public GLTFBufferView bufferViewFloatVec3;
+        public GLTFBufferView bufferViewFloatVec4;
+        public GLTFBufferView bufferViewFloatVec2;
+        public GLTFBufferView bufferViewImage;
+
         public GLTF(string outputPath)
         {
-            OutputPath = outputPath;
+            OutputFolder = Path.GetDirectoryName(outputPath);
+            OutputFile = Path.GetFileNameWithoutExtension(outputPath);
 
             NodesList = new List<GLTFNode>();
             CamerasList = new List<GLTFCamera>();

+ 4 - 1
Exporters/3ds Max/GltfExport.Entities/GLTFBuffer.cs

@@ -1,4 +1,5 @@
-using System.Runtime.Serialization;
+using System.Collections.Generic;
+using System.Runtime.Serialization;
 
 namespace GLTFExport.Entities
 {
@@ -10,5 +11,7 @@ namespace GLTFExport.Entities
 
         [DataMember(IsRequired = true)]
         public int byteLength { get; set; }
+
+        public List<byte> bytesList;
     }
 }

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

@@ -1,4 +1,5 @@
-using System.Runtime.Serialization;
+using System.Collections.Generic;
+using System.Runtime.Serialization;
 
 namespace GLTFExport.Entities
 {
@@ -18,5 +19,6 @@ namespace GLTFExport.Entities
         public int? byteStride { get; set; }
 
         public GLTFBuffer Buffer;
+        public List<byte> bytesList = new List<byte>();
     }
 }

+ 2 - 0
Exporters/3ds Max/GltfExport.Entities/GLTFImage.cs

@@ -13,5 +13,7 @@ namespace GLTFExport.Entities
 
         [DataMember(EmitDefaultValue = false)]
         public int? bufferView { get; set; }
+
+        public string FileExtension;
     }
 }

BIN
Exporters/3ds Max/Max2Babylon-0.15.0.zip


BIN
Exporters/3ds Max/Max2Babylon-0.16.0.zip


+ 177 - 22
Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.GLTFExporter.Material.cs

@@ -24,9 +24,9 @@ namespace Max2Babylon
 
                 RaiseMessage("GLTFExporter.Material | babylonMaterial data", 2);
                 RaiseMessage("GLTFExporter.Material | babylonMaterial.alpha=" + babylonMaterial.alpha, 3);
+                RaiseMessage("GLTFExporter.Material | babylonMaterial.alphaMode=" + babylonMaterial.alphaMode, 3);
                 RaiseMessage("GLTFExporter.Material | babylonMaterial.backFaceCulling=" + babylonMaterial.backFaceCulling, 3);
                 RaiseMessage("GLTFExporter.Material | babylonMaterial.wireframe=" + babylonMaterial.wireframe, 3);
-                RaiseMessage("GLTFExporter.Material | babylonStandardMaterial.specularPower=" + babylonStandardMaterial.specularPower, 3);
 
                 // Ambient
                 for (int i = 0; i < babylonStandardMaterial.ambient.Length; i++)
@@ -128,7 +128,7 @@ namespace Max2Babylon
                 };
 
                 MetallicRoughness _metallicRoughness = ConvertToMetallicRoughness(_specularGlossiness, true);
-
+                
                 // Base color
                 gltfPbrMetallicRoughness.baseColorFactor = new float[4]
                 {
@@ -147,43 +147,40 @@ namespace Max2Babylon
 
                 if (babylonStandardMaterial.diffuseTexture != null)
                 {
-                    Func<string, Bitmap> loadTexture = delegate (string textureName)
+                    Func<string, Bitmap> loadTextureFromOutput = delegate (string textureName)
                     {
-                        var pathDiffuse = Path.Combine(gltf.OutputPath, textureName);
-                        if (File.Exists(pathDiffuse))
-                        {
-                            return new Bitmap(pathDiffuse);
-                        }
-                        else
-                        {
-                            RaiseWarning(string.Format("GLTFExporter.Material | Texture {0} not found.", textureName), 2);
-                            return null;
-                        }
+                        return LoadTexture(Path.Combine(gltf.OutputFolder, textureName));
                     };
 
-                    Bitmap diffuseBitmap = loadTexture(babylonStandardMaterial.diffuseTexture.name);
+                    Bitmap diffuseBitmap = loadTextureFromOutput(babylonStandardMaterial.diffuseTexture.name);
 
                     if (diffuseBitmap != null)
                     {
                         Bitmap specularBitmap = null;
                         if (babylonStandardMaterial.specularTexture != null)
                         {
-                            specularBitmap = loadTexture(babylonStandardMaterial.specularTexture.name);
+                            specularBitmap = loadTextureFromOutput(babylonStandardMaterial.specularTexture.name);
                         }
 
                         Bitmap opacityBitmap = null;
                         if (babylonStandardMaterial.diffuseTexture.hasAlpha == false && babylonStandardMaterial.opacityTexture != null)
                         {
-                            opacityBitmap = loadTexture(babylonStandardMaterial.opacityTexture.name);
+                            opacityBitmap = loadTextureFromOutput(babylonStandardMaterial.opacityTexture.name);
                         }
 
-                        // Retreive dimension from diffuse map
-                        var width = diffuseBitmap.Width;
-                        var height = diffuseBitmap.Height;
+                        // Retreive dimensions
+                        int width = 0;
+                        int height = 0;
+                        var haveSameDimensions = _getMinimalBitmapDimensions(out width, out height, diffuseBitmap, specularBitmap, opacityBitmap);
+                        if (!haveSameDimensions)
+                        {
+                            RaiseWarning("Diffuse, specular and opacity maps should have same dimensions", 2);
+                        }
 
                         // Create base color and metallic+roughness maps
                         Bitmap baseColorBitmap = new Bitmap(width, height);
                         Bitmap metallicRoughnessBitmap = new Bitmap(width, height);
+                        var hasAlpha = false;
                         for (int x = 0; x < width; x++)
                         {
                             for (int y = 0; y < height; y++)
@@ -199,7 +196,7 @@ namespace Max2Babylon
                                     specular = specularBitmap != null ? new BabylonColor3(specularBitmap.GetPixel(x, y)) :
                                                new BabylonColor3(),
                                     glossiness = babylonStandardMaterial.useGlossinessFromSpecularMapAlpha && specularBitmap != null ? specularBitmap.GetPixel(x, y).A / 255.0f :
-                                                 babylonStandardMaterial.specularPower / 256.0f
+                                                 0
                                 };
 
                                 var displayPrints = x == width / 2 && y == height / 2;
@@ -212,6 +209,10 @@ namespace Max2Babylon
                                     (int)(metallicRoughnessTexture.baseColor.b * 255)
                                 );
                                 baseColorBitmap.SetPixel(x, y, colorBase);
+                                if (metallicRoughnessTexture.opacity != 1)
+                                {
+                                    hasAlpha = true;
+                                }
 
                                 // The metalness values are sampled from the B channel.
                                 // The roughness values are sampled from the G channel.
@@ -226,11 +227,150 @@ namespace Max2Babylon
                         }
 
                         // Export maps and textures
-                        gltfPbrMetallicRoughness.baseColorTexture = ExportBitmapTexture(babylonStandardMaterial.diffuseTexture, baseColorBitmap, babylonMaterial.name + "_baseColor" + ".png", gltf);
-                        gltfPbrMetallicRoughness.metallicRoughnessTexture = ExportBitmapTexture(babylonStandardMaterial.diffuseTexture, metallicRoughnessBitmap, babylonMaterial.name + "_metallicRoughness" + ".jpg", gltf);
+                        var baseColorFileName = babylonMaterial.name + "_baseColor" + (hasAlpha ? ".png" : ".jpg");
+                        gltfPbrMetallicRoughness.baseColorTexture = ExportBitmapTexture(babylonStandardMaterial.diffuseTexture, baseColorBitmap, baseColorFileName, gltf);
+                        if (specularBitmap != null)
+                        {
+                            gltfPbrMetallicRoughness.metallicRoughnessTexture = ExportBitmapTexture(babylonStandardMaterial.diffuseTexture, metallicRoughnessBitmap, babylonMaterial.name + "_metallicRoughness" + ".jpg", gltf);
+                        }
                     }
                 }
             }
+            else if (babylonMaterial.GetType() == typeof(BabylonPBRMetallicRoughnessMaterial))
+            {
+
+                var babylonPBRMetallicRoughnessMaterial = babylonMaterial as BabylonPBRMetallicRoughnessMaterial;
+
+
+                // --- prints ---
+
+                RaiseMessage("GLTFExporter.Material | babylonMaterial data", 2);
+                RaiseMessage("GLTFExporter.Material | babylonMaterial.alpha=" + babylonMaterial.alpha, 3);
+                RaiseMessage("GLTFExporter.Material | babylonMaterial.alphaMode=" + babylonMaterial.alphaMode, 3);
+                RaiseMessage("GLTFExporter.Material | babylonMaterial.backFaceCulling=" + babylonMaterial.backFaceCulling, 3);
+                RaiseMessage("GLTFExporter.Material | babylonMaterial.wireframe=" + babylonMaterial.wireframe, 3);
+
+                // Global
+                RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.maxSimultaneousLights=" + babylonPBRMetallicRoughnessMaterial.maxSimultaneousLights, 3);
+                RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.disableLighting=" + babylonPBRMetallicRoughnessMaterial.disableLighting, 3);
+                RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.alphaCutOff=" + babylonPBRMetallicRoughnessMaterial.alphaCutOff, 3);
+                RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.transparencyMode=" + babylonPBRMetallicRoughnessMaterial.transparencyMode, 3);
+                RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.doubleSided=" + babylonPBRMetallicRoughnessMaterial.doubleSided, 3);
+
+                // Base color
+                RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.baseColor.Length=" + babylonPBRMetallicRoughnessMaterial.baseColor.Length, 3);
+                for (int i = 0; i < babylonPBRMetallicRoughnessMaterial.baseColor.Length; i++)
+                {
+                    RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.baseColor[" + i + "]=" + babylonPBRMetallicRoughnessMaterial.baseColor[i], 3);
+                }
+                if (babylonPBRMetallicRoughnessMaterial.baseTexture == null)
+                {
+                    RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.baseTexture=null", 3);
+                }
+
+                // Metallic+roughness
+                RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.metallic=" + babylonPBRMetallicRoughnessMaterial.metallic, 3);
+                RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.roughness=" + babylonPBRMetallicRoughnessMaterial.roughness, 3);
+                if (babylonPBRMetallicRoughnessMaterial.metallicRoughnessTexture == null)
+                {
+                    RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.metallicRoughnessTexture=null", 3);
+                }
+
+                // Environment
+                if (babylonPBRMetallicRoughnessMaterial.environmentTexture == null)
+                {
+                    RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.environmentTexture=null", 3);
+                }
+
+                // Normal / bump
+                if (babylonPBRMetallicRoughnessMaterial.normalTexture == null)
+                {
+                    RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.normalTexture=null", 3);
+                }
+                RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.invertNormalMapX=" + babylonPBRMetallicRoughnessMaterial.invertNormalMapX, 3);
+                RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.invertNormalMapY=" + babylonPBRMetallicRoughnessMaterial.invertNormalMapY, 3);
+
+                // Emissive
+                for (int i = 0; i < babylonPBRMetallicRoughnessMaterial.emissiveColor.Length; i++)
+                {
+                    RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.emissiveColor[" + i + "]=" + babylonPBRMetallicRoughnessMaterial.emissiveColor[i], 3);
+                }
+                if (babylonPBRMetallicRoughnessMaterial.emissiveTexture == null)
+                {
+                    RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.emissiveTexture=null", 3);
+                }
+
+                // Ambient occlusion
+                RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.occlusionStrength=" + babylonPBRMetallicRoughnessMaterial.occlusionStrength, 3);
+                if (babylonPBRMetallicRoughnessMaterial.occlusionTexture == null)
+                {
+                    RaiseMessage("GLTFExporter.Material | babylonPBRMetallicRoughnessMaterial.occlusionTexture=null", 3);
+                }
+
+
+                // --------------------------------
+                // --------- gltfMaterial ---------
+                // --------------------------------
+
+                RaiseMessage("GLTFExporter.Material | create gltfMaterial", 2);
+                var gltfMaterial = new GLTFMaterial
+                {
+                    name = name
+                };
+                gltfMaterial.id = babylonMaterial.id;
+                gltfMaterial.index = gltf.MaterialsList.Count;
+                gltf.MaterialsList.Add(gltfMaterial);
+
+                // Alpha
+                string alphaMode;
+                float? alphaCutoff;
+                getAlphaMode(babylonPBRMetallicRoughnessMaterial, out alphaMode, out alphaCutoff);
+                gltfMaterial.alphaMode = alphaMode;
+                gltfMaterial.alphaCutoff = alphaCutoff;
+
+                // DoubleSided
+                gltfMaterial.doubleSided = babylonPBRMetallicRoughnessMaterial.doubleSided;
+
+                // Normal
+                gltfMaterial.normalTexture = ExportTexture(babylonPBRMetallicRoughnessMaterial.normalTexture, gltf);
+
+                // Occulison
+                gltfMaterial.occlusionTexture = ExportTexture(babylonPBRMetallicRoughnessMaterial.occlusionTexture, gltf);
+
+                // Emissive
+                gltfMaterial.emissiveFactor = babylonPBRMetallicRoughnessMaterial.emissiveColor;
+                gltfMaterial.emissiveTexture = ExportTexture(babylonPBRMetallicRoughnessMaterial.emissiveTexture, gltf);
+
+
+                // --------------------------------
+                // --- gltfPbrMetallicRoughness ---
+                // --------------------------------
+
+                RaiseMessage("GLTFExporter.Material | create gltfPbrMetallicRoughness", 2);
+                var gltfPbrMetallicRoughness = new GLTFPBRMetallicRoughness();
+                gltfMaterial.pbrMetallicRoughness = gltfPbrMetallicRoughness;
+
+                // --- Global ---
+
+                // Base color
+                gltfPbrMetallicRoughness.baseColorFactor = new float[4]
+                {
+                    babylonPBRMetallicRoughnessMaterial.baseColor[0],
+                    babylonPBRMetallicRoughnessMaterial.baseColor[1],
+                    babylonPBRMetallicRoughnessMaterial.baseColor[2],
+                    1.0f // TODO - alpha
+                };
+                gltfPbrMetallicRoughness.baseColorTexture = ExportTexture(babylonPBRMetallicRoughnessMaterial.baseTexture, gltf);
+
+                // Metallic roughness
+                gltfPbrMetallicRoughness.metallicFactor = babylonPBRMetallicRoughnessMaterial.metallic;
+                gltfPbrMetallicRoughness.roughnessFactor = babylonPBRMetallicRoughnessMaterial.roughness;
+                gltfPbrMetallicRoughness.metallicRoughnessTexture = ExportTexture(babylonPBRMetallicRoughnessMaterial.metallicRoughnessTexture, gltf);
+            }
+            else
+            {
+                RaiseWarning("GLTFExporter.Material | Unsupported material type: " + babylonMaterial.GetType(), 2);
+            }
         }
 
         private void getAlphaMode(BabylonStandardMaterial babylonMaterial, out string alphaMode, out float? alphaCutoff)
@@ -249,6 +389,21 @@ namespace Max2Babylon
             alphaCutoff = null;
         }
 
+        private void getAlphaMode(BabylonPBRMetallicRoughnessMaterial babylonMaterial, out string alphaMode, out float? alphaCutoff)
+        {
+            if (babylonMaterial.baseTexture != null && babylonMaterial.baseTexture.hasAlpha)
+            {
+                // TODO - Babylon standard material is assumed to useAlphaFromDiffuseTexture. If not, the alpha mode is a mask.
+                alphaMode = GLTFMaterial.AlphaMode.BLEND.ToString();
+            }
+            else
+            {
+                // glTF alpha mode default value is "OPAQUE"
+                alphaMode = null; // GLTFMaterial.AlphaMode.OPAQUE.ToString();
+            }
+            alphaCutoff = null;
+        }
+
         BabylonColor3 dielectricSpecular = new BabylonColor3(0.04f, 0.04f, 0.04f);
         const float epsilon = 1e-6f;
 

+ 103 - 75
Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.GLTFExporter.Mesh.cs

@@ -92,64 +92,89 @@ namespace Max2Babylon
             gltfMesh.idGroupInstance = babylonMesh.idGroupInstance;
 
             // Buffer
-            var buffer = new GLTFBuffer
+            var buffer = gltf.buffer;
+            if (buffer == null)
             {
-                uri = gltfMesh.name + ".bin"
-            };
-            buffer.index = gltf.BuffersList.Count;
-            gltf.BuffersList.Add(buffer);
+                buffer = new GLTFBuffer
+                {
+                    uri = gltf.OutputFile + ".bin"
+                };
+                buffer.index = gltf.BuffersList.Count;
+                gltf.BuffersList.Add(buffer);
+                gltf.buffer = buffer;
+            }
 
             // BufferView - Scalar
-            var bufferViewScalar = new GLTFBufferView
+            var bufferViewScalar = gltf.bufferViewScalar;
+            if (bufferViewScalar == null)
             {
-                name = "bufferViewScalar",
-                buffer = buffer.index,
-                Buffer = buffer
-            };
-            bufferViewScalar.index = gltf.BufferViewsList.Count;
-            gltf.BufferViewsList.Add(bufferViewScalar);
+                bufferViewScalar = new GLTFBufferView
+                {
+                    name = "bufferViewScalar",
+                    buffer = buffer.index,
+                    Buffer = buffer
+                };
+                bufferViewScalar.index = gltf.BufferViewsList.Count;
+                gltf.BufferViewsList.Add(bufferViewScalar);
+                gltf.bufferViewScalar = bufferViewScalar;
+            }
 
             // BufferView - Vector3
-            var bufferViewFloatVec3 = new GLTFBufferView
+            var bufferViewFloatVec3 = gltf.bufferViewFloatVec3;
+            if (bufferViewFloatVec3 == null)
             {
-                name = "bufferViewFloatVec3",
-                buffer = buffer.index,
-                Buffer = buffer,
-                byteOffset = 0,
-                byteStride = 12 // Field only defined for buffer views that contain vertex attributes. A vertex needs 3 * 4 bytes
-            };
-            bufferViewFloatVec3.index = gltf.BufferViewsList.Count;
-            gltf.BufferViewsList.Add(bufferViewFloatVec3);
+                bufferViewFloatVec3 = new GLTFBufferView
+                {
+                    name = "bufferViewFloatVec3",
+                    buffer = buffer.index,
+                    Buffer = buffer,
+                    byteOffset = 0,
+                    byteStride = 12 // Field only defined for buffer views that contain vertex attributes. A vertex needs 3 * 4 bytes
+                };
+                bufferViewFloatVec3.index = gltf.BufferViewsList.Count;
+                gltf.BufferViewsList.Add(bufferViewFloatVec3);
+                gltf.bufferViewFloatVec3 = bufferViewFloatVec3;
+            }
 
             // BufferView - Vector4
             GLTFBufferView bufferViewFloatVec4 = null;
             if (hasColor)
             {
-                bufferViewFloatVec4 = new GLTFBufferView
+                bufferViewFloatVec4 = gltf.bufferViewFloatVec4;
+                if (bufferViewFloatVec4 == null)
                 {
-                    name = "bufferViewFloatVec4",
-                    buffer = buffer.index,
-                    Buffer = buffer,
-                    byteOffset = 0,
-                    byteStride = 16 // Field only defined for buffer views that contain vertex attributes. A vertex needs 4 * 4 bytes
-                };
-                bufferViewFloatVec4.index = gltf.BufferViewsList.Count;
-                gltf.BufferViewsList.Add(bufferViewFloatVec4);
+                    bufferViewFloatVec4 = new GLTFBufferView
+                    {
+                        name = "bufferViewFloatVec4",
+                        buffer = buffer.index,
+                        Buffer = buffer,
+                        byteOffset = 0,
+                        byteStride = 16 // Field only defined for buffer views that contain vertex attributes. A vertex needs 4 * 4 bytes
+                    };
+                    bufferViewFloatVec4.index = gltf.BufferViewsList.Count;
+                    gltf.BufferViewsList.Add(bufferViewFloatVec4);
+                    gltf.bufferViewFloatVec4 = bufferViewFloatVec4;
+                }
             }
 
             // BufferView - Vector2
             GLTFBufferView bufferViewFloatVec2 = null;
             if (hasUV || hasUV2)
             {
-                bufferViewFloatVec2 = new GLTFBufferView
+                bufferViewFloatVec2 = gltf.bufferViewFloatVec2;
+                if (bufferViewFloatVec2 == null)
                 {
-                    name = "bufferViewFloatVec2",
-                    buffer = buffer.index,
-                    Buffer = buffer,
-                    byteStride = 8 // Field only defined for buffer views that contain vertex attributes. A vertex needs 2 * 4 bytes
-                };
-                bufferViewFloatVec2.index = gltf.BufferViewsList.Count;
-                gltf.BufferViewsList.Add(bufferViewFloatVec2);
+                    bufferViewFloatVec2 = new GLTFBufferView
+                    {
+                        name = "bufferViewFloatVec2",
+                        buffer = buffer.index,
+                        Buffer = buffer,
+                        byteStride = 8 // Field only defined for buffer views that contain vertex attributes. A vertex needs 2 * 4 bytes
+                    };
+                    bufferViewFloatVec2.index = gltf.BufferViewsList.Count;
+                    gltf.BufferViewsList.Add(bufferViewFloatVec2);
+                    gltf.bufferViewFloatVec2 = bufferViewFloatVec2;
+                }
             }
 
             // --------------------------
@@ -391,51 +416,54 @@ namespace Max2Babylon
             // --------- Saving ---------
             // --------------------------
 
-            string outputBinaryFile = Path.Combine(gltf.OutputPath, gltfMesh.name + ".bin");
-            RaiseMessage("GLTFExporter.Mesh | Saving " + outputBinaryFile, 2);
+            RaiseMessage("GLTFExporter.Mesh | saving", 2);
 
-            // Write data to binary file
-            using (BinaryWriter writer = new BinaryWriter(File.Open(outputBinaryFile, FileMode.Create)))
+            // BufferView - Scalar
+            gltfIndices.ForEach(n => bufferViewScalar.bytesList.AddRange(BitConverter.GetBytes(n)));
+
+            // BufferView - Vector3
+            globalVerticesSubMeshes.ForEach(globalVerticesSubMesh =>
             {
-                // BufferView - Scalar
-                gltfIndices.ForEach(n => writer.Write(n));
+                List<float> vertices = globalVerticesSubMesh.SelectMany(v => new[] { v.Position.X, v.Position.Y, v.Position.Z }).ToList();
+                vertices.ForEach(n => bufferViewFloatVec3.bytesList.AddRange(BitConverter.GetBytes(n)));
 
-                // BufferView - Vector3
-                globalVerticesSubMeshes.ForEach(globalVerticesSubMesh =>
-                {
-                    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> normals = globalVerticesSubMesh.SelectMany(v => new[] { v.Normal.X, v.Normal.Y, v.Normal.Z }).ToList();
+                normals.ForEach(n => bufferViewFloatVec3.bytesList.AddRange(BitConverter.GetBytes(n)));
+            });
 
-                    List<float> normals = globalVerticesSubMesh.SelectMany(v => new[] { v.Normal.X, v.Normal.Y, v.Normal.Z }).ToList();
-                    normals.ForEach(n => writer.Write(n));
-                });
+            // BufferView - Vector4
+            globalVerticesSubMeshes.ForEach(globalVerticesSubMesh =>
+            {
+                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 => bufferViewFloatVec4.bytesList.AddRange(BitConverter.GetBytes(n)));
+                }
+            });
 
-                // BufferView - Vector4
-                globalVerticesSubMeshes.ForEach(globalVerticesSubMesh =>
+            // BufferView - Vector2
+            globalVerticesSubMeshes.ForEach(globalVerticesSubMesh =>
+            {
+                if (hasUV)
                 {
-                    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));
-                    }
-                });
+                    List<float> uvs = globalVerticesSubMesh.SelectMany(v => new[] { v.UV.X, v.UV.Y }).ToList();
+                    uvs.ForEach(n => bufferViewFloatVec2.bytesList.AddRange(BitConverter.GetBytes(n)));
+                }
 
-                // BufferView - Vector2
-                globalVerticesSubMeshes.ForEach(globalVerticesSubMesh =>
+                if (hasUV2)
                 {
-                    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));
-                    }
-                });
-            }
+                    List<float> uvs2 = globalVerticesSubMesh.SelectMany(v => new[] { v.UV2.X, v.UV2.Y }).ToList();
+                    uvs2.ForEach(n => bufferViewFloatVec2.bytesList.AddRange(BitConverter.GetBytes(n)));
+                }
+            });
+
+            //// Write data to binary file
+            //string outputBinaryFile = Path.Combine(gltf.OutputPath, gltfMesh.name + ".bin");
+            //RaiseMessage("GLTFExporter.Mesh | Saving " + outputBinaryFile, 2);
+            //using (BinaryWriter writer = new BinaryWriter(File.Open(outputBinaryFile, FileMode.Create)))
+            //{
+            //    bytesList.ForEach(b => writer.Write(b));
+            //}
 
             return gltfMesh;
         }

+ 12 - 2
Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.GLTFExporter.Texture.cs

@@ -21,9 +21,10 @@ namespace Max2Babylon
             // Copy image to output
             if (CopyTexturesToOutput)
             {
-                var absolutePath = Path.Combine(gltf.OutputPath, name);
+                var absolutePath = Path.Combine(gltf.OutputFolder, name);
+                var imageFormat = Path.GetExtension(name) == ".jpg" ? System.Drawing.Imaging.ImageFormat.Jpeg : System.Drawing.Imaging.ImageFormat.Png;
                 RaiseMessage($"GLTFExporter.Texture | write image '{name}' to '{absolutePath}'", 1);
-                bitmap.Save(absolutePath);
+                bitmap.Save(absolutePath, imageFormat);
             }
 
             return ExportTexture(babylonTexture, gltf, name);
@@ -76,6 +77,15 @@ namespace Max2Babylon
 
             gltfImage.index = gltf.ImagesList.Count;
             gltf.ImagesList.Add(gltfImage);
+            switch (Path.GetExtension(name))
+            {
+                case ".jpg":
+                    gltfImage.FileExtension = "jpeg";
+                    break;
+                case ".png":
+                    gltfImage.FileExtension = "png";
+                    break;
+            }
 
 
             // --------------------------

+ 167 - 16
Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.GLTFExporter.cs

@@ -3,6 +3,7 @@ using GLTFExport.Entities;
 using Newtonsoft.Json;
 using System;
 using System.Collections.Generic;
+using System.Drawing;
 using System.Globalization;
 using System.IO;
 using System.Text;
@@ -16,7 +17,7 @@ namespace Max2Babylon
 
         private List<BabylonNode> babylonNodes;
 
-        public void ExportGltf(BabylonScene babylonScene, string outputFile, bool generateBinary)
+        public void ExportGltf(BabylonScene babylonScene, string outputFile, bool generateBinary, bool exportGltfImagesAsBinary)
         {
             RaiseMessage("GLTFExporter | Export outputFile=" + outputFile + " generateBinary=" + generateBinary);
             RaiseMessage("GLTFExporter | Exportation started", Color.Blue);
@@ -29,7 +30,7 @@ namespace Max2Babylon
             initBabylonNodes(babylonScene);
             babylonMaterialsToExport = new List<BabylonMaterial>();
 
-            var gltf = new GLTF(Path.GetDirectoryName(outputFile));
+            var gltf = new GLTF(outputFile);
 
             // Asset
             gltf.asset = new GLTFAsset
@@ -96,30 +97,113 @@ namespace Max2Babylon
                 CheckCancelled();
             };
             RaiseMessage(string.Format("GLTFExporter | Nb materials exported: {0}", gltf.MaterialsList.Count), Color.Gray, 1);
+            
+            if (exportGltfImagesAsBinary)
+            {
+                SwitchImagesFromUriToBinary(gltf);
+            }
 
-            // Output
-            RaiseMessage("GLTFExporter | Saving to output file");
             // Cast lists to arrays
             gltf.Prepare();
-            var jsonSerializer = JsonSerializer.Create(new JsonSerializerSettings());
-            var sb = new StringBuilder();
-            var sw = new StringWriter(sb, CultureInfo.InvariantCulture);
 
-            // 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))
+            // Output
+            RaiseMessage("GLTFExporter | Saving to output file");
+            
+            string outputGltfFile = Path.ChangeExtension(outputFile, "gltf");
+            File.WriteAllText(outputGltfFile, gltfToJson(gltf));
+
+            // Write data to binary file
+            string outputBinaryFile = Path.ChangeExtension(outputFile, "bin");
+            using (BinaryWriter writer = new BinaryWriter(File.Open(outputBinaryFile, FileMode.Create)))
             {
-                jsonWriter.Formatting = Formatting.None;
-                jsonSerializer.Serialize(jsonWriter, gltf);
+                gltf.BuffersList.ForEach(buffer =>
+                {
+                    buffer.bytesList = new List<byte>();
+                    gltf.BufferViewsList.FindAll(bufferView => bufferView.buffer == buffer.index).ForEach(bufferView =>
+                    {
+                        bufferView.bytesList.ForEach(b => writer.Write(b));
+                        buffer.bytesList.AddRange(bufferView.bytesList);
+                    });
+                });
             }
-            string outputGltfFile = Path.ChangeExtension(outputFile, "gltf");
-            File.WriteAllText(outputGltfFile, sb.ToString());
 
             // Binary
             if (generateBinary)
             {
-                // TODO - Export glTF data to binary format .glb
-                RaiseError("GLTFExporter | TODO - Generating binary files");
+                // Export glTF data to binary format .glb
+                RaiseMessage("GLTFExporter | Generating .glb file");
+
+                // Header
+                UInt32 magic = 0x46546C67; // ASCII code for glTF
+                UInt32 version = 2;
+                UInt32 length = 12; // Header length
+
+                // --- JSON chunk ---
+                UInt32 chunkTypeJson = 0x4E4F534A; // ASCII code for JSON
+                // Remove buffers uri
+                foreach (GLTFBuffer gltfBuffer in gltf.BuffersList)
+                {
+                    gltfBuffer.uri = null;
+                }
+                // Switch images to binary if not already done
+                // TODO - make it optional
+                if (!exportGltfImagesAsBinary)
+                {
+                    var imageBufferViews = SwitchImagesFromUriToBinary(gltf);
+                    imageBufferViews.ForEach(imageBufferView =>
+                    {
+                        imageBufferView.Buffer.bytesList.AddRange(imageBufferView.bytesList);
+                    });
+                }
+                gltf.Prepare();
+                // Serialize gltf data to JSON string then convert it to bytes
+                byte[] chunkDataJson = Encoding.ASCII.GetBytes(gltfToJson(gltf));
+                // JSON chunk must be padded with trailing Space chars (0x20) to satisfy alignment requirements 
+                var nbSpaceToAdd = chunkDataJson.Length % 4 == 0 ? 0 : (4 - chunkDataJson.Length % 4);
+                var chunkDataJsonList = new List<byte>(chunkDataJson);
+                for (int i = 0; i < nbSpaceToAdd; i++)
+                {
+                    chunkDataJsonList.Add(0x20);
+                }
+                chunkDataJson = chunkDataJsonList.ToArray();
+                UInt32 chunkLengthJson = (UInt32)chunkDataJson.Length;
+                length += chunkLengthJson + 8; // 8 = JSON chunk header length
+                
+                // bin chunk
+                UInt32 chunkTypeBin = 0x004E4942; // ASCII code for BIN
+                UInt32 chunkLengthBin = 0;
+                if (gltf.BuffersList.Count > 0)
+                {
+                    foreach (GLTFBuffer gltfBuffer in gltf.BuffersList)
+                    {
+                        chunkLengthBin += (uint)gltfBuffer.byteLength;
+                    }
+                    length += chunkLengthBin + 8; // 8 = bin chunk header length
+                }
+                
+
+                // Write binary file
+                string outputGlbFile = Path.ChangeExtension(outputFile, "glb");
+                using (BinaryWriter writer = new BinaryWriter(File.Open(outputGlbFile, FileMode.Create)))
+                {
+                    // Header
+                    writer.Write(magic);
+                    writer.Write(version);
+                    writer.Write(length);
+                    
+                    // JSON chunk
+                    writer.Write(chunkLengthJson);
+                    writer.Write(chunkTypeJson);
+                    writer.Write(chunkDataJson);
+
+                    // bin chunk
+                    if (gltf.BuffersList.Count > 0)
+                    {
+                        writer.Write(chunkLengthBin);
+                        writer.Write(chunkTypeBin);
+                        gltf.BuffersList[0].bytesList.ForEach(b => writer.Write(b));
+                    }
+                };
             }
 
             ReportProgressChanged(100);
@@ -236,5 +320,72 @@ namespace Max2Babylon
             // No relevant node found in hierarchy
             return false;
         }
+
+        private string gltfToJson(GLTF gltf)
+        {
+            var jsonSerializer = JsonSerializer.Create(new JsonSerializerSettings());
+            var sb = new StringBuilder();
+            var sw = new StringWriter(sb, CultureInfo.InvariantCulture);
+
+            // 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);
+            }
+            return sb.ToString();
+        }
+
+        private List<GLTFBufferView> SwitchImagesFromUriToBinary(GLTF gltf)
+        {
+            var imageBufferViews = new List<GLTFBufferView>();
+
+            foreach (GLTFImage gltfImage in gltf.ImagesList)
+            {
+                var path = Path.Combine(gltf.OutputFolder, gltfImage.uri);
+                using (Image image = Image.FromFile(path))
+                {
+                    using (MemoryStream m = new MemoryStream())
+                    {
+                        var imageFormat = gltfImage.FileExtension == "jpeg" ? System.Drawing.Imaging.ImageFormat.Jpeg : System.Drawing.Imaging.ImageFormat.Png;
+                        image.Save(m, imageFormat);
+                        byte[] imageBytes = m.ToArray();
+
+                        // JSON chunk must be padded with trailing Space chars (0x20) to satisfy alignment requirements 
+                        var nbSpaceToAdd = imageBytes.Length % 4 == 0 ? 0 : (4 - imageBytes.Length % 4);
+                        var imageBytesList = new List<byte>(imageBytes);
+                        for (int i = 0; i < nbSpaceToAdd; i++)
+                        {
+                            imageBytesList.Add(0x00);
+                        }
+                        imageBytes = imageBytesList.ToArray();
+
+                        // BufferView - Image
+                        var buffer = gltf.buffer;
+                        var bufferViewImage = new GLTFBufferView
+                        {
+                            name = "bufferViewImage",
+                            buffer = buffer.index,
+                            Buffer = buffer,
+                            byteOffset = buffer.byteLength
+                        };
+                        bufferViewImage.index = gltf.BufferViewsList.Count;
+                        gltf.BufferViewsList.Add(bufferViewImage);
+                        imageBufferViews.Add(bufferViewImage);
+
+
+                        gltfImage.uri = null;
+                        gltfImage.bufferView = bufferViewImage.index;
+                        gltfImage.mimeType = "image/" + gltfImage.FileExtension;
+
+                        bufferViewImage.bytesList.AddRange(imageBytes);
+                        bufferViewImage.byteLength += imageBytes.Length;
+                        bufferViewImage.Buffer.byteLength += imageBytes.Length;
+                    }
+                }
+            }
+            return imageBufferViews;
+        }
     }
 }

+ 173 - 18
Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Material.cs

@@ -16,6 +16,65 @@ namespace Max2Babylon
 
             RaiseMessage(name, 1);
 
+            // --- prints ---
+            {
+                RaiseMessage("materialNode.MaterialClass=" + materialNode.MaterialClass, 2);
+                RaiseMessage("materialNode.NumberOfTextureMaps=" + materialNode.NumberOfTextureMaps, 2);
+
+                var propertyContainer = materialNode.IPropertyContainer;
+                RaiseMessage("propertyContainer=" + propertyContainer, 2);
+                if (propertyContainer != null)
+                {
+                    RaiseMessage("propertyContainer.NumberOfProperties=" + propertyContainer.NumberOfProperties, 3);
+                    for (int i = 0; i < propertyContainer.NumberOfProperties; i++)
+                    {
+                        var prop = propertyContainer.GetProperty(i);
+                        if (prop != null)
+                        {
+                            RaiseMessage("propertyContainer.GetProperty(" + i + ")=" + prop.Name, 3);
+                            switch (prop.GetType_)
+                            {
+                                case PropType.StringProp:
+                                    string propertyString = "";
+                                    RaiseMessage("prop.GetPropertyValue(ref propertyString, 0)=" + prop.GetPropertyValue(ref propertyString, 0), 4);
+                                    RaiseMessage("propertyString=" + propertyString, 4);
+                                    break;
+                                case PropType.IntProp:
+                                    int propertyInt = 0;
+                                    RaiseMessage("prop.GetPropertyValue(ref propertyInt, 0)=" + prop.GetPropertyValue(ref propertyInt, 0), 4);
+                                    RaiseMessage("propertyInt=" + propertyInt, 4);
+                                    break;
+                                case PropType.FloatProp:
+                                    float propertyFloat = 0;
+                                    RaiseMessage("prop.GetPropertyValue(ref propertyFloat, 0)=" + prop.GetPropertyValue(ref propertyFloat, 0, true), 4);
+                                    RaiseMessage("propertyFloat=" + propertyFloat, 4);
+                                    RaiseMessage("prop.GetPropertyValue(ref propertyFloat, 0)=" + prop.GetPropertyValue(ref propertyFloat, 0, false), 4);
+                                    RaiseMessage("propertyFloat=" + propertyFloat, 4);
+                                    break;
+                                case PropType.Point3Prop:
+                                    IPoint3 propertyPoint3 = Loader.Global.Point3.Create(0, 0, 0); 
+                                    RaiseMessage("prop.GetPropertyValue(ref propertyPoint3, 0)=" + prop.GetPropertyValue(propertyPoint3, 0), 4);
+                                    RaiseMessage("propertyPoint3=" + Point3ToString(propertyPoint3), 4);
+                                    break;
+                                case PropType.Point4Prop:
+                                    IPoint4 propertyPoint4 = Loader.Global.Point4.Create(0,0,0,0);
+                                    RaiseMessage("prop.GetPropertyValue(ref propertyPoint4, 0)=" + prop.GetPropertyValue(propertyPoint4, 0), 4);
+                                    RaiseMessage("propertyPoint4=" + Point4ToString(propertyPoint4), 4);
+                                    break;
+                                case PropType.UnknownProp:
+                                default:
+                                    RaiseMessage("Unknown property type", 4);
+                                    break;
+                            }
+                        }
+                        else
+                        {
+                            RaiseMessage("propertyContainer.GetProperty(" + i + ") IS NULL", 3);
+                        }
+                    }
+                }
+            }
+
             if (materialNode.SubMaterialCount > 0)
             {
                 var babylonMultimaterial = new BabylonMultiMaterial { name = name, id = id };
@@ -47,27 +106,26 @@ namespace Max2Babylon
                 babylonScene.MultiMaterialsList.Add(babylonMultimaterial);
                 return;
             }
-
-            var babylonMaterial = new BabylonStandardMaterial
-            {
-                name = name,
-                id = id,
-                ambient = materialNode.MaxMaterial.GetAmbient(0, false).ToArray(),
-                diffuse = materialNode.MaxMaterial.GetDiffuse(0, false).ToArray(),
-                specular = materialNode.MaxMaterial.GetSpecular(0, false).Scale(materialNode.MaxMaterial.GetShinStr(0, false)),
-                specularPower = materialNode.MaxMaterial.GetShininess(0, false) * 256,
-                emissive =
-                    materialNode.MaxMaterial.GetSelfIllumColorOn(0, false)
-                        ? materialNode.MaxMaterial.GetSelfIllumColor(0, false).ToArray()
-                        : materialNode.MaxMaterial.GetDiffuse(0, false).Scale(materialNode.MaxMaterial.GetSelfIllum(0, false)),
-                alpha = 1.0f - materialNode.MaxMaterial.GetXParency(0, false)
-            };
-
-
+            
             var stdMat = materialNode.MaxMaterial.GetParamBlock(0).Owner as IStdMat2;
 
             if (stdMat != null)
             {
+                var babylonMaterial = new BabylonStandardMaterial
+                {
+                    name = name,
+                    id = id,
+                    ambient = materialNode.MaxMaterial.GetAmbient(0, false).ToArray(),
+                    diffuse = materialNode.MaxMaterial.GetDiffuse(0, false).ToArray(),
+                    specular = materialNode.MaxMaterial.GetSpecular(0, false).Scale(materialNode.MaxMaterial.GetShinStr(0, false)),
+                    specularPower = materialNode.MaxMaterial.GetShininess(0, false) * 256,
+                    emissive =
+                        materialNode.MaxMaterial.GetSelfIllumColorOn(0, false)
+                            ? materialNode.MaxMaterial.GetSelfIllumColor(0, false).ToArray()
+                            : materialNode.MaxMaterial.GetDiffuse(0, false).Scale(materialNode.MaxMaterial.GetSelfIllum(0, false)),
+                    alpha = 1.0f - materialNode.MaxMaterial.GetXParency(0, false)
+                };
+
                 babylonMaterial.backFaceCulling = !stdMat.TwoSided;
                 babylonMaterial.wireframe = stdMat.Wire;
 
@@ -141,9 +199,106 @@ namespace Max2Babylon
                     RaiseWarning("Opacity texture was removed because alpha from diffuse texture can be use instead", 2);
                     RaiseWarning("If you do not want this behavior, just set Alpha Source = None on your diffuse texture", 2);
                 }
+
+                babylonScene.MaterialsList.Add(babylonMaterial);
+            }
+            else if (materialNode.MaterialClass == "Physical Material")
+            {
+                var propertyContainer = materialNode.IPropertyContainer;
+
+                var babylonMaterial = new BabylonPBRMetallicRoughnessMaterial
+                {
+                    name = name,
+                    id = id
+                };
+
+                // --- Global ---
+
+                babylonMaterial.alpha = 1.0f - materialNode.MaxMaterial.GetXParency(0, false);
+
+                // TODO - Add alpha
+                babylonMaterial.baseColor = materialNode.MaxMaterial.GetDiffuse(0, false).ToArray();
+
+                babylonMaterial.metallic = propertyContainer.GetFloatProperty(6);
+
+                babylonMaterial.roughness = propertyContainer.GetFloatProperty(4);
+                if (propertyContainer.GetIntProperty(5) == 1)
+                {
+                    // Inverse roughness
+                    babylonMaterial.roughness = 1 - babylonMaterial.roughness;
+                }
+
+                // Self illumination is computed from emission color, luminance, temperature and weight
+                babylonMaterial.emissiveColor = materialNode.MaxMaterial.GetSelfIllumColorOn(0, false)
+                                                ? materialNode.MaxMaterial.GetSelfIllumColor(0, false).ToArray()
+                                                : materialNode.MaxMaterial.GetDiffuse(0, false).Scale(materialNode.MaxMaterial.GetSelfIllum(0, false));
+
+                // TODO - occlusionStrength - use default? ignored?
+
+                // TODO - alphaCutOff - use default?
+
+                // TODO - transparencyMode - private or public ?
+
+                // TODO - doubleSided - use default?
+
+                // --- Textures ---
+
+                // TODO - Add alpha
+                babylonMaterial.baseTexture = ExportPBRTexture(materialNode, 1, babylonScene);
+
+                babylonMaterial.metallicRoughnessTexture = ExportMetallicRoughnessTexture(materialNode, babylonMaterial.metallic, babylonMaterial.roughness, babylonScene, name);
+
+                // TODO - environmentTexture - as simple as that?
+                babylonMaterial.environmentTexture = ExportPBRTexture(materialNode, 3, babylonScene);
+
+                var normalMapAmount = propertyContainer.GetFloatProperty(91);
+                babylonMaterial.normalTexture = ExportPBRTexture(materialNode, 30, babylonScene, normalMapAmount);
+                
+                babylonMaterial.emissiveTexture = ExportPBRTexture(materialNode, 17, babylonScene);
+                
+                // TODO - occlusionTexture - ignored?
+
+
+                babylonScene.MaterialsList.Add(babylonMaterial);
+            }
+            else
+            {
+                RaiseWarning("Unsupported material type: " + materialNode.MaterialClass, 2);
+            }
+        }
+
+        // -------------------------
+        // --------- Utils ---------
+        // -------------------------
+
+        private string ColorToString(IColor color)
+        {
+            if (color == null)
+            {
+                return "";
+            }
+
+            return "{ r=" + color.R + ", g=" + color.G + ", b=" + color.B + " }";
+        }
+
+        private string Point3ToString(IPoint3 point)
+        {
+            if (point == null)
+            {
+                return "";
+            }
+
+            return "{ x=" + point.X + ", y=" + point.Y + ", z=" + point.Z + " }";
+        }
+
+        private string Point4ToString(IPoint4 point)
+        {
+            if (point == null)
+            {
+                return "";
             }
 
-            babylonScene.MaterialsList.Add(babylonMaterial);
+            return "{ x=" + point.X + ", y=" + point.Y + ", z=" + point.Z + ", w=" + point.W + " }";
         }
     }
 }

+ 324 - 82
Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Texture.cs

@@ -3,77 +3,226 @@ using System.Collections.Generic;
 using System.IO;
 using Autodesk.Max;
 using BabylonExport.Entities;
+using System.Drawing;
 
 namespace Max2Babylon
 {
     partial class BabylonExporter
     {
-        bool IsTextureCube(string filepath)
+        // -------------------------------
+        // --- "public" export methods ---
+        // -------------------------------
+
+        private BabylonTexture ExportTexture(IStdMat2 stdMat, int index, out BabylonFresnelParameters fresnelParameters, BabylonScene babylonScene, bool allowCube = false, bool forceAlpha = false)
         {
-            try
+            fresnelParameters = null;
+
+            if (!stdMat.MapEnabled(index))
             {
-                if (Path.GetExtension(filepath).ToLower() != ".dds")
-                {
-                    return false;
-                }
+                return null;
+            }
 
-                var data = File.ReadAllBytes(filepath);
-                var intArray = new int[data.Length / 4];
+            var texMap = stdMat.GetSubTexmap(index);
 
-                Buffer.BlockCopy(data, 0, intArray, 0, intArray.Length * 4);
+            if (texMap == null)
+            {
+                RaiseWarning("Texture channel " + index + " activated but no texture found.", 2);
+                return null;
+            }
 
+            texMap = _exportFresnelParameters(texMap, out fresnelParameters);
 
-                int width = intArray[4];
-                int height = intArray[3];
-                int mipmapsCount = intArray[7];
+            var amount = stdMat.GetTexmapAmt(index, 0);
 
-                if ((width >> (mipmapsCount - 1)) > 1)
-                {
-                    var expected = 1;
-                    var currentSize = Math.Max(width, height);
+            return _exportTexture(texMap, amount, babylonScene, allowCube, forceAlpha);
+        }
 
-                    while (currentSize > 1)
-                    {
-                        currentSize = currentSize >> 1;
-                        expected++;
-                    }
+        private BabylonTexture ExportPBRTexture(IIGameMaterial materialNode, int index, BabylonScene babylonScene, float amount = 1.0f)
+        {
+            var texMap = _getTexMap(materialNode, index);
+            if (texMap != null)
+            {
+                return _exportTexture(texMap, amount, babylonScene);
+            }
+            return null;
+        }
 
-                    RaiseWarning(string.Format("Mipmaps chain is not complete: {0} maps instead of {1} (based on texture max size: {2})", mipmapsCount, expected, width), 2);
-                    RaiseWarning(string.Format("You must generate a complete mipmaps chain for .dds)"), 2);
-                    RaiseWarning(string.Format("Mipmaps will be disabled for this texture. If you want automatic texture generation you cannot use a .dds)"), 2);
-                }
+        private BabylonTexture ExportMetallicRoughnessTexture(IIGameMaterial materialNode, float metallic, float roughness, BabylonScene babylonScene, string materialName)
+        {
+            ITexmap metallicTexMap = _getTexMap(materialNode, 5);
+            ITexmap roughnessTexMap = _getTexMap(materialNode, 4);
 
-                bool isCube = (intArray[28] & 0x200) == 0x200;
+            if (metallicTexMap == null && roughnessTexMap == null)
+            {
+                return null;
+            }
 
-                return isCube;
+            // Use one as a reference for UVs parameters
+            var referenceTexMap = metallicTexMap != null ? metallicTexMap : roughnessTexMap;
+
+
+            // --- Babylon texture ---
+
+            if (referenceTexMap.GetParamBlock(0) == null || referenceTexMap.GetParamBlock(0).Owner == null)
+            {
+                return null;
             }
-            catch
+
+            var texture = referenceTexMap.GetParamBlock(0).Owner as IBitmapTex;
+
+            if (texture == null)
             {
-                return false;
+                return null;
             }
+
+            var babylonTexture = new BabylonTexture
+            {
+                name = materialName + "_metallicRoughness" + ".jpg" // TODO - unsafe name, may conflict with another texture name
+            };
+
+            // Level
+            babylonTexture.level = 1.0f;
+
+            // No alpha
+            babylonTexture.hasAlpha = false;
+            babylonTexture.getAlphaFromRGB = false;
+
+            // UVs
+            var uvGen = _exportUV(texture, babylonTexture);
+
+            // Is cube
+            _exportIsCube(texture, babylonTexture, false);
+
+
+            // --- Merge metallic and roughness maps ---
+
+            // Load bitmaps
+            var metallicBitmap = _loadTexture(metallicTexMap);
+            var roughnessBitmap = _loadTexture(roughnessTexMap);
+
+            // Retreive dimensions
+            int width = 0;
+            int height = 0;
+            var haveSameDimensions = _getMinimalBitmapDimensions(out width, out height, metallicBitmap, roughnessBitmap);
+            if (!haveSameDimensions)
+            {
+                RaiseWarning("Metallic and roughness maps should have same dimensions", 2);
+            }
+
+            // Create metallic+roughness map
+            Bitmap metallicRoughnessBitmap = new Bitmap(width, height);
+            for (int x = 0; x < width; x++)
+            {
+                for (int y = 0; y < height; y++)
+                {
+                    var _metallic = metallicBitmap != null ? metallicBitmap.GetPixel(x, y).R :
+                                    metallic * 255.0f;
+                    var _roughness = roughnessBitmap != null ? roughnessBitmap.GetPixel(x, y).R :
+                                    roughness * 255.0f;
+
+                    // The metalness values are sampled from the B channel.
+                    // The roughness values are sampled from the G channel.
+                    // These values are linear. If other channels are present (R or A), they are ignored for metallic-roughness calculations.
+                    Color colorMetallicRoughness = Color.FromArgb(
+                        0,
+                        (int)_roughness,
+                        (int)_metallic
+                    );
+                    metallicRoughnessBitmap.SetPixel(x, y, colorMetallicRoughness);
+                }
+            }
+
+            // Write bitmap
+            var absolutePath = Path.Combine(babylonScene.OutputPath, babylonTexture.name);
+            RaiseMessage($"Texture | write image '{babylonTexture.name}'", 2);
+            metallicRoughnessBitmap.Save(absolutePath);
+
+            return babylonTexture;
         }
 
-        private BabylonTexture ExportTexture(IStdMat2 stdMat, int index, out BabylonFresnelParameters fresnelParameters, BabylonScene babylonScene, bool allowCube = false, bool forceAlpha = false)
-        {
-            fresnelParameters = null;
+        // -------------------------
+        // -- Export sub methods ---
+        // -------------------------
 
-            if (!stdMat.MapEnabled(index))
+        private BabylonTexture _exportTexture(ITexmap texMap, float amount, BabylonScene babylonScene, bool allowCube = false, bool forceAlpha = false)
+        {
+            if (texMap.GetParamBlock(0) == null || texMap.GetParamBlock(0).Owner == null)
             {
                 return null;
             }
-            var babylonTexture = new BabylonTexture();
 
-            var texMap = stdMat.GetSubTexmap(index);
+            var texture = texMap.GetParamBlock(0).Owner as IBitmapTex;
 
-            if (texMap == null)
+            if (texture == null)
             {
-                RaiseWarning("Texture channel " + index + " activated but no texture found.");
                 return null;
             }
 
+            var babylonTexture = new BabylonTexture
+            {
+                name = Path.GetFileName(texture.MapName)
+            };
+
+            // Level
+            babylonTexture.level = amount;
+
+            // Alpha
+            if (forceAlpha)
+            {
+                babylonTexture.hasAlpha = true;
+                babylonTexture.getAlphaFromRGB = (texture.AlphaSource == 2) || (texture.AlphaSource == 3);
+            }
+            else
+            {
+                babylonTexture.hasAlpha = (texture.AlphaSource != 3);
+                babylonTexture.getAlphaFromRGB = (texture.AlphaSource == 2);
+            }
+
+            // UVs
+            var uvGen = _exportUV(texture, babylonTexture);
+
+            // Animations
+            var animations = new List<BabylonAnimation>();
+            ExportFloatAnimation("uOffset", animations, key => new[] { uvGen.GetUOffs(key) });
+            ExportFloatAnimation("vOffset", animations, key => new[] { -uvGen.GetVOffs(key) });
+            ExportFloatAnimation("uScale", animations, key => new[] { uvGen.GetUScl(key) });
+            ExportFloatAnimation("vScale", animations, key => new[] { uvGen.GetVScl(key) });
+            ExportFloatAnimation("uAng", animations, key => new[] { uvGen.GetUAng(key) });
+            ExportFloatAnimation("vAng", animations, key => new[] { uvGen.GetVAng(key) });
+            ExportFloatAnimation("wAng", animations, key => new[] { uvGen.GetWAng(key) });
+            babylonTexture.animations = animations.ToArray();
+
+            // Is cube
+            _exportIsCube(texture, babylonTexture, allowCube);
+
+            // Copy texture to output
+            var absolutePath = texture.Map.FullFilePath;
+            try
+            {
+                if (File.Exists(absolutePath))
+                {
+                    if (CopyTexturesToOutput)
+                    {
+                        File.Copy(absolutePath, Path.Combine(babylonScene.OutputPath, babylonTexture.name), true);
+                    }
+                }
+            }
+            catch
+            {
+                // silently fails
+            }
+
+            return babylonTexture;
+        }
+
+        private ITexmap _exportFresnelParameters(ITexmap texMap, out BabylonFresnelParameters fresnelParameters)
+        {
+            fresnelParameters = null;
+
             // Fallout
             if (texMap.ClassName == "Falloff") // This is the only way I found to detect it. This is crappy but it works
             {
+                RaiseMessage("fresnelParameters", 2);
                 fresnelParameters = new BabylonFresnelParameters();
 
                 var paramBlock = texMap.GetParamBlock(0);
@@ -119,33 +268,11 @@ namespace Max2Babylon
                 }
             }
 
-            // Bitmap
-            if (texMap.GetParamBlock(0) == null || texMap.GetParamBlock(0).Owner == null)
-            {
-                return null;
-            }
-
-            var texture = texMap.GetParamBlock(0).Owner as IBitmapTex;
-
-            if (texture == null)
-            {
-                return null;
-            }
-
-            if (forceAlpha)
-            {
-                babylonTexture.hasAlpha = true;
-                babylonTexture.getAlphaFromRGB = (texture.AlphaSource == 2) || (texture.AlphaSource == 3);
-            }
-            else
-            {
-                babylonTexture.hasAlpha = (texture.AlphaSource != 3);
-                babylonTexture.getAlphaFromRGB = (texture.AlphaSource == 2);
-            }
-
-
-            babylonTexture.level = stdMat.GetTexmapAmt(index, 0);
+            return texMap;
+        }
 
+        private IStdUVGen _exportUV(IBitmapTex texture, BabylonTexture babylonTexture)
+        {
             var uvGen = texture.UVGen;
 
             switch (uvGen.GetCoordMapping(0))
@@ -202,30 +329,18 @@ namespace Max2Babylon
                 babylonTexture.wrapV = BabylonTexture.AddressMode.MIRROR_ADDRESSMODE;
             }
 
-            babylonTexture.name = Path.GetFileName(texture.MapName);
-
-            // Animations
-            var animations = new List<BabylonAnimation>();
-            ExportFloatAnimation("uOffset", animations, key => new[] { uvGen.GetUOffs(key) });
-            ExportFloatAnimation("vOffset", animations, key => new[] { -uvGen.GetVOffs(key) });
-            ExportFloatAnimation("uScale", animations, key => new[] { uvGen.GetUScl(key) });
-            ExportFloatAnimation("vScale", animations, key => new[] { uvGen.GetVScl(key) });
-            ExportFloatAnimation("uAng", animations, key => new[] { uvGen.GetUAng(key) });
-            ExportFloatAnimation("vAng", animations, key => new[] { uvGen.GetVAng(key) });
-            ExportFloatAnimation("wAng", animations, key => new[] { uvGen.GetWAng(key) });
+            return uvGen;
+        }
 
-            babylonTexture.animations = animations.ToArray();
+        private void _exportIsCube(IBitmapTex texture, BabylonTexture babylonTexture, bool allowCube)
+        {
             var absolutePath = texture.Map.FullFilePath;
-            // Copy texture to output
+
             try
             {
                 if (File.Exists(absolutePath))
                 {
-                    babylonTexture.isCube = IsTextureCube(absolutePath);
-                    if (CopyTexturesToOutput)
-                    {
-                        File.Copy(absolutePath, Path.Combine(babylonScene.OutputPath, babylonTexture.name), true);
-                    }
+                    babylonTexture.isCube = _isTextureCube(absolutePath);
                 }
                 else
                 {
@@ -242,8 +357,135 @@ namespace Max2Babylon
             {
                 RaiseWarning(string.Format("Cube texture are only supported for reflection channel"), 2);
             }
+        }
 
-            return babylonTexture;
+        private bool _isTextureCube(string filepath)
+        {
+            try
+            {
+                if (Path.GetExtension(filepath).ToLower() != ".dds")
+                {
+                    return false;
+                }
+
+                var data = File.ReadAllBytes(filepath);
+                var intArray = new int[data.Length / 4];
+
+                Buffer.BlockCopy(data, 0, intArray, 0, intArray.Length * 4);
+
+
+                int width = intArray[4];
+                int height = intArray[3];
+                int mipmapsCount = intArray[7];
+
+                if ((width >> (mipmapsCount - 1)) > 1)
+                {
+                    var expected = 1;
+                    var currentSize = Math.Max(width, height);
+
+                    while (currentSize > 1)
+                    {
+                        currentSize = currentSize >> 1;
+                        expected++;
+                    }
+
+                    RaiseWarning(string.Format("Mipmaps chain is not complete: {0} maps instead of {1} (based on texture max size: {2})", mipmapsCount, expected, width), 2);
+                    RaiseWarning(string.Format("You must generate a complete mipmaps chain for .dds)"), 2);
+                    RaiseWarning(string.Format("Mipmaps will be disabled for this texture. If you want automatic texture generation you cannot use a .dds)"), 2);
+                }
+
+                bool isCube = (intArray[28] & 0x200) == 0x200;
+
+                return isCube;
+            }
+            catch
+            {
+                return false;
+            }
+        }
+
+        // -------------------------
+        // --------- Utils ---------
+        // -------------------------
+
+        private ITexmap _getTexMap(IIGameMaterial materialNode, int index)
+        {
+            ITexmap texMap = null;
+            if (materialNode.MaxMaterial.SubTexmapOn(index) == 1)
+            {
+                texMap = materialNode.MaxMaterial.GetSubTexmap(index);
+
+                // No warning displayed because by default, physical material in 3ds Max have all maps on
+                // Would be tedious for the user to uncheck all unused maps
+
+                //if (texMap == null)
+                //{
+                //    RaiseWarning("Texture channel " + index + " activated but no texture found.", 2);
+                //}
+            }
+            return texMap;
+        }
+
+        private bool _getMinimalBitmapDimensions(out int width, out int height, params Bitmap[] bitmaps)
+        {
+            var haveSameDimensions = true;
+
+            var bitmapsNoNull = ((new List<Bitmap>(bitmaps)).FindAll(bitmap => bitmap != null)).ToArray();
+            if (bitmapsNoNull.Length > 0)
+            {
+                // Init with first element
+                width = bitmapsNoNull[0].Width;
+                height = bitmapsNoNull[0].Height;
+
+                // Update with others
+                for (int i = 1; i < bitmapsNoNull.Length; i++)
+                {
+                    var bitmap = bitmapsNoNull[i];
+                    if (width != bitmap.Width || height != bitmap.Height)
+                    {
+                        haveSameDimensions = false;
+                    }
+                    width = Math.Min(width, bitmap.Width);
+                    height = Math.Min(height, bitmap.Height);
+                }
+            }
+            else
+            {
+                width = 0;
+                height = 0;
+            }
+
+            return haveSameDimensions;
+        }
+
+        private Bitmap LoadTexture(string absolutePath)
+        {
+            if (File.Exists(absolutePath))
+            {
+                return new Bitmap(absolutePath);
+            }
+            else
+            {
+                RaiseWarning(string.Format("Texture {0} not found.", Path.GetFileName(absolutePath), 2));
+                return null;
+            }
+        }
+
+        private Bitmap _loadTexture(ITexmap texMap)
+        {
+            if (texMap == null || texMap.GetParamBlock(0) == null || texMap.GetParamBlock(0).Owner == null)
+            {
+                return null;
+            }
+
+            var texture = texMap.GetParamBlock(0).Owner as IBitmapTex;
+
+            if (texture == null)
+            {
+                return null;
+            }
+
+            return LoadTexture(texture.Map.FullFilePath);
         }
     }
 }

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

@@ -77,7 +77,7 @@ namespace Max2Babylon
             }
         }
 
-        public async Task ExportAsync(string outputFile, bool generateManifest, bool onlySelected, bool generateBinary, bool exportGltf, Form callerForm)
+        public async Task ExportAsync(string outputFile, bool generateManifest, bool onlySelected, bool generateBinary, bool exportGltf, bool exportGltfImagesAsBinary, Form callerForm)
         {
             var gameConversionManger = Loader.Global.ConversionManager;
             gameConversionManger.CoordSystem = Autodesk.Max.IGameConversionManager.CoordSystem.D3d;
@@ -240,15 +240,6 @@ namespace Max2Babylon
                         babylonScene.fogColor = fog.GetColor(0).ToArray();
                         babylonScene.fogMode = 3;
                     }
-#if !MAX2015 && !MAX2016 && !MAX2017
-                    else
-                    {
-                        var paramBlock = atmospheric.GetReference(0) as IIParamBlock;
-
-                        babylonScene.fogColor = Tools.GetParamBlockValueColor(paramBlock, "Fog Color");
-                        babylonScene.fogMode = 3;
-                    }
-#endif
                     if (babylonMainCamera != null)
                     {
                         babylonScene.fogStart = maxMainCameraObject.GetEnvRange(0, 0, Tools.Forever);
@@ -307,7 +298,7 @@ namespace Max2Babylon
             // Export glTF
             if (exportGltf)
             {
-                ExportGltf(babylonScene, outputFile, generateBinary);
+                ExportGltf(babylonScene, outputFile, generateBinary, exportGltfImagesAsBinary);
             }
 
             watch.Stop();

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

@@ -48,6 +48,7 @@
             this.butExportAndRun = new System.Windows.Forms.Button();
             this.butClose = new System.Windows.Forms.Button();
             this.chkGltf = new System.Windows.Forms.CheckBox();
+            this.chkGltfImagesAsBinary = new System.Windows.Forms.CheckBox();
             ((System.ComponentModel.ISupportInitialize)(this.pictureBox2)).BeginInit();
             this.groupBox1.SuspendLayout();
             this.SuspendLayout();
@@ -180,6 +181,7 @@
             // 
             this.groupBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) 
             | System.Windows.Forms.AnchorStyles.Right)));
+            this.groupBox1.Controls.Add(this.chkGltfImagesAsBinary);
             this.groupBox1.Controls.Add(this.chkBinary);
             this.groupBox1.Controls.Add(this.chkOnlySelected);
             this.groupBox1.Controls.Add(this.chkAutoSave);
@@ -277,6 +279,18 @@
             this.chkGltf.UseVisualStyleBackColor = true;
             this.chkGltf.CheckedChanged += new System.EventHandler(this.chkGltf_CheckedChanged);
             // 
+            // chkGltfImageAsBinary
+            // 
+            this.chkGltfImagesAsBinary.AutoSize = true;
+            this.chkGltfImagesAsBinary.FlatStyle = System.Windows.Forms.FlatStyle.Flat;
+            this.chkGltfImagesAsBinary.Location = new System.Drawing.Point(166, 127);
+            this.chkGltfImagesAsBinary.Name = "chkGltfImagesAsBinary";
+            this.chkGltfImagesAsBinary.Size = new System.Drawing.Size(158, 17);
+            this.chkGltfImagesAsBinary.TabIndex = 18;
+            this.chkGltfImagesAsBinary.Text = "Export glTF images as binary";
+            this.chkGltfImagesAsBinary.UseVisualStyleBackColor = true;
+            this.chkGltfImagesAsBinary.CheckedChanged += new System.EventHandler(this.checkGltfImagesAsBinary_CheckedChanged);
+            // 
             // ExporterForm
             // 
             this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@@ -330,5 +344,6 @@
         private System.Windows.Forms.Button butClose;
         private System.Windows.Forms.CheckBox chkBinary;
         private System.Windows.Forms.CheckBox chkGltf;
+        private System.Windows.Forms.CheckBox chkGltfImagesAsBinary;
     }
 }

+ 8 - 1
Exporters/3ds Max/Max2Babylon/Forms/ExporterForm.cs

@@ -33,6 +33,7 @@ namespace Max2Babylon
             Tools.PrepareCheckBox(chkOnlySelected, Loader.Core.RootNode, "babylonjs_onlySelected");
             Tools.PrepareCheckBox(chkBinary, Loader.Core.RootNode, "babylonjs_binary");
             Tools.PrepareCheckBox(chkGltf, Loader.Core.RootNode, "babylonjs_exportGltf");
+            Tools.PrepareCheckBox(chkGltfImagesAsBinary, Loader.Core.RootNode, "babylonjs_exportGltfImagesAsBinary");
         }
 
         private void butBrowse_Click(object sender, EventArgs e)
@@ -57,6 +58,7 @@ namespace Max2Babylon
             Tools.UpdateCheckBox(chkOnlySelected, Loader.Core.RootNode, "babylonjs_onlySelected");
             Tools.UpdateCheckBox(chkBinary, Loader.Core.RootNode, "babylonjs_binary");
             Tools.UpdateCheckBox(chkGltf, Loader.Core.RootNode, "babylonjs_exportGltf");
+            Tools.UpdateCheckBox(chkGltfImagesAsBinary, Loader.Core.RootNode, "babylonjs_exportGltfImagesAsBinary");
 
             Loader.Core.RootNode.SetLocalData(txtFilename.Text);
 
@@ -123,7 +125,7 @@ namespace Max2Babylon
                 exporter.AutoSave3dsMaxFile = chkAutoSave.Checked;
                 exporter.ExportHiddenObjects = chkHidden.Checked;
                 exporter.CopyTexturesToOutput = chkCopyTextures.Checked;
-                await exporter.ExportAsync(txtFilename.Text, chkManifest.Checked, chkOnlySelected.Checked, chkBinary.Checked, chkGltf.Checked, this);
+                await exporter.ExportAsync(txtFilename.Text, chkManifest.Checked, chkOnlySelected.Checked, chkBinary.Checked, chkGltf.Checked, chkGltfImagesAsBinary.Checked, this);
             }
             catch (OperationCanceledException)
             {
@@ -232,5 +234,10 @@ namespace Max2Babylon
         {
 
         }
+
+        private void checkGltfImagesAsBinary_CheckedChanged(object sender, EventArgs e)
+        {
+
+        }
     }
 }

+ 47 - 116
Exporters/3ds Max/Max2Babylon/Tools/Tools.cs

@@ -13,13 +13,55 @@ namespace Max2Babylon
 {
     public static class Tools
     {
+        // -------------------------
+        // -- IIPropertyContainer --
+        // -------------------------
+
+        public static string GetStringProperty(this IIPropertyContainer propertyContainer, int indexProperty)
+        {
+            string value = "";
+            propertyContainer.GetProperty(indexProperty).GetPropertyValue(ref value, 0);
+            return value;
+        }
+
+        public static int GetIntProperty(this IIPropertyContainer propertyContainer, int indexProperty)
+        {
+            int value = 0;
+            propertyContainer.GetProperty(indexProperty).GetPropertyValue(ref value, 0);
+            return value;
+        }
+
+        public static bool GetBoolProperty(this IIPropertyContainer propertyContainer, int indexProperty)
+        {
+            return propertyContainer.GetIntProperty(indexProperty) == 1;
+        }
+
+        public static float GetFloatProperty(this IIPropertyContainer propertyContainer, int indexProperty)
+        {
+            float value = 0.0f;
+            propertyContainer.GetProperty(indexProperty).GetPropertyValue(ref value, 0, true);
+            return value;
+        }
+
+        public static IPoint3 GetPoint3Property(this IIPropertyContainer propertyContainer, int indexProperty)
+        {
+            IPoint3 value = Loader.Global.Point3.Create(0, 0, 0);
+            propertyContainer.GetProperty(indexProperty).GetPropertyValue(value, 0);
+            return value;
+        }
+
+        public static IPoint4 GetPoint4Property(this IIPropertyContainer propertyContainer, int indexProperty)
+        {
+            IPoint4 value = Loader.Global.Point4.Create(0, 0, 0, 0);
+            propertyContainer.GetProperty(indexProperty).GetPropertyValue(value, 0);
+            return value;
+        }
+
+        // -------------------------
+
         public static IntPtr GetNativeHandle(this INativeObject obj)
         {
-#if MAX2015 || MAX2016 || MAX2017
             return obj.NativePointer;
-#else
-            return obj.Handle;
-#endif
 
         }
         static Assembly GetWrappersAssembly()
@@ -76,59 +118,7 @@ namespace Max2Babylon
         }
 
         public static IMatrix3 Identity { get { return Loader.Global.Matrix3.Create(XAxis, YAxis, ZAxis, Origin); } }
-
-#if !MAX2015 && !MAX2016 && !MAX2017
-        unsafe public static int GetParamBlockIndex(IIParamBlock paramBlock, string name)
-        {
-            for (short index = 0; index < paramBlock.NumParams; index++)
-            {
-                IGetParamName gpn = Loader.Global.GetParamName.Create("", index);
-
-                paramBlock.NotifyDependents(Tools.Forever, (UIntPtr)gpn.Handle.ToPointer(), RefMessage.GetParamName, (SClass_ID)0xfffffff0, false, null);
-
-                if (gpn.Name == name)
-                {
-                    return index;
-                }
-            }
-
-            return -1;
-        }
-
-
-        public static int GetParamBlockValueInt(IIParamBlock paramBlock, string name)
-        {
-            var index = Tools.GetParamBlockIndex(paramBlock, name);
-
-            if (index == -1)
-            {
-                return 0;
-            }
-            return paramBlock.GetInt(index, 0);
-        }
-
-        public static float GetParamBlockValueFloat(IIParamBlock paramBlock, string name)
-        {
-            var index = Tools.GetParamBlockIndex(paramBlock, name);
-
-            if (index == -1)
-            {
-                return 0;
-            }
-            return paramBlock.GetFloat(index, 0);
-        }
-
-        public static float[] GetParamBlockValueColor(IIParamBlock paramBlock, string name)
-        {
-            var index = Tools.GetParamBlockIndex(paramBlock, name);
-
-            if (index == -1)
-            {
-                return null;
-            }
-            return paramBlock.GetColor(index, 0).ToArray();
-        }
-#endif
+        
         public static Vector3 ToEulerAngles(this IQuat q)
         {
             // Store the Euler angles in radians
@@ -561,46 +551,27 @@ namespace Max2Babylon
         public static void SetStringProperty(this IINode node, string propertyName, string defaultState)
         {
             string state = defaultState;
-#if MAX2015 || MAX2016 || MAX2017
             node.SetUserPropString(propertyName, state);
-#else
-            node.SetUserPropString(ref propertyName, ref state);
-#endif
         }
 
         public static bool GetBoolProperty(this IINode node, string propertyName, int defaultState = 0)
         {
             int state = defaultState;
-#if MAX2015 || MAX2016 || MAX2017
             node.GetUserPropBool(propertyName, ref state);
-#else
-            node.GetUserPropBool(ref propertyName, ref state);
-#endif
-
             return state == 1;
         }
 
         public static string GetStringProperty(this IINode node, string propertyName, string defaultState)
         {
             string state = defaultState;
-#if MAX2015 || MAX2016 || MAX2017
             node.GetUserPropString(propertyName, ref state);
-#else
-            node.GetUserPropString(ref propertyName, ref state);
-#endif
-
             return state;
         }
 
         public static float GetFloatProperty(this IINode node, string propertyName, float defaultState = 0)
         {
             float state = defaultState;
-#if MAX2015 || MAX2016 || MAX2017
             node.GetUserPropFloat(propertyName, ref state);
-#else
-            node.GetUserPropFloat(ref propertyName, ref state);
-#endif
-
             return state;
         }
 
@@ -608,28 +579,16 @@ namespace Max2Babylon
         {
             float state0 = 0;
             string name = propertyName + "_x";
-#if MAX2015 || MAX2016 || MAX2017
             node.GetUserPropFloat(name, ref state0);
-#else
-            node.GetUserPropFloat(ref name, ref state0);
-#endif
 
 
             float state1 = 0;
             name = propertyName + "_y";
-#if MAX2015 || MAX2016 || MAX2017
             node.GetUserPropFloat(name, ref state1);
-#else
-            node.GetUserPropFloat(ref name, ref state1);
-#endif
 
             float state2 = 0;
             name = propertyName + "_z";
-#if MAX2015 || MAX2016 || MAX2017
             node.GetUserPropFloat(name, ref state2);
-#else
-            node.GetUserPropFloat(ref name, ref state2);
-#endif
 
             return new[] { state0, state1, state2 };
         }
@@ -690,11 +649,7 @@ namespace Max2Babylon
         {
             if (checkBox.CheckState != CheckState.Indeterminate)
             {
-#if MAX2015 || MAX2016 || MAX2017
                 node.SetUserPropBool(propertyName, checkBox.CheckState == CheckState.Checked);
-#else
-                node.SetUserPropBool(ref propertyName, checkBox.CheckState == CheckState.Checked);
-#endif
             }
         }
 
@@ -711,11 +666,7 @@ namespace Max2Babylon
             foreach (var node in nodes)
             {
                 var value = textBox.Text;
-#if MAX2015 || MAX2016 || MAX2017
                 node.SetUserPropString(propertyName, value);
-#else
-                node.SetUserPropString(ref propertyName, ref value);
-#endif
             }
         }
 
@@ -728,11 +679,7 @@ namespace Max2Babylon
         {
             foreach (var node in nodes)
             {
-#if MAX2015 || MAX2016 || MAX2017
                 node.SetUserPropFloat(propertyName, (float)nup.Value);
-#else
-                node.SetUserPropFloat(ref propertyName, (float)nup.Value);
-#endif
             }
         }
 
@@ -746,25 +693,13 @@ namespace Max2Babylon
         public static void UpdateVector3Control(Vector3Control vector3Control, IINode node, string propertyName)
         {
             string name = propertyName + "_x";
-#if MAX2015 || MAX2016 || MAX2017
             node.SetUserPropFloat(name, vector3Control.X);
-#else
-            node.SetUserPropFloat(ref name, vector3Control.X);
-#endif
 
             name = propertyName + "_y";
-#if MAX2015 || MAX2016 || MAX2017
             node.SetUserPropFloat(name, vector3Control.Y);
-#else
-            node.SetUserPropFloat(ref name, vector3Control.Y);
-#endif
 
             name = propertyName + "_z";
-#if MAX2015 || MAX2016 || MAX2017
             node.SetUserPropFloat(name, vector3Control.Z);
-#else
-            node.SetUserPropFloat(ref name, vector3Control.Z);
-#endif
         }
 
         public static void UpdateVector3Control(Vector3Control vector3Control, List<IINode> nodes, string propertyName)
@@ -778,11 +713,7 @@ namespace Max2Babylon
         public static void UpdateComboBox(ComboBox comboBox, IINode node, string propertyName)
         {
             var value = comboBox.SelectedItem.ToString();
-#if MAX2015 || MAX2016 || MAX2017
             node.SetUserPropString(propertyName, value);
-#else
-            node.SetUserPropString(ref propertyName, ref value);
-#endif
         }
 
         public static void UpdateComboBox(ComboBox comboBox, List<IINode> nodes, string propertyName)

+ 2 - 2
Playground/frame.html

@@ -69,7 +69,7 @@
 </head>
 
 <body>
-    <canvas touch-action="none" id="renderCanvas"></canvas>
+    <canvas touch-action="none" id="renderCanvas" tabindex="1"></canvas>
 
     <span class="label" id="fpsLabel">FPS</span>
 
@@ -77,7 +77,7 @@
     <a class="link" id="link" href="#" target="_blank">Edit</a>
 
     <script src="https://code.jquery.com/jquery.js"></script>
-    <script src="/js/frame.js"></script>
+    <script src="js/frame.js"></script>
 </body>
 
 </html>

+ 0 - 1
Playground/js/frame.js

@@ -50,7 +50,6 @@
 
             var canvas = document.getElementById("renderCanvas");
             engine = new BABYLON.Engine(canvas, true, {stencil: true});
-            engine.renderEvenInBackground = false;
             BABYLON.Camera.ForceAttachControlToAlwaysPreventDefault = true;
 
             engine.runRenderLoop(function () {

Plik diff jest za duży
+ 7880 - 7860
dist/preview release/babylon.d.ts


Plik diff jest za duży
+ 21 - 21
dist/preview release/babylon.js


Plik diff jest za duży
+ 162 - 32
dist/preview release/babylon.max.js


Plik diff jest za duży
+ 7880 - 7860
dist/preview release/babylon.module.d.ts


Plik diff jest za duży
+ 21 - 21
dist/preview release/babylon.worker.js


+ 449 - 429
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts

@@ -3533,249 +3533,6 @@ declare module BABYLON {
 }
 
 declare module BABYLON {
-    class Collider {
-        radius: Vector3;
-        retry: number;
-        velocity: Vector3;
-        basePoint: Vector3;
-        epsilon: number;
-        collisionFound: boolean;
-        velocityWorldLength: number;
-        basePointWorld: Vector3;
-        velocityWorld: Vector3;
-        normalizedVelocity: Vector3;
-        initialVelocity: Vector3;
-        initialPosition: Vector3;
-        nearestDistance: number;
-        intersectionPoint: Vector3;
-        collidedMesh: AbstractMesh;
-        private _collisionPoint;
-        private _planeIntersectionPoint;
-        private _tempVector;
-        private _tempVector2;
-        private _tempVector3;
-        private _tempVector4;
-        private _edge;
-        private _baseToVertex;
-        private _destinationPoint;
-        private _slidePlaneNormal;
-        private _displacementVector;
-        private _collisionMask;
-        collisionMask: number;
-        _initialize(source: Vector3, dir: Vector3, e: number): void;
-        _checkPointInTriangle(point: Vector3, pa: Vector3, pb: Vector3, pc: Vector3, n: Vector3): boolean;
-        _canDoCollision(sphereCenter: Vector3, sphereRadius: number, vecMin: Vector3, vecMax: Vector3): boolean;
-        _testTriangle(faceIndex: number, trianglePlaneArray: Array<Plane>, p1: Vector3, p2: Vector3, p3: Vector3, hasMaterial: boolean): void;
-        _collide(trianglePlaneArray: Array<Plane>, pts: Vector3[], indices: IndicesArray, indexStart: number, indexEnd: number, decal: number, hasMaterial: boolean): void;
-        _getResponse(pos: Vector3, vel: Vector3): void;
-    }
-}
-
-declare module BABYLON {
-    var CollisionWorker: string;
-    interface ICollisionCoordinator {
-        getNewPosition(position: Vector3, displacement: Vector3, collider: Collider, maximumRetry: number, excludedMesh: AbstractMesh, onNewPosition: (collisionIndex: number, newPosition: Vector3, collidedMesh?: AbstractMesh) => void, collisionIndex: number): void;
-        init(scene: Scene): void;
-        destroy(): void;
-        onMeshAdded(mesh: AbstractMesh): any;
-        onMeshUpdated(mesh: AbstractMesh): any;
-        onMeshRemoved(mesh: AbstractMesh): any;
-        onGeometryAdded(geometry: Geometry): any;
-        onGeometryUpdated(geometry: Geometry): any;
-        onGeometryDeleted(geometry: Geometry): any;
-    }
-    interface SerializedMesh {
-        id: string;
-        name: string;
-        uniqueId: number;
-        geometryId: string;
-        sphereCenter: Array<number>;
-        sphereRadius: number;
-        boxMinimum: Array<number>;
-        boxMaximum: Array<number>;
-        worldMatrixFromCache: any;
-        subMeshes: Array<SerializedSubMesh>;
-        checkCollisions: boolean;
-    }
-    interface SerializedSubMesh {
-        position: number;
-        verticesStart: number;
-        verticesCount: number;
-        indexStart: number;
-        indexCount: number;
-        hasMaterial: boolean;
-        sphereCenter: Array<number>;
-        sphereRadius: number;
-        boxMinimum: Array<number>;
-        boxMaximum: Array<number>;
-    }
-    interface SerializedGeometry {
-        id: string;
-        positions: Float32Array;
-        indices: Uint32Array;
-        normals: Float32Array;
-    }
-    interface BabylonMessage {
-        taskType: WorkerTaskType;
-        payload: InitPayload | CollidePayload | UpdatePayload;
-    }
-    interface SerializedColliderToWorker {
-        position: Array<number>;
-        velocity: Array<number>;
-        radius: Array<number>;
-    }
-    enum WorkerTaskType {
-        INIT = 0,
-        UPDATE = 1,
-        COLLIDE = 2,
-    }
-    interface WorkerReply {
-        error: WorkerReplyType;
-        taskType: WorkerTaskType;
-        payload?: any;
-    }
-    interface CollisionReplyPayload {
-        newPosition: Array<number>;
-        collisionId: number;
-        collidedMeshUniqueId: number;
-    }
-    interface InitPayload {
-    }
-    interface CollidePayload {
-        collisionId: number;
-        collider: SerializedColliderToWorker;
-        maximumRetry: number;
-        excludedMeshUniqueId?: number;
-    }
-    interface UpdatePayload {
-        updatedMeshes: {
-            [n: number]: SerializedMesh;
-        };
-        updatedGeometries: {
-            [s: string]: SerializedGeometry;
-        };
-        removedMeshes: Array<number>;
-        removedGeometries: Array<string>;
-    }
-    enum WorkerReplyType {
-        SUCCESS = 0,
-        UNKNOWN_ERROR = 1,
-    }
-    class CollisionCoordinatorWorker implements ICollisionCoordinator {
-        private _scene;
-        private _scaledPosition;
-        private _scaledVelocity;
-        private _collisionsCallbackArray;
-        private _init;
-        private _runningUpdated;
-        private _runningCollisionTask;
-        private _worker;
-        private _addUpdateMeshesList;
-        private _addUpdateGeometriesList;
-        private _toRemoveMeshesArray;
-        private _toRemoveGeometryArray;
-        constructor();
-        static SerializeMesh: (mesh: AbstractMesh) => SerializedMesh;
-        static SerializeGeometry: (geometry: Geometry) => SerializedGeometry;
-        getNewPosition(position: Vector3, displacement: Vector3, collider: Collider, maximumRetry: number, excludedMesh: AbstractMesh, onNewPosition: (collisionIndex: number, newPosition: Vector3, collidedMesh?: AbstractMesh) => void, collisionIndex: number): void;
-        init(scene: Scene): void;
-        destroy(): void;
-        onMeshAdded(mesh: AbstractMesh): void;
-        onMeshUpdated: (mesh: AbstractMesh) => void;
-        onMeshRemoved(mesh: AbstractMesh): void;
-        onGeometryAdded(geometry: Geometry): void;
-        onGeometryUpdated: (geometry: Geometry) => void;
-        onGeometryDeleted(geometry: Geometry): void;
-        private _afterRender;
-        private _onMessageFromWorker;
-    }
-    class CollisionCoordinatorLegacy implements ICollisionCoordinator {
-        private _scene;
-        private _scaledPosition;
-        private _scaledVelocity;
-        private _finalPosition;
-        getNewPosition(position: Vector3, displacement: Vector3, collider: Collider, maximumRetry: number, excludedMesh: AbstractMesh, onNewPosition: (collisionIndex: number, newPosition: Vector3, collidedMesh?: AbstractMesh) => void, collisionIndex: number): void;
-        init(scene: Scene): void;
-        destroy(): void;
-        onMeshAdded(mesh: AbstractMesh): void;
-        onMeshUpdated(mesh: AbstractMesh): void;
-        onMeshRemoved(mesh: AbstractMesh): void;
-        onGeometryAdded(geometry: Geometry): void;
-        onGeometryUpdated(geometry: Geometry): void;
-        onGeometryDeleted(geometry: Geometry): void;
-        private _collideWithWorld(position, velocity, collider, maximumRetry, finalPosition, excludedMesh?);
-    }
-}
-
-declare module BABYLON {
-    var WorkerIncluded: boolean;
-    class CollisionCache {
-        private _meshes;
-        private _geometries;
-        getMeshes(): {
-            [n: number]: SerializedMesh;
-        };
-        getGeometries(): {
-            [s: number]: SerializedGeometry;
-        };
-        getMesh(id: any): SerializedMesh;
-        addMesh(mesh: SerializedMesh): void;
-        removeMesh(uniqueId: number): void;
-        getGeometry(id: string): SerializedGeometry;
-        addGeometry(geometry: SerializedGeometry): void;
-        removeGeometry(id: string): void;
-    }
-    class CollideWorker {
-        collider: Collider;
-        private _collisionCache;
-        private finalPosition;
-        private collisionsScalingMatrix;
-        private collisionTranformationMatrix;
-        constructor(collider: Collider, _collisionCache: CollisionCache, finalPosition: Vector3);
-        collideWithWorld(position: Vector3, velocity: Vector3, maximumRetry: number, excludedMeshUniqueId?: number): void;
-        private checkCollision(mesh);
-        private processCollisionsForSubMeshes(transformMatrix, mesh);
-        private collideForSubMesh(subMesh, transformMatrix, meshGeometry);
-        private checkSubmeshCollision(subMesh);
-    }
-    interface ICollisionDetector {
-        onInit(payload: InitPayload): void;
-        onUpdate(payload: UpdatePayload): void;
-        onCollision(payload: CollidePayload): void;
-    }
-    class CollisionDetectorTransferable implements ICollisionDetector {
-        private _collisionCache;
-        onInit(payload: InitPayload): void;
-        onUpdate(payload: UpdatePayload): void;
-        onCollision(payload: CollidePayload): void;
-    }
-}
-
-declare module BABYLON {
-    class IntersectionInfo {
-        bu: number;
-        bv: number;
-        distance: number;
-        faceId: number;
-        subMeshId: number;
-        constructor(bu: number, bv: number, distance: number);
-    }
-    class PickingInfo {
-        hit: boolean;
-        distance: number;
-        pickedPoint: Vector3;
-        pickedMesh: AbstractMesh;
-        bu: number;
-        bv: number;
-        faceId: number;
-        subMeshId: number;
-        pickedSprite: Sprite;
-        getNormal(useWorldCoordinates?: boolean, useVerticesNormals?: boolean): Vector3;
-        getTextureCoordinates(): Vector2;
-    }
-}
-
-declare module BABYLON {
     class ArcRotateCamera extends TargetCamera {
         alpha: number;
         beta: number;
@@ -4282,21 +4039,392 @@ declare module BABYLON {
         getClassName(): string;
         _setupInputs(): void;
     }
-}
-
-declare module BABYLON {
-    class UniversalCamera extends TouchCamera {
-        gamepadAngularSensibility: number;
-        gamepadMoveSensibility: number;
-        constructor(name: string, position: Vector3, scene: Scene);
-        getClassName(): string;
+}
+
+declare module BABYLON {
+    class UniversalCamera extends TouchCamera {
+        gamepadAngularSensibility: number;
+        gamepadMoveSensibility: number;
+        constructor(name: string, position: Vector3, scene: Scene);
+        getClassName(): string;
+    }
+}
+
+declare module BABYLON {
+    class VirtualJoysticksCamera extends FreeCamera {
+        constructor(name: string, position: Vector3, scene: Scene);
+        getClassName(): string;
+    }
+}
+
+declare module BABYLON.Debug {
+    class AxesViewer {
+        private _xline;
+        private _yline;
+        private _zline;
+        private _xmesh;
+        private _ymesh;
+        private _zmesh;
+        scene: Scene;
+        scaleLines: number;
+        constructor(scene: Scene, scaleLines?: number);
+        update(position: Vector3, xaxis: Vector3, yaxis: Vector3, zaxis: Vector3): void;
+        dispose(): void;
+    }
+}
+
+declare module BABYLON.Debug {
+    class BoneAxesViewer extends Debug.AxesViewer {
+        mesh: Mesh;
+        bone: Bone;
+        pos: Vector3;
+        xaxis: Vector3;
+        yaxis: Vector3;
+        zaxis: Vector3;
+        constructor(scene: Scene, bone: Bone, mesh: Mesh, scaleLines?: number);
+        update(): void;
+        dispose(): void;
+    }
+}
+
+declare module BABYLON {
+    class DebugLayer {
+        private _scene;
+        static InspectorURL: string;
+        private _inspector;
+        constructor(scene: Scene);
+        /** Creates the inspector window. */
+        private _createInspector(config?);
+        isVisible(): boolean;
+        hide(): void;
+        show(config?: {
+            popup?: boolean;
+            initialTab?: number;
+            parentElement?: HTMLElement;
+            newColors?: {
+                backgroundColor?: string;
+                backgroundColorLighter?: string;
+                backgroundColorLighter2?: string;
+                backgroundColorLighter3?: string;
+                color?: string;
+                colorTop?: string;
+                colorBot?: string;
+            };
+        }): void;
+    }
+}
+
+declare module BABYLON.Debug {
+    class PhysicsViewer {
+        protected _impostors: Array<PhysicsImpostor>;
+        protected _meshes: Array<AbstractMesh>;
+        protected _scene: Scene;
+        protected _numMeshes: number;
+        protected _physicsEnginePlugin: IPhysicsEnginePlugin;
+        private _renderFunction;
+        private _debugBoxMesh;
+        private _debugSphereMesh;
+        private _debugMaterial;
+        constructor(scene: Scene);
+        protected _updateDebugMeshes(): void;
+        showImpostor(impostor: PhysicsImpostor): void;
+        hideImpostor(impostor: PhysicsImpostor): void;
+        private _getDebugMaterial(scene);
+        private _getDebugBoxMesh(scene);
+        private _getDebugSphereMesh(scene);
+        private _getDebugMesh(impostor, scene);
+        dispose(): void;
+    }
+}
+
+declare module BABYLON {
+    class RayHelper {
+        ray: Ray;
+        private _renderPoints;
+        private _renderLine;
+        private _renderFunction;
+        private _scene;
+        private _updateToMeshFunction;
+        private _attachedToMesh;
+        private _meshSpaceDirection;
+        private _meshSpaceOrigin;
+        static CreateAndShow(ray: Ray, scene: Scene, color: Color3): RayHelper;
+        constructor(ray: Ray);
+        show(scene: Scene, color: Color3): void;
+        hide(): void;
+        private _render();
+        attachToMesh(mesh: AbstractMesh, meshSpaceDirection?: Vector3, meshSpaceOrigin?: Vector3, length?: number): void;
+        detachFromMesh(): void;
+        private _updateToMesh();
+        dispose(): void;
+    }
+}
+
+declare module BABYLON.Debug {
+    /**
+    * Demo available here: http://www.babylonjs-playground.com/#1BZJVJ#8
+    */
+    class SkeletonViewer {
+        skeleton: Skeleton;
+        mesh: AbstractMesh;
+        autoUpdateBonesMatrices: boolean;
+        renderingGroupId: number;
+        color: Color3;
+        private _scene;
+        private _debugLines;
+        private _debugMesh;
+        private _isEnabled;
+        private _renderFunction;
+        constructor(skeleton: Skeleton, mesh: AbstractMesh, scene: Scene, autoUpdateBonesMatrices?: boolean, renderingGroupId?: number);
+        isEnabled: boolean;
+        private _getBonePosition(position, bone, meshMat, x?, y?, z?);
+        private _getLinesForBonesWithLength(bones, meshMat);
+        private _getLinesForBonesNoLength(bones, meshMat);
+        update(): void;
+        dispose(): void;
+    }
+}
+
+declare module BABYLON {
+    class Collider {
+        radius: Vector3;
+        retry: number;
+        velocity: Vector3;
+        basePoint: Vector3;
+        epsilon: number;
+        collisionFound: boolean;
+        velocityWorldLength: number;
+        basePointWorld: Vector3;
+        velocityWorld: Vector3;
+        normalizedVelocity: Vector3;
+        initialVelocity: Vector3;
+        initialPosition: Vector3;
+        nearestDistance: number;
+        intersectionPoint: Vector3;
+        collidedMesh: AbstractMesh;
+        private _collisionPoint;
+        private _planeIntersectionPoint;
+        private _tempVector;
+        private _tempVector2;
+        private _tempVector3;
+        private _tempVector4;
+        private _edge;
+        private _baseToVertex;
+        private _destinationPoint;
+        private _slidePlaneNormal;
+        private _displacementVector;
+        private _collisionMask;
+        collisionMask: number;
+        _initialize(source: Vector3, dir: Vector3, e: number): void;
+        _checkPointInTriangle(point: Vector3, pa: Vector3, pb: Vector3, pc: Vector3, n: Vector3): boolean;
+        _canDoCollision(sphereCenter: Vector3, sphereRadius: number, vecMin: Vector3, vecMax: Vector3): boolean;
+        _testTriangle(faceIndex: number, trianglePlaneArray: Array<Plane>, p1: Vector3, p2: Vector3, p3: Vector3, hasMaterial: boolean): void;
+        _collide(trianglePlaneArray: Array<Plane>, pts: Vector3[], indices: IndicesArray, indexStart: number, indexEnd: number, decal: number, hasMaterial: boolean): void;
+        _getResponse(pos: Vector3, vel: Vector3): void;
+    }
+}
+
+declare module BABYLON {
+    var CollisionWorker: string;
+    interface ICollisionCoordinator {
+        getNewPosition(position: Vector3, displacement: Vector3, collider: Collider, maximumRetry: number, excludedMesh: AbstractMesh, onNewPosition: (collisionIndex: number, newPosition: Vector3, collidedMesh?: AbstractMesh) => void, collisionIndex: number): void;
+        init(scene: Scene): void;
+        destroy(): void;
+        onMeshAdded(mesh: AbstractMesh): any;
+        onMeshUpdated(mesh: AbstractMesh): any;
+        onMeshRemoved(mesh: AbstractMesh): any;
+        onGeometryAdded(geometry: Geometry): any;
+        onGeometryUpdated(geometry: Geometry): any;
+        onGeometryDeleted(geometry: Geometry): any;
+    }
+    interface SerializedMesh {
+        id: string;
+        name: string;
+        uniqueId: number;
+        geometryId: string;
+        sphereCenter: Array<number>;
+        sphereRadius: number;
+        boxMinimum: Array<number>;
+        boxMaximum: Array<number>;
+        worldMatrixFromCache: any;
+        subMeshes: Array<SerializedSubMesh>;
+        checkCollisions: boolean;
+    }
+    interface SerializedSubMesh {
+        position: number;
+        verticesStart: number;
+        verticesCount: number;
+        indexStart: number;
+        indexCount: number;
+        hasMaterial: boolean;
+        sphereCenter: Array<number>;
+        sphereRadius: number;
+        boxMinimum: Array<number>;
+        boxMaximum: Array<number>;
+    }
+    interface SerializedGeometry {
+        id: string;
+        positions: Float32Array;
+        indices: Uint32Array;
+        normals: Float32Array;
+    }
+    interface BabylonMessage {
+        taskType: WorkerTaskType;
+        payload: InitPayload | CollidePayload | UpdatePayload;
+    }
+    interface SerializedColliderToWorker {
+        position: Array<number>;
+        velocity: Array<number>;
+        radius: Array<number>;
+    }
+    enum WorkerTaskType {
+        INIT = 0,
+        UPDATE = 1,
+        COLLIDE = 2,
+    }
+    interface WorkerReply {
+        error: WorkerReplyType;
+        taskType: WorkerTaskType;
+        payload?: any;
+    }
+    interface CollisionReplyPayload {
+        newPosition: Array<number>;
+        collisionId: number;
+        collidedMeshUniqueId: number;
+    }
+    interface InitPayload {
+    }
+    interface CollidePayload {
+        collisionId: number;
+        collider: SerializedColliderToWorker;
+        maximumRetry: number;
+        excludedMeshUniqueId?: number;
+    }
+    interface UpdatePayload {
+        updatedMeshes: {
+            [n: number]: SerializedMesh;
+        };
+        updatedGeometries: {
+            [s: string]: SerializedGeometry;
+        };
+        removedMeshes: Array<number>;
+        removedGeometries: Array<string>;
+    }
+    enum WorkerReplyType {
+        SUCCESS = 0,
+        UNKNOWN_ERROR = 1,
+    }
+    class CollisionCoordinatorWorker implements ICollisionCoordinator {
+        private _scene;
+        private _scaledPosition;
+        private _scaledVelocity;
+        private _collisionsCallbackArray;
+        private _init;
+        private _runningUpdated;
+        private _runningCollisionTask;
+        private _worker;
+        private _addUpdateMeshesList;
+        private _addUpdateGeometriesList;
+        private _toRemoveMeshesArray;
+        private _toRemoveGeometryArray;
+        constructor();
+        static SerializeMesh: (mesh: AbstractMesh) => SerializedMesh;
+        static SerializeGeometry: (geometry: Geometry) => SerializedGeometry;
+        getNewPosition(position: Vector3, displacement: Vector3, collider: Collider, maximumRetry: number, excludedMesh: AbstractMesh, onNewPosition: (collisionIndex: number, newPosition: Vector3, collidedMesh?: AbstractMesh) => void, collisionIndex: number): void;
+        init(scene: Scene): void;
+        destroy(): void;
+        onMeshAdded(mesh: AbstractMesh): void;
+        onMeshUpdated: (mesh: AbstractMesh) => void;
+        onMeshRemoved(mesh: AbstractMesh): void;
+        onGeometryAdded(geometry: Geometry): void;
+        onGeometryUpdated: (geometry: Geometry) => void;
+        onGeometryDeleted(geometry: Geometry): void;
+        private _afterRender;
+        private _onMessageFromWorker;
+    }
+    class CollisionCoordinatorLegacy implements ICollisionCoordinator {
+        private _scene;
+        private _scaledPosition;
+        private _scaledVelocity;
+        private _finalPosition;
+        getNewPosition(position: Vector3, displacement: Vector3, collider: Collider, maximumRetry: number, excludedMesh: AbstractMesh, onNewPosition: (collisionIndex: number, newPosition: Vector3, collidedMesh?: AbstractMesh) => void, collisionIndex: number): void;
+        init(scene: Scene): void;
+        destroy(): void;
+        onMeshAdded(mesh: AbstractMesh): void;
+        onMeshUpdated(mesh: AbstractMesh): void;
+        onMeshRemoved(mesh: AbstractMesh): void;
+        onGeometryAdded(geometry: Geometry): void;
+        onGeometryUpdated(geometry: Geometry): void;
+        onGeometryDeleted(geometry: Geometry): void;
+        private _collideWithWorld(position, velocity, collider, maximumRetry, finalPosition, excludedMesh?);
+    }
+}
+
+declare module BABYLON {
+    var WorkerIncluded: boolean;
+    class CollisionCache {
+        private _meshes;
+        private _geometries;
+        getMeshes(): {
+            [n: number]: SerializedMesh;
+        };
+        getGeometries(): {
+            [s: number]: SerializedGeometry;
+        };
+        getMesh(id: any): SerializedMesh;
+        addMesh(mesh: SerializedMesh): void;
+        removeMesh(uniqueId: number): void;
+        getGeometry(id: string): SerializedGeometry;
+        addGeometry(geometry: SerializedGeometry): void;
+        removeGeometry(id: string): void;
+    }
+    class CollideWorker {
+        collider: Collider;
+        private _collisionCache;
+        private finalPosition;
+        private collisionsScalingMatrix;
+        private collisionTranformationMatrix;
+        constructor(collider: Collider, _collisionCache: CollisionCache, finalPosition: Vector3);
+        collideWithWorld(position: Vector3, velocity: Vector3, maximumRetry: number, excludedMeshUniqueId?: number): void;
+        private checkCollision(mesh);
+        private processCollisionsForSubMeshes(transformMatrix, mesh);
+        private collideForSubMesh(subMesh, transformMatrix, meshGeometry);
+        private checkSubmeshCollision(subMesh);
+    }
+    interface ICollisionDetector {
+        onInit(payload: InitPayload): void;
+        onUpdate(payload: UpdatePayload): void;
+        onCollision(payload: CollidePayload): void;
+    }
+    class CollisionDetectorTransferable implements ICollisionDetector {
+        private _collisionCache;
+        onInit(payload: InitPayload): void;
+        onUpdate(payload: UpdatePayload): void;
+        onCollision(payload: CollidePayload): void;
     }
 }
 
 declare module BABYLON {
-    class VirtualJoysticksCamera extends FreeCamera {
-        constructor(name: string, position: Vector3, scene: Scene);
-        getClassName(): string;
+    class IntersectionInfo {
+        bu: number;
+        bv: number;
+        distance: number;
+        faceId: number;
+        subMeshId: number;
+        constructor(bu: number, bv: number, distance: number);
+    }
+    class PickingInfo {
+        hit: boolean;
+        distance: number;
+        pickedPoint: Vector3;
+        pickedMesh: AbstractMesh;
+        bu: number;
+        bv: number;
+        faceId: number;
+        subMeshId: number;
+        pickedSprite: Sprite;
+        getNormal(useWorldCoordinates?: boolean, useVerticesNormals?: boolean): Vector3;
+        getTextureCoordinates(): Vector2;
     }
 }
 
@@ -4481,134 +4609,6 @@ declare module BABYLON {
     }
 }
 
-declare module BABYLON.Debug {
-    class AxesViewer {
-        private _xline;
-        private _yline;
-        private _zline;
-        private _xmesh;
-        private _ymesh;
-        private _zmesh;
-        scene: Scene;
-        scaleLines: number;
-        constructor(scene: Scene, scaleLines?: number);
-        update(position: Vector3, xaxis: Vector3, yaxis: Vector3, zaxis: Vector3): void;
-        dispose(): void;
-    }
-}
-
-declare module BABYLON.Debug {
-    class BoneAxesViewer extends Debug.AxesViewer {
-        mesh: Mesh;
-        bone: Bone;
-        pos: Vector3;
-        xaxis: Vector3;
-        yaxis: Vector3;
-        zaxis: Vector3;
-        constructor(scene: Scene, bone: Bone, mesh: Mesh, scaleLines?: number);
-        update(): void;
-        dispose(): void;
-    }
-}
-
-declare module BABYLON {
-    class DebugLayer {
-        private _scene;
-        static InspectorURL: string;
-        private _inspector;
-        constructor(scene: Scene);
-        /** Creates the inspector window. */
-        private _createInspector(config?);
-        isVisible(): boolean;
-        hide(): void;
-        show(config?: {
-            popup?: boolean;
-            initialTab?: number;
-            parentElement?: HTMLElement;
-            newColors?: {
-                backgroundColor?: string;
-                backgroundColorLighter?: string;
-                backgroundColorLighter2?: string;
-                backgroundColorLighter3?: string;
-                color?: string;
-                colorTop?: string;
-                colorBot?: string;
-            };
-        }): void;
-    }
-}
-
-declare module BABYLON.Debug {
-    class PhysicsViewer {
-        protected _impostors: Array<PhysicsImpostor>;
-        protected _meshes: Array<AbstractMesh>;
-        protected _scene: Scene;
-        protected _numMeshes: number;
-        protected _physicsEnginePlugin: IPhysicsEnginePlugin;
-        private _renderFunction;
-        private _debugBoxMesh;
-        private _debugSphereMesh;
-        private _debugMaterial;
-        constructor(scene: Scene);
-        protected _updateDebugMeshes(): void;
-        showImpostor(impostor: PhysicsImpostor): void;
-        hideImpostor(impostor: PhysicsImpostor): void;
-        private _getDebugMaterial(scene);
-        private _getDebugBoxMesh(scene);
-        private _getDebugSphereMesh(scene);
-        private _getDebugMesh(impostor, scene);
-        dispose(): void;
-    }
-}
-
-declare module BABYLON {
-    class RayHelper {
-        ray: Ray;
-        private _renderPoints;
-        private _renderLine;
-        private _renderFunction;
-        private _scene;
-        private _updateToMeshFunction;
-        private _attachedToMesh;
-        private _meshSpaceDirection;
-        private _meshSpaceOrigin;
-        static CreateAndShow(ray: Ray, scene: Scene, color: Color3): RayHelper;
-        constructor(ray: Ray);
-        show(scene: Scene, color: Color3): void;
-        hide(): void;
-        private _render();
-        attachToMesh(mesh: AbstractMesh, meshSpaceDirection?: Vector3, meshSpaceOrigin?: Vector3, length?: number): void;
-        detachFromMesh(): void;
-        private _updateToMesh();
-        dispose(): void;
-    }
-}
-
-declare module BABYLON.Debug {
-    /**
-    * Demo available here: http://www.babylonjs-playground.com/#1BZJVJ#8
-    */
-    class SkeletonViewer {
-        skeleton: Skeleton;
-        mesh: AbstractMesh;
-        autoUpdateBonesMatrices: boolean;
-        renderingGroupId: number;
-        color: Color3;
-        private _scene;
-        private _debugLines;
-        private _debugMesh;
-        private _isEnabled;
-        private _renderFunction;
-        constructor(skeleton: Skeleton, mesh: AbstractMesh, scene: Scene, autoUpdateBonesMatrices?: boolean, renderingGroupId?: number);
-        isEnabled: boolean;
-        private _getBonePosition(position, bone, meshMat, x?, y?, z?);
-        private _getLinesForBonesWithLength(bones, meshMat);
-        private _getLinesForBonesNoLength(bones, meshMat);
-        update(): void;
-        dispose(): void;
-    }
-}
-
 declare module BABYLON {
     class StickValues {
         x: any;
@@ -5016,6 +5016,51 @@ declare module BABYLON {
 }
 
 declare module BABYLON {
+    class LensFlare {
+        size: number;
+        position: number;
+        color: Color3;
+        texture: Texture;
+        alphaMode: number;
+        private _system;
+        constructor(size: number, position: number, color: any, imgUrl: string, system: LensFlareSystem);
+        dispose: () => void;
+    }
+}
+
+declare module BABYLON {
+    class LensFlareSystem {
+        name: string;
+        lensFlares: LensFlare[];
+        borderLimit: number;
+        viewportBorder: number;
+        meshesSelectionPredicate: (mesh: Mesh) => boolean;
+        layerMask: number;
+        id: string;
+        private _scene;
+        private _emitter;
+        private _vertexBuffers;
+        private _indexBuffer;
+        private _effect;
+        private _positionX;
+        private _positionY;
+        private _isEnabled;
+        constructor(name: string, emitter: any, scene: Scene);
+        isEnabled: boolean;
+        getScene(): Scene;
+        getEmitter(): any;
+        setEmitter(newEmitter: any): void;
+        getEmitterPosition(): Vector3;
+        computeEffectivePosition(globalViewport: Viewport): boolean;
+        _isVisible(): boolean;
+        render(): boolean;
+        dispose(): void;
+        static Parse(parsedLensFlareSystem: any, scene: Scene, rootUrl: string): LensFlareSystem;
+        serialize(): any;
+    }
+}
+
+declare module BABYLON {
     class DirectionalLight extends ShadowLight {
         private _shadowFrustumSize;
         /**
@@ -5549,51 +5594,6 @@ declare module BABYLON {
 }
 
 declare module BABYLON {
-    class LensFlare {
-        size: number;
-        position: number;
-        color: Color3;
-        texture: Texture;
-        alphaMode: number;
-        private _system;
-        constructor(size: number, position: number, color: any, imgUrl: string, system: LensFlareSystem);
-        dispose: () => void;
-    }
-}
-
-declare module BABYLON {
-    class LensFlareSystem {
-        name: string;
-        lensFlares: LensFlare[];
-        borderLimit: number;
-        viewportBorder: number;
-        meshesSelectionPredicate: (mesh: Mesh) => boolean;
-        layerMask: number;
-        id: string;
-        private _scene;
-        private _emitter;
-        private _vertexBuffers;
-        private _indexBuffer;
-        private _effect;
-        private _positionX;
-        private _positionY;
-        private _isEnabled;
-        constructor(name: string, emitter: any, scene: Scene);
-        isEnabled: boolean;
-        getScene(): Scene;
-        getEmitter(): any;
-        setEmitter(newEmitter: any): void;
-        getEmitterPosition(): Vector3;
-        computeEffectivePosition(globalViewport: Viewport): boolean;
-        _isVisible(): boolean;
-        render(): boolean;
-        dispose(): void;
-        static Parse(parsedLensFlareSystem: any, scene: Scene, rootUrl: string): LensFlareSystem;
-        serialize(): any;
-    }
-}
-
-declare module BABYLON {
     interface ILoadingScreen {
         displayLoadingUI: () => void;
         hideLoadingUI: () => void;
@@ -12750,6 +12750,7 @@ declare module BABYLON {
 
 declare module BABYLON {
     class Particle {
+        private particleSystem;
         position: Vector3;
         direction: Vector3;
         color: Color4;
@@ -12759,6 +12760,12 @@ declare module BABYLON {
         size: number;
         angle: number;
         angularSpeed: number;
+        private _currentFrameCounter;
+        cellIndex: number;
+        constructor(particleSystem: ParticleSystem);
+        updateCellIndex: (scaledUpdateSpeed: number) => void;
+        private updateCellIndexWithSpeedCalculated(scaledUpdateSpeed);
+        private updateCellIndexWithCustomSpeed();
         copyTo(other: Particle): void;
     }
 }
@@ -12780,6 +12787,7 @@ declare module BABYLON {
     }
     class ParticleSystem implements IDisposable, IAnimatable, IParticleSystem {
         name: string;
+        private _isAnimationSheetEnabled;
         static BLENDMODE_ONEONE: number;
         static BLENDMODE_STANDARD: number;
         animations: Animation[];
@@ -12803,6 +12811,7 @@ declare module BABYLON {
         layerMask: number;
         customShader: any;
         preventAutoStart: boolean;
+        private _epsilon;
         /**
         * An event triggered when the system is disposed.
         * @type {BABYLON.Observable}
@@ -12847,7 +12856,15 @@ declare module BABYLON {
         private _stopped;
         private _actualFrame;
         private _scaledUpdateSpeed;
-        constructor(name: string, capacity: number, scene: Scene, customEffect?: Effect);
+        startSpriteCellID: number;
+        endSpriteCellID: number;
+        spriteCellLoop: boolean;
+        spriteCellChangeSpeed: number;
+        spriteCellWidth: number;
+        spriteCellHeight: number;
+        private _vertexBufferSize;
+        readonly isAnimationSheetEnabled: Boolean;
+        constructor(name: string, capacity: number, scene: Scene, customEffect?: Effect, _isAnimationSheetEnabled?: boolean, epsilon?: number);
         private _createIndexBuffer();
         recycleParticle(particle: Particle): void;
         getCapacity(): number;
@@ -12856,9 +12873,13 @@ declare module BABYLON {
         start(): void;
         stop(): void;
         _appendParticleVertex(index: number, particle: Particle, offsetX: number, offsetY: number): void;
+        _appendParticleVertexWithAnimation(index: number, particle: Particle, offsetX: number, offsetY: number): void;
         private _update(newParticles);
         private _getEffect();
         animate(): void;
+        appendParticleVertexes: (offset: number, particle: Particle) => void;
+        private appenedParticleVertexesWithSheet(offset, particle);
+        private appenedParticleVertexesNoSheet(offset, particle);
         rebuild(): void;
         render(): number;
         dispose(): void;
@@ -13032,7 +13053,6 @@ declare module BABYLON {
         private _cosPitch;
         private _sinYaw;
         private _cosYaw;
-        private _w;
         private _mustUnrotateFixedNormals;
         private _minimum;
         private _maximum;

Plik diff jest za duży
+ 23 - 23
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js


Plik diff jest za duży
+ 162 - 32
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js


+ 449 - 429
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.module.d.ts

@@ -3533,249 +3533,6 @@ declare module BABYLON {
 }
 
 declare module BABYLON {
-    class Collider {
-        radius: Vector3;
-        retry: number;
-        velocity: Vector3;
-        basePoint: Vector3;
-        epsilon: number;
-        collisionFound: boolean;
-        velocityWorldLength: number;
-        basePointWorld: Vector3;
-        velocityWorld: Vector3;
-        normalizedVelocity: Vector3;
-        initialVelocity: Vector3;
-        initialPosition: Vector3;
-        nearestDistance: number;
-        intersectionPoint: Vector3;
-        collidedMesh: AbstractMesh;
-        private _collisionPoint;
-        private _planeIntersectionPoint;
-        private _tempVector;
-        private _tempVector2;
-        private _tempVector3;
-        private _tempVector4;
-        private _edge;
-        private _baseToVertex;
-        private _destinationPoint;
-        private _slidePlaneNormal;
-        private _displacementVector;
-        private _collisionMask;
-        collisionMask: number;
-        _initialize(source: Vector3, dir: Vector3, e: number): void;
-        _checkPointInTriangle(point: Vector3, pa: Vector3, pb: Vector3, pc: Vector3, n: Vector3): boolean;
-        _canDoCollision(sphereCenter: Vector3, sphereRadius: number, vecMin: Vector3, vecMax: Vector3): boolean;
-        _testTriangle(faceIndex: number, trianglePlaneArray: Array<Plane>, p1: Vector3, p2: Vector3, p3: Vector3, hasMaterial: boolean): void;
-        _collide(trianglePlaneArray: Array<Plane>, pts: Vector3[], indices: IndicesArray, indexStart: number, indexEnd: number, decal: number, hasMaterial: boolean): void;
-        _getResponse(pos: Vector3, vel: Vector3): void;
-    }
-}
-
-declare module BABYLON {
-    var CollisionWorker: string;
-    interface ICollisionCoordinator {
-        getNewPosition(position: Vector3, displacement: Vector3, collider: Collider, maximumRetry: number, excludedMesh: AbstractMesh, onNewPosition: (collisionIndex: number, newPosition: Vector3, collidedMesh?: AbstractMesh) => void, collisionIndex: number): void;
-        init(scene: Scene): void;
-        destroy(): void;
-        onMeshAdded(mesh: AbstractMesh): any;
-        onMeshUpdated(mesh: AbstractMesh): any;
-        onMeshRemoved(mesh: AbstractMesh): any;
-        onGeometryAdded(geometry: Geometry): any;
-        onGeometryUpdated(geometry: Geometry): any;
-        onGeometryDeleted(geometry: Geometry): any;
-    }
-    interface SerializedMesh {
-        id: string;
-        name: string;
-        uniqueId: number;
-        geometryId: string;
-        sphereCenter: Array<number>;
-        sphereRadius: number;
-        boxMinimum: Array<number>;
-        boxMaximum: Array<number>;
-        worldMatrixFromCache: any;
-        subMeshes: Array<SerializedSubMesh>;
-        checkCollisions: boolean;
-    }
-    interface SerializedSubMesh {
-        position: number;
-        verticesStart: number;
-        verticesCount: number;
-        indexStart: number;
-        indexCount: number;
-        hasMaterial: boolean;
-        sphereCenter: Array<number>;
-        sphereRadius: number;
-        boxMinimum: Array<number>;
-        boxMaximum: Array<number>;
-    }
-    interface SerializedGeometry {
-        id: string;
-        positions: Float32Array;
-        indices: Uint32Array;
-        normals: Float32Array;
-    }
-    interface BabylonMessage {
-        taskType: WorkerTaskType;
-        payload: InitPayload | CollidePayload | UpdatePayload;
-    }
-    interface SerializedColliderToWorker {
-        position: Array<number>;
-        velocity: Array<number>;
-        radius: Array<number>;
-    }
-    enum WorkerTaskType {
-        INIT = 0,
-        UPDATE = 1,
-        COLLIDE = 2,
-    }
-    interface WorkerReply {
-        error: WorkerReplyType;
-        taskType: WorkerTaskType;
-        payload?: any;
-    }
-    interface CollisionReplyPayload {
-        newPosition: Array<number>;
-        collisionId: number;
-        collidedMeshUniqueId: number;
-    }
-    interface InitPayload {
-    }
-    interface CollidePayload {
-        collisionId: number;
-        collider: SerializedColliderToWorker;
-        maximumRetry: number;
-        excludedMeshUniqueId?: number;
-    }
-    interface UpdatePayload {
-        updatedMeshes: {
-            [n: number]: SerializedMesh;
-        };
-        updatedGeometries: {
-            [s: string]: SerializedGeometry;
-        };
-        removedMeshes: Array<number>;
-        removedGeometries: Array<string>;
-    }
-    enum WorkerReplyType {
-        SUCCESS = 0,
-        UNKNOWN_ERROR = 1,
-    }
-    class CollisionCoordinatorWorker implements ICollisionCoordinator {
-        private _scene;
-        private _scaledPosition;
-        private _scaledVelocity;
-        private _collisionsCallbackArray;
-        private _init;
-        private _runningUpdated;
-        private _runningCollisionTask;
-        private _worker;
-        private _addUpdateMeshesList;
-        private _addUpdateGeometriesList;
-        private _toRemoveMeshesArray;
-        private _toRemoveGeometryArray;
-        constructor();
-        static SerializeMesh: (mesh: AbstractMesh) => SerializedMesh;
-        static SerializeGeometry: (geometry: Geometry) => SerializedGeometry;
-        getNewPosition(position: Vector3, displacement: Vector3, collider: Collider, maximumRetry: number, excludedMesh: AbstractMesh, onNewPosition: (collisionIndex: number, newPosition: Vector3, collidedMesh?: AbstractMesh) => void, collisionIndex: number): void;
-        init(scene: Scene): void;
-        destroy(): void;
-        onMeshAdded(mesh: AbstractMesh): void;
-        onMeshUpdated: (mesh: AbstractMesh) => void;
-        onMeshRemoved(mesh: AbstractMesh): void;
-        onGeometryAdded(geometry: Geometry): void;
-        onGeometryUpdated: (geometry: Geometry) => void;
-        onGeometryDeleted(geometry: Geometry): void;
-        private _afterRender;
-        private _onMessageFromWorker;
-    }
-    class CollisionCoordinatorLegacy implements ICollisionCoordinator {
-        private _scene;
-        private _scaledPosition;
-        private _scaledVelocity;
-        private _finalPosition;
-        getNewPosition(position: Vector3, displacement: Vector3, collider: Collider, maximumRetry: number, excludedMesh: AbstractMesh, onNewPosition: (collisionIndex: number, newPosition: Vector3, collidedMesh?: AbstractMesh) => void, collisionIndex: number): void;
-        init(scene: Scene): void;
-        destroy(): void;
-        onMeshAdded(mesh: AbstractMesh): void;
-        onMeshUpdated(mesh: AbstractMesh): void;
-        onMeshRemoved(mesh: AbstractMesh): void;
-        onGeometryAdded(geometry: Geometry): void;
-        onGeometryUpdated(geometry: Geometry): void;
-        onGeometryDeleted(geometry: Geometry): void;
-        private _collideWithWorld(position, velocity, collider, maximumRetry, finalPosition, excludedMesh?);
-    }
-}
-
-declare module BABYLON {
-    var WorkerIncluded: boolean;
-    class CollisionCache {
-        private _meshes;
-        private _geometries;
-        getMeshes(): {
-            [n: number]: SerializedMesh;
-        };
-        getGeometries(): {
-            [s: number]: SerializedGeometry;
-        };
-        getMesh(id: any): SerializedMesh;
-        addMesh(mesh: SerializedMesh): void;
-        removeMesh(uniqueId: number): void;
-        getGeometry(id: string): SerializedGeometry;
-        addGeometry(geometry: SerializedGeometry): void;
-        removeGeometry(id: string): void;
-    }
-    class CollideWorker {
-        collider: Collider;
-        private _collisionCache;
-        private finalPosition;
-        private collisionsScalingMatrix;
-        private collisionTranformationMatrix;
-        constructor(collider: Collider, _collisionCache: CollisionCache, finalPosition: Vector3);
-        collideWithWorld(position: Vector3, velocity: Vector3, maximumRetry: number, excludedMeshUniqueId?: number): void;
-        private checkCollision(mesh);
-        private processCollisionsForSubMeshes(transformMatrix, mesh);
-        private collideForSubMesh(subMesh, transformMatrix, meshGeometry);
-        private checkSubmeshCollision(subMesh);
-    }
-    interface ICollisionDetector {
-        onInit(payload: InitPayload): void;
-        onUpdate(payload: UpdatePayload): void;
-        onCollision(payload: CollidePayload): void;
-    }
-    class CollisionDetectorTransferable implements ICollisionDetector {
-        private _collisionCache;
-        onInit(payload: InitPayload): void;
-        onUpdate(payload: UpdatePayload): void;
-        onCollision(payload: CollidePayload): void;
-    }
-}
-
-declare module BABYLON {
-    class IntersectionInfo {
-        bu: number;
-        bv: number;
-        distance: number;
-        faceId: number;
-        subMeshId: number;
-        constructor(bu: number, bv: number, distance: number);
-    }
-    class PickingInfo {
-        hit: boolean;
-        distance: number;
-        pickedPoint: Vector3;
-        pickedMesh: AbstractMesh;
-        bu: number;
-        bv: number;
-        faceId: number;
-        subMeshId: number;
-        pickedSprite: Sprite;
-        getNormal(useWorldCoordinates?: boolean, useVerticesNormals?: boolean): Vector3;
-        getTextureCoordinates(): Vector2;
-    }
-}
-
-declare module BABYLON {
     class ArcRotateCamera extends TargetCamera {
         alpha: number;
         beta: number;
@@ -4282,21 +4039,392 @@ declare module BABYLON {
         getClassName(): string;
         _setupInputs(): void;
     }
-}
-
-declare module BABYLON {
-    class UniversalCamera extends TouchCamera {
-        gamepadAngularSensibility: number;
-        gamepadMoveSensibility: number;
-        constructor(name: string, position: Vector3, scene: Scene);
-        getClassName(): string;
+}
+
+declare module BABYLON {
+    class UniversalCamera extends TouchCamera {
+        gamepadAngularSensibility: number;
+        gamepadMoveSensibility: number;
+        constructor(name: string, position: Vector3, scene: Scene);
+        getClassName(): string;
+    }
+}
+
+declare module BABYLON {
+    class VirtualJoysticksCamera extends FreeCamera {
+        constructor(name: string, position: Vector3, scene: Scene);
+        getClassName(): string;
+    }
+}
+
+declare module BABYLON.Debug {
+    class AxesViewer {
+        private _xline;
+        private _yline;
+        private _zline;
+        private _xmesh;
+        private _ymesh;
+        private _zmesh;
+        scene: Scene;
+        scaleLines: number;
+        constructor(scene: Scene, scaleLines?: number);
+        update(position: Vector3, xaxis: Vector3, yaxis: Vector3, zaxis: Vector3): void;
+        dispose(): void;
+    }
+}
+
+declare module BABYLON.Debug {
+    class BoneAxesViewer extends Debug.AxesViewer {
+        mesh: Mesh;
+        bone: Bone;
+        pos: Vector3;
+        xaxis: Vector3;
+        yaxis: Vector3;
+        zaxis: Vector3;
+        constructor(scene: Scene, bone: Bone, mesh: Mesh, scaleLines?: number);
+        update(): void;
+        dispose(): void;
+    }
+}
+
+declare module BABYLON {
+    class DebugLayer {
+        private _scene;
+        static InspectorURL: string;
+        private _inspector;
+        constructor(scene: Scene);
+        /** Creates the inspector window. */
+        private _createInspector(config?);
+        isVisible(): boolean;
+        hide(): void;
+        show(config?: {
+            popup?: boolean;
+            initialTab?: number;
+            parentElement?: HTMLElement;
+            newColors?: {
+                backgroundColor?: string;
+                backgroundColorLighter?: string;
+                backgroundColorLighter2?: string;
+                backgroundColorLighter3?: string;
+                color?: string;
+                colorTop?: string;
+                colorBot?: string;
+            };
+        }): void;
+    }
+}
+
+declare module BABYLON.Debug {
+    class PhysicsViewer {
+        protected _impostors: Array<PhysicsImpostor>;
+        protected _meshes: Array<AbstractMesh>;
+        protected _scene: Scene;
+        protected _numMeshes: number;
+        protected _physicsEnginePlugin: IPhysicsEnginePlugin;
+        private _renderFunction;
+        private _debugBoxMesh;
+        private _debugSphereMesh;
+        private _debugMaterial;
+        constructor(scene: Scene);
+        protected _updateDebugMeshes(): void;
+        showImpostor(impostor: PhysicsImpostor): void;
+        hideImpostor(impostor: PhysicsImpostor): void;
+        private _getDebugMaterial(scene);
+        private _getDebugBoxMesh(scene);
+        private _getDebugSphereMesh(scene);
+        private _getDebugMesh(impostor, scene);
+        dispose(): void;
+    }
+}
+
+declare module BABYLON {
+    class RayHelper {
+        ray: Ray;
+        private _renderPoints;
+        private _renderLine;
+        private _renderFunction;
+        private _scene;
+        private _updateToMeshFunction;
+        private _attachedToMesh;
+        private _meshSpaceDirection;
+        private _meshSpaceOrigin;
+        static CreateAndShow(ray: Ray, scene: Scene, color: Color3): RayHelper;
+        constructor(ray: Ray);
+        show(scene: Scene, color: Color3): void;
+        hide(): void;
+        private _render();
+        attachToMesh(mesh: AbstractMesh, meshSpaceDirection?: Vector3, meshSpaceOrigin?: Vector3, length?: number): void;
+        detachFromMesh(): void;
+        private _updateToMesh();
+        dispose(): void;
+    }
+}
+
+declare module BABYLON.Debug {
+    /**
+    * Demo available here: http://www.babylonjs-playground.com/#1BZJVJ#8
+    */
+    class SkeletonViewer {
+        skeleton: Skeleton;
+        mesh: AbstractMesh;
+        autoUpdateBonesMatrices: boolean;
+        renderingGroupId: number;
+        color: Color3;
+        private _scene;
+        private _debugLines;
+        private _debugMesh;
+        private _isEnabled;
+        private _renderFunction;
+        constructor(skeleton: Skeleton, mesh: AbstractMesh, scene: Scene, autoUpdateBonesMatrices?: boolean, renderingGroupId?: number);
+        isEnabled: boolean;
+        private _getBonePosition(position, bone, meshMat, x?, y?, z?);
+        private _getLinesForBonesWithLength(bones, meshMat);
+        private _getLinesForBonesNoLength(bones, meshMat);
+        update(): void;
+        dispose(): void;
+    }
+}
+
+declare module BABYLON {
+    class Collider {
+        radius: Vector3;
+        retry: number;
+        velocity: Vector3;
+        basePoint: Vector3;
+        epsilon: number;
+        collisionFound: boolean;
+        velocityWorldLength: number;
+        basePointWorld: Vector3;
+        velocityWorld: Vector3;
+        normalizedVelocity: Vector3;
+        initialVelocity: Vector3;
+        initialPosition: Vector3;
+        nearestDistance: number;
+        intersectionPoint: Vector3;
+        collidedMesh: AbstractMesh;
+        private _collisionPoint;
+        private _planeIntersectionPoint;
+        private _tempVector;
+        private _tempVector2;
+        private _tempVector3;
+        private _tempVector4;
+        private _edge;
+        private _baseToVertex;
+        private _destinationPoint;
+        private _slidePlaneNormal;
+        private _displacementVector;
+        private _collisionMask;
+        collisionMask: number;
+        _initialize(source: Vector3, dir: Vector3, e: number): void;
+        _checkPointInTriangle(point: Vector3, pa: Vector3, pb: Vector3, pc: Vector3, n: Vector3): boolean;
+        _canDoCollision(sphereCenter: Vector3, sphereRadius: number, vecMin: Vector3, vecMax: Vector3): boolean;
+        _testTriangle(faceIndex: number, trianglePlaneArray: Array<Plane>, p1: Vector3, p2: Vector3, p3: Vector3, hasMaterial: boolean): void;
+        _collide(trianglePlaneArray: Array<Plane>, pts: Vector3[], indices: IndicesArray, indexStart: number, indexEnd: number, decal: number, hasMaterial: boolean): void;
+        _getResponse(pos: Vector3, vel: Vector3): void;
+    }
+}
+
+declare module BABYLON {
+    var CollisionWorker: string;
+    interface ICollisionCoordinator {
+        getNewPosition(position: Vector3, displacement: Vector3, collider: Collider, maximumRetry: number, excludedMesh: AbstractMesh, onNewPosition: (collisionIndex: number, newPosition: Vector3, collidedMesh?: AbstractMesh) => void, collisionIndex: number): void;
+        init(scene: Scene): void;
+        destroy(): void;
+        onMeshAdded(mesh: AbstractMesh): any;
+        onMeshUpdated(mesh: AbstractMesh): any;
+        onMeshRemoved(mesh: AbstractMesh): any;
+        onGeometryAdded(geometry: Geometry): any;
+        onGeometryUpdated(geometry: Geometry): any;
+        onGeometryDeleted(geometry: Geometry): any;
+    }
+    interface SerializedMesh {
+        id: string;
+        name: string;
+        uniqueId: number;
+        geometryId: string;
+        sphereCenter: Array<number>;
+        sphereRadius: number;
+        boxMinimum: Array<number>;
+        boxMaximum: Array<number>;
+        worldMatrixFromCache: any;
+        subMeshes: Array<SerializedSubMesh>;
+        checkCollisions: boolean;
+    }
+    interface SerializedSubMesh {
+        position: number;
+        verticesStart: number;
+        verticesCount: number;
+        indexStart: number;
+        indexCount: number;
+        hasMaterial: boolean;
+        sphereCenter: Array<number>;
+        sphereRadius: number;
+        boxMinimum: Array<number>;
+        boxMaximum: Array<number>;
+    }
+    interface SerializedGeometry {
+        id: string;
+        positions: Float32Array;
+        indices: Uint32Array;
+        normals: Float32Array;
+    }
+    interface BabylonMessage {
+        taskType: WorkerTaskType;
+        payload: InitPayload | CollidePayload | UpdatePayload;
+    }
+    interface SerializedColliderToWorker {
+        position: Array<number>;
+        velocity: Array<number>;
+        radius: Array<number>;
+    }
+    enum WorkerTaskType {
+        INIT = 0,
+        UPDATE = 1,
+        COLLIDE = 2,
+    }
+    interface WorkerReply {
+        error: WorkerReplyType;
+        taskType: WorkerTaskType;
+        payload?: any;
+    }
+    interface CollisionReplyPayload {
+        newPosition: Array<number>;
+        collisionId: number;
+        collidedMeshUniqueId: number;
+    }
+    interface InitPayload {
+    }
+    interface CollidePayload {
+        collisionId: number;
+        collider: SerializedColliderToWorker;
+        maximumRetry: number;
+        excludedMeshUniqueId?: number;
+    }
+    interface UpdatePayload {
+        updatedMeshes: {
+            [n: number]: SerializedMesh;
+        };
+        updatedGeometries: {
+            [s: string]: SerializedGeometry;
+        };
+        removedMeshes: Array<number>;
+        removedGeometries: Array<string>;
+    }
+    enum WorkerReplyType {
+        SUCCESS = 0,
+        UNKNOWN_ERROR = 1,
+    }
+    class CollisionCoordinatorWorker implements ICollisionCoordinator {
+        private _scene;
+        private _scaledPosition;
+        private _scaledVelocity;
+        private _collisionsCallbackArray;
+        private _init;
+        private _runningUpdated;
+        private _runningCollisionTask;
+        private _worker;
+        private _addUpdateMeshesList;
+        private _addUpdateGeometriesList;
+        private _toRemoveMeshesArray;
+        private _toRemoveGeometryArray;
+        constructor();
+        static SerializeMesh: (mesh: AbstractMesh) => SerializedMesh;
+        static SerializeGeometry: (geometry: Geometry) => SerializedGeometry;
+        getNewPosition(position: Vector3, displacement: Vector3, collider: Collider, maximumRetry: number, excludedMesh: AbstractMesh, onNewPosition: (collisionIndex: number, newPosition: Vector3, collidedMesh?: AbstractMesh) => void, collisionIndex: number): void;
+        init(scene: Scene): void;
+        destroy(): void;
+        onMeshAdded(mesh: AbstractMesh): void;
+        onMeshUpdated: (mesh: AbstractMesh) => void;
+        onMeshRemoved(mesh: AbstractMesh): void;
+        onGeometryAdded(geometry: Geometry): void;
+        onGeometryUpdated: (geometry: Geometry) => void;
+        onGeometryDeleted(geometry: Geometry): void;
+        private _afterRender;
+        private _onMessageFromWorker;
+    }
+    class CollisionCoordinatorLegacy implements ICollisionCoordinator {
+        private _scene;
+        private _scaledPosition;
+        private _scaledVelocity;
+        private _finalPosition;
+        getNewPosition(position: Vector3, displacement: Vector3, collider: Collider, maximumRetry: number, excludedMesh: AbstractMesh, onNewPosition: (collisionIndex: number, newPosition: Vector3, collidedMesh?: AbstractMesh) => void, collisionIndex: number): void;
+        init(scene: Scene): void;
+        destroy(): void;
+        onMeshAdded(mesh: AbstractMesh): void;
+        onMeshUpdated(mesh: AbstractMesh): void;
+        onMeshRemoved(mesh: AbstractMesh): void;
+        onGeometryAdded(geometry: Geometry): void;
+        onGeometryUpdated(geometry: Geometry): void;
+        onGeometryDeleted(geometry: Geometry): void;
+        private _collideWithWorld(position, velocity, collider, maximumRetry, finalPosition, excludedMesh?);
+    }
+}
+
+declare module BABYLON {
+    var WorkerIncluded: boolean;
+    class CollisionCache {
+        private _meshes;
+        private _geometries;
+        getMeshes(): {
+            [n: number]: SerializedMesh;
+        };
+        getGeometries(): {
+            [s: number]: SerializedGeometry;
+        };
+        getMesh(id: any): SerializedMesh;
+        addMesh(mesh: SerializedMesh): void;
+        removeMesh(uniqueId: number): void;
+        getGeometry(id: string): SerializedGeometry;
+        addGeometry(geometry: SerializedGeometry): void;
+        removeGeometry(id: string): void;
+    }
+    class CollideWorker {
+        collider: Collider;
+        private _collisionCache;
+        private finalPosition;
+        private collisionsScalingMatrix;
+        private collisionTranformationMatrix;
+        constructor(collider: Collider, _collisionCache: CollisionCache, finalPosition: Vector3);
+        collideWithWorld(position: Vector3, velocity: Vector3, maximumRetry: number, excludedMeshUniqueId?: number): void;
+        private checkCollision(mesh);
+        private processCollisionsForSubMeshes(transformMatrix, mesh);
+        private collideForSubMesh(subMesh, transformMatrix, meshGeometry);
+        private checkSubmeshCollision(subMesh);
+    }
+    interface ICollisionDetector {
+        onInit(payload: InitPayload): void;
+        onUpdate(payload: UpdatePayload): void;
+        onCollision(payload: CollidePayload): void;
+    }
+    class CollisionDetectorTransferable implements ICollisionDetector {
+        private _collisionCache;
+        onInit(payload: InitPayload): void;
+        onUpdate(payload: UpdatePayload): void;
+        onCollision(payload: CollidePayload): void;
     }
 }
 
 declare module BABYLON {
-    class VirtualJoysticksCamera extends FreeCamera {
-        constructor(name: string, position: Vector3, scene: Scene);
-        getClassName(): string;
+    class IntersectionInfo {
+        bu: number;
+        bv: number;
+        distance: number;
+        faceId: number;
+        subMeshId: number;
+        constructor(bu: number, bv: number, distance: number);
+    }
+    class PickingInfo {
+        hit: boolean;
+        distance: number;
+        pickedPoint: Vector3;
+        pickedMesh: AbstractMesh;
+        bu: number;
+        bv: number;
+        faceId: number;
+        subMeshId: number;
+        pickedSprite: Sprite;
+        getNormal(useWorldCoordinates?: boolean, useVerticesNormals?: boolean): Vector3;
+        getTextureCoordinates(): Vector2;
     }
 }
 
@@ -4481,134 +4609,6 @@ declare module BABYLON {
     }
 }
 
-declare module BABYLON.Debug {
-    class AxesViewer {
-        private _xline;
-        private _yline;
-        private _zline;
-        private _xmesh;
-        private _ymesh;
-        private _zmesh;
-        scene: Scene;
-        scaleLines: number;
-        constructor(scene: Scene, scaleLines?: number);
-        update(position: Vector3, xaxis: Vector3, yaxis: Vector3, zaxis: Vector3): void;
-        dispose(): void;
-    }
-}
-
-declare module BABYLON.Debug {
-    class BoneAxesViewer extends Debug.AxesViewer {
-        mesh: Mesh;
-        bone: Bone;
-        pos: Vector3;
-        xaxis: Vector3;
-        yaxis: Vector3;
-        zaxis: Vector3;
-        constructor(scene: Scene, bone: Bone, mesh: Mesh, scaleLines?: number);
-        update(): void;
-        dispose(): void;
-    }
-}
-
-declare module BABYLON {
-    class DebugLayer {
-        private _scene;
-        static InspectorURL: string;
-        private _inspector;
-        constructor(scene: Scene);
-        /** Creates the inspector window. */
-        private _createInspector(config?);
-        isVisible(): boolean;
-        hide(): void;
-        show(config?: {
-            popup?: boolean;
-            initialTab?: number;
-            parentElement?: HTMLElement;
-            newColors?: {
-                backgroundColor?: string;
-                backgroundColorLighter?: string;
-                backgroundColorLighter2?: string;
-                backgroundColorLighter3?: string;
-                color?: string;
-                colorTop?: string;
-                colorBot?: string;
-            };
-        }): void;
-    }
-}
-
-declare module BABYLON.Debug {
-    class PhysicsViewer {
-        protected _impostors: Array<PhysicsImpostor>;
-        protected _meshes: Array<AbstractMesh>;
-        protected _scene: Scene;
-        protected _numMeshes: number;
-        protected _physicsEnginePlugin: IPhysicsEnginePlugin;
-        private _renderFunction;
-        private _debugBoxMesh;
-        private _debugSphereMesh;
-        private _debugMaterial;
-        constructor(scene: Scene);
-        protected _updateDebugMeshes(): void;
-        showImpostor(impostor: PhysicsImpostor): void;
-        hideImpostor(impostor: PhysicsImpostor): void;
-        private _getDebugMaterial(scene);
-        private _getDebugBoxMesh(scene);
-        private _getDebugSphereMesh(scene);
-        private _getDebugMesh(impostor, scene);
-        dispose(): void;
-    }
-}
-
-declare module BABYLON {
-    class RayHelper {
-        ray: Ray;
-        private _renderPoints;
-        private _renderLine;
-        private _renderFunction;
-        private _scene;
-        private _updateToMeshFunction;
-        private _attachedToMesh;
-        private _meshSpaceDirection;
-        private _meshSpaceOrigin;
-        static CreateAndShow(ray: Ray, scene: Scene, color: Color3): RayHelper;
-        constructor(ray: Ray);
-        show(scene: Scene, color: Color3): void;
-        hide(): void;
-        private _render();
-        attachToMesh(mesh: AbstractMesh, meshSpaceDirection?: Vector3, meshSpaceOrigin?: Vector3, length?: number): void;
-        detachFromMesh(): void;
-        private _updateToMesh();
-        dispose(): void;
-    }
-}
-
-declare module BABYLON.Debug {
-    /**
-    * Demo available here: http://www.babylonjs-playground.com/#1BZJVJ#8
-    */
-    class SkeletonViewer {
-        skeleton: Skeleton;
-        mesh: AbstractMesh;
-        autoUpdateBonesMatrices: boolean;
-        renderingGroupId: number;
-        color: Color3;
-        private _scene;
-        private _debugLines;
-        private _debugMesh;
-        private _isEnabled;
-        private _renderFunction;
-        constructor(skeleton: Skeleton, mesh: AbstractMesh, scene: Scene, autoUpdateBonesMatrices?: boolean, renderingGroupId?: number);
-        isEnabled: boolean;
-        private _getBonePosition(position, bone, meshMat, x?, y?, z?);
-        private _getLinesForBonesWithLength(bones, meshMat);
-        private _getLinesForBonesNoLength(bones, meshMat);
-        update(): void;
-        dispose(): void;
-    }
-}
-
 declare module BABYLON {
     class StickValues {
         x: any;
@@ -5016,6 +5016,51 @@ declare module BABYLON {
 }
 
 declare module BABYLON {
+    class LensFlare {
+        size: number;
+        position: number;
+        color: Color3;
+        texture: Texture;
+        alphaMode: number;
+        private _system;
+        constructor(size: number, position: number, color: any, imgUrl: string, system: LensFlareSystem);
+        dispose: () => void;
+    }
+}
+
+declare module BABYLON {
+    class LensFlareSystem {
+        name: string;
+        lensFlares: LensFlare[];
+        borderLimit: number;
+        viewportBorder: number;
+        meshesSelectionPredicate: (mesh: Mesh) => boolean;
+        layerMask: number;
+        id: string;
+        private _scene;
+        private _emitter;
+        private _vertexBuffers;
+        private _indexBuffer;
+        private _effect;
+        private _positionX;
+        private _positionY;
+        private _isEnabled;
+        constructor(name: string, emitter: any, scene: Scene);
+        isEnabled: boolean;
+        getScene(): Scene;
+        getEmitter(): any;
+        setEmitter(newEmitter: any): void;
+        getEmitterPosition(): Vector3;
+        computeEffectivePosition(globalViewport: Viewport): boolean;
+        _isVisible(): boolean;
+        render(): boolean;
+        dispose(): void;
+        static Parse(parsedLensFlareSystem: any, scene: Scene, rootUrl: string): LensFlareSystem;
+        serialize(): any;
+    }
+}
+
+declare module BABYLON {
     class DirectionalLight extends ShadowLight {
         private _shadowFrustumSize;
         /**
@@ -5549,51 +5594,6 @@ declare module BABYLON {
 }
 
 declare module BABYLON {
-    class LensFlare {
-        size: number;
-        position: number;
-        color: Color3;
-        texture: Texture;
-        alphaMode: number;
-        private _system;
-        constructor(size: number, position: number, color: any, imgUrl: string, system: LensFlareSystem);
-        dispose: () => void;
-    }
-}
-
-declare module BABYLON {
-    class LensFlareSystem {
-        name: string;
-        lensFlares: LensFlare[];
-        borderLimit: number;
-        viewportBorder: number;
-        meshesSelectionPredicate: (mesh: Mesh) => boolean;
-        layerMask: number;
-        id: string;
-        private _scene;
-        private _emitter;
-        private _vertexBuffers;
-        private _indexBuffer;
-        private _effect;
-        private _positionX;
-        private _positionY;
-        private _isEnabled;
-        constructor(name: string, emitter: any, scene: Scene);
-        isEnabled: boolean;
-        getScene(): Scene;
-        getEmitter(): any;
-        setEmitter(newEmitter: any): void;
-        getEmitterPosition(): Vector3;
-        computeEffectivePosition(globalViewport: Viewport): boolean;
-        _isVisible(): boolean;
-        render(): boolean;
-        dispose(): void;
-        static Parse(parsedLensFlareSystem: any, scene: Scene, rootUrl: string): LensFlareSystem;
-        serialize(): any;
-    }
-}
-
-declare module BABYLON {
     interface ILoadingScreen {
         displayLoadingUI: () => void;
         hideLoadingUI: () => void;
@@ -12750,6 +12750,7 @@ declare module BABYLON {
 
 declare module BABYLON {
     class Particle {
+        private particleSystem;
         position: Vector3;
         direction: Vector3;
         color: Color4;
@@ -12759,6 +12760,12 @@ declare module BABYLON {
         size: number;
         angle: number;
         angularSpeed: number;
+        private _currentFrameCounter;
+        cellIndex: number;
+        constructor(particleSystem: ParticleSystem);
+        updateCellIndex: (scaledUpdateSpeed: number) => void;
+        private updateCellIndexWithSpeedCalculated(scaledUpdateSpeed);
+        private updateCellIndexWithCustomSpeed();
         copyTo(other: Particle): void;
     }
 }
@@ -12780,6 +12787,7 @@ declare module BABYLON {
     }
     class ParticleSystem implements IDisposable, IAnimatable, IParticleSystem {
         name: string;
+        private _isAnimationSheetEnabled;
         static BLENDMODE_ONEONE: number;
         static BLENDMODE_STANDARD: number;
         animations: Animation[];
@@ -12803,6 +12811,7 @@ declare module BABYLON {
         layerMask: number;
         customShader: any;
         preventAutoStart: boolean;
+        private _epsilon;
         /**
         * An event triggered when the system is disposed.
         * @type {BABYLON.Observable}
@@ -12847,7 +12856,15 @@ declare module BABYLON {
         private _stopped;
         private _actualFrame;
         private _scaledUpdateSpeed;
-        constructor(name: string, capacity: number, scene: Scene, customEffect?: Effect);
+        startSpriteCellID: number;
+        endSpriteCellID: number;
+        spriteCellLoop: boolean;
+        spriteCellChangeSpeed: number;
+        spriteCellWidth: number;
+        spriteCellHeight: number;
+        private _vertexBufferSize;
+        readonly isAnimationSheetEnabled: Boolean;
+        constructor(name: string, capacity: number, scene: Scene, customEffect?: Effect, _isAnimationSheetEnabled?: boolean, epsilon?: number);
         private _createIndexBuffer();
         recycleParticle(particle: Particle): void;
         getCapacity(): number;
@@ -12856,9 +12873,13 @@ declare module BABYLON {
         start(): void;
         stop(): void;
         _appendParticleVertex(index: number, particle: Particle, offsetX: number, offsetY: number): void;
+        _appendParticleVertexWithAnimation(index: number, particle: Particle, offsetX: number, offsetY: number): void;
         private _update(newParticles);
         private _getEffect();
         animate(): void;
+        appendParticleVertexes: (offset: number, particle: Particle) => void;
+        private appenedParticleVertexesWithSheet(offset, particle);
+        private appenedParticleVertexesNoSheet(offset, particle);
         rebuild(): void;
         render(): number;
         dispose(): void;
@@ -13032,7 +13053,6 @@ declare module BABYLON {
         private _cosPitch;
         private _sinYaw;
         private _cosYaw;
-        private _w;
         private _mustUnrotateFixedNormals;
         private _minimum;
         private _maximum;

+ 1 - 0
dist/preview release/what's new.md

@@ -14,6 +14,7 @@
 - New VirtualKeyboard for Babylon.GUI. [Doc here](http://doc.babylonjs.com/overviews/gui#virtualkeyboard) ([deltakosh](https://github.com/deltakosh) / [adam](https://github.com/abow))
 - Added support for depth pre-pass rendering. [Doc here](http://doc.babylonjs.com/tutorials/transparency_and_how_meshes_are_rendered#depth-pre-pass-meshes) ([deltakosh](https://github.com/deltakosh))
 - Added support for Windows Motion Controllers ([Lewis Weaver](https://github.com/leweaver))
+- Added support for Particle animation in ParticleSystem ([Ibraheem Osama](https://github.com/IbraheemOsama))
 
 ## Updates
 - New `camera.storeState()` and `camera.restoreState()` functions to store / restore cameras position / rotation / fov. (Doc here)[http://doc.babylonjs.com/tutorials/cameras#state] ([deltakosh](https://github.com/deltakosh))

+ 2 - 2
package.json

@@ -8,7 +8,7 @@
   ],
   "name": "babylonjs",
   "description": "Babylon.js is a JavaScript 3D engine based on webgl.",
-  "version": "3.1.0-alpha1",
+  "version": "3.1.0-alpha2",
   "repository": {
     "type": "git",
     "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -70,6 +70,6 @@
   },
   "readme": "Babylon.js is a 3D engine based on webgl and javascript",
   "readmeFilename": "README.md",
-  "_id": "babylonjs@3.1.0-alpha1",
+  "_id": "babylonjs@3.1.0-alpha2",
   "_from": "babylonjs@"
 }

+ 2 - 3
src/Mesh/babylon.meshBuilder.ts

@@ -422,9 +422,8 @@
         public static CreateDashedLines(name: string, options: { points: Vector3[], dashSize?: number, gapSize?: number, dashNb?: number, updatable?: boolean, instance?: LinesMesh }, scene: Scene): LinesMesh {
             var points = options.points;
             var instance = options.instance;
-            var gapSize = options.gapSize;
-            var dashNb = options.dashNb;
-            var dashSize = options.dashSize;
+            var gapSize = options.gapSize || 1;
+            var dashSize = options.dashSize || 3;
 
             if (instance) {  //  dashed lines update
                 var positionFunction = (positions: number[]): void => {

+ 55 - 0
src/Particles/babylon.particle.ts

@@ -1,4 +1,5 @@
 module BABYLON {
+
     export class Particle {
         public position = Vector3.Zero();
         public direction = Vector3.Zero();
@@ -10,6 +11,58 @@
         public angle = 0;
         public angularSpeed = 0;
 
+        private _currentFrameCounter = 0;
+        public cellIndex: number = 0;
+
+        constructor(private particleSystem: ParticleSystem) {
+            if (!this.particleSystem.isAnimationSheetEnabled) {
+                return;
+            }
+
+            this.cellIndex = this.particleSystem.startSpriteCellID;
+
+            if (this.particleSystem.spriteCellChangeSpeed == 0) {
+                this.updateCellIndex = this.updateCellIndexWithSpeedCalculated;
+            }
+            else {
+                this.updateCellIndex = this.updateCellIndexWithCustomSpeed;
+            }
+        }
+
+        public updateCellIndex: (scaledUpdateSpeed: number) => void;
+
+        private updateCellIndexWithSpeedCalculated(scaledUpdateSpeed: number): void {
+            //   (ageOffset / scaledUpdateSpeed) / available cells
+            var numberOfScaledUpdatesPerCell = ((this.lifeTime - this.age) / scaledUpdateSpeed) / (this.particleSystem.endSpriteCellID + 1 - this.cellIndex);
+
+            this._currentFrameCounter += scaledUpdateSpeed;
+            if (this._currentFrameCounter >= numberOfScaledUpdatesPerCell * scaledUpdateSpeed) {
+                this._currentFrameCounter = 0;
+                this.cellIndex++;
+                if (this.cellIndex > this.particleSystem.endSpriteCellID) {
+                    this.cellIndex = this.particleSystem.endSpriteCellID;
+                }
+            }
+        }
+
+        private updateCellIndexWithCustomSpeed(): void {
+            if (this._currentFrameCounter >= this.particleSystem.spriteCellChangeSpeed) {
+                this.cellIndex++;
+                this._currentFrameCounter = 0;
+                if (this.cellIndex > this.particleSystem.endSpriteCellID) {
+                    if (this.particleSystem.spriteCellLoop) {
+                        this.cellIndex = this.particleSystem.startSpriteCellID;
+                    }
+                    else {
+                        this.cellIndex = this.particleSystem.endSpriteCellID;
+                    }
+                }
+            }
+            else {
+                this._currentFrameCounter++;
+            }
+        }
+
         public copyTo(other: Particle) {
             other.position.copyFrom(this.position);
             other.direction.copyFrom(this.direction);
@@ -20,6 +73,8 @@
             other.size = this.size;
             other.angle = this.angle;
             other.angularSpeed = this.angularSpeed;
+            other.particleSystem = this.particleSystem;
+            other.cellIndex = this.cellIndex;
         }
     }
 } 

+ 128 - 21
src/Particles/babylon.particleSystem.ts

@@ -12,13 +12,13 @@
     export interface IParticleSystem {
         id: string;
         name: string;
-        emitter: AbstractMesh | Vector3;        
+        emitter: AbstractMesh | Vector3;
         renderingGroupId: number;
         layerMask: number;
-        isStarted(): boolean;  
-        animate(): void;   
-        render();  
-        dispose(): void; 
+        isStarted(): boolean;
+        animate(): void;
+        render();
+        dispose(): void;
         clone(name: string, newEmitter: any): IParticleSystem;
         serialize(): any;
 
@@ -59,7 +59,10 @@
 
         public customShader: any = null;
         public preventAutoStart: boolean = false;
-        
+
+        private _epsilon: number;
+
+
         /**
         * An event triggered when the system is disposed.
         * @type {BABYLON.Observable}
@@ -119,10 +122,30 @@
         private _actualFrame = 0;
         private _scaledUpdateSpeed: number;
 
-        constructor(public name: string, capacity: number, scene: Scene, customEffect?: Effect) {
+        // sheet animation
+        public startSpriteCellID = 0;
+        public endSpriteCellID = 0;
+        public spriteCellLoop = true;
+        public spriteCellChangeSpeed = 0;
+
+        public spriteCellWidth = 0;
+        public spriteCellHeight = 0;
+        private _vertexBufferSize = 11;
+
+        public get isAnimationSheetEnabled(): Boolean {
+            return this._isAnimationSheetEnabled;
+        }
+        // end of sheet animation
+
+        constructor(public name: string, capacity: number, scene: Scene, customEffect?: Effect, private _isAnimationSheetEnabled: boolean = false, epsilon: number = 0.01) {
             this.id = name;
             this._capacity = capacity;
 
+            this._epsilon = epsilon;
+            if (_isAnimationSheetEnabled) {
+                this._vertexBufferSize = 12;
+            }
+
             this._scene = scene || Engine.LastCreatedScene;
 
             this._customEffect = customEffect;
@@ -132,13 +155,18 @@
             this._createIndexBuffer();
 
             // 11 floats per particle (x, y, z, r, g, b, a, angle, size, offsetX, offsetY) + 1 filler
-            this._vertexData = new Float32Array(capacity * 11 * 4);
-            this._vertexBuffer = new Buffer(scene.getEngine(), this._vertexData, true, 11);
+            this._vertexData = new Float32Array(capacity * this._vertexBufferSize * 4);
+            this._vertexBuffer = new Buffer(scene.getEngine(), this._vertexData, true, this._vertexBufferSize);
 
             var positions = this._vertexBuffer.createVertexBuffer(VertexBuffer.PositionKind, 0, 3);
             var colors = this._vertexBuffer.createVertexBuffer(VertexBuffer.ColorKind, 3, 4);
             var options = this._vertexBuffer.createVertexBuffer("options", 7, 4);
 
+            if (this._isAnimationSheetEnabled) {
+                var cellIndexBuffer = this._vertexBuffer.createVertexBuffer("cellIndex", 11, 1);
+                this._vertexBuffers["cellIndex"] = cellIndexBuffer;
+            }
+
             this._vertexBuffers[VertexBuffer.PositionKind] = positions;
             this._vertexBuffers[VertexBuffer.ColorKind] = colors;
             this._vertexBuffers["options"] = options;
@@ -184,6 +212,10 @@
 
                         this.gravity.scaleToRef(this._scaledUpdateSpeed, this._scaledGravity);
                         particle.direction.addInPlace(this._scaledGravity);
+
+                        if (this._isAnimationSheetEnabled) {
+                            particle.updateCellIndex(this._scaledUpdateSpeed);
+                        }
                     }
                 }
             }
@@ -192,7 +224,7 @@
         private _createIndexBuffer() {
             var indices = [];
             var index = 0;
-            for (var count = 0; count < this._capacity ; count++) {
+            for (var count = 0; count < this._capacity; count++) {
                 indices.push(index);
                 indices.push(index + 1);
                 indices.push(index + 2);
@@ -236,8 +268,36 @@
             this._stopped = true;
         }
 
+        // animation sheet
+
         public _appendParticleVertex(index: number, particle: Particle, offsetX: number, offsetY: number): void {
-            var offset = index * 11;
+            var offset = index * this._vertexBufferSize;
+            this._vertexData[offset] = particle.position.x;
+            this._vertexData[offset + 1] = particle.position.y;
+            this._vertexData[offset + 2] = particle.position.z;
+            this._vertexData[offset + 3] = particle.color.r;
+            this._vertexData[offset + 4] = particle.color.g;
+            this._vertexData[offset + 5] = particle.color.b;
+            this._vertexData[offset + 6] = particle.color.a;
+            this._vertexData[offset + 7] = particle.angle;
+            this._vertexData[offset + 8] = particle.size;
+            this._vertexData[offset + 9] = offsetX;
+            this._vertexData[offset + 10] = offsetY;
+        }
+
+        public _appendParticleVertexWithAnimation(index: number, particle: Particle, offsetX: number, offsetY: number): void {
+
+            if (offsetX === 0)
+                offsetX = this._epsilon;
+            else if (offsetX === 1)
+                offsetX = 1 - this._epsilon;
+
+            if (offsetY === 0)
+                offsetY = this._epsilon;
+            else if (offsetY === 1)
+                offsetY = 1 - this._epsilon;
+
+            var offset = index * this._vertexBufferSize;
             this._vertexData[offset] = particle.position.x;
             this._vertexData[offset + 1] = particle.position.y;
             this._vertexData[offset + 2] = particle.position.z;
@@ -249,6 +309,7 @@
             this._vertexData[offset + 8] = particle.size;
             this._vertexData[offset + 9] = offsetX;
             this._vertexData[offset + 10] = offsetY;
+            this._vertexData[offset + 11] = particle.cellIndex;
         }
 
         private _update(newParticles: number): void {
@@ -267,6 +328,7 @@
                 var emitterPosition = (<Vector3>this.emitter);
                 worldMatrix = Matrix.Translation(emitterPosition.x, emitterPosition.y, emitterPosition.z);
             }
+
             var particle: Particle;
             for (var index = 0; index < newParticles; index++) {
                 if (this.particles.length === this._capacity) {
@@ -276,9 +338,11 @@
                 if (this._stockParticles.length !== 0) {
                     particle = this._stockParticles.pop();
                     particle.age = 0;
+                    particle.cellIndex = this.startSpriteCellID;
                 } else {
-                    particle = new Particle();
+                    particle = new Particle(this);
                 }
+
                 this.particles.push(particle);
 
                 var emitPower = randomNumber(this.minEmitPower, this.maxEmitPower);
@@ -312,15 +376,31 @@
                 defines.push("#define CLIPPLANE");
             }
 
+            if (this._isAnimationSheetEnabled) {
+                defines.push("#define ANIMATESHEET");
+            }
+
             // Effect
             var join = defines.join("\n");
             if (this._cachedDefines !== join) {
                 this._cachedDefines = join;
 
+                var attributesNamesOrOptions: any;
+                var effectCreationOption: any;
+
+                if (this._isAnimationSheetEnabled) {
+                    attributesNamesOrOptions = [VertexBuffer.PositionKind, VertexBuffer.ColorKind, "options", "cellIndex"];
+                    effectCreationOption = ["invView", "view", "projection", "particlesInfos", "vClipPlane", "textureMask"];
+                }
+                else {
+                    attributesNamesOrOptions = [VertexBuffer.PositionKind, VertexBuffer.ColorKind, "options"];
+                    effectCreationOption = ["invView", "view", "projection", "vClipPlane", "textureMask"]
+                }
+
                 this._effect = this._scene.getEngine().createEffect(
                     "particles",
-                    [VertexBuffer.PositionKind, VertexBuffer.ColorKind, "options"],
-                    ["invView", "view", "projection", "vClipPlane", "textureMask"],
+                    attributesNamesOrOptions,
+                    effectCreationOption,
                     ["diffuseSampler"], join);
             }
 
@@ -345,7 +425,7 @@
 
             this._scaledUpdateSpeed = this.updateSpeed * this._scene.getAnimationRatio();
 
-            // determine the number of particles we need to create   
+            // determine the number of particles we need to create
             var newParticles;
 
             if (this.manualEmitCount > -1) {
@@ -388,20 +468,41 @@
                 }
             }
 
+            // Animation sheet
+            if (this._isAnimationSheetEnabled) {
+                this.appendParticleVertexes = this.appenedParticleVertexesWithSheet;
+            }
+            else {
+                this.appendParticleVertexes = this.appenedParticleVertexesNoSheet;
+            }
+
             // Update VBO
             var offset = 0;
             for (var index = 0; index < this.particles.length; index++) {
                 var particle = this.particles[index];
-
-                this._appendParticleVertex(offset++, particle, 0, 0);
-                this._appendParticleVertex(offset++, particle, 1, 0);
-                this._appendParticleVertex(offset++, particle, 1, 1);
-                this._appendParticleVertex(offset++, particle, 0, 1);
+                this.appendParticleVertexes(offset, particle);
+                offset += 4;
             }
 
             this._vertexBuffer.update(this._vertexData);
         }
 
+        public appendParticleVertexes: (offset: number, particle: Particle) => void = null;
+
+        private appenedParticleVertexesWithSheet(offset: number, particle: Particle) {
+            this._appendParticleVertexWithAnimation(offset++, particle, 0, 0);
+            this._appendParticleVertexWithAnimation(offset++, particle, 1, 0);
+            this._appendParticleVertexWithAnimation(offset++, particle, 1, 1);
+            this._appendParticleVertexWithAnimation(offset++, particle, 0, 1);
+        }
+
+        private appenedParticleVertexesNoSheet(offset: number, particle: Particle) {
+            this._appendParticleVertex(offset++, particle, 0, 0);
+            this._appendParticleVertex(offset++, particle, 1, 0);
+            this._appendParticleVertex(offset++, particle, 1, 1);
+            this._appendParticleVertex(offset++, particle, 0, 1);
+        }
+
         public rebuild(): void {
             this._createIndexBuffer();
 
@@ -425,6 +526,12 @@
             effect.setTexture("diffuseSampler", this.particleTexture);
             effect.setMatrix("view", viewMatrix);
             effect.setMatrix("projection", this._scene.getProjectionMatrix());
+
+            if (this._isAnimationSheetEnabled) {
+                var baseSize = this.particleTexture.getBaseSize();
+                effect.setFloat3("particlesInfos", this.spriteCellWidth / baseSize.width, this.spriteCellHeight / baseSize.height, baseSize.width / this.spriteCellWidth);
+            }
+
             effect.setFloat4("textureMask", this.textureMask.r, this.textureMask.g, this.textureMask.b, this.textureMask.a);
 
             if (this._scene.clipPlane) {
@@ -525,7 +632,7 @@
             } else {
                 var emitterPosition = (<Vector3>this.emitter);
                 serializationObject.emitter = emitterPosition.asArray();
-            }       
+            }
 
             serializationObject.capacity = this.getCapacity();
 

+ 13 - 16
src/Particles/babylon.solidParticleSystem.ts

@@ -103,7 +103,6 @@
         private _cosPitch: number = 0.0;
         private _sinYaw: number = 0.0;
         private _cosYaw: number = 0.0;
-        private _w: number = 0.0;
         private _mustUnrotateFixedNormals = false;
         private _minimum: Vector3 = Tmp.Vector3[0];
         private _maximum: Vector3 = Tmp.Vector3[1];
@@ -707,10 +706,9 @@
                         this._vertex.y *= this._particle.scaling.y;
                         this._vertex.z *= this._particle.scaling.z;
 
-                        this._w = (this._vertex.x * this._rotMatrix.m[3]) + (this._vertex.y * this._rotMatrix.m[7]) + (this._vertex.z * this._rotMatrix.m[11]) + this._rotMatrix.m[15];
-                        this._rotated.x = ((this._vertex.x * this._rotMatrix.m[0]) + (this._vertex.y * this._rotMatrix.m[4]) + (this._vertex.z * this._rotMatrix.m[8]) + this._rotMatrix.m[12]) / this._w;
-                        this._rotated.y = ((this._vertex.x * this._rotMatrix.m[1]) + (this._vertex.y * this._rotMatrix.m[5]) + (this._vertex.z * this._rotMatrix.m[9]) + this._rotMatrix.m[13]) / this._w;
-                        this._rotated.z = ((this._vertex.x * this._rotMatrix.m[2]) + (this._vertex.y * this._rotMatrix.m[6]) + (this._vertex.z * this._rotMatrix.m[10]) + this._rotMatrix.m[14]) / this._w;
+                        this._rotated.x = this._vertex.x * this._rotMatrix.m[0] + this._vertex.y * this._rotMatrix.m[4] + this._vertex.z * this._rotMatrix.m[8];
+                        this._rotated.y = this._vertex.x * this._rotMatrix.m[1] + this._vertex.y * this._rotMatrix.m[5] + this._vertex.z * this._rotMatrix.m[9];
+                        this._rotated.z = this._vertex.x * this._rotMatrix.m[2] + this._vertex.y * this._rotMatrix.m[6] + this._vertex.z * this._rotMatrix.m[10];
 
                         this._positions32[idx] = this._particle.position.x + this._cam_axisX.x * this._rotated.x + this._cam_axisY.x * this._rotated.y + this._cam_axisZ.x * this._rotated.z;
                         this._positions32[idx + 1] = this._particle.position.y + this._cam_axisX.y * this._rotated.x + this._cam_axisY.y * this._rotated.y + this._cam_axisZ.y * this._rotated.z;
@@ -743,9 +741,9 @@
                             this._normal.y = this._fixedNormal32[idx + 1];
                             this._normal.z = this._fixedNormal32[idx + 2];
 
-                            this._rotated.x = ((this._normal.x * this._rotMatrix.m[0]) + (this._normal.y * this._rotMatrix.m[4]) + (this._normal.z * this._rotMatrix.m[8]) + this._rotMatrix.m[12]);
-                            this._rotated.y = ((this._normal.x * this._rotMatrix.m[1]) + (this._normal.y * this._rotMatrix.m[5]) + (this._normal.z * this._rotMatrix.m[9]) + this._rotMatrix.m[13]);
-                            this._rotated.z = ((this._normal.x * this._rotMatrix.m[2]) + (this._normal.y * this._rotMatrix.m[6]) + (this._normal.z * this._rotMatrix.m[10]) + this._rotMatrix.m[14]);
+                            this._rotated.x = this._normal.x * this._rotMatrix.m[0] + this._normal.y * this._rotMatrix.m[4] + this._normal.z * this._rotMatrix.m[8];
+                            this._rotated.y = this._normal.x * this._rotMatrix.m[1] + this._normal.y * this._rotMatrix.m[5] + this._normal.z * this._rotMatrix.m[9];
+                            this._rotated.z = this._normal.x * this._rotMatrix.m[2] + this._normal.y * this._rotMatrix.m[6] + this._normal.z * this._rotMatrix.m[10];
 
                             this._normals32[idx] = this._cam_axisX.x * this._rotated.x + this._cam_axisY.x * this._rotated.y + this._cam_axisZ.x * this._rotated.z;
                             this._normals32[idx + 1] = this._cam_axisX.y * this._rotated.x + this._cam_axisY.y * this._rotated.y + this._cam_axisZ.y * this._rotated.z;
@@ -803,10 +801,9 @@
                             this._vertex.x = this._particle._modelBoundingInfo.boundingBox.vectors[b].x * this._particle.scaling.x;
                             this._vertex.y = this._particle._modelBoundingInfo.boundingBox.vectors[b].y * this._particle.scaling.y;
                             this._vertex.z = this._particle._modelBoundingInfo.boundingBox.vectors[b].z * this._particle.scaling.z;
-                            this._w = (this._vertex.x * this._rotMatrix.m[3]) + (this._vertex.y * this._rotMatrix.m[7]) + (this._vertex.z * this._rotMatrix.m[11]) + this._rotMatrix.m[15];
-                            this._rotated.x = ((this._vertex.x * this._rotMatrix.m[0]) + (this._vertex.y * this._rotMatrix.m[4]) + (this._vertex.z * this._rotMatrix.m[8]) + this._rotMatrix.m[12]) / this._w;
-                            this._rotated.y = ((this._vertex.x * this._rotMatrix.m[1]) + (this._vertex.y * this._rotMatrix.m[5]) + (this._vertex.z * this._rotMatrix.m[9]) + this._rotMatrix.m[13]) / this._w;
-                            this._rotated.z = ((this._vertex.x * this._rotMatrix.m[2]) + (this._vertex.y * this._rotMatrix.m[6]) + (this._vertex.z * this._rotMatrix.m[10]) + this._rotMatrix.m[14]) / this._w;
+                            this._rotated.x = this._vertex.x * this._rotMatrix.m[0] + this._vertex.y * this._rotMatrix.m[4] + this._vertex.z * this._rotMatrix.m[8];
+                            this._rotated.y = this._vertex.x * this._rotMatrix.m[1] + this._vertex.y * this._rotMatrix.m[5] + this._vertex.z * this._rotMatrix.m[9];
+                            this._rotated.z = this._vertex.x * this._rotMatrix.m[2] + this._vertex.y * this._rotMatrix.m[6] + this._vertex.z * this._rotMatrix.m[10];
                             bBox.vectors[b].x = this._particle.position.x + this._cam_axisX.x * this._rotated.x + this._cam_axisY.x * this._rotated.y + this._cam_axisZ.x * this._rotated.z;
                             bBox.vectors[b].y = this._particle.position.y + this._cam_axisX.y * this._rotated.x + this._cam_axisY.y * this._rotated.y + this._cam_axisZ.y * this._rotated.z;
                             bBox.vectors[b].z = this._particle.position.z + this._cam_axisX.z * this._rotated.x + this._cam_axisY.z * this._rotated.y + this._cam_axisZ.z * this._rotated.z;
@@ -874,10 +871,10 @@
             this._cosPitch = Math.cos(this._halfpitch);
             this._sinYaw = Math.sin(this._halfyaw);
             this._cosYaw = Math.cos(this._halfyaw);
-            this._quaternion.x = (this._cosYaw * this._sinPitch * this._cosRoll) + (this._sinYaw * this._cosPitch * this._sinRoll);
-            this._quaternion.y = (this._sinYaw * this._cosPitch * this._cosRoll) - (this._cosYaw * this._sinPitch * this._sinRoll);
-            this._quaternion.z = (this._cosYaw * this._cosPitch * this._sinRoll) - (this._sinYaw * this._sinPitch * this._cosRoll);
-            this._quaternion.w = (this._cosYaw * this._cosPitch * this._cosRoll) + (this._sinYaw * this._sinPitch * this._sinRoll);
+            this._quaternion.x = this._cosYaw * this._sinPitch * this._cosRoll + this._sinYaw * this._cosPitch * this._sinRoll;
+            this._quaternion.y = this._sinYaw * this._cosPitch * this._cosRoll - this._cosYaw * this._sinPitch * this._sinRoll;
+            this._quaternion.z = this._cosYaw * this._cosPitch * this._sinRoll - this._sinYaw * this._sinPitch * this._cosRoll;
+            this._quaternion.w = this._cosYaw * this._cosPitch * this._cosRoll + this._sinYaw * this._sinPitch * this._sinRoll;
         }
 
         private _quaternionToRotationMatrix(): void {

+ 13 - 1
src/Shaders/particles.vertex.fx

@@ -2,10 +2,12 @@
 attribute vec3 position;
 attribute vec4 color;
 attribute vec4 options;
+attribute float cellIndex;
 
 // Uniforms
 uniform mat4 view;
 uniform mat4 projection;
+uniform vec3 particlesInfos; // x (number of rows) y(number of columns) z(rowSize)
 
 // Output
 varying vec2 vUV;
@@ -23,7 +25,7 @@ void main(void) {
 	float size = options.y;
 	float angle = options.x;
 	vec2 offset = options.zw;
-
+	
 	cornerPos = vec3(offset.x - 0.5, offset.y  - 0.5, 0.) * size;
 
 	// Rotate
@@ -37,7 +39,17 @@ void main(void) {
 	gl_Position = projection * vec4(viewPos, 1.0);   
 	
 	vColor = color;
+
+	#ifdef ANIMATESHEET
+	float rowOffset = floor(cellIndex / particlesInfos.z);
+    float columnOffset = cellIndex - rowOffset * particlesInfos.z;
+
+	vec2 uvScale = particlesInfos.xy;
+	vec2 uvOffset = vec2(offset.x , 1.0 - offset.y);
+	vUV = (uvOffset + vec2(columnOffset, rowOffset)) * uvScale;
+	#else
 	vUV = offset;
+	#endif
 
 	// Clip plane
 #ifdef CLIPPLANE