Przeglądaj źródła

Merge remote-tracking branch 'upstream/master' into trackedNode

nockawa 8 lat temu
rodzic
commit
b31a7538a3
42 zmienionych plików z 4047 dodań i 2564 usunięć
  1. 1 1
      Babylon.csproj
  2. 12 0
      Exporters/3ds Max/BabylonExport.Entities/BabylonAnimation.cs
  3. 30 0
      Exporters/3ds Max/BabylonExport.Entities/BabylonCamera.cs
  4. 8 1
      Exporters/3ds Max/BabylonExport.Entities/BabylonPBRMaterial.cs
  5. 1 24
      Exporters/3ds Max/BabylonExport.Entities/BabylonUniversalCamera.cs
  6. BIN
      Exporters/Blender/Blender2Babylon-5.1.zip
  7. 1 1
      Exporters/Blender/src/babylon-js/__init__.py
  8. 11 0
      Exporters/Blender/src/babylon-js/mesh.py
  9. 1 1
      Exporters/Blender/zip_media.xml
  10. 69 0
      Tools/CompressedTextured/ktx-files.bat
  11. 9 0
      Tools/CompressedTextured/make-ktx-batch.bat
  12. 1 0
      Tools/Gulp/config.json
  13. 26 25
      dist/preview release/babylon.core.js
  14. 2149 2037
      dist/preview release/babylon.d.ts
  15. 33 33
      dist/preview release/babylon.js
  16. 599 118
      dist/preview release/babylon.max.js
  17. 33 33
      dist/preview release/babylon.noworker.js
  18. 8 1
      dist/preview release/loaders/babylon.glTFFileLoader.d.ts
  19. 65 31
      dist/preview release/loaders/babylon.glTFFileLoader.js
  20. 2 2
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  21. 3 0
      dist/preview release/what's new.md
  22. 7 0
      loaders/src/glTF/README.md
  23. 20 40
      loaders/src/glTF/babylon.glTFFileLoader.ts
  24. 54 0
      loaders/src/glTF/babylon.glTFFileLoaderUtils.ts
  25. 13 0
      src/Animations/babylon.animation.ts
  26. 2 2
      src/Cameras/VR/babylon.vrCameraMetrics.ts
  27. 4 2
      src/Culling/babylon.ray.ts
  28. 146 0
      src/Culling/babylon.rayHelper.ts
  29. 2 0
      src/Lights/Shadows/babylon.shadowGenerator.ts
  30. 2 1
      src/Materials/Textures/babylon.hdrCubeTexture.ts
  31. 86 0
      src/Mesh/babylon.abstractMesh.ts
  32. 304 7
      src/Mesh/babylon.mesh.ts
  33. 159 47
      src/Mesh/babylon.mesh.vertexData.ts
  34. 9 7
      src/Mesh/babylon.meshBuilder.ts
  35. 12 3
      src/Particles/babylon.particleSystem.ts
  36. 20 13
      src/Particles/babylon.solidParticleSystem.ts
  37. 17 9
      src/PostProcess/babylon.hdrRenderingPipeline.ts
  38. 2 0
      src/PostProcess/babylon.ssaoRenderingPipeline.ts
  39. 20 37
      src/Tools/babylon.filesInput.ts
  40. 27 13
      src/Tools/babylon.tools.ts
  41. 5 5
      src/Tools/babylon.virtualJoystick.ts
  42. 74 70
      src/babylon.engine.ts

+ 1 - 1
Babylon.csproj

@@ -543,7 +543,7 @@
           <AutoAssignPort>True</AutoAssignPort>
           <DevelopmentServerPort>0</DevelopmentServerPort>
           <DevelopmentServerVPath>/</DevelopmentServerVPath>
-          <IISUrl>http://localhost:51793/</IISUrl>
+          <IISUrl>http://localhost:10683/</IISUrl>
           <NTLMAuthentication>False</NTLMAuthentication>
           <UseCustomServer>False</UseCustomServer>
           <CustomServerUrl>

+ 12 - 0
Exporters/3ds Max/BabylonExport.Entities/BabylonAnimation.cs

@@ -15,6 +15,12 @@ namespace BabylonExport.Entities
         public int dataType { get; set; }
 
         [DataMember]
+        public bool enableBlending { get; set; }
+
+        [DataMember]
+        public float blendingSpeed { get; set; }
+
+        [DataMember]
         public int loopBehavior { get; set; }
 
         [DataMember]
@@ -38,5 +44,11 @@ namespace BabylonExport.Entities
             Cycle = 1,
             Constant = 2
         }
+
+        public BabylonAnimation()
+        {
+            this.enableBlending = false;
+            this.blendingSpeed = 0.01f;
+        }
     }
 }

+ 30 - 0
Exporters/3ds Max/BabylonExport.Entities/BabylonCamera.cs

@@ -45,6 +45,9 @@ namespace BabylonExport.Entities
         public float inertia { get; set; }
 
         [DataMember]
+        public float interaxialDistance { get; set; }
+
+        [DataMember]
         public bool checkCollisions { get; set; }
 
         [DataMember]
@@ -69,6 +72,24 @@ namespace BabylonExport.Entities
         public BabylonAnimation[] animations { get; set; }
 
         [DataMember]
+        public int mode { get; set; }
+
+        [DataMember]
+        public float? orthoLeft { get; set; }
+
+        [DataMember]
+        public float? orthoRight { get; set; }
+
+        [DataMember]
+        public float? orthoBottom { get; set; }
+
+        [DataMember]
+        public float? orthoTop { get; set; }
+
+        [DataMember]
+        public bool isStereoscopicSideBySide;
+
+        [DataMember]
         public object metadata { get; set; }
 
         [DataMember]
@@ -85,6 +106,15 @@ namespace BabylonExport.Entities
             maxZ = 5000.0f;
             speed = 1.0f;
             inertia = 0.9f;
+            interaxialDistance = 0.0637f;
+
+            mode = 0;
+            orthoLeft = null;
+            orthoRight = null;
+            orthoBottom = null;
+            orthoTop = null;
+
+            type = "FreeCamera";
         }
     }
 }

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

@@ -95,6 +95,9 @@ namespace BabylonExport.Entities
         public BabylonTexture lightmapTexture { get; set; }
 
         [DataMember]
+        public BabylonTexture metallicTexture { get; set; }
+
+        [DataMember]
         public bool useLightmapAsShadowmap { get; set; }
 
         [DataMember]
@@ -119,6 +122,9 @@ namespace BabylonExport.Entities
         public float roughness { get; set; }
 
         [DataMember]
+        public float metallic { get; set; }
+
+        [DataMember]
         public bool useRoughnessFromMetallicTextureAlpha { get; set; }
 
         [DataMember]
@@ -166,7 +172,8 @@ namespace BabylonExport.Entities
             cameraContrast = 1.0f;
             useEmissiveAsIllumination = false;
 
-            roughness = 1.0f;
+            metallic = 0.0f;
+            roughness = 0.0f;
             useRoughnessFromMetallicTextureAlpha = false;
             useRoughnessFromMetallicTextureGreen = false;
 

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

@@ -4,32 +4,9 @@ namespace BabylonExport.Entities
     [DataContract]
     public class BabylonUniversalCamera : BabylonCamera
     {
-        [DataMember]
-        public int mode { get; set; }
-
-        [DataMember]
-        public float? orthoLeft { get; set; }
-
-        [DataMember]
-        public float? orthoRight { get; set; }
-
-        [DataMember]
-        public float? orthoBottom { get; set; }
-
-        [DataMember]
-        public float? orthoTop { get; set; }
-
-        [DataMember]
-        public bool isStereoscopicSideBySide;
-
         public BabylonUniversalCamera()
         {
-            this.mode = 0;
-            this.orthoLeft = null;
-            this.orthoRight = null;
-            this.orthoBottom = null;
-            this.orthoTop = null;
-            this.type = "BABYLON.UniversalCamera";
+            this.type = "UniversalCamera";
         }
     }
 }

BIN
Exporters/Blender/Blender2Babylon-5.1.zip


+ 1 - 1
Exporters/Blender/src/babylon-js/__init__.py

@@ -1,7 +1,7 @@
 bl_info = {
     'name': 'Babylon.js',
     'author': 'David Catuhe, Jeff Palmer',
-    'version': (5, 1, 2),
+    'version': (5, 2, 0),
     'blender': (2, 76, 0),
     'location': 'File > Export > Babylon.js (.babylon)',
     'description': 'Export Babylon.js scenes (.babylon)',

+ 11 - 0
Exporters/Blender/src/babylon-js/mesh.py

@@ -46,6 +46,7 @@ class Mesh(FCurveAnimatable):
         self.castShadows = object.data.castShadows
         self.freezeWorldMatrix = object.data.freezeWorldMatrix
         self.layer = getLayer(object) # used only for lights with 'This Layer Only' checked, not exported
+        self.tags = object.data.tags
 
         # hasSkeleton detection & skeletonID determination
         hasSkeleton = False
@@ -537,6 +538,7 @@ class Mesh(FCurveAnimatable):
         write_bool(file_handler, 'isEnabled', self.isEnabled)
         write_bool(file_handler, 'checkCollisions', self.checkCollisions)
         write_bool(file_handler, 'receiveShadows', self.receiveShadows)
+        write_string(file_handler, 'tags', self.tags)
 
         if hasattr(self, 'physicsImpostor'):
             write_int(file_handler, 'physicsImpostor', self.physicsImpostor)
@@ -649,6 +651,7 @@ class Node(FCurveAnimatable):
         self.billboardMode = BILLBOARDMODE_NONE
         self.castShadows = False
         self.receiveShadows = False
+        self.tags = ''
         self.layer = -1 # nodes do not have layers attribute
 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     def to_scene_file(self, file_handler):
@@ -668,6 +671,7 @@ class Node(FCurveAnimatable):
         write_bool(file_handler, 'checkCollisions', self.checkCollisions)
         write_int(file_handler, 'billboardMode', self.billboardMode)
         write_bool(file_handler, 'receiveShadows', self.receiveShadows)
+        write_string(file_handler, 'tags', self.tags)
 
         super().to_scene_file(file_handler) # Animations
         file_handler.write('}')
@@ -714,6 +718,11 @@ bpy.types.Mesh.receiveShadows = bpy.props.BoolProperty(
     description='',
     default = False
 )
+bpy.types.Mesh.tags = bpy.props.StringProperty(
+    name='Tags',
+    description='Add meta-data to mesh (space delimited for multiples)',
+    default = ''
+)
 # not currently in use
 bpy.types.Mesh.forceBaking = bpy.props.BoolProperty(
     name='Combine Multi-textures / resize',
@@ -821,6 +830,8 @@ class MeshPanel(bpy.types.Panel):
         
         layout.prop(ob.data, 'autoAnimate')
         
+        layout.prop(ob.data, 'tags')
+        
         box = layout.box()
         box.label(text='Skeleton:')
         box.prop(ob.data, 'ignoreSkeleton')

+ 1 - 1
Exporters/Blender/zip_media.xml

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <project name="zipper">
-	<property name="version" value="5.1"/>
+	<property name="version" value="5.2"/>
 	
 	<!-- this target assumes it is run from Babylon.js/Exporters/Blender directory.  -->
     <target name="make-zip">

+ 69 - 0
Tools/CompressedTextured/ktx-files.bat

@@ -0,0 +1,69 @@
+echo off
+REM Create a series of compressed textures versions of the file name passed in. Skips files which already
+REM exist, since script can be very long running.
+REM arg 1: file
+REM arg 2: file without extension
+REM arg 3: Y when need alpha, else N
+REM arg 4: Q when best image required, else D for developer quality
+
+REM -i specifies the input file passed as the first arg (full path) dos use 1%
+REM -pot + indicates force power of 2
+REM -m indicates to generate mipmaps
+REM -f is the format, variable type (UBN unsigned byte normalized), colorspace
+REM -q indicates how much time to spend, varies by encoding type
+REM -o specifies output file name, uses arg without extension adds -family.ktx
+REM - - - - - - - - - - - - - - - ASTC  - - - - - - - - - - - - - - - 
+echo working with %1
+REM all ASTC formats have alpha
+IF EXIST %2-astc.ktx GOTO PVRTC
+
+SET quality=astcveryfast
+if %4 == 'Q' SET quality=astcexhaustive
+echo compressing...
+PVRTexToolCLI.exe -i %1 -flip y -pot + -m -f ASTC_8x8,UBN,lRGB -q %quality% -shh -o %2-astc.ktx >junk.txt
+echo Saved texture to %2-astc.ktx
+REM - - - - - - - - - - - - - - - PVRTC - - - - - - - - - - - - - - - 
+:PVRTC
+REM PVRTC must be square on iOS
+IF EXIST %2-pvrtc.ktx GOTO DXT
+
+SET format=PVRTC1_2_RGB
+if %3 == 'Y' SET format=PVRTC1_2
+
+SET quality=pvrtcfastest
+if %4 == 'Q' SET quality=pvrtcbest
+
+PVRTexToolCLI.exe -i %1 -flip y -pot + -square + -m -f %format%,UBN,lRGB -q %quality% -o %2-pvrtc.ktx
+
+REM - - - - - - - - - - - - - - -  DXT  - - - - - - - - - - - - - - -
+:DXT
+IF EXIST %2-dxt.ktx GOTO ETC1
+
+SET format=BC1
+if %3 == 'Y' SET format=BC2
+
+PVRTexToolCLI.exe -i %1 -flip y -pot + -m -f %format%,UBN,lRGB -o %2-dxt.ktx
+
+REM - - - - - - - - - - - - - - - ETC1  - - - - - - - - - - - - - - - 
+REM ETC1 does not have an alpha capable format
+:ETC1
+IF EXIST %2-etc1.ktx GOTO ETC2
+
+SET quality=etcfast
+if %4 == 'Q' SET quality=etcslowperceptual
+
+if %3 == 'N' PVRTexToolCLI.exe -i %1 -flip y -pot + -m -f ETC1,UBN,lRGB -q %quality% -o %2-etc1.ktx
+
+REM - - - - - - - - - - - - - - - ETC2  - - - - - - - - - - - - - - - 
+:ETC2
+IF EXIST %2-etc2.ktx GOTO END
+
+SET format=ETC2_RGB
+if %3 == 'Y' SET format=ETC2_RGBA
+
+SET quality=etcfast
+if %4 == 'Q' SET quality=etcslowperceptual
+
+PVRTexToolCLI.exe -i %1 -flip y -pot + -m -f %format%,UBN,lRGB -q %quality% -o %2-etc2.ktx
+REM - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
+:END

+ 9 - 0
Tools/CompressedTextured/make-ktx-batch.bat

@@ -0,0 +1,9 @@
+echo off
+REM create compressed textures for each .jpg & .png in the current directory
+REM arg 1: Q when best image required, else D for developer quality
+
+REM erasing of any previous file
+erase ktx-batch.bat
+
+for %%f in (*.jpg) do echo call ktx-files.bat %%f %%~nf 'N' '%1' >>ktx-batch.bat
+for %%f in (*.png) do echo call ktx-files.bat %%f %%~nf 'Y' '%1' >>ktx-batch.bat

+ 1 - 0
Tools/Gulp/config.json

@@ -34,6 +34,7 @@
       "../../src/Culling/babylon.boundingBox.js",
       "../../src/Culling/babylon.boundingInfo.js",
       "../../src/Culling/babylon.ray.js",
+      "../../src/Culling/babylon.rayHelper.js",
       "../../src/Mesh/babylon.abstractMesh.js",
       "../../src/Lights/babylon.light.js",
       "../../src/Lights/babylon.pointLight.js",

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


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


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


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


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


+ 8 - 1
dist/preview release/loaders/babylon.glTFFileLoader.d.ts

@@ -345,8 +345,8 @@ declare module BABYLON {
         /**
         * Static members
         */
-        static MakeYUP: boolean;
         static HomogeneousCoordinates: boolean;
+        static IncrementalLoading: boolean;
         static Extensions: {
             [name: string]: GLTFFileLoaderExtension;
         };
@@ -425,6 +425,13 @@ declare module BABYLON {
          * @param view: the buffer view
          */
         static DecodeBufferToText(view: ArrayBufferView): string;
+        /**
+         * Returns the default material of gltf. Related to
+         * https://github.com/KhronosGroup/glTF/tree/master/specification/1.0#appendix-a-default-material
+         * @param scene: the Babylon.js scene
+         */
+        static GetDefaultMaterial(scene: Scene): ShaderMaterial;
+        private static _DefaultMaterial;
     }
 }
 

+ 65 - 31
dist/preview release/loaders/babylon.glTFFileLoader.js

@@ -311,10 +311,6 @@ var BABYLON;
                         }
                         else if (targetPath === "rotationQuaternion") {
                             rotationQuaternion = value;
-                            // Y is Up
-                            if (GLTFFileLoader.MakeYUP) {
-                                rotationQuaternion = rotationQuaternion.multiply(new BABYLON.Quaternion(-0.707107, 0, 0, 0.707107));
-                            }
                         }
                         else {
                             scaling = value;
@@ -351,10 +347,6 @@ var BABYLON;
             var scale = BABYLON.Vector3.FromArray(node.scale || [1, 1, 1]);
             var rotation = BABYLON.Quaternion.FromArray(node.rotation || [0, 0, 0, 1]);
             var position = BABYLON.Vector3.FromArray(node.translation || [0, 0, 0]);
-            // Y is Up
-            if (GLTFFileLoader.MakeYUP) {
-                rotation = rotation.multiply(new BABYLON.Quaternion(-0.707107, 0, 0, 0.707107));
-            }
             mat = BABYLON.Matrix.Compose(scale, rotation, position);
         }
         else {
@@ -555,11 +547,6 @@ var BABYLON;
                     }
                 }
             }
-            if (!parentBone && nodesToRoot.length === 0) {
-                var inverseBindMatrix = BABYLON.Matrix.FromArray(buffer, i * 16);
-                var invertMesh = BABYLON.Matrix.Invert(mesh.getWorldMatrix());
-                mat = mat.multiply(mesh.getWorldMatrix());
-            }
             var bone = new BABYLON.Bone(node.jointName, newSkeleton, parentBone, mat);
             bone.id = id;
         }
@@ -688,7 +675,7 @@ var BABYLON;
                 tempVertexData = undefined;
                 // Sub material
                 var material = gltfRuntime.scene.getMaterialByID(primitive.material);
-                multiMat.subMaterials.push(material === null ? gltfRuntime.scene.defaultMaterial : material);
+                multiMat.subMaterials.push(material === null ? BABYLON.GLTFUtils.GetDefaultMaterial(gltfRuntime.scene) : material);
                 // Update vertices start and index start
                 verticesStarts.push(verticesStarts.length === 0 ? 0 : verticesStarts[verticesStarts.length - 1] + verticesCounts[verticesCounts.length - 2]);
                 indexStarts.push(indexStarts.length === 0 ? 0 : indexStarts[indexStarts.length - 1] + indexCounts[indexCounts.length - 2]);
@@ -733,21 +720,15 @@ var BABYLON;
     /**
     * Configures node from transformation matrix
     */
-    var configureNodeFromMatrix = function (newNode, node) {
+    var configureNodeFromMatrix = function (newNode, node, parent) {
         if (node.matrix) {
             var position = new BABYLON.Vector3(0, 0, 0);
             var rotation = new BABYLON.Quaternion();
             var scaling = new BABYLON.Vector3(0, 0, 0);
             var mat = BABYLON.Matrix.FromArray(node.matrix);
             mat.decompose(scaling, rotation, position);
-            // Y is Up
-            if (GLTFFileLoader.MakeYUP) {
-                rotation = rotation.multiply(new BABYLON.Quaternion(-0.707107, 0, 0, 0.707107));
-            }
             configureNode(newNode, position, rotation, scaling);
-            if (newNode instanceof BABYLON.TargetCamera) {
-                newNode.setTarget(BABYLON.Vector3.Zero());
-            }
+            newNode.computeWorldMatrix(true);
         }
         else {
             configureNode(newNode, BABYLON.Vector3.FromArray(node.translation), BABYLON.Quaternion.FromArray(node.rotation), BABYLON.Vector3.FromArray(node.scale));
@@ -756,7 +737,7 @@ var BABYLON;
     /**
     * Imports a node
     */
-    var importNode = function (gltfRuntime, node, id) {
+    var importNode = function (gltfRuntime, node, id, parent) {
         var lastNode = null;
         if (gltfRuntime.importOnlyMeshes && (node.skin || node.meshes)) {
             if (gltfRuntime.importMeshesNames.length > 0 && gltfRuntime.importMeshesNames.indexOf(node.name) === -1) {
@@ -775,8 +756,6 @@ var BABYLON;
                         skin.babylonSkeleton = newMesh.skeleton;
                     }
                 }
-                if (newMesh.skeleton !== null) {
-                }
                 lastNode = newMesh;
             }
         }
@@ -873,8 +852,8 @@ var BABYLON;
             }
         }
         if (lastNode !== null) {
-            if (node.matrix) {
-                configureNodeFromMatrix(lastNode, node);
+            if (node.matrix && lastNode instanceof BABYLON.Mesh) {
+                configureNodeFromMatrix(lastNode, node, parent);
             }
             else {
                 var translation = node.translation || [0, 0, 0];
@@ -905,7 +884,7 @@ var BABYLON;
             meshIncluded = true;
         }
         if (!node.jointName && meshIncluded) {
-            newNode = importNode(gltfRuntime, node, id);
+            newNode = importNode(gltfRuntime, node, id, parent);
             if (newNode !== null) {
                 newNode.id = id;
                 newNode.parent = parent;
@@ -1424,9 +1403,12 @@ var BABYLON;
                     _this._loadShadersAsync(gltfRuntime, function () {
                         importMaterials(gltfRuntime);
                         postLoad(gltfRuntime);
+                        if (!GLTFFileLoader.IncrementalLoading && onSuccess) {
+                            onSuccess(meshes, null, skeletons);
+                        }
                     });
                 });
-                if (onSuccess) {
+                if (GLTFFileLoader.IncrementalLoading && onSuccess) {
                     onSuccess(meshes, null, skeletons);
                 }
             }, onError);
@@ -1446,9 +1428,14 @@ var BABYLON;
                     _this._loadShadersAsync(gltfRuntime, function () {
                         importMaterials(gltfRuntime);
                         postLoad(gltfRuntime);
+                        if (!GLTFFileLoader.IncrementalLoading) {
+                            onSuccess();
+                        }
                     });
                 });
-                onSuccess();
+                if (GLTFFileLoader.IncrementalLoading) {
+                    onSuccess();
+                }
             }, onError);
             return true;
         };
@@ -1542,8 +1529,8 @@ var BABYLON;
     /**
     * Static members
     */
-    GLTFFileLoader.MakeYUP = false;
     GLTFFileLoader.HomogeneousCoordinates = false;
+    GLTFFileLoader.IncrementalLoading = true;
     GLTFFileLoader.Extensions = {};
     BABYLON.GLTFFileLoader = GLTFFileLoader;
     ;
@@ -1748,8 +1735,55 @@ var BABYLON;
             }
             return result;
         };
+        /**
+         * Returns the default material of gltf. Related to
+         * https://github.com/KhronosGroup/glTF/tree/master/specification/1.0#appendix-a-default-material
+         * @param scene: the Babylon.js scene
+         */
+        GLTFUtils.GetDefaultMaterial = function (scene) {
+            if (!GLTFUtils._DefaultMaterial) {
+                BABYLON.Effect.ShadersStore["GLTFDefaultMaterialVertexShader"] = [
+                    "precision highp float;",
+                    "",
+                    "uniform mat4 worldView;",
+                    "uniform mat4 projection;",
+                    "",
+                    "attribute vec3 position;",
+                    "",
+                    "void main(void)",
+                    "{",
+                    "    gl_Position = projection * worldView * vec4(position, 1.0);",
+                    "}"
+                ].join("\n");
+                BABYLON.Effect.ShadersStore["GLTFDefaultMaterialPixelShader"] = [
+                    "precision highp float;",
+                    "",
+                    "uniform vec4 u_emission;",
+                    "",
+                    "void main(void)",
+                    "{",
+                    "    gl_FragColor = u_emission;",
+                    "}"
+                ].join("\n");
+                var shaderPath = {
+                    vertex: "GLTFDefaultMaterial",
+                    fragment: "GLTFDefaultMaterial"
+                };
+                var options = {
+                    attributes: ["position"],
+                    uniforms: ["worldView", "projection", "u_emission"],
+                    samplers: [],
+                    needAlphaBlending: false
+                };
+                GLTFUtils._DefaultMaterial = new BABYLON.ShaderMaterial("GLTFDefaultMaterial", scene, shaderPath, options);
+                GLTFUtils._DefaultMaterial.setColor4("u_emission", new BABYLON.Color4(0.5, 0.5, 0.5, 1.0));
+            }
+            return GLTFUtils._DefaultMaterial;
+        };
         return GLTFUtils;
     }());
+    // The GLTF default material
+    GLTFUtils._DefaultMaterial = null;
     BABYLON.GLTFUtils = GLTFUtils;
 })(BABYLON || (BABYLON = {}));
 

Plik diff jest za duży
+ 2 - 2
dist/preview release/loaders/babylon.glTFFileLoader.min.js


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

@@ -7,9 +7,12 @@
  - New DebugLayer. [Doc](TODO) - ([temechon](https://github.com/temechon))
  - New `VideoTexture.CreateFromWebCam` to generate video texture using WebRTC. [Demo](https://www.babylonjs-playground.com#1R77YT#2) - (Sebastien Vandenberghe)(https://github.com/sebavanmicrosoft) / ([deltakosh](https://github.com/deltakosh))
  - New `HolographicCamera` to support rendering on Windows Holographic. - ([sebavan](https://github.com/sebavan))
+ - New Facet Data feature ([jerome](https://github.com/jbousquie))
  - babylon.fontTexture.ts was moved from babylon.js to canvas2D ([nockawa](https://github.com/nockawa))
+ - Multi-platform Compressed Textures for Desktops & Mobile Devices with fall back.  Batch (dos) scripts to convert entire directories of .jpg's & .png's ([jcpalmer](https://github.com/Palmer-JC))
 
 ### Updates
+ - Added addChild, removeChild, setParent to AbstractMesh.  ([abow](https://github.com/abow))
  - `Effect.getVertexShaderSource()` and `Effect.getFragmentShaderSource()` now returns the effective shader code (including evaluation of #define) ([deltakosh](https://github.com/deltakosh))
 
 ### Canvas2D

+ 7 - 0
loaders/src/glTF/README.md

@@ -29,6 +29,13 @@ In order the fix the UP vector (Y with Babylon.js) if you want to play with phys
 BABYLON.GLTFFileLoader.MakeYUP = true; // false by default
 ```
 
+If you want to disable incremental loading (which is the default behavior), you can set the property IncrementalLoading to false.
+Then, you'll be able to be called back with all geometries and shaders loaded.
+For example, you can retrieve the real bounding infos of a mesh loaded using the loader.
+```
+BABYLON.GLTFFileLoader.IncrementalLoading = false; // true by default
+```
+
 In order to work with homogeneous coordinates (that can be available with some converters and exporters):
 ```
 BABYLON.GLTFFileLoader.HomogeneousCoordinates = true; // false by default

+ 20 - 40
loaders/src/glTF/babylon.glTFFileLoader.ts

@@ -264,10 +264,6 @@ module BABYLON {
                         }
                         else if (targetPath === "rotationQuaternion") {
                             rotationQuaternion = value;
-                            // Y is Up
-                            if (GLTFFileLoader.MakeYUP) {
-                                rotationQuaternion = rotationQuaternion.multiply(new Quaternion(-0.707107, 0, 0, 0.707107));
-                            }
                         }
                         else {
                             scaling = value;
@@ -312,11 +308,6 @@ module BABYLON {
             var rotation = Quaternion.FromArray(node.rotation || [0, 0, 0, 1]);
             var position = Vector3.FromArray(node.translation || [0, 0, 0]);
 
-            // Y is Up
-            if (GLTFFileLoader.MakeYUP) {
-                rotation = rotation.multiply(new Quaternion(-0.707107, 0, 0, 0.707107));
-            }
-
             mat = Matrix.Compose(scale, rotation, position);
         }
         else {
@@ -564,13 +555,6 @@ module BABYLON {
                 }
             }
 
-            if (!parentBone && nodesToRoot.length === 0) {
-                var inverseBindMatrix = Matrix.FromArray(buffer, i * 16);
-                var invertMesh = Matrix.Invert(mesh.getWorldMatrix());
-
-                mat = mat.multiply(mesh.getWorldMatrix());
-            }
-
             var bone = new Bone(node.jointName, newSkeleton, parentBone, mat);
             bone.id = id;
         }
@@ -727,7 +711,7 @@ module BABYLON {
 
                 // Sub material
                 var material = gltfRuntime.scene.getMaterialByID(primitive.material);
-                multiMat.subMaterials.push(material === null ? gltfRuntime.scene.defaultMaterial : material);
+                multiMat.subMaterials.push(material === null ? GLTFUtils.GetDefaultMaterial(gltfRuntime.scene) : material);
 
                 // Update vertices start and index start
                 verticesStarts.push(verticesStarts.length === 0 ? 0 : verticesStarts[verticesStarts.length - 1] + verticesCounts[verticesCounts.length - 2]);
@@ -737,7 +721,6 @@ module BABYLON {
 
         // Apply geometry
         geometry.setAllVerticesData(vertexData, false);
-
         newMesh.computeWorldMatrix(true);
 
         // Apply submeshes
@@ -785,7 +768,7 @@ module BABYLON {
     /**
     * Configures node from transformation matrix
     */
-    var configureNodeFromMatrix = (newNode: any, node: IGLTFNode) => {
+    var configureNodeFromMatrix = (newNode: Mesh, node: IGLTFNode, parent: Node) => {
         if (node.matrix) {
             var position = new Vector3(0, 0, 0);
             var rotation = new Quaternion();
@@ -793,16 +776,8 @@ module BABYLON {
             var mat = Matrix.FromArray(node.matrix);
             mat.decompose(scaling, rotation, position);
 
-            // Y is Up
-            if (GLTFFileLoader.MakeYUP) {
-                rotation = rotation.multiply(new Quaternion(-0.707107, 0, 0, 0.707107));
-            }
-
             configureNode(newNode, position, rotation, scaling);
-
-            if (newNode instanceof TargetCamera) {
-                (<TargetCamera>newNode).setTarget(Vector3.Zero());
-            }
+            newNode.computeWorldMatrix(true);
         }
         else {
             configureNode(newNode, Vector3.FromArray(node.translation), Quaternion.FromArray(node.rotation), Vector3.FromArray(node.scale));
@@ -812,7 +787,7 @@ module BABYLON {
     /**
     * Imports a node
     */
-    var importNode = (gltfRuntime: IGLTFRuntime, node: IGLTFNode, id: string): Node => {
+    var importNode = (gltfRuntime: IGLTFRuntime, node: IGLTFNode, id: string, parent: Node): Node => {
         var lastNode: Node = null;
 
         if (gltfRuntime.importOnlyMeshes && (node.skin || node.meshes)) {
@@ -837,10 +812,6 @@ module BABYLON {
                     }
                 }
 
-                if (newMesh.skeleton !== null) {
-                    //newMesh.useBones = true;
-                }
-
                 lastNode = newMesh;
             }
         }
@@ -959,8 +930,8 @@ module BABYLON {
         }
 
         if (lastNode !== null) {
-            if (node.matrix) {
-                configureNodeFromMatrix(lastNode, node);
+            if (node.matrix && lastNode instanceof Mesh) {
+                configureNodeFromMatrix(lastNode, node, parent);
             }
             else {
                 var translation = node.translation || [0, 0, 0];
@@ -970,7 +941,6 @@ module BABYLON {
             }
 
             lastNode.updateCache(true);
-
             node.babylonNode = lastNode;
         }
 
@@ -997,7 +967,7 @@ module BABYLON {
         }
 
         if (!node.jointName && meshIncluded) {
-            newNode = importNode(gltfRuntime, node, id);
+            newNode = importNode(gltfRuntime, node, id, parent);
 
             if (newNode !== null) {
                 newNode.id = id;
@@ -1571,8 +1541,8 @@ module BABYLON {
         /**
         * Static members
         */
-        public static MakeYUP: boolean = false;
         public static HomogeneousCoordinates: boolean = false;
+        public static IncrementalLoading: boolean = true;
 
         public static Extensions: { [name: string]: GLTFFileLoaderExtension } = {};
 
@@ -1636,10 +1606,14 @@ module BABYLON {
                     this._loadShadersAsync(gltfRuntime, () => {
                         importMaterials(gltfRuntime);
                         postLoad(gltfRuntime);
+
+                        if (!GLTFFileLoader.IncrementalLoading && onSuccess) {
+                            onSuccess(meshes, null, skeletons);
+                        }
                     });
                 });
 
-                if (onSuccess) {
+                if (GLTFFileLoader.IncrementalLoading && onSuccess) {
                     onSuccess(meshes, null, skeletons);
                 }
             }, onError);
@@ -1662,10 +1636,16 @@ module BABYLON {
                     this._loadShadersAsync(gltfRuntime, () => {
                         importMaterials(gltfRuntime);
                         postLoad(gltfRuntime);
+
+                        if (!GLTFFileLoader.IncrementalLoading) {
+                            onSuccess();
+                        }
                     });
                 });
 
-                onSuccess();
+                if (GLTFFileLoader.IncrementalLoading) {
+                    onSuccess();
+                }
             }, onError);
 
             return true;

+ 54 - 0
loaders/src/glTF/babylon.glTFFileLoaderUtils.ts

@@ -197,5 +197,59 @@ module BABYLON {
 
             return result;
         }
+
+        /**
+         * Returns the default material of gltf. Related to
+         * https://github.com/KhronosGroup/glTF/tree/master/specification/1.0#appendix-a-default-material
+         * @param scene: the Babylon.js scene
+         */
+        public static GetDefaultMaterial(scene: Scene): ShaderMaterial {
+            if (!GLTFUtils._DefaultMaterial) {
+                Effect.ShadersStore["GLTFDefaultMaterialVertexShader"] = [
+                    "precision highp float;",
+                    "",
+                    "uniform mat4 worldView;",
+                    "uniform mat4 projection;",
+                    "",
+                    "attribute vec3 position;",
+                    "",
+                    "void main(void)",
+                    "{",
+                    "    gl_Position = projection * worldView * vec4(position, 1.0);",
+                    "}"
+                ].join("\n");
+
+                Effect.ShadersStore["GLTFDefaultMaterialPixelShader"] = [
+                    "precision highp float;",
+                    "",
+                    "uniform vec4 u_emission;",
+                    "",
+                    "void main(void)",
+                    "{",
+                    "    gl_FragColor = u_emission;",
+                    "}"
+                ].join("\n");
+
+                var shaderPath = {
+                    vertex: "GLTFDefaultMaterial",
+                    fragment: "GLTFDefaultMaterial"
+                };
+
+                var options = {
+                    attributes: ["position"],
+                    uniforms: ["worldView", "projection", "u_emission"],
+                    samplers: [],
+                    needAlphaBlending: false
+                };
+
+                GLTFUtils._DefaultMaterial = new ShaderMaterial("GLTFDefaultMaterial", scene, shaderPath, options);
+                GLTFUtils._DefaultMaterial.setColor4("u_emission", new Color4(0.5, 0.5, 0.5, 1.0));
+            }
+
+            return GLTFUtils._DefaultMaterial;
+        }
+
+        // The GLTF default material
+        private static _DefaultMaterial: ShaderMaterial = null;
     }
 }

+ 13 - 0
src/Animations/babylon.animation.ts

@@ -308,6 +308,9 @@
         public clone(): Animation {
             var clone = new Animation(this.name, this.targetPropertyPath.join("."), this.framePerSecond, this.dataType, this.loopMode);
 
+            clone.enableBlending = this.enableBlending;
+            clone.blendingSpeed = this.blendingSpeed;
+
             if (this._keys) {
                 clone.setKeys(this._keys);
             }
@@ -658,6 +661,8 @@
             serializationObject.framePerSecond = this.framePerSecond;
             serializationObject.dataType = this.dataType;
             serializationObject.loopBehavior = this.loopMode;
+            serializationObject.enableBlending = this.enableBlending;
+            serializationObject.blendingSpeed = this.blendingSpeed;
 
             var dataType = this.dataType;
             serializationObject.keys = [];
@@ -755,6 +760,14 @@
             var data;
             var index: number;
 
+            if (parsedAnimation.enableBlending) {
+                animation.enableBlending = parsedAnimation.enableBlending;
+            }
+
+            if (parsedAnimation.blendingSpeed) {
+                animation.blendingSpeed = parsedAnimation.blendingSpeed;
+            }
+
             for (index = 0; index < parsedAnimation.keys.length; index++) {
                 var key = parsedAnimation.keys[index];
 

+ 2 - 2
src/Cameras/VR/babylon.vrCameraMetrics.ts

@@ -51,8 +51,8 @@
             result.vResolution = 800;
             result.hScreenSize = 0.149759993;
             result.vScreenSize = 0.0935999975;
-            result.vScreenCenter = 0.0467999987,
-                result.eyeToScreenDistance = 0.0410000011;
+            result.vScreenCenter = 0.0467999987;
+            result.eyeToScreenDistance = 0.0410000011;
             result.lensSeparationDistance = 0.0635000020;
             result.interpupillaryDistance = 0.0640000030;
             result.distortionK = [1.0, 0.219999999, 0.239999995, 0.0];

+ 4 - 2
src/Culling/babylon.ray.ts

@@ -241,6 +241,7 @@
             if(this._show){
                 this._show = false;
                 this._scene.unregisterBeforeRender(this._renderFunction);
+                this._scene = null;
             }
 
             if(this._renderLine){
@@ -254,9 +255,10 @@
         private _render(): void {
 
             var point = this._renderPoints[1];
-
+            var len = Math.min(this.length, 1000000);
+            
             point.copyFrom(this.direction);
-            point.scaleInPlace(this.length);
+            point.scaleInPlace(len);
             point.addInPlace(this.origin);
 
             Mesh.CreateLines("ray", this._renderPoints, this._scene, true, this._renderLine);

+ 146 - 0
src/Culling/babylon.rayHelper.ts

@@ -0,0 +1,146 @@
+module BABYLON {
+    export class RayHelper {
+        
+        public ray:Ray;
+
+        private _renderPoints: Vector3[];
+        private _renderLine: LinesMesh;
+        private _renderFunction: () => void;
+        private _scene: Scene;
+        
+        private _updateToMeshFunction: () => void;
+        private _attachedToMesh: AbstractMesh;
+        private _meshSpaceDirection: Vector3;
+        private _meshSpaceOrigin: Vector3;
+
+        constructor(ray:Ray) {
+            this.ray = ray;
+        }
+
+        public show(scene:Scene, color:Color3): void{
+
+            if(!this._renderFunction){
+
+                var ray = this.ray;
+
+                this._renderFunction = this._render.bind(this);
+                this._scene = scene;
+                this._renderPoints = [ray.origin, ray.origin.add(ray.direction.scale(ray.length))];
+                this._renderLine = Mesh.CreateLines("ray", this._renderPoints, scene, true);
+
+                this._scene.registerBeforeRender(this._renderFunction);
+
+            }
+
+            if (color) {
+                this._renderLine.color.copyFrom(color);
+            }
+
+        }
+
+        public hide(): void{
+
+            if(this._renderFunction){
+                this._scene.unregisterBeforeRender(this._renderFunction);
+                this._scene = null;
+                this._renderFunction = null;
+                this._renderLine.dispose();
+                this._renderLine = null;
+                this._renderPoints = null;
+            }
+
+        }
+
+        private _render(): void {
+
+            var ray = this.ray;
+
+            var point = this._renderPoints[1];
+            var len = Math.min(ray.length, 1000000);
+            
+            point.copyFrom(ray.direction);
+            point.scaleInPlace(len);
+            point.addInPlace(ray.origin);
+
+            Mesh.CreateLines("ray", this._renderPoints, this._scene, true, this._renderLine);
+
+        }
+
+        public attachToMesh(mesh:AbstractMesh, meshSpaceDirection?:Vector3, meshSpaceOrigin?:Vector3, length?:number): void{
+
+            this._attachedToMesh = mesh;
+
+            var ray = this.ray;
+
+            if(!ray.direction){
+                ray.direction = Vector3.Zero();
+            }
+
+            if(!ray.origin){
+                ray.origin = Vector3.Zero();
+            }
+
+            if(length){
+                ray.length = length;
+            }
+
+            if(!meshSpaceOrigin){
+                meshSpaceOrigin = Vector3.Zero();
+            }
+
+            if(!meshSpaceDirection){
+                // -1 so that this will work with Mesh.lookAt
+                meshSpaceDirection = new Vector3(0, 0, -1);
+            }
+
+            if(!this._meshSpaceDirection){
+                this._meshSpaceDirection = meshSpaceDirection.clone();
+                this._meshSpaceOrigin = meshSpaceOrigin.clone();
+            }else{
+                this._meshSpaceDirection.copyFrom(meshSpaceDirection);
+                this._meshSpaceOrigin.copyFrom(meshSpaceOrigin);
+            }
+
+            if(!this._updateToMeshFunction){
+                this._updateToMeshFunction = this._updateToMesh.bind(this);
+                this._attachedToMesh.getScene().registerBeforeRender(this._updateToMeshFunction);
+            }
+
+            this._updateToMesh();
+
+        }
+
+        public detachFromMesh(): void{
+
+            if(this._attachedToMesh){
+                this._attachedToMesh.getScene().unregisterBeforeRender(this._updateToMeshFunction);
+                this._attachedToMesh = null;
+                this._updateToMeshFunction = null;
+            }
+
+        }
+
+        private _updateToMesh(): void{
+
+            var ray = this.ray;
+
+            if(this._attachedToMesh._isDisposed){
+                this.detachFromMesh();
+                return;
+            }
+
+            this._attachedToMesh.getDirectionToRef(this._meshSpaceDirection, ray.direction);
+            Vector3.TransformCoordinatesToRef(this._meshSpaceOrigin, this._attachedToMesh.getWorldMatrix(), ray.origin);
+
+        }
+
+        public dispose(): void{
+
+            this.hide();
+            this.detachFromMesh();
+            this.ray = null;
+
+        }
+
+    }
+}

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

@@ -436,6 +436,8 @@
             if (this._boxBlurPostprocess) {
                 this._boxBlurPostprocess.dispose();
             }
+
+            this._light._shadowGenerator = null;
         }
 
         public serialize(): any {

+ 2 - 1
src/Materials/Textures/babylon.hdrCubeTexture.ts

@@ -384,7 +384,7 @@ module BABYLON {
             var texture = null;
             if (parsedTexture.name && !parsedTexture.isRenderTarget) {
                 var size = parsedTexture.isBABYLONPreprocessed ? null : parsedTexture.size;
-                texture = new BABYLON.HDRCubeTexture(rootUrl + parsedTexture.name, scene, size,
+                texture = new BABYLON.HDRCubeTexture(rootUrl + parsedTexture.name, scene, size, parsedTexture.noMipmap,
                     parsedTexture.generateHarmonics, parsedTexture.useInGammaSpace, parsedTexture.usePMREMGenerator);
                 texture.name = parsedTexture.name;
                 texture.hasAlpha = parsedTexture.hasAlpha;
@@ -411,6 +411,7 @@ module BABYLON {
             serializationObject.usePMREMGenerator = this._usePMREMGenerator;
             serializationObject.isBABYLONPreprocessed = this._isBABYLONPreprocessed;
             serializationObject.customType = "BABYLON.HDRCubeTexture";
+            serializationObject.noMipmap = this._noMipmap;
             
             return serializationObject;
         }

+ 86 - 0
src/Mesh/babylon.abstractMesh.ts

@@ -1277,6 +1277,92 @@
 
         }
 
+        public setParent(mesh:AbstractMesh, keepWorldPositionRotation = false): void{
+
+            var child = this;
+            var parent = mesh;
+
+            if(mesh == null){
+
+                if(child.parent && keepWorldPositionRotation){
+                  
+                    var rotation = Tmp.Quaternion[0];
+                    var position = Tmp.Vector3[0];
+                    var scale = Tmp.Vector3[1];
+
+                    child.getWorldMatrix().decompose(scale, rotation, position);
+
+                    if (child.rotationQuaternion) {
+                        child.rotationQuaternion.copyFrom(rotation);
+                    } else {
+                        rotation.toEulerAnglesToRef(child.rotation);
+                    }
+
+                    child.position.x = position.x;
+                    child.position.y = position.y;
+                    child.position.z = position.z;
+
+               }
+
+            } else {
+
+                if(keepWorldPositionRotation){
+                    
+                    var rotation = Tmp.Quaternion[0];
+                    var position = Tmp.Vector3[0];
+                    var scale = Tmp.Vector3[1];
+                    var m1 = Tmp.Matrix[0];
+                    var m2 = Tmp.Matrix[1];
+
+                    parent.getWorldMatrix().decompose(scale, rotation, position);
+
+                    rotation.toRotationMatrix(m1);
+                    m2.setTranslation(position);
+
+                    m2.multiplyToRef(m1, m1);
+
+                    var invParentMatrix = Matrix.Invert(m1);
+
+                    var m = child.getWorldMatrix().multiply(invParentMatrix);
+
+                    m.decompose(scale, rotation, position);
+
+                    if (child.rotationQuaternion) {
+                        child.rotationQuaternion.copyFrom(rotation);
+                    } else {
+                        rotation.toEulerAnglesToRef(child.rotation);
+                    }
+
+                    invParentMatrix = Matrix.Invert(parent.getWorldMatrix());
+
+                    var m = child.getWorldMatrix().multiply(invParentMatrix);
+
+                    m.decompose(scale, rotation, position);
+
+                    child.position.x = position.x;
+                    child.position.y = position.y;
+                    child.position.z = position.z;
+
+                }
+
+            }
+
+            child.parent = parent;
+
+        }
+
+        public addChild(mesh:AbstractMesh, keepWorldPositionRotation = false): void{
+
+            mesh.setParent(this, keepWorldPositionRotation);
+
+        }
+
+        public removeChild(mesh:AbstractMesh, keepWorldPositionRotation = false): void{
+
+            mesh.setParent(null, keepWorldPositionRotation);
+
+        }
+
         public getAbsolutePivotPointToRef(result:Vector3): void{
 
             result.x = this._pivotMatrix.m[12];

+ 304 - 7
src/Mesh/babylon.mesh.ts

@@ -119,7 +119,54 @@
         private _areNormalsFrozen: boolean = false; // Will be used by ribbons mainly
 
         private _sourcePositions: Float32Array; // Will be used to save original positions when using software skinning
-        private _sourceNormals: Float32Array; // Will be used to save original normals when using software skinning
+        private _sourceNormals: Float32Array;   // Will be used to save original normals when using software skinning
+
+        private _facetPositions: Vector3[];             // facet local positions
+        private _facetNormals: Vector3[];               // facet local normals
+        private _facetPartitioning: number[][];           // partitioning array of facet index arrays
+        private _facetNb: number = 0;                   // facet number
+        private _partitioningSubdivisions: number = 10; // number of subdivisions per axis in the partioning space  
+        private _partitioningBBoxRatio: number = 1.01;  // the partioning array space is by default 1% bigger than the bounding box
+        private _facetDataEnabled: boolean = false;     // is the facet data feature enabled on this mesh ?
+        private _facetParameters: any = {};                  // keep a reference to the object parameters to avoid memory re-allocation
+        private _bbSize: Vector3 = Vector3.Zero();      // bbox size approximated for facet data
+        private _subDiv = {                         // actual number of subdivisions per axis for ComputeNormals()
+            max: 1,
+            X: 1,
+            Y: 1,
+            Z: 1
+        };
+        /**
+         * Read-only : the number of facets in the mesh
+         */
+        public get facetNb(): number {
+            return this._facetNb;
+        }
+        /**
+         * The number of subdivisions per axis in the partioning space
+         */
+        public get partitioningSubdivisions(): number {
+            return this._partitioningSubdivisions;
+        }
+        public set partitioningSubdivisions(nb: number) {
+            this._partitioningSubdivisions = nb;
+        } 
+        /**
+         * The ratio to apply to the bouding box size to set to the partioning space.  
+         * Ex : 1.01 (default) the partioning space is 1% bigger than the bounding box.
+         */
+        public get partitioningBBoxRatio(): number {
+            return this._partitioningBBoxRatio;
+        }
+        public set partitioningBBoxRatio(ratio: number) {
+            this._partitioningBBoxRatio = ratio;
+        }
+        /**
+         * Read-only : is the feature facetData enabled ?
+         */
+        public get isFacetDataEnabled(): boolean {
+            return this._facetDataEnabled;
+        }
 
         // Will be used to save a source mesh reference, If any
         private _source: BABYLON.Mesh = null; 
@@ -1377,6 +1424,11 @@
                 }
             }
 
+            // facet data
+            if (this._facetDataEnabled) {
+                this.disableFacetData();
+            }
+
             super.dispose(doNotRecurse);
         }
 
@@ -1715,10 +1767,10 @@
         }
 
         /**
-         * Optimization of the mesh's indices, in case a mesh has duplicated vertices.
-         * The function will only reorder the indices and will not remove unused vertices to avoid problems with submeshes.
-         * This should be used together with the simplification to avoid disappearing triangles.
-         * @param successCallback an optional success callback to be called after the optimization finished.
+         * Optimization of the mesh's indices, in case a mesh has duplicated vertices.   
+         * The function will only reorder the indices and will not remove unused vertices to avoid problems with submeshes.   
+         * This should be used together with the simplification to avoid disappearing triangles.   
+         * @param successCallback an optional success callback to be called after the optimization finished.   
          */
         public optimizeIndices(successCallback?: (mesh?: Mesh) => void) {
             var indices = this.getIndices();
@@ -1754,10 +1806,255 @@
             });
         }
 
+        // Facet data
+        /** 
+         *  Initialize the facet data arrays : facetNormals, facetPositions and facetPartitioning
+         */
+        private _initFacetData(): Mesh {
+            if (!this._facetNormals) {
+                this._facetNormals = new Array<Vector3>();
+            }
+            if (!this._facetPositions) {
+                this._facetPositions = new Array<Vector3>();
+            }
+            if (!this._facetPartitioning) {
+                this._facetPartitioning = new Array<number[]>();
+            }
+            this._facetNb = this.getIndices().length / 3;
+            this._partitioningSubdivisions = (this._partitioningSubdivisions) ? this._partitioningSubdivisions : 10;   // default nb of partitioning subdivisions = 10
+            this._partitioningBBoxRatio = (this._partitioningBBoxRatio) ? this._partitioningBBoxRatio : 1.01;          // default ratio 1.01 = the partitioning is 1% bigger than the bounding box
+            for (var f = 0; f < this._facetNb; f++) {
+                this._facetNormals[f] = Vector3.Zero();
+                this._facetPositions[f] = Vector3.Zero();
+            }
+            this._facetDataEnabled = true;           
+            return this;
+        }
+
+        /**
+         * Updates the mesh facetData arrays and the internal partitioning when the mesh is morphed or updated.  
+         * This method can be called within the render loop.  
+         * You don't need to call this method by yourself in the render loop when you update/morph a mesh with the methods CreateXXX() as they automatically manage this computation.  
+         */
+        public updateFacetData(): Mesh {
+            if (!this._facetDataEnabled) {
+                this._initFacetData();
+            }
+            var positions = this.getVerticesData(VertexBuffer.PositionKind);
+            var indices = this.getIndices();
+            var normals = this.getVerticesData(VertexBuffer.NormalKind);
+            var bInfo = this.getBoundingInfo();
+            this._bbSize.x = (bInfo.maximum.x - bInfo.minimum.x > Epsilon) ? bInfo.maximum.x - bInfo.minimum.x : Epsilon;
+            this._bbSize.y = (bInfo.maximum.y - bInfo.minimum.y > Epsilon) ? bInfo.maximum.y - bInfo.minimum.y : Epsilon;
+            this._bbSize.z = (bInfo.maximum.z - bInfo.minimum.z > Epsilon) ? bInfo.maximum.z - bInfo.minimum.z : Epsilon;
+            var bbSizeMax = (this._bbSize.x > this._bbSize.y) ? this._bbSize.x : this._bbSize.y;
+            bbSizeMax = (bbSizeMax > this._bbSize.z) ? bbSizeMax : this._bbSize.z;
+            this._subDiv.max = this._partitioningSubdivisions;
+            this._subDiv.X = Math.floor(this._subDiv.max * this._bbSize.x / bbSizeMax);   // adjust the number of subdivisions per axis
+            this._subDiv.Y = Math.floor(this._subDiv.max * this._bbSize.y / bbSizeMax);   // according to each bbox size per axis
+            this._subDiv.Z = Math.floor(this._subDiv.max * this._bbSize.z / bbSizeMax);
+            this._subDiv.X = this._subDiv.X < 1 ? 1 : this._subDiv.X;                     // at least one subdivision
+            this._subDiv.Y = this._subDiv.Y < 1 ? 1 : this._subDiv.Y;
+            this._subDiv.Z = this._subDiv.Z < 1 ? 1 : this._subDiv.Z;
+            // set the parameters for ComputeNormals()
+            this._facetParameters.facetNormals = this.getFacetLocalNormals(); 
+            this._facetParameters.facetPositions = this.getFacetLocalPositions();
+            this._facetParameters.facetPartitioning = this.getFacetLocalPartitioning();
+            this._facetParameters.bInfo = bInfo;
+            this._facetParameters.bbSize = this._bbSize;
+            this._facetParameters.subDiv = this._subDiv;
+            this._facetParameters.ratio = this.partitioningBBoxRatio;
+            VertexData.ComputeNormals(positions, indices, normals, this._facetParameters);
+            return this;
+        }
+        /**
+         * Returns the facetLocalNormals array.  
+         * The normals are expressed in the mesh local space.  
+         */
+        public getFacetLocalNormals(): Vector3[] {
+            if (!this._facetNormals) {
+                this.updateFacetData();
+            }
+            return this._facetNormals;
+        }
+        /**
+         * Returns the facetLocalPositions array.  
+         * The facet positions are expressed in the mesh local space.  
+         */
+        public getFacetLocalPositions(): Vector3[] {
+            if (!this._facetPositions) {
+                this.updateFacetData();
+            }
+            return this._facetPositions;           
+        }
+        /**
+         * Returns the facetLocalPartioning array
+         */
+        public getFacetLocalPartitioning(): number[][] {
+            if (!this._facetPartitioning) {
+                this.updateFacetData();
+            }
+            return this._facetPartitioning;
+        }
+        /**
+         * Returns the i-th facet position in the world system.  
+         * This method allocates a new Vector3 per call.  
+         */
+        public getFacetPosition(i: number): Vector3 {
+            var pos = Vector3.Zero();
+            this.getFacetPositionToRef(i, pos);
+            return pos;
+        }
+        /**
+         * Sets the reference Vector3 with the i-th facet position in the world system.  
+         * Returns the mesh.  
+         */
+        public getFacetPositionToRef(i: number, ref: Vector3): Mesh {
+            var localPos = (this.getFacetLocalPositions())[i];
+            var world = this.getWorldMatrix();
+            Vector3.TransformCoordinatesToRef(localPos, world, ref);
+            return this;
+        }
+        /**
+         * Returns the i-th facet normal in the world system.  
+         * This method allocates a new Vector3 per call.  
+         */
+        public getFacetNormal(i: number): Vector3 {
+            var norm = Vector3.Zero();
+            this.getFacetNormalToRef(i, norm);
+            return norm;
+        }
+        /**
+         * Sets the reference Vector3 with the i-th facet normal in the world system.  
+         * Returns the mesh.  
+         */
+        public getFacetNormalToRef(i: number, ref: Vector3) {
+            var localNorm = (this.getFacetLocalNormals())[i];
+            (this.getWorldMatrix()).getRotationMatrixToRef(Tmp.Matrix[0]);
+            Vector3.TransformCoordinatesToRef(localNorm, Tmp.Matrix[0], ref);
+            return this;
+        }
+        /** 
+         * Returns the facets (in an array) in the same partitioning block than the one the passed coordinates are located (expressed in the mesh local system).
+         */
+        public getFacetsAtLocalCoordinates(x: number, y: number, z: number): number[] {
+            var bInfo = this.getBoundingInfo();
+            var ox = Math.floor((x - bInfo.minimum.x * this._partitioningBBoxRatio) * this._subDiv.X * this._partitioningBBoxRatio / this._bbSize.x);
+            var oy = Math.floor((y - bInfo.minimum.y * this._partitioningBBoxRatio) * this._subDiv.Y * this._partitioningBBoxRatio / this._bbSize.y);
+            var oz = Math.floor((z - bInfo.minimum.z * this._partitioningBBoxRatio) * this._subDiv.Z * this._partitioningBBoxRatio / this._bbSize.z);
+            if (ox < 0 || ox > this._subDiv.max || oy < 0 || oy > this._subDiv.max || oz < 0 || oz > this._subDiv.max) {
+                return null;
+            }
+            return this._facetPartitioning[ox + this._subDiv.max * oy + this._subDiv.max * this._subDiv.max * oz];
+        }
+        /** 
+         * Returns the closest mesh facet index at (x,y,z) World coordinates, null if not found.  
+         * If the parameter projected (vector3) is passed, it is set as the (x,y,z) World projection on the facet.  
+         * If checkFace is true (default false), only the facet "facing" to (x,y,z) or only the ones "turning their backs", according to the parameter "facing" are returned.
+         * If facing and checkFace are true, only the facet "facing" to (x, y, z) are returned : positive dot (x, y, z) * facet position.
+         * If facing si false and checkFace is true, only the facet "turning their backs" to (x, y, z) are returned : negative dot (x, y, z) * facet position. 
+         */
+        public getClosestFacetAtCoordinates(x: number, y: number, z: number, projected?: Vector3, checkFace: boolean = false, facing: boolean = true): number {
+            var world = this.getWorldMatrix();
+            var invMat = Tmp.Matrix[5];
+            world.invertToRef(invMat);
+            var invVect = Tmp.Vector3[8];
+            var closest = null;
+            Vector3.TransformCoordinatesFromFloatsToRef(x, y, z, invMat, invVect);  // transform (x,y,z) to coordinates in the mesh local space
+            closest = this.getClosestFacetAtLocalCoordinates(invVect.x, invVect.y, invVect.z, projected, checkFace, facing);
+            if (projected) {
+                // tranform the local computed projected vector to world coordinates
+                Vector3.TransformCoordinatesFromFloatsToRef(projected.x, projected.y, projected.z, world, projected);
+            }
+            return closest;
+        }
+        /** 
+         * Returns the closest mesh facet index at (x,y,z) local coordinates, null if not found.   
+         * If the parameter projected (vector3) is passed, it is set as the (x,y,z) local projection on the facet.  
+         * If checkFace is true (default false), only the facet "facing" to (x,y,z) or only the ones "turning their backs", according to the parameter "facing" are returned.
+         * If facing and checkFace are true, only the facet "facing" to (x, y, z) are returned : positive dot (x, y, z) * facet position.
+         * If facing si false and checkFace is true, only the facet "turning their backs"  to (x, y, z) are returned : negative dot (x, y, z) * facet position.
+         */
+        public getClosestFacetAtLocalCoordinates(x: number, y: number, z: number, projected?: Vector3, checkFace: boolean = false, facing: boolean = true) {
+            var closest = null;
+            var tmpx = 0.0;         
+            var tmpy = 0.0;
+            var tmpz = 0.0;
+            var d = 0.0;            // tmp dot facet normal * facet position
+            var t0 = 0.0;
+            var projx = 0.0;
+            var projy = 0.0;
+            var projz = 0.0;
+            // Get all the facets in the same partitioning block than (x, y, z)
+            var facetPositions = this.getFacetLocalPositions();
+            var facetNormals = this.getFacetLocalNormals();
+            var facetsInBlock = this.getFacetsAtLocalCoordinates(x, y, z);
+            if (!facetsInBlock) {
+                return null;
+            }
+            // Get the closest facet to (x, y, z)
+            var shortest = Number.MAX_VALUE;            // init distance vars
+            var tmpDistance = shortest;
+            var fib;                                    // current facet in the block
+            var norm;                                   // current facet normal
+            var p0;                                     // current facet barycenter position
+            // loop on all the facets in the current partitioning block
+            for (var idx = 0; idx < facetsInBlock.length; idx++) {
+                fib = facetsInBlock[idx];           
+                norm = facetNormals[fib];
+                p0 = facetPositions[fib];
+
+                d = (x - p0.x) * norm.x + (y - p0.y) * norm.y + (z - p0.z) * norm.z;
+                if ( !checkFace || (checkFace && facing && d >= 0.0) || (checkFace && !facing && d <= 0.0) ) {
+                    // compute (x,y,z) projection on the facet = (projx, projy, projz)
+                    d = norm.x * p0.x + norm.y * p0.y + norm.z * p0.z; 
+                    t0 = -(norm.x * x + norm.y * y + norm.z * z - d) / (norm.x * norm.x + norm.y * norm.y + norm.z * norm.z);
+                    projx = x + norm.x * t0;
+                    projy = y + norm.y * t0;
+                    projz = z + norm.z * t0;
+
+                    tmpx = projx - x;
+                    tmpy = projy - y;
+                    tmpz = projz - z;
+                    tmpDistance = tmpx * tmpx + tmpy * tmpy + tmpz * tmpz;             // compute length between (x, y, z) and its projection on the facet
+                    if (tmpDistance < shortest) {                                      // just keep the closest facet to (x, y, z)
+                        shortest = tmpDistance;
+                        closest = fib; 
+                        if (projected) {
+                            projected.x = projx;
+                            projected.y = projy;
+                            projected.z = projz;
+                        }
+                    }
+                }
+            }
+            return closest;
+        }
+        /**
+         * Returns the object "parameter" set with all the expected parameters for facetData computation by ComputeNormals()  
+         */
+        public getFacetDataParameters(): any {
+            return this._facetParameters;
+        }
+        /** 
+         * Disables the feature FacetData and frees the related memory.  
+         * Returns the mesh.  
+         */
+        public disableFacetData(): Mesh {
+            if (this._facetDataEnabled) {
+                this._facetDataEnabled = false;
+                this._facetPositions = null;
+                this._facetNormals = null;
+                this._facetPartitioning = null;
+                this._facetParameters = null;
+            }
+            return this;
+        }
+
         // Statics
         /**
-         * Returns a new Mesh object what is a deep copy of the passed mesh. 
-         * The parameter `parsedMesh` is the mesh to be copied.
+         * Returns a new Mesh object what is a deep copy of the passed mesh.   
+         * The parameter `parsedMesh` is the mesh to be copied.   
          * The parameter `rootUrl` is a string, it's the root URL to prefix the `delayLoadingFile` property with
          */
         public static Parse(parsedMesh: any, scene: Scene, rootUrl: string): Mesh {

+ 159 - 47
src/Mesh/babylon.mesh.vertexData.ts

@@ -538,8 +538,8 @@
             var v: number;
             for (p = 0; p < pathArray.length; p++) {
                 for (i = 0; i < minlg + closePathCorr; i++) {
-                    u = us[p][i] / uTotalDistance[p];
-                    v = vs[i][p] / vTotalDistance[i];
+                    u = (uTotalDistance[p] != 0.0) ? us[p][i] / uTotalDistance[p] : 0.0;
+                    v = (vTotalDistance[i] != 0.0) ? vs[i][p] / vTotalDistance[i] : 0.0;
                     if (invertUV) {
                         uvs.push(v, u);
                     } else {
@@ -1199,7 +1199,7 @@
 
                     positions.push(position.x, position.y, position.z);
                     normals.push(normal.x, normal.y, normal.z);
-                    uvs.push(col / subdivisionsX, 1.0 - row / subdivisionsX);
+                    uvs.push(col / subdivisionsX, 1.0 - row / subdivisionsY);
                 }
             }
 
@@ -1961,66 +1961,178 @@
          * @param {any} - positions (number[] or Float32Array)
          * @param {any} - indices   (number[] or Uint16Array)
          * @param {any} - normals   (number[] or Float32Array)
+         * options (optional) :
+         * facetPositions : optional array of facet positions (vector3)
+         * facetNormals : optional array of facet normals (vector3)
+         * facetPartitioning : optional partitioning array. facetPositions is required for facetPartitioning computation
+         * subDiv : optional partitioning data about subdivsions on  each axis (int), required for facetPartitioning computation
+         * ratio : optional partitioning ratio / bounding box, required for facetPartitioning computation
+         * bbSize : optional bounding box size data, required for facetPartitioning computation
+         * bInfo : optional bounding info, required for facetPartitioning computation
          */
-        public static ComputeNormals(positions: any, indices: any, normals: any) {
-            var index = 0;
-
-            var p1p2x = 0.0;
-            var p1p2y = 0.0;
-            var p1p2z = 0.0;
-            var p3p2x = 0.0;
-            var p3p2y = 0.0;
-            var p3p2z = 0.0;
-            var faceNormalx = 0.0;
-            var faceNormaly = 0.0;
-            var faceNormalz = 0.0;
-
-            var length = 0.0;
-
-            var i1 = 0;
-            var i2 = 0;
-            var i3 = 0;
-
+        public static ComputeNormals(positions: any, indices: any, normals: any, 
+            options?: { facetNormals?: any, facetPositions?: any, facetPartitioning?: any, ratio?: number, bInfo?: any, bbSize?: Vector3, subDiv?: any}): void {
+
+            // temporary scalar variables
+            var index = 0;                      // facet index     
+            var p1p2x = 0.0;                    // p1p2 vector x coordinate
+            var p1p2y = 0.0;                    // p1p2 vector y coordinate
+            var p1p2z = 0.0;                    // p1p2 vector z coordinate
+            var p3p2x = 0.0;                    // p3p2 vector x coordinate
+            var p3p2y = 0.0;                    // p3p2 vector y coordinate
+            var p3p2z = 0.0;                    // p3p2 vector z coordinate
+            var faceNormalx = 0.0;              // facet normal x coordinate
+            var faceNormaly = 0.0;              // facet normal y coordinate
+            var faceNormalz = 0.0;              // facet normal z coordinate
+            var length = 0.0;                   // facet normal length before normalization
+            var v1x = 0;                        // vector1 x index in the positions array
+            var v1y = 0;                        // vector1 y index in the positions array
+            var v1z = 0;                        // vector1 z index in the positions array
+            var v2x = 0;                        // vector2 x index in the positions array
+            var v2y = 0;                        // vector2 y index in the positions array
+            var v2z = 0;                        // vector2 z index in the positions array
+            var v3x = 0;                        // vector3 x index in the positions array
+            var v3y = 0;                        // vector3 y index in the positions array
+            var v3z = 0;                        // vector3 z index in the positions array
+            var computeFacetNormals = false;
+            var computeFacetPositions = false;
+            var computeFacetPartitioning = false;
+            if (options) {
+                computeFacetNormals = (options.facetNormals) ? true : false;
+                computeFacetPositions = (options.facetPositions) ? true : false;
+                computeFacetPartitioning = (options.facetPartitioning) ? true : false;
+            }
+
+            // facetPartitioning reinit if needed
+            if (computeFacetPartitioning) {  
+                var ox = 0;                 // X partitioning index for facet position
+                var oy = 0;                 // Y partinioning index for facet position
+                var oz = 0;                 // Z partinioning index for facet position
+                var b1x = 0;                // X partitioning index for facet v1 vertex
+                var b1y = 0;                // Y partitioning index for facet v1 vertex
+                var b1z = 0;                // z partitioning index for facet v1 vertex
+                var b2x = 0;                // X partitioning index for facet v2 vertex
+                var b2y = 0;                // Y partitioning index for facet v2 vertex
+                var b2z = 0;                // Z partitioning index for facet v2 vertex
+                var b3x = 0;                // X partitioning index for facet v3 vertex
+                var b3y = 0;                // Y partitioning index for facet v3 vertex
+                var b3z = 0;                // Z partitioning index for facet v3 vertex
+                var block_idx_o = 0;        // facet barycenter block index
+                var block_idx_v1 = 0;       // v1 vertex block index
+                var block_idx_v2 = 0;       // v2 vertex block index
+                var block_idx_v3 = 0;       // v3 vertex block index  
+
+                var bbSizeMax = (options.bbSize.x > options.bbSize.y) ? options.bbSize.x : options.bbSize.y;
+                bbSizeMax = (bbSizeMax > options.bbSize.z) ? bbSizeMax : options.bbSize.z;
+                var xSubRatio = options.subDiv.X * options.ratio / options.bbSize.x;
+                var ySubRatio = options.subDiv.Y * options.ratio / options.bbSize.y;
+                var zSubRatio = options.subDiv.Z * options.ratio / options.bbSize.z;
+                var subSq = options.subDiv.max * options.subDiv.max;
+                options.facetPartitioning.length = 0;
+            }
+        
+            // reset the normals
             for (index = 0; index < positions.length; index++) {
                 normals[index] = 0.0;
             }
 
-            // indice triplet = 1 face
+            // Loop : 1 indice triplet = 1 facet
             var nbFaces = indices.length / 3;
             for (index = 0; index < nbFaces; index++) {
-                i1 = indices[index * 3];            // get the indexes of each vertex of the face
-                i2 = indices[index * 3 + 1];
-                i3 = indices[index * 3 + 2];
 
-                p1p2x = positions[i1 * 3] - positions[i2 * 3];          // compute two vectors per face
-                p1p2y = positions[i1 * 3 + 1] - positions[i2 * 3 + 1];
-                p1p2z = positions[i1 * 3 + 2] - positions[i2 * 3 + 2];
-
-                p3p2x = positions[i3 * 3] - positions[i2 * 3];
-                p3p2y = positions[i3 * 3 + 1] - positions[i2 * 3 + 1];
-                p3p2z = positions[i3 * 3 + 2] - positions[i2 * 3 + 2];
-
-                faceNormalx = p1p2y * p3p2z - p1p2z * p3p2y;            // compute the face normal with cross product
+                // get the indexes of the coordinates of each vertex of the facet
+                v1x = indices[index * 3] * 3;
+                v1y = v1x + 1;
+                v1z = v1x + 2;
+                v2x = indices[index * 3 + 1] * 3;
+                v2y = v2x + 1;
+                v2z = v2x + 2;
+                v3x = indices[index * 3 + 2] * 3;
+                v3y = v3x + 1;
+                v3z = v3x + 2;        
+
+                p1p2x = positions[v1x] - positions[v2x];          // compute two vectors per facet : p1p2 and p3p2
+                p1p2y = positions[v1y] - positions[v2y];
+                p1p2z = positions[v1z] - positions[v2z];
+
+                p3p2x = positions[v3x] - positions[v2x];
+                p3p2y = positions[v3y] - positions[v2y];
+                p3p2z = positions[v3z] - positions[v2z];
+
+                // compute the face normal with the cross product
+                faceNormalx = p1p2y * p3p2z - p1p2z * p3p2y;            
                 faceNormaly = p1p2z * p3p2x - p1p2x * p3p2z;
                 faceNormalz = p1p2x * p3p2y - p1p2y * p3p2x;
-
+                // normalize this normal and store it in the array facetData
                 length = Math.sqrt(faceNormalx * faceNormalx + faceNormaly * faceNormaly + faceNormalz * faceNormalz);
                 length = (length === 0) ? 1.0 : length;
-                faceNormalx /= length;                                  // normalize this normal
+                faceNormalx /= length;
                 faceNormaly /= length;
                 faceNormalz /= length;
 
-                normals[i1 * 3] += faceNormalx;                         // accumulate all the normals per face
-                normals[i1 * 3 + 1] += faceNormaly;
-                normals[i1 * 3 + 2] += faceNormalz;
-                normals[i2 * 3] += faceNormalx;
-                normals[i2 * 3 + 1] += faceNormaly;
-                normals[i2 * 3 + 2] += faceNormalz;
-                normals[i3 * 3] += faceNormalx;
-                normals[i3 * 3 + 1] += faceNormaly;
-                normals[i3 * 3 + 2] += faceNormalz;
-            }
+                if (computeFacetNormals) {
+                    options.facetNormals[index].x = faceNormalx;                                  
+                    options.facetNormals[index].y = faceNormaly;
+                    options.facetNormals[index].z = faceNormalz;
+                }
+
+                if (computeFacetPositions) {
+                    // compute and the facet barycenter coordinates in the array facetPositions 
+                    options.facetPositions[index].x = (positions[v1x] + positions[v2x] + positions[v3x]) / 3.0;
+                    options.facetPositions[index].y = (positions[v1y] + positions[v2y] + positions[v3y]) / 3.0;
+                    options.facetPositions[index].z = (positions[v1z] + positions[v2z] + positions[v3z]) / 3.0;
+                }
 
+                if (computeFacetPartitioning) {
+                    // store the facet indexes in arrays in the main facetPartitioning array :
+                    // compute each facet vertex (+ facet barycenter) index in the partiniong array
+                    ox = Math.floor((options.facetPositions[index].x - options.bInfo.minimum.x * options.ratio) * xSubRatio);
+                    oy = Math.floor((options.facetPositions[index].y - options.bInfo.minimum.y * options.ratio) * ySubRatio);
+                    oz = Math.floor((options.facetPositions[index].z - options.bInfo.minimum.z * options.ratio) * zSubRatio);
+                    b1x = Math.floor((positions[v1x] - options.bInfo.minimum.x * options.ratio) * xSubRatio);
+                    b1y = Math.floor((positions[v1y] - options.bInfo.minimum.y * options.ratio) * ySubRatio);
+                    b1z = Math.floor((positions[v1z] - options.bInfo.minimum.z * options.ratio) * zSubRatio);
+                    b2x = Math.floor((positions[v2x] - options.bInfo.minimum.x * options.ratio) * xSubRatio);
+                    b2y = Math.floor((positions[v2y] - options.bInfo.minimum.y * options.ratio) * ySubRatio);
+                    b2z = Math.floor((positions[v2z] - options.bInfo.minimum.z * options.ratio) * zSubRatio);
+                    b3x = Math.floor((positions[v3x] - options.bInfo.minimum.x * options.ratio) * xSubRatio);
+                    b3y = Math.floor((positions[v3y] - options.bInfo.minimum.y * options.ratio) * ySubRatio);
+                    b3z = Math.floor((positions[v3z] - options.bInfo.minimum.z * options.ratio) * zSubRatio);
+                    
+                    block_idx_v1 = b1x + options.subDiv.max * b1y + subSq * b1z;
+                    block_idx_v2 = b2x + options.subDiv.max * b2y + subSq * b2z;
+                    block_idx_v3 = b3x + options.subDiv.max * b3y + subSq * b3z;
+                    block_idx_o = ox + options.subDiv.max * oy + subSq * oz;
+
+                    options.facetPartitioning[block_idx_o] = options.facetPartitioning[block_idx_o] ? options.facetPartitioning[block_idx_o] :new Array();
+                    options.facetPartitioning[block_idx_v1] = options.facetPartitioning[block_idx_v1] ? options.facetPartitioning[block_idx_v1] :new Array();
+                    options.facetPartitioning[block_idx_v2] = options.facetPartitioning[block_idx_v2] ? options.facetPartitioning[block_idx_v2] :new Array();
+                    options.facetPartitioning[block_idx_v3] = options.facetPartitioning[block_idx_v3] ? options.facetPartitioning[block_idx_v3] :new Array();
+
+                    // push each facet index in each block containing the vertex
+                    options.facetPartitioning[block_idx_v1].push(index);
+                    if (block_idx_v2 != block_idx_v1) {
+                        options.facetPartitioning[block_idx_v2].push(index);
+                    }
+                    if (!(block_idx_v3 == block_idx_v2 || block_idx_v3 == block_idx_v1)) {
+                        options.facetPartitioning[block_idx_v3].push(index);
+                    }
+                    if (!(block_idx_o == block_idx_v1 || block_idx_o == block_idx_v2 || block_idx_o == block_idx_v3)) {
+                        options.facetPartitioning[block_idx_o].push(index); 
+                    }
+                }
+
+                // compute the normals anyway
+                normals[v1x] += faceNormalx;                         // accumulate all the normals per face
+                normals[v1y] += faceNormaly;
+                normals[v1z] += faceNormalz;
+                normals[v2x] += faceNormalx;
+                normals[v2y] += faceNormaly;
+                normals[v2z] += faceNormalz;
+                normals[v3x] += faceNormalx;
+                normals[v3y] += faceNormaly;
+                normals[v3z] += faceNormalz;
+            }
             // last normalization of each normal
             for (index = 0; index < normals.length / 3; index++) {
                 faceNormalx = normals[index * 3];

+ 9 - 7
src/Mesh/babylon.meshBuilder.ts

@@ -187,10 +187,11 @@
                 instance._boundingInfo = new BoundingInfo(Tmp.Vector3[0], Tmp.Vector3[1]);
                 instance._boundingInfo.update(instance._worldMatrix);
                 instance.updateVerticesData(VertexBuffer.PositionKind, positions, false, false);
-                if (!(instance.areNormalsFrozen)) {
+                if (!instance.areNormalsFrozen || instance.isFacetDataEnabled) {
                     var indices = instance.getIndices();
                     var normals = instance.getVerticesData(VertexBuffer.NormalKind);
-                    VertexData.ComputeNormals(positions, indices, normals);
+                    var params = instance.isFacetDataEnabled ? instance.getFacetDataParameters() : null;
+                    VertexData.ComputeNormals(positions, indices, normals, params);
 
                     if ((<any>instance)._closePath) {
                         var indexFirst: number = 0;
@@ -211,8 +212,9 @@
                             normals[indexLast + 2] = normals[indexFirst + 2];
                         }
                     }
-
-                    instance.updateVerticesData(VertexBuffer.NormalKind, normals, false, false);
+                    if (!(instance.areNormalsFrozen)) {
+                        instance.updateVerticesData(VertexBuffer.NormalKind, normals, false, false);
+                    }
                 }
 
                 return instance;
@@ -1152,7 +1154,7 @@
                     for (i = 0; i < shapePath.length; i++) {
                         barycenter.addInPlace(shapePath[i]);
                     }
-                    barycenter.scaleInPlace(1 / shapePath.length);
+                    barycenter.scaleInPlace(1.0 / shapePath.length);
                     for (i = 0; i < shapePath.length; i++) {
                         pointCap.push(barycenter);
                     }
@@ -1163,7 +1165,7 @@
                         break;
                     case Mesh.CAP_START:
                         shapePaths[0] = capPath(shapePaths[2]);
-                        shapePaths[1] = shapePaths[2].slice(0);
+                        shapePaths[1] = shapePaths[2];
                         break;
                     case Mesh.CAP_END:
                         shapePaths[index] = shapePaths[index - 1];
@@ -1171,7 +1173,7 @@
                         break;
                     case Mesh.CAP_ALL:
                         shapePaths[0] = capPath(shapePaths[2]);
-                        shapePaths[1] = shapePaths[2].slice(0);
+                        shapePaths[1] = shapePaths[2];
                         shapePaths[index] = shapePaths[index - 1];
                         shapePaths[index + 1] = capPath(shapePaths[index - 1]);
                         break;

+ 12 - 3
src/Particles/babylon.particleSystem.ts

@@ -42,7 +42,8 @@
         public layerMask: number = 0x0FFFFFFF;
 
         public customShader: any = null;
-
+        public preventAutoStart: boolean = false;
+        
         /**
         * An event triggered when the system is disposed.
         * @type {BABYLON.Observable}
@@ -470,7 +471,9 @@
                 result.particleTexture = new Texture(this.particleTexture.url, this._scene);
             }
 
-            result.start();
+            if (!this.preventAutoStart) {
+                result.start();
+            }
 
             return result;
         }
@@ -520,6 +523,7 @@
             serializationObject.textureMask = this.textureMask.asArray();
             serializationObject.blendMode = this.blendMode;
             serializationObject.customShader = this.customShader;
+            serializationObject.preventAutoStart = this.preventAutoStart;
 
             return serializationObject;
         }
@@ -540,6 +544,11 @@
                 particleSystem.id = parsedParticleSystem.id;
             }
 
+            // Auto start
+            if (parsedParticleSystem.preventAutoStart) {
+                particleSystem.preventAutoStart = parsedParticleSystem.preventAutoStart;
+            }
+
             // Texture
             if (parsedParticleSystem.textureName) {
                 particleSystem.particleTexture = new Texture(rootUrl + parsedParticleSystem.textureName, scene);
@@ -588,7 +597,7 @@
             particleSystem.textureMask = Color4.FromArray(parsedParticleSystem.textureMask);
             particleSystem.blendMode = parsedParticleSystem.blendMode;
 
-            if (!parsedParticleSystem.preventAutoStart) {
+            if (!particleSystem.preventAutoStart) {
                 particleSystem.start();
             }
 

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

@@ -562,13 +562,17 @@
             }
 
             Matrix.IdentityToRef(this._rotMatrix);
-            var idx = 0;
-            var index = 0;
-            var colidx = 0;
-            var colorIndex = 0;
-            var uvidx = 0;
-            var uvIndex = 0;
-            var pt = 0;
+            var idx = 0;            // current position index in the global array positions32
+            var index = 0;          // position start index in the global array positions32 of the current particle
+            var colidx = 0;         // current color index in the global array colors32
+            var colorIndex = 0;     // color start index in the global array colors32 of the current particle
+            var uvidx = 0;          // current uv index in the global array uvs32
+            var uvIndex = 0;        // uv start index in the global array uvs32 of the current particle
+            var pt = 0;             // current index in the particle model shape
+
+            if (this.mesh.isFacetDataEnabled) {
+                this._computeBoundingBox = true;
+            }
 
             if (this._computeBoundingBox) {
                 Vector3.FromFloatsToRef(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE, this._minimum);
@@ -653,7 +657,7 @@
                             }
                         }
 
-                        // normals : if the particles can't be morphed then just rotate the normals, what if much more faster than ComputeNormals()
+                        // normals : if the particles can't be morphed then just rotate the normals, what is much more faster than ComputeNormals()
                         if (!this._computeParticleVertex) {
                             this._normal.x = this._fixedNormal32[idx];
                             this._normal.y = this._fixedNormal32[idx + 1];
@@ -666,7 +670,7 @@
 
                             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;
-                            this._normals32[idx + 2] = this._cam_axisX.z * this._rotated.x + this._cam_axisY.z * this._rotated.y + this._cam_axisZ.z * this._rotated.z;
+                            this._normals32[idx + 2] = this._cam_axisX.z * this._rotated.x + this._cam_axisY.z * this._rotated.y + this._cam_axisZ.z * this._rotated.z;                          
                         }
 
                         if (this._computeParticleColor) {
@@ -757,15 +761,18 @@
                     this.mesh.updateVerticesData(VertexBuffer.UVKind, this._uvs32, false, false);
                 }
                 this.mesh.updateVerticesData(VertexBuffer.PositionKind, this._positions32, false, false);
-                if (!this.mesh.areNormalsFrozen) {
-                    if (this._computeParticleVertex) {
+                if (!this.mesh.areNormalsFrozen || this.mesh.isFacetDataEnabled) {
+                    if (this._computeParticleVertex || this.mesh.isFacetDataEnabled) {
                         // recompute the normals only if the particles can be morphed, update then also the normal reference array _fixedNormal32[]
-                        VertexData.ComputeNormals(this._positions32, this._indices, this._normals32);
+                        var params = this.mesh.isFacetDataEnabled ? this.mesh.getFacetDataParameters() : null;
+                        VertexData.ComputeNormals(this._positions32, this._indices, this._normals32, params);
                         for (var i = 0; i < this._normals32.length; i++) {
                             this._fixedNormal32[i] = this._normals32[i];
                         }
                     }
-                    this.mesh.updateVerticesData(VertexBuffer.NormalKind, this._normals32, false, false);
+                    if (!this.mesh.areNormalsFrozen) {
+                        this.mesh.updateVerticesData(VertexBuffer.NormalKind, this._normals32, false, false);
+                    }
                 }
             }
             if (this._computeBoundingBox) {

+ 17 - 9
src/PostProcess/babylon.hdrRenderingPipeline.ts

@@ -183,18 +183,26 @@
         * Releases the rendering pipeline and its internal effects. Detaches pipeline from cameras
         */
         public dispose(): void {
-            this._originalPostProcess = undefined;
-            this._brightPassPostProcess = undefined;
-            this._downSampleX4PostProcess = undefined;
-            this._guassianBlurHPostProcess = undefined;
-            this._guassianBlurVPostProcess = undefined;
-            this._textureAdderPostProcess = undefined;
-            for (var i = HDRRenderingPipeline.LUM_STEPS - 1; i >= 0; i--) {
-                this._downSamplePostProcesses[i] = undefined;
+            for (var i = 0; i < this._scene.cameras.length; i++) {
+                var camera = this._scene.cameras[i];
+
+                this._originalPostProcess.dispose(camera);
+                this._brightPassPostProcess.dispose(camera);
+                this._downSampleX4PostProcess.dispose(camera);
+                this._guassianBlurHPostProcess.dispose(camera);
+                this._guassianBlurVPostProcess.dispose(camera);
+                this._textureAdderPostProcess.dispose(camera);
+
+                for (var j = HDRRenderingPipeline.LUM_STEPS - 1; j >= 0; j--) {
+                    this._downSamplePostProcesses[j].dispose(camera);
+                }
+
+                this._hdrPostProcess.dispose(camera);
             }
-            this._hdrPostProcess = undefined;
 
             this._scene.postProcessRenderPipelineManager.detachCamerasFromRenderPipeline(this._name, this._scene.cameras);
+
+            super.dispose();
         }
 
         /**

+ 2 - 0
src/PostProcess/babylon.ssaoRenderingPipeline.ts

@@ -164,6 +164,8 @@
                 this._scene.disableDepthRenderer();
 
             this._scene.postProcessRenderPipelineManager.detachCamerasFromRenderPipeline(this._name, this._scene.cameras);
+
+            super.dispose();
         }
 
         // Private Methods

+ 20 - 37
src/Tools/babylon.filesInput.ts

@@ -9,8 +9,8 @@
         private _textureLoadingCallback;
         private _startingProcessingFilesCallback;
         private _elementToMonitor: HTMLElement;
-        public static FilesTextures: any[] = new Array();
-        public static FilesToLoad: any[] = new Array();
+        public static FilesTextures: File[] = new Array();
+        public static FilesToLoad: File[] = new Array();
 
         private _sceneFileToLoad: File;
         private _filesToLoad: File[];
@@ -55,12 +55,12 @@
             }
         }
 
-        private drag(e): void {
+        private drag(e: DragEvent): void {
             e.stopPropagation();
             e.preventDefault();
         }
 
-        private drop(eventDrop): void {
+        private drop(eventDrop: DragEvent): void {
             eventDrop.stopPropagation();
             eventDrop.preventDefault();
 
@@ -82,39 +82,22 @@
 
             if (this._filesToLoad && this._filesToLoad.length > 0) {
                 for (var i = 0; i < this._filesToLoad.length; i++) {
-                    switch (this._filesToLoad[i].type) {
-                        case "image/jpeg":
-                        case "image/png":
-                        case "image/bmp":
-                            FilesInput.FilesTextures[this._filesToLoad[i].name.toLowerCase()] = this._filesToLoad[i];
-                            break;
-                        case "image/targa":
-                        case "image/vnd.ms-dds":
-                        case "audio/wav":
-                        case "audio/x-wav":
-                        case "audio/mp3":
-                        case "audio/mpeg":
-                        case "audio/mpeg3":
-                        case "audio/x-mpeg-3":
-                        case "audio/ogg":
-                            FilesInput.FilesToLoad[this._filesToLoad[i].name.toLowerCase()] = this._filesToLoad[i];
-                            break;
-                        default:
-                            if (this._filesToLoad[i].name.indexOf(".mtl") !== -1) {
-                                FilesInput.FilesToLoad[this._filesToLoad[i].name.toLowerCase()] = this._filesToLoad[i];
-                            }
-                            else if ((
-                                this._filesToLoad[i].name.indexOf(".babylon") !== -1 || 
-                                this._filesToLoad[i].name.indexOf(".stl") !== -1 ||
-                                this._filesToLoad[i].name.indexOf(".obj") !== -1
-                                )   
-                                && this._filesToLoad[i].name.indexOf(".manifest") === -1
-                                && this._filesToLoad[i].name.indexOf(".incremental") === -1 && this._filesToLoad[i].name.indexOf(".babylonmeshdata") === -1
-                                && this._filesToLoad[i].name.indexOf(".babylongeometrydata") === -1 && this._filesToLoad[i].name.indexOf(".babylonbinarymeshdata") === -1 && 
-                                this._filesToLoad[i].name.indexOf(".binary.babylon") === -1) {
-                                this._sceneFileToLoad = this._filesToLoad[i];
-                            }
-                            break;
+                    let name = this._filesToLoad[i].name.toLowerCase();
+                    let extension = name.split('.').pop();
+                    let type = this._filesToLoad[i].type;
+                    
+                    if (extension === "jpg" || extension === "png" || extension === "bmp" || extension === "jpeg" || 
+                        type === "image/jpeg" || type === "image/png" || type === "image/bmp") {
+                           FilesInput.FilesTextures[name] = this._filesToLoad[i]; 
+                        }
+                    else {
+                        if ((extension === "babylon" || extension === "stl" || extension === "obj") 
+                            && name.indexOf(".binary.babylon") === -1 && name.indexOf(".incremental.babylon") === -1) {
+                            this._sceneFileToLoad = this._filesToLoad[i];
+                        }
+                        else {
+                            FilesInput.FilesToLoad[name] = this._filesToLoad[i];
+                        }
                     }
                 }
 

Plik diff jest za duży
+ 27 - 13
src/Tools/babylon.tools.ts


+ 5 - 5
src/Tools/babylon.virtualJoystick.ts

@@ -298,8 +298,8 @@ module BABYLON {
 
         private _drawVirtualJoystick() {
             if (this.pressed) {
-                this._touches.forEach((touch: any) => {
-                    if (touch.pointerId === this._joystickPointerID) {
+                this._touches.forEach((key, touch) => {
+                    if ((<PointerEvent>touch).pointerId === this._joystickPointerID) {
                         VirtualJoystick.vjCanvasContext.clearRect(this._joystickPointerStartPos.x - 63, this._joystickPointerStartPos.y - 63, 126, 126);                       
                         VirtualJoystick.vjCanvasContext.clearRect(this._joystickPreviousPointerPos.x - 41, this._joystickPreviousPointerPos.y - 41, 82, 82);
                         VirtualJoystick.vjCanvasContext.beginPath();
@@ -322,7 +322,7 @@ module BABYLON {
                         this._joystickPreviousPointerPos = this._joystickPointerPos.clone();
                     }
                     else {
-                        VirtualJoystick.vjCanvasContext.clearRect(touch.prevX - 43, touch.prevY - 43, 86, 86);
+                        VirtualJoystick.vjCanvasContext.clearRect((<any>touch).prevX - 43, (<any>touch).prevY - 43, 86, 86);
                         VirtualJoystick.vjCanvasContext.beginPath();
                         VirtualJoystick.vjCanvasContext.fillStyle = "white";
                         VirtualJoystick.vjCanvasContext.beginPath();
@@ -331,8 +331,8 @@ module BABYLON {
                         VirtualJoystick.vjCanvasContext.arc(touch.x, touch.y, 40, 0, Math.PI * 2, true);
                         VirtualJoystick.vjCanvasContext.stroke();
                         VirtualJoystick.vjCanvasContext.closePath();
-                        touch.prevX = touch.x;
-                        touch.prevY = touch.y;
+                        (<any>touch).prevX = touch.x;
+                        (<any>touch).prevY = touch.y;
                     };
                 });
             }

+ 74 - 70
src/babylon.engine.ts

@@ -2055,8 +2055,7 @@
          * for description see https://www.khronos.org/opengles/sdk/tools/KTX/
          * for file layout see https://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/
          * 
-         * Note: The result of this call is not taken into account when a texture is base64 or when
-         * using a database / manifest.
+         * Note: The result of this call is not taken into account when a texture is base64.
          * 
          * @param {Array<string>} formatsAvailable- The list of those format families you have created
          * on your server.  Syntax: '-' + format family + '.ktx'.  (Case and order do not matter.)
@@ -2077,12 +2076,13 @@
             return this._textureFormatInUse = null;
         }
 
-        public createTexture(url: string, noMipmap: boolean, invertY: boolean, scene: Scene, samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE, onLoad: () => void = null, onError: () => void = null, buffer: any = null): WebGLTexture {
-            var texture = this._gl.createTexture();
+        public createTexture(urlArg: string, noMipmap: boolean, invertY: boolean, scene: Scene, samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE, onLoad: () => void = null, onError: () => void = null, buffer: any = null, fallBack?: WebGLTexture): WebGLTexture {
+            var texture = fallBack ? fallBack : this._gl.createTexture();
 
             var extension: string;
             var isKTX = false;
             var fromData: any = false;
+            var url = String(urlArg);
             if (url.substr(0, 5) === "data:") {
                 fromData = true;
             }
@@ -2090,10 +2090,11 @@
             if (!fromData) {
                 var lastDot = url.lastIndexOf('.')
                 extension = url.substring(lastDot).toLowerCase();
-                if (this._textureFormatInUse && !fromData && !scene.database) {
+                if (this._textureFormatInUse && !fromData && !fallBack) {
                     extension = this._textureFormatInUse;
                     url = url.substring(0, lastDot) + this._textureFormatInUse;
                     isKTX = true;
+                    
                 }
             } else {
                 var oldUrl = url;
@@ -2102,7 +2103,7 @@
                 extension = fromData[1].substr(fromData[1].length - 4, 4).toLowerCase();
             }
 
-            var isDDS = (extension === ".dds");
+            var isDDS = this.getCaps().s3tc && (extension === ".dds");
             var isTGA = (extension === ".tga");
 
             scene._addPendingData(texture);
@@ -2114,12 +2115,15 @@
             if (onLoad) {
                 texture.onLoadedCallbacks.push(onLoad);
             }
-            this._loadedTexturesCache.push(texture);
+            if (!fallBack) this._loadedTexturesCache.push(texture);
 
             var onerror = () => {
                 scene._removePendingData(texture);
 
-                if (onError) {
+                // fallback for when compressed file not found to try again.  For instance, etc1 does not have an alpha capable type
+                if (isKTX) {
+                    this.createTexture(urlArg, noMipmap, invertY, scene, samplingMode, onLoad, onError, buffer, texture);
+                } else if (onError) {
                     onError();
                 }
             };
@@ -2604,12 +2608,12 @@
             var isKTX = false;
             var lastDot = rootUrl.lastIndexOf('.');
             var extension = rootUrl.substring(lastDot).toLowerCase();
-            if (this._textureFormatInUse && !scene.database) {
+            if (this._textureFormatInUse) {
                 extension = this._textureFormatInUse;
                 rootUrl = rootUrl.substring(0, lastDot) + this._textureFormatInUse;
                 isKTX = true;
             }
-            var isDDS = (extension === ".dds");
+            var isDDS = this.getCaps().s3tc && (extension === ".dds");
 
             if (isKTX) {
                 Tools.LoadFile(rootUrl, data => {
@@ -2769,74 +2773,74 @@
                 this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, texture);
                 gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 0);
 
-                if (!noMipmap && isPot) {
-                    if (mipmmapGenerator) {
-
-                        var arrayTemp: ArrayBufferView[] = [];
-                        // Data are known to be in +X +Y +Z -X -Y -Z
-                        // mipmmapGenerator data is expected to be order in +X -X +Y -Y +Z -Z
-                        arrayTemp.push(rgbeDataArrays[0]); // +X
-                        arrayTemp.push(rgbeDataArrays[3]); // -X
-                        arrayTemp.push(rgbeDataArrays[1]); // +Y
-                        arrayTemp.push(rgbeDataArrays[4]); // -Y
-                        arrayTemp.push(rgbeDataArrays[2]); // +Z
-                        arrayTemp.push(rgbeDataArrays[5]); // -Z
-
-                        var mipData = mipmmapGenerator(arrayTemp);
-                        for (var level = 0; level < mipData.length; level++) {
-                            var mipSize = width >> level;
-
-                            // mipData is order in +X -X +Y -Y +Z -Z
-                            gl.texImage2D(facesIndex[0], level, internalSizedFomat, mipSize, mipSize, 0, internalFormat, textureType, mipData[level][0]);
-                            gl.texImage2D(facesIndex[1], level, internalSizedFomat, mipSize, mipSize, 0, internalFormat, textureType, mipData[level][2]);
-                            gl.texImage2D(facesIndex[2], level, internalSizedFomat, mipSize, mipSize, 0, internalFormat, textureType, mipData[level][4]);
-                            gl.texImage2D(facesIndex[3], level, internalSizedFomat, mipSize, mipSize, 0, internalFormat, textureType, mipData[level][1]);
-                            gl.texImage2D(facesIndex[4], level, internalSizedFomat, mipSize, mipSize, 0, internalFormat, textureType, mipData[level][3]);
-                            gl.texImage2D(facesIndex[5], level, internalSizedFomat, mipSize, mipSize, 0, internalFormat, textureType, mipData[level][5]);
-                        }
+                if (mipmmapGenerator) {
+
+                    var arrayTemp: ArrayBufferView[] = [];
+                    // Data are known to be in +X +Y +Z -X -Y -Z
+                    // mipmmapGenerator data is expected to be order in +X -X +Y -Y +Z -Z
+                    arrayTemp.push(rgbeDataArrays[0]); // +X
+                    arrayTemp.push(rgbeDataArrays[3]); // -X
+                    arrayTemp.push(rgbeDataArrays[1]); // +Y
+                    arrayTemp.push(rgbeDataArrays[4]); // -Y
+                    arrayTemp.push(rgbeDataArrays[2]); // +Z
+                    arrayTemp.push(rgbeDataArrays[5]); // -Z
+
+                    var mipData = mipmmapGenerator(arrayTemp);
+                    for (var level = 0; level < mipData.length; level++) {
+                        var mipSize = width >> level;
+
+                        // mipData is order in +X -X +Y -Y +Z -Z
+                        gl.texImage2D(facesIndex[0], level, internalSizedFomat, mipSize, mipSize, 0, internalFormat, textureType, mipData[level][0]);
+                        gl.texImage2D(facesIndex[1], level, internalSizedFomat, mipSize, mipSize, 0, internalFormat, textureType, mipData[level][2]);
+                        gl.texImage2D(facesIndex[2], level, internalSizedFomat, mipSize, mipSize, 0, internalFormat, textureType, mipData[level][4]);
+                        gl.texImage2D(facesIndex[3], level, internalSizedFomat, mipSize, mipSize, 0, internalFormat, textureType, mipData[level][1]);
+                        gl.texImage2D(facesIndex[4], level, internalSizedFomat, mipSize, mipSize, 0, internalFormat, textureType, mipData[level][3]);
+                        gl.texImage2D(facesIndex[5], level, internalSizedFomat, mipSize, mipSize, 0, internalFormat, textureType, mipData[level][5]);
                     }
-                    else {
-                        if (internalFormat === gl.RGB) {
-                            internalFormat = gl.RGBA;
-
-                             // Data are known to be in +X +Y +Z -X -Y -Z
-                            for (let index = 0; index < facesIndex.length; index++) {
-                                let faceData = <Float32Array>rgbeDataArrays[index];
-
-                                // Create a new RGBA Face.
-                                let newFaceData = new Float32Array(width * height * 4);
-                                for (let x = 0; x < width; x++) {
-                                    for (let y = 0; y < height; y++) {
-                                        let index = (y * width + x) * 3;
-                                        let newIndex = (y * width + x) * 4;
-
-                                        // Map Old Value to new value.
-                                        newFaceData[newIndex + 0] = faceData[index + 0];
-                                        newFaceData[newIndex + 1] = faceData[index + 1];
-                                        newFaceData[newIndex + 2] = faceData[index + 2];
-
-                                        // Add fully opaque alpha channel.
-                                        newFaceData[newIndex + 3] = 1;
-                                    }
-                                }
+                }
+                else {
+                    if (internalFormat === gl.RGB) {
+                        internalFormat = gl.RGBA;
 
-                                // Reupload the face.
-                                gl.texImage2D(facesIndex[index], 0, internalSizedFomat, width, height, 0, internalFormat, textureType, newFaceData);
-                            }
-                        }
-                        else {
                             // Data are known to be in +X +Y +Z -X -Y -Z
-                            for (let index = 0; index < facesIndex.length; index++) {
-                                let faceData = rgbeDataArrays[index];
-                                gl.texImage2D(facesIndex[index], 0, internalSizedFomat, width, height, 0, internalFormat, textureType, faceData);
+                        for (let index = 0; index < facesIndex.length; index++) {
+                            let faceData = <Float32Array>rgbeDataArrays[index];
+
+                            // Create a new RGBA Face.
+                            let newFaceData = new Float32Array(width * height * 4);
+                            for (let x = 0; x < width; x++) {
+                                for (let y = 0; y < height; y++) {
+                                    let index = (y * width + x) * 3;
+                                    let newIndex = (y * width + x) * 4;
+
+                                    // Map Old Value to new value.
+                                    newFaceData[newIndex + 0] = faceData[index + 0];
+                                    newFaceData[newIndex + 1] = faceData[index + 1];
+                                    newFaceData[newIndex + 2] = faceData[index + 2];
+
+                                    // Add fully opaque alpha channel.
+                                    newFaceData[newIndex + 3] = 1;
+                                }
                             }
+
+                            // Reupload the face.
+                            gl.texImage2D(facesIndex[index], 0, internalSizedFomat, width, height, 0, internalFormat, textureType, newFaceData);
+                        }
+                    }
+                    else {
+                        // Data are known to be in +X +Y +Z -X -Y -Z
+                        for (let index = 0; index < facesIndex.length; index++) {
+                            let faceData = rgbeDataArrays[index];
+                            gl.texImage2D(facesIndex[index], 0, internalSizedFomat, width, height, 0, internalFormat, textureType, faceData);
                         }
+                    }
 
+                    if (!noMipmap && isPot) {
                         gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
                     }
-                }
-                else {
-                    noMipmap = true;
+                    else {
+                        noMipmap = true;
+                    }
                 }
 
                 if (textureType === gl.FLOAT && !this._caps.textureFloatLinearFiltering) {