浏览代码

Fixing JSKompactor.exe
Adding Gamepad
New octrees

David Catuhe 11 年之前
父节点
当前提交
6899c20502
共有 78 个文件被更改,包括 2821 次插入644 次删除
  1. 1 0
      Babylon/Cameras/babylon.camera.js
  2. 1 1
      Babylon/Cameras/babylon.camera.ts
  3. 58 0
      Babylon/Cameras/babylon.gamepadCamera.js
  4. 48 0
      Babylon/Cameras/babylon.gamepadCamera.ts
  5. 1 2
      Babylon/Collisions/babylon.collider.js
  6. 1 2
      Babylon/Collisions/babylon.collider.ts
  7. 65 15
      Babylon/Culling/Octrees/babylon.octree.js
  8. 72 21
      Babylon/Culling/Octrees/babylon.octree.ts
  9. 86 32
      Babylon/Culling/Octrees/babylon.octreeBlock.js
  10. 79 34
      Babylon/Culling/Octrees/babylon.octreeBlock.ts
  11. 15 3
      Babylon/Culling/babylon.BoundingBox.ts
  12. 13 3
      Babylon/Culling/babylon.boundingBox.js
  13. 2 0
      Babylon/Culling/babylon.boundingInfo.js
  14. 1 1
      Babylon/Culling/babylon.boundingInfo.ts
  15. 1 1
      Babylon/Layer/babylon.layer.js
  16. 1 1
      Babylon/Layer/babylon.layer.ts
  17. 1 1
      Babylon/LensFlare/babylon.lensFlareSystem.js
  18. 1 1
      Babylon/LensFlare/babylon.lensFlareSystem.ts
  19. 64 10
      Babylon/Lights/Shadows/babylon.shadowGenerator.js
  20. 65 11
      Babylon/Lights/Shadows/babylon.shadowGenerator.ts
  21. 18 19
      Babylon/Loading/Plugins/babylon.babylonFileLoader.js
  22. 1 1
      Babylon/Materials/babylon.effect.ts
  23. 4 0
      Babylon/Materials/babylon.material.js
  24. 4 0
      Babylon/Materials/babylon.material.ts
  25. 1 1
      Babylon/Materials/babylon.shaderMaterial.js
  26. 1 1
      Babylon/Materials/babylon.shaderMaterial.ts
  27. 11 7
      Babylon/Materials/babylon.standardMaterial.js
  28. 18 14
      Babylon/Materials/babylon.standardMaterial.ts
  29. 19 0
      Babylon/Materials/textures/babylon.baseTexture.js
  30. 24 3
      Babylon/Materials/textures/babylon.baseTexture.ts
  31. 14 1
      Babylon/Materials/textures/babylon.cubeTexture.js
  32. 14 2
      Babylon/Materials/textures/babylon.cubeTexture.ts
  33. 49 6
      Babylon/Materials/textures/babylon.renderTargetTexture.js
  34. 46 8
      Babylon/Materials/textures/babylon.renderTargetTexture.ts
  35. 6 13
      Babylon/Materials/textures/babylon.texture.js
  36. 6 15
      Babylon/Materials/textures/babylon.texture.ts
  37. 14 10
      Babylon/Math/babylon.math.js
  38. 14 10
      Babylon/Math/babylon.math.ts
  39. 70 8
      Babylon/Mesh/babylon.abstractMesh.js
  40. 73 8
      Babylon/Mesh/babylon.abstractMesh.ts
  41. 3 3
      Babylon/Mesh/babylon.csg.js
  42. 3 3
      Babylon/Mesh/babylon.csg.ts
  43. 3 3
      Babylon/Mesh/babylon.geometry.js
  44. 3 3
      Babylon/Mesh/babylon.geometry.ts
  45. 54 0
      Babylon/Mesh/babylon.groundMesh.js
  46. 43 0
      Babylon/Mesh/babylon.groundMesh.ts
  47. 67 32
      Babylon/Mesh/babylon.mesh.js
  48. 67 34
      Babylon/Mesh/babylon.mesh.ts
  49. 7 7
      Babylon/Mesh/babylon.mesh.vertexData.js
  50. 8 8
      Babylon/Mesh/babylon.mesh.vertexData.ts
  51. 21 5
      Babylon/Mesh/babylon.subMesh.js
  52. 20 5
      Babylon/Mesh/babylon.subMesh.ts
  53. 5 1
      Babylon/Particles/babylon.particleSystem.js
  54. 5 1
      Babylon/Particles/babylon.particleSystem.ts
  55. 4 5
      Babylon/Rendering/babylon.boundingBoxRenderer.js
  56. 5 6
      Babylon/Rendering/babylon.boundingBoxRenderer.ts
  57. 2 2
      Babylon/Rendering/babylon.renderingManager.ts
  58. 2 2
      Babylon/Shaders/default.fragment.fx
  59. 10 0
      Babylon/Shaders/shadowMap.fragment.fx
  60. 20 0
      Babylon/Shaders/shadowMap.vertex.fx
  61. 3 3
      Babylon/Tools/babylon.filesInput.js
  62. 7 8
      Babylon/Tools/babylon.filesInput.ts
  63. 573 0
      Babylon/Tools/babylon.gamepads.js
  64. 512 0
      Babylon/Tools/babylon.gamepads.ts
  65. 15 7
      Babylon/Tools/babylon.sceneSerializer.js
  66. 16 8
      Babylon/Tools/babylon.sceneSerializer.ts
  67. 2 2
      Babylon/Tools/babylon.smartArray.ts
  68. 33 0
      Babylon/Tools/babylon.tools.js
  69. 36 2
      Babylon/Tools/babylon.tools.ts
  70. 8 7
      Babylon/babylon.engine.js
  71. 7 7
      Babylon/babylon.engine.ts
  72. 16 0
      Babylon/babylon.node.js
  73. 19 1
      Babylon/babylon.node.ts
  74. 114 99
      Babylon/babylon.scene.js
  75. 107 101
      Babylon/babylon.scene.ts
  76. 3 0
      Tools/BuildOurOwnBabylonJS/BuildOurOwnBabylonJS/babylonJS.xml
  77. 二进制
      Tools/BuildOurOwnBabylonJS/BuildOurOwnBabylonJS/executables/JSKompactor.exe
  78. 15 13
      babylon.1.12-beta.js

+ 1 - 0
Babylon/Cameras/babylon.camera.js

@@ -25,6 +25,7 @@ var BABYLON;
             this.isIntermediate = false;
             this.viewport = new BABYLON.Viewport(0, 0, 1.0, 1.0);
             this.subCameras = [];
+            this.layerMask = 0xFFFFFFFF;
             this._computedViewMatrix = BABYLON.Matrix.Identity();
             this._projectionMatrix = new BABYLON.Matrix();
             this._postProcesses = new Array();

+ 1 - 1
Babylon/Cameras/babylon.camera.ts

@@ -17,8 +17,8 @@
         public mode = Camera.PERSPECTIVE_CAMERA;
         public isIntermediate = false;
         public viewport = new Viewport(0, 0, 1.0, 1.0);
-        public layerMask: number = 0xFFFFFFFF;
         public subCameras = [];
+        public layerMask: number = 0xFFFFFFFF;
 
         private _computedViewMatrix = BABYLON.Matrix.Identity();
         private _projectionMatrix = new BABYLON.Matrix();

+ 58 - 0
Babylon/Cameras/babylon.gamepadCamera.js

@@ -0,0 +1,58 @@
+var __extends = this.__extends || function (d, b) {
+    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
+    function __() { this.constructor = d; }
+    __.prototype = b.prototype;
+    d.prototype = new __();
+};
+var BABYLON;
+(function (BABYLON) {
+    // We're mainly based on the logic defined into the FreeCamera code
+    var GamepadCamera = (function (_super) {
+        __extends(GamepadCamera, _super);
+        function GamepadCamera(name, position, scene) {
+            var _this = this;
+            _super.call(this, name, position, scene);
+            this.angularSensibility = 200;
+            this.moveSensibility = 75;
+            this._gamepads = new BABYLON.Gamepads(function (gamepad) {
+                _this._onNewGameConnected(gamepad);
+            });
+        }
+        GamepadCamera.prototype._onNewGameConnected = function (gamepad) {
+            // Only the first gamepad can control the camera
+            if (gamepad.index === 0) {
+                this._gamepad = gamepad;
+            }
+        };
+
+        GamepadCamera.prototype._checkInputs = function () {
+            if (!this._gamepad) {
+                return;
+            }
+
+            var LSValues = this._gamepad.leftStick;
+            var normalizedLX = LSValues.x / this.moveSensibility;
+            var normalizedLY = LSValues.y / this.moveSensibility;
+            LSValues.x = Math.abs(normalizedLX) > 0.005 ? 0 + normalizedLX : 0;
+            LSValues.y = Math.abs(normalizedLY) > 0.005 ? 0 + normalizedLY : 0;
+
+            var RSValues = this._gamepad.rightStick;
+            var normalizedRX = RSValues.x / this.angularSensibility;
+            var normalizedRY = RSValues.y / this.angularSensibility;
+            RSValues.x = Math.abs(normalizedRX) > 0.001 ? 0 + normalizedRX : 0;
+            RSValues.y = Math.abs(normalizedRY) > 0.001 ? 0 + normalizedRY : 0;
+            ;
+
+            var cameraTransform = BABYLON.Matrix.RotationYawPitchRoll(this.rotation.y, this.rotation.x, 0);
+            var deltaTransform = BABYLON.Vector3.TransformCoordinates(new BABYLON.Vector3(LSValues.x, 0, -LSValues.y), cameraTransform);
+            this.cameraDirection = this.cameraDirection.add(deltaTransform);
+            this.cameraRotation = this.cameraRotation.add(new BABYLON.Vector3(RSValues.y, RSValues.x, 0));
+        };
+
+        GamepadCamera.prototype.dispose = function () {
+        };
+        return GamepadCamera;
+    })(BABYLON.FreeCamera);
+    BABYLON.GamepadCamera = GamepadCamera;
+})(BABYLON || (BABYLON = {}));
+//# sourceMappingURL=babylon.gamepadCamera.js.map

+ 48 - 0
Babylon/Cameras/babylon.gamepadCamera.ts

@@ -0,0 +1,48 @@
+module BABYLON {
+    // We're mainly based on the logic defined into the FreeCamera code
+    export class GamepadCamera extends FreeCamera {
+        private _gamepad: BABYLON.Gamepad;
+        private _gamepads: BABYLON.Gamepads;
+        public angularSensibility = 200;
+        public moveSensibility = 75;
+
+        constructor(name: string, position: Vector3, scene: Scene) {
+            super(name, position, scene);
+            this._gamepads = new BABYLON.Gamepads((gamepad: BABYLON.Gamepad) => { this._onNewGameConnected(gamepad); });
+        }
+
+        private _onNewGameConnected(gamepad: BABYLON.Gamepad) {
+            // Only the first gamepad can control the camera
+            if (gamepad.index === 0) {
+                this._gamepad = gamepad;
+            }
+        }
+
+        public _checkInputs(): void {
+            if (!this._gamepad) {
+                return;
+            }
+
+            var LSValues = this._gamepad.leftStick;
+            var normalizedLX = LSValues.x / this.moveSensibility;
+            var normalizedLY = LSValues.y / this.moveSensibility;
+            LSValues.x = Math.abs(normalizedLX) > 0.005 ? 0 + normalizedLX : 0;
+            LSValues.y = Math.abs(normalizedLY) > 0.005 ? 0 + normalizedLY : 0;
+
+            var RSValues = this._gamepad.rightStick;
+            var normalizedRX = RSValues.x / this.angularSensibility;
+            var normalizedRY = RSValues.y / this.angularSensibility;
+            RSValues.x = Math.abs(normalizedRX) > 0.001 ? 0 + normalizedRX : 0;
+            RSValues.y = Math.abs(normalizedRY) > 0.001 ? 0 + normalizedRY : 0;;
+
+            var cameraTransform = BABYLON.Matrix.RotationYawPitchRoll(this.rotation.y, this.rotation.x, 0);
+            var deltaTransform = BABYLON.Vector3.TransformCoordinates(new BABYLON.Vector3(LSValues.x, 0, -LSValues.y), cameraTransform);
+            this.cameraDirection = this.cameraDirection.add(deltaTransform);
+            this.cameraRotation = this.cameraRotation.add(new BABYLON.Vector3(RSValues.y, RSValues.x, 0));
+        }
+
+        public dispose(): void {
+            
+        }
+    }
+}

+ 1 - 2
Babylon/Collisions/babylon.collider.js

@@ -111,8 +111,7 @@
         Collider.prototype._canDoCollision = function (sphereCenter, sphereRadius, vecMin, vecMax) {
             var distance = BABYLON.Vector3.Distance(this.basePointWorld, sphereCenter);
 
-            var max = Math.max(this.radius.x, this.radius.y);
-            max = Math.max(max, this.radius.z);
+            var max = Math.max(this.radius.x, this.radius.y, this.radius.z);
 
             if (distance > this.velocityWorldLength + max + sphereRadius) {
                 return false;

+ 1 - 2
Babylon/Collisions/babylon.collider.ts

@@ -120,8 +120,7 @@
         public _canDoCollision(sphereCenter: Vector3, sphereRadius: number, vecMin: Vector3, vecMax: Vector3): boolean {
             var distance = BABYLON.Vector3.Distance(this.basePointWorld, sphereCenter);
 
-            var max = Math.max(this.radius.x, this.radius.y);
-            max = Math.max(max, this.radius.z);
+            var max = Math.max(this.radius.x, this.radius.y, this.radius.z);
 
             if (distance > this.velocityWorldLength + max + sphereRadius) {
                 return false;

+ 65 - 15
Babylon/Culling/Octrees/babylon.octree.js

@@ -1,36 +1,74 @@
 var BABYLON;
 (function (BABYLON) {
     var Octree = (function () {
-        function Octree(maxBlockCapacity) {
+        function Octree(creationFunc, maxBlockCapacity) {
+            this.maxDepth = 2;
+            this.dynamicContent = new Array();
             this._maxBlockCapacity = maxBlockCapacity || 64;
-            this._selection = new BABYLON.SmartArray(256);
+            this._selectionContent = new BABYLON.SmartArray(1024);
+            this._creationFunc = creationFunc;
         }
         // Methods
-        Octree.prototype.update = function (worldMin, worldMax, meshes) {
-            Octree._CreateBlocks(worldMin, worldMax, meshes, this._maxBlockCapacity, this);
+        Octree.prototype.update = function (worldMin, worldMax, entries) {
+            Octree._CreateBlocks(worldMin, worldMax, entries, this._maxBlockCapacity, 0, this.maxDepth, this, this._creationFunc);
         };
 
-        Octree.prototype.addMesh = function (mesh) {
+        Octree.prototype.addMesh = function (entry) {
             for (var index = 0; index < this.blocks.length; index++) {
                 var block = this.blocks[index];
-                block.addMesh(mesh);
+                block.addEntry(entry);
             }
         };
 
-        Octree.prototype.select = function (frustumPlanes) {
-            this._selection.reset();
+        Octree.prototype.select = function (frustumPlanes, allowDuplicate) {
+            this._selectionContent.reset();
 
             for (var index = 0; index < this.blocks.length; index++) {
                 var block = this.blocks[index];
-                block.select(frustumPlanes, this._selection);
+                block.select(frustumPlanes, this._selectionContent, allowDuplicate);
             }
 
-            return this._selection;
+            if (allowDuplicate) {
+                this._selectionContent.concat(this.dynamicContent);
+            } else {
+                this._selectionContent.concatWithNoDuplicate(this.dynamicContent);
+            }
+
+            return this._selectionContent;
         };
 
-        // Statics
-        Octree._CreateBlocks = function (worldMin, worldMax, meshes, maxBlockCapacity, target) {
-            target.blocks = [];
+        Octree.prototype.intersects = function (sphereCenter, sphereRadius, allowDuplicate) {
+            this._selectionContent.reset();
+
+            for (var index = 0; index < this.blocks.length; index++) {
+                var block = this.blocks[index];
+                block.intersects(sphereCenter, sphereRadius, this._selectionContent, allowDuplicate);
+            }
+
+            if (allowDuplicate) {
+                this._selectionContent.concat(this.dynamicContent);
+            } else {
+                this._selectionContent.concatWithNoDuplicate(this.dynamicContent);
+            }
+
+            return this._selectionContent;
+        };
+
+        Octree.prototype.intersectsRay = function (ray) {
+            this._selectionContent.reset();
+
+            for (var index = 0; index < this.blocks.length; index++) {
+                var block = this.blocks[index];
+                block.intersectsRay(ray, this._selectionContent);
+            }
+
+            this._selectionContent.concatWithNoDuplicate(this.dynamicContent);
+
+            return this._selectionContent;
+        };
+
+        Octree._CreateBlocks = function (worldMin, worldMax, entries, maxBlockCapacity, currentDepth, maxDepth, target, creationFunc) {
+            target.blocks = new Array();
             var blockSize = new BABYLON.Vector3((worldMax.x - worldMin.x) / 2, (worldMax.y - worldMin.y) / 2, (worldMax.z - worldMin.z) / 2);
 
             for (var x = 0; x < 2; x++) {
@@ -39,13 +77,25 @@
                         var localMin = worldMin.add(blockSize.multiplyByFloats(x, y, z));
                         var localMax = worldMin.add(blockSize.multiplyByFloats(x + 1, y + 1, z + 1));
 
-                        var block = new BABYLON.OctreeBlock(localMin, localMax, maxBlockCapacity);
-                        block.addEntries(meshes);
+                        var block = new BABYLON.OctreeBlock(localMin, localMax, maxBlockCapacity, currentDepth + 1, maxDepth, creationFunc);
+                        block.addEntries(entries);
                         target.blocks.push(block);
                     }
                 }
             }
         };
+
+        Octree.CreationFuncForMeshes = function (entry, block) {
+            if (entry.getBoundingInfo().boundingBox.intersectsMinMax(block.minPoint, block.maxPoint)) {
+                block.entries.push(entry);
+            }
+        };
+
+        Octree.CreationFuncForSubMeshes = function (entry, block) {
+            if (entry.getBoundingInfo().boundingBox.intersectsMinMax(block.minPoint, block.maxPoint)) {
+                block.entries.push(entry);
+            }
+        };
         return Octree;
     })();
     BABYLON.Octree = Octree;

+ 72 - 21
Babylon/Culling/Octrees/babylon.octree.ts

@@ -1,45 +1,84 @@
 module BABYLON {
-    export interface IOctreeContainer {
-        blocks: Array<OctreeBlock>;
+    export interface IOctreeContainer<T> {
+        blocks: Array<OctreeBlock<T>>;
     }
 
-    export class Octree {
-        public blocks: Array<OctreeBlock>;
-        private _maxBlockCapacity: number;
-        private _selection;
+    export class Octree<T> {
+        public blocks: Array<OctreeBlock<T>>;
+        public maxDepth = 2;
+        public dynamicContent = new Array<T>();
 
+        private _maxBlockCapacity: number;
+        private _selectionContent: SmartArray<T>;       
+        private _creationFunc: (entry: T, block: OctreeBlock<T>) => void;
 
-        constructor(maxBlockCapacity?: number) {
+        constructor(creationFunc: (entry: T, block: OctreeBlock<T>) => void, maxBlockCapacity?: number) {
             this._maxBlockCapacity = maxBlockCapacity || 64;
-            this._selection = new BABYLON.SmartArray<OctreeBlock>(256);
+            this._selectionContent = new BABYLON.SmartArray<T>(1024);
+            this._creationFunc = creationFunc;
         }
 
         // Methods
-        public update(worldMin: Vector3, worldMax: Vector3, meshes): void {
-            Octree._CreateBlocks(worldMin, worldMax, meshes, this._maxBlockCapacity, this);
+        public update(worldMin: Vector3, worldMax: Vector3, entries: T[]): void {
+            Octree._CreateBlocks(worldMin, worldMax, entries, this._maxBlockCapacity, 0, this.maxDepth, this, this._creationFunc);
+        }
+
+        public addMesh(entry: T): void {
+            for (var index = 0; index < this.blocks.length; index++) {
+                var block = this.blocks[index];
+                block.addEntry(entry);
+            }
         }
 
-        public addMesh(mesh): void {
+        public select(frustumPlanes: Plane[], allowDuplicate?: boolean): SmartArray<T> {
+            this._selectionContent.reset();
+
             for (var index = 0; index < this.blocks.length; index++) {
                 var block = this.blocks[index];
-                block.addMesh(mesh);
+                block.select(frustumPlanes, this._selectionContent, allowDuplicate);
+            }
+
+            if (allowDuplicate) {
+                this._selectionContent.concat(this.dynamicContent);
+            } else {
+                this._selectionContent.concatWithNoDuplicate(this.dynamicContent);                
             }
+
+            return this._selectionContent;
         }
 
-        public select(frustumPlanes: Plane[]): SmartArray<OctreeBlock> {
-            this._selection.reset();
+        public intersects(sphereCenter: Vector3, sphereRadius: number, allowDuplicate?: boolean): SmartArray<T> {
+            this._selectionContent.reset();
 
             for (var index = 0; index < this.blocks.length; index++) {
                 var block = this.blocks[index];
-                block.select(frustumPlanes, this._selection);
+                block.intersects(sphereCenter, sphereRadius, this._selectionContent, allowDuplicate);
             }
 
-            return this._selection;
+            if (allowDuplicate) {
+                this._selectionContent.concat(this.dynamicContent);
+            } else {
+                this._selectionContent.concatWithNoDuplicate(this.dynamicContent);
+            }
+
+            return this._selectionContent;
         }
 
-        // Statics
-        static _CreateBlocks(worldMin: Vector3, worldMax: Vector3, meshes, maxBlockCapacity: number, target: IOctreeContainer): void {
-            target.blocks = [];
+        public intersectsRay(ray: Ray): SmartArray<T> {
+            this._selectionContent.reset();
+
+            for (var index = 0; index < this.blocks.length; index++) {
+                var block = this.blocks[index];
+                block.intersectsRay(ray, this._selectionContent);
+            }
+
+            this._selectionContent.concatWithNoDuplicate(this.dynamicContent);
+
+            return this._selectionContent;
+        }
+
+        public static _CreateBlocks<T>(worldMin: Vector3, worldMax: Vector3, entries: T[], maxBlockCapacity: number, currentDepth: number, maxDepth: number, target: IOctreeContainer<T>, creationFunc: (entry: T, block: OctreeBlock<T>) => void): void {
+            target.blocks = new Array<OctreeBlock<T>>();
             var blockSize = new BABYLON.Vector3((worldMax.x - worldMin.x) / 2, (worldMax.y - worldMin.y) / 2, (worldMax.z - worldMin.z) / 2);
 
             // Segmenting space
@@ -49,12 +88,24 @@
                         var localMin = worldMin.add(blockSize.multiplyByFloats(x, y, z));
                         var localMax = worldMin.add(blockSize.multiplyByFloats(x + 1, y + 1, z + 1));
 
-                        var block = new BABYLON.OctreeBlock(localMin, localMax, maxBlockCapacity);
-                        block.addEntries(meshes);
+                        var block = new BABYLON.OctreeBlock<T>(localMin, localMax, maxBlockCapacity, currentDepth + 1, maxDepth, creationFunc);
+                        block.addEntries(entries);
                         target.blocks.push(block);
                     }
                 }
             }
         }
+
+        public static CreationFuncForMeshes = (entry: AbstractMesh, block: OctreeBlock<AbstractMesh>): void => {
+            if (entry.getBoundingInfo().boundingBox.intersectsMinMax(block.minPoint, block.maxPoint)) {
+                block.entries.push(entry);
+            }
+        }
+
+        public static CreationFuncForSubMeshes = (entry: SubMesh, block: OctreeBlock<SubMesh>): void => {
+            if (entry.getBoundingInfo().boundingBox.intersectsMinMax(block.minPoint, block.maxPoint)) {
+                block.entries.push(entry);
+            }
+        }
     }
 } 

+ 86 - 32
Babylon/Culling/Octrees/babylon.octreeBlock.js

@@ -1,11 +1,13 @@
 var BABYLON;
 (function (BABYLON) {
     var OctreeBlock = (function () {
-        function OctreeBlock(minPoint, maxPoint, capacity) {
-            this.meshes = new Array();
-            this.subMeshes = new Array();
+        function OctreeBlock(minPoint, maxPoint, capacity, depth, maxDepth, creationFunc) {
+            this.entries = new Array();
             this._boundingVectors = new Array();
             this._capacity = capacity;
+            this._depth = depth;
+            this._maxDepth = maxDepth;
+            this._creationFunc = creationFunc;
 
             this._minPoint = minPoint;
             this._maxPoint = maxPoint;
@@ -31,55 +33,107 @@
             this._boundingVectors.push(maxPoint.clone());
             this._boundingVectors[7].y = minPoint.y;
         }
+        Object.defineProperty(OctreeBlock.prototype, "capacity", {
+            // Property
+            get: function () {
+                return this._capacity;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+        Object.defineProperty(OctreeBlock.prototype, "minPoint", {
+            get: function () {
+                return this._minPoint;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+        Object.defineProperty(OctreeBlock.prototype, "maxPoint", {
+            get: function () {
+                return this._maxPoint;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
         // Methods
-        OctreeBlock.prototype.addMesh = function (mesh) {
+        OctreeBlock.prototype.addEntry = function (entry) {
             if (this.blocks) {
                 for (var index = 0; index < this.blocks.length; index++) {
                     var block = this.blocks[index];
-                    block.addMesh(mesh);
+                    block.addEntry(entry);
                 }
                 return;
             }
 
-            if (mesh.getBoundingInfo().boundingBox.intersectsMinMax(this._minPoint, this._maxPoint)) {
-                var localMeshIndex = this.meshes.length;
-                this.meshes.push(mesh);
-
-                this.subMeshes[localMeshIndex] = [];
-                if (mesh.subMeshes) {
-                    for (var subIndex = 0; subIndex < mesh.subMeshes.length; subIndex++) {
-                        var subMesh = mesh.subMeshes[subIndex];
-                        if (mesh.subMeshes.length === 1 || subMesh.getBoundingInfo().boundingBox.intersectsMinMax(this._minPoint, this._maxPoint)) {
-                            this.subMeshes[localMeshIndex].push(subMesh);
-                        }
-                    }
-                }
+            this._creationFunc(entry, this);
+
+            if (this.entries.length > this.capacity && this._depth < this._maxDepth) {
+                this.createInnerBlocks();
             }
+        };
 
-            if (this.subMeshes.length > this._capacity) {
-                BABYLON.Octree._CreateBlocks(this._minPoint, this._maxPoint, this.meshes, this._capacity, this);
+        OctreeBlock.prototype.addEntries = function (entries) {
+            for (var index = 0; index < entries.length; index++) {
+                var mesh = entries[index];
+                this.addEntry(mesh);
             }
         };
 
-        OctreeBlock.prototype.addEntries = function (meshes) {
-            for (var index = 0; index < meshes.length; index++) {
-                var mesh = meshes[index];
-                this.addMesh(mesh);
+        OctreeBlock.prototype.select = function (frustumPlanes, selection, allowDuplicate) {
+            if (BABYLON.BoundingBox.IsInFrustum(this._boundingVectors, frustumPlanes)) {
+                if (this.blocks) {
+                    for (var index = 0; index < this.blocks.length; index++) {
+                        var block = this.blocks[index];
+                        block.select(frustumPlanes, selection, allowDuplicate);
+                    }
+                    return;
+                }
+
+                if (allowDuplicate) {
+                    selection.concat(this.entries);
+                } else {
+                    selection.concatWithNoDuplicate(this.entries);
+                }
             }
         };
 
-        OctreeBlock.prototype.select = function (frustumPlanes, selection) {
-            if (this.blocks) {
-                for (var index = 0; index < this.blocks.length; index++) {
-                    var block = this.blocks[index];
-                    block.select(frustumPlanes, selection);
+        OctreeBlock.prototype.intersects = function (sphereCenter, sphereRadius, selection, allowDuplicate) {
+            if (BABYLON.BoundingBox.IntersectsSphere(this._minPoint, this._maxPoint, sphereCenter, sphereRadius)) {
+                if (this.blocks) {
+                    for (var index = 0; index < this.blocks.length; index++) {
+                        var block = this.blocks[index];
+                        block.intersects(sphereCenter, sphereRadius, selection, allowDuplicate);
+                    }
+                    return;
+                }
+
+                if (allowDuplicate) {
+                    selection.concat(this.entries);
+                } else {
+                    selection.concatWithNoDuplicate(this.entries);
                 }
-                return;
             }
-            if (BABYLON.BoundingBox.IsInFrustum(this._boundingVectors, frustumPlanes)) {
-                selection.push(this);
+        };
+
+        OctreeBlock.prototype.intersectsRay = function (ray, selection) {
+            if (ray.intersectsBoxMinMax(this._minPoint, this._maxPoint)) {
+                if (this.blocks) {
+                    for (var index = 0; index < this.blocks.length; index++) {
+                        var block = this.blocks[index];
+                        block.intersectsRay(ray, selection);
+                    }
+                    return;
+                }
+                selection.concatWithNoDuplicate(this.entries);
             }
         };
+
+        OctreeBlock.prototype.createInnerBlocks = function () {
+            BABYLON.Octree._CreateBlocks(this._minPoint, this._maxPoint, this.entries, this._capacity, this._depth, this._maxDepth, this, this._creationFunc);
+        };
         return OctreeBlock;
     })();
     BABYLON.OctreeBlock = OctreeBlock;

+ 79 - 34
Babylon/Culling/Octrees/babylon.octreeBlock.ts

@@ -1,16 +1,21 @@
 module BABYLON {
-    export class OctreeBlock {
-        public meshes = new Array<AbstractMesh>();
-        public subMeshes = new Array <Array<SubMesh>>();
-        public blocks: Array<OctreeBlock>;
+    export class OctreeBlock<T> {
+        public entries = new Array<T>();
+        public blocks: Array<OctreeBlock<T>>;
 
+        private _depth: number;
+        private _maxDepth: number;
         private _capacity: number;
         private _minPoint: Vector3;
         private _maxPoint: Vector3;
         private _boundingVectors = new Array<Vector3>();
+        private _creationFunc: (entry: T, block: OctreeBlock<T>) => void;
 
-        constructor(minPoint: Vector3, maxPoint: Vector3, capacity: number) {
+        constructor(minPoint: Vector3, maxPoint: Vector3, capacity: number, depth: number, maxDepth: number, creationFunc: (entry: T, block: OctreeBlock<T>) => void) {
             this._capacity = capacity;
+            this._depth = depth;
+            this._maxDepth = maxDepth;
+            this._creationFunc = creationFunc;
 
             this._minPoint = minPoint;
             this._maxPoint = maxPoint;
@@ -37,54 +42,94 @@
             this._boundingVectors[7].y = minPoint.y;
         }
 
+        // Property
+        public get capacity(): number {
+            return this._capacity;
+        }
+
+        public get minPoint(): Vector3 {
+            return this._minPoint;
+        }
+
+        public get maxPoint(): Vector3 {
+            return this._maxPoint;
+        }
+
         // Methods
-        public addMesh(mesh: Mesh): void {
+        public addEntry(entry: T): void {
             if (this.blocks) {
                 for (var index = 0; index < this.blocks.length; index++) {
                     var block = this.blocks[index];
-                    block.addMesh(mesh);
+                    block.addEntry(entry);
                 }
                 return;
             }
 
-            if (mesh.getBoundingInfo().boundingBox.intersectsMinMax(this._minPoint, this._maxPoint)) {
-                var localMeshIndex = this.meshes.length;
-                this.meshes.push(mesh);
-
-                this.subMeshes[localMeshIndex] = [];
-                if (mesh.subMeshes) {
-                    for (var subIndex = 0; subIndex < mesh.subMeshes.length; subIndex++) {
-                        var subMesh = mesh.subMeshes[subIndex];
-                        if (mesh.subMeshes.length === 1 || subMesh.getBoundingInfo().boundingBox.intersectsMinMax(this._minPoint, this._maxPoint)) {
-                            this.subMeshes[localMeshIndex].push(subMesh);
-                        }
-                    }
-                }
+            this._creationFunc(entry, this);
+
+            if (this.entries.length > this.capacity && this._depth < this._maxDepth) {
+                this.createInnerBlocks();
             }
+        }
 
-            if (this.subMeshes.length > this._capacity) {
-                Octree._CreateBlocks(this._minPoint, this._maxPoint, this.meshes, this._capacity, this);
+        public addEntries(entries: T[]): void {
+            for (var index = 0; index < entries.length; index++) {
+                var mesh = entries[index];
+                this.addEntry(mesh);
             }
         }
 
-        public addEntries(meshes: Mesh[]): void {
-            for (var index = 0; index < meshes.length; index++) {
-                var mesh = meshes[index];
-                this.addMesh(mesh);
+        public select(frustumPlanes: Plane[], selection: SmartArray<T>, allowDuplicate?: boolean): void {
+            if (BABYLON.BoundingBox.IsInFrustum(this._boundingVectors, frustumPlanes)) {
+                if (this.blocks) {
+                    for (var index = 0; index < this.blocks.length; index++) {
+                        var block = this.blocks[index];
+                        block.select(frustumPlanes, selection, allowDuplicate);
+                    }
+                    return;
+                }
+
+                if (allowDuplicate) {
+                    selection.concat(this.entries);
+                } else {
+                    selection.concatWithNoDuplicate(this.entries);
+                }
             }
         }
 
-        public select(frustumPlanes: Plane[], selection: OctreeBlock[]): void {
-            if (this.blocks) {
-                for (var index = 0; index < this.blocks.length; index++) {
-                    var block = this.blocks[index];
-                    block.select(frustumPlanes, selection);
+        public intersects(sphereCenter: Vector3, sphereRadius: number, selection: SmartArray<T>, allowDuplicate?: boolean): void {
+            if (BABYLON.BoundingBox.IntersectsSphere(this._minPoint, this._maxPoint, sphereCenter, sphereRadius)) {
+                if (this.blocks) {
+                    for (var index = 0; index < this.blocks.length; index++) {
+                        var block = this.blocks[index];
+                        block.intersects(sphereCenter, sphereRadius, selection, allowDuplicate);
+                    }
+                    return;
+                }
+
+                if (allowDuplicate) {
+                    selection.concat(this.entries);
+                } else {
+                    selection.concatWithNoDuplicate(this.entries);
                 }
-                return;
             }
-            if (BABYLON.BoundingBox.IsInFrustum(this._boundingVectors, frustumPlanes)) {
-                selection.push(this);
+        }
+
+        public intersectsRay(ray: Ray, selection: SmartArray<T>): void {
+            if (ray.intersectsBoxMinMax(this._minPoint, this._maxPoint)) {
+                if (this.blocks) {
+                    for (var index = 0; index < this.blocks.length; index++) {
+                        var block = this.blocks[index];
+                        block.intersectsRay(ray, selection);
+                    }
+                    return;
+                }
+                selection.concatWithNoDuplicate(this.entries);
             }
         }
+
+        public createInnerBlocks(): void {
+            Octree._CreateBlocks(this._minPoint, this._maxPoint, this.entries, this._capacity, this._depth, this._maxDepth, this, this._creationFunc);
+        }
     }
 } 

+ 15 - 3
Babylon/Culling/babylon.BoundingBox.ts

@@ -8,6 +8,8 @@
         public minimumWorld: Vector3;
         public maximumWorld: Vector3;
 
+        private _worldMatrix: Matrix;
+
         constructor(public minimum: Vector3, public maximum: Vector3) {
             // Bounding vectors            
             this.vectors.push(this.minimum.clone());
@@ -47,6 +49,10 @@
         }
 
         // Methods
+        public getWorldMatrix(): Matrix {
+            return this._worldMatrix;
+        }
+
         public _update(world: Matrix): void {
             Vector3.FromFloatsToRef(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE, this.minimumWorld);
             Vector3.FromFloatsToRef(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE, this.maximumWorld);
@@ -77,6 +83,8 @@
             Vector3.FromFloatArrayToRef(world.m, 0, this.directions[0]);
             Vector3.FromFloatArrayToRef(world.m, 4, this.directions[1]);
             Vector3.FromFloatArrayToRef(world.m, 8, this.directions[2]);
+
+            this._worldMatrix = world;
         }
 
         public isInFrustum(frustumPlanes: Plane[]): boolean {
@@ -99,9 +107,7 @@
         }
 
         public intersectsSphere(sphere: BoundingSphere): boolean {
-            var vector = BABYLON.Vector3.Clamp(sphere.centerWorld, this.minimumWorld, this.maximumWorld);
-            var num = BABYLON.Vector3.DistanceSquared(sphere.centerWorld, vector);
-            return (num <= (sphere.radiusWorld * sphere.radiusWorld));
+            return BoundingBox.IntersectsSphere(this.minimumWorld, this.maximumWorld, sphere.centerWorld, sphere.radiusWorld);
         }
 
         public intersectsMinMax(min: Vector3, max: Vector3): boolean {
@@ -131,6 +137,12 @@
             return true;
         }
 
+        public static IntersectsSphere(minPoint: Vector3, maxPoint: Vector3, sphereCenter: Vector3, sphereRadius: number): boolean {
+            var vector = BABYLON.Vector3.Clamp(sphereCenter, minPoint, maxPoint);
+            var num = BABYLON.Vector3.DistanceSquared(sphereCenter, vector);
+            return (num <= (sphereRadius * sphereRadius));
+        }
+
         public static IsInFrustum(boundingVectors: Vector3[], frustumPlanes: Plane[]): boolean {
             for (var p = 0; p < 6; p++) {
                 var inCount = 8;

+ 13 - 3
Babylon/Culling/babylon.boundingBox.js

@@ -42,6 +42,10 @@
             this._update(BABYLON.Matrix.Identity());
         }
         // Methods
+        BoundingBox.prototype.getWorldMatrix = function () {
+            return this._worldMatrix;
+        };
+
         BoundingBox.prototype._update = function (world) {
             BABYLON.Vector3.FromFloatsToRef(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE, this.minimumWorld);
             BABYLON.Vector3.FromFloatsToRef(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE, this.maximumWorld);
@@ -72,6 +76,8 @@
             BABYLON.Vector3.FromFloatArrayToRef(world.m, 0, this.directions[0]);
             BABYLON.Vector3.FromFloatArrayToRef(world.m, 4, this.directions[1]);
             BABYLON.Vector3.FromFloatArrayToRef(world.m, 8, this.directions[2]);
+
+            this._worldMatrix = world;
         };
 
         BoundingBox.prototype.isInFrustum = function (frustumPlanes) {
@@ -94,9 +100,7 @@
         };
 
         BoundingBox.prototype.intersectsSphere = function (sphere) {
-            var vector = BABYLON.Vector3.Clamp(sphere.centerWorld, this.minimumWorld, this.maximumWorld);
-            var num = BABYLON.Vector3.DistanceSquared(sphere.centerWorld, vector);
-            return (num <= (sphere.radiusWorld * sphere.radiusWorld));
+            return BoundingBox.IntersectsSphere(this.minimumWorld, this.maximumWorld, sphere.centerWorld, sphere.radiusWorld);
         };
 
         BoundingBox.prototype.intersectsMinMax = function (min, max) {
@@ -126,6 +130,12 @@
             return true;
         };
 
+        BoundingBox.IntersectsSphere = function (minPoint, maxPoint, sphereCenter, sphereRadius) {
+            var vector = BABYLON.Vector3.Clamp(sphereCenter, minPoint, maxPoint);
+            var num = BABYLON.Vector3.DistanceSquared(sphereCenter, vector);
+            return (num <= (sphereRadius * sphereRadius));
+        };
+
         BoundingBox.IsInFrustum = function (boundingVectors, frustumPlanes) {
             for (var p = 0; p < 6; p++) {
                 var inCount = 8;

+ 2 - 0
Babylon/Culling/babylon.boundingInfo.js

@@ -27,6 +27,8 @@
 
     var BoundingInfo = (function () {
         function BoundingInfo(minimum, maximum) {
+            this.minimum = minimum;
+            this.maximum = maximum;
             this.boundingBox = new BABYLON.BoundingBox(minimum, maximum);
             this.boundingSphere = new BABYLON.BoundingSphere(minimum, maximum);
         }

+ 1 - 1
Babylon/Culling/babylon.boundingInfo.ts

@@ -26,7 +26,7 @@
         public boundingBox: BoundingBox;
         public boundingSphere: BoundingSphere;
 
-        constructor(minimum: Vector3, maximum: Vector3) {
+        constructor(public minimum: Vector3, public maximum: Vector3) {
             this.boundingBox = new BABYLON.BoundingBox(minimum, maximum);
             this.boundingSphere = new BABYLON.BoundingSphere(minimum, maximum);
         }

+ 1 - 1
Babylon/Layer/babylon.layer.js

@@ -49,7 +49,7 @@
 
             // Texture
             this._effect.setTexture("textureSampler", this.texture);
-            this._effect.setMatrix("textureMatrix", this.texture._computeTextureMatrix());
+            this._effect.setMatrix("textureMatrix", this.texture.getTextureMatrix());
 
             // Color
             this._effect.setFloat4("color", this.color.r, this.color.g, this.color.b, this.color.a);

+ 1 - 1
Babylon/Layer/babylon.layer.ts

@@ -61,7 +61,7 @@
 
             // Texture
             this._effect.setTexture("textureSampler", this.texture);
-            this._effect.setMatrix("textureMatrix", this.texture._computeTextureMatrix());
+            this._effect.setMatrix("textureMatrix", this.texture.getTextureMatrix());
 
             // Color
             this._effect.setFloat4("color", this.color.r, this.color.g, this.color.b, this.color.a);

+ 1 - 1
Babylon/LensFlare/babylon.lensFlareSystem.js

@@ -12,7 +12,7 @@
             scene.lensFlareSystems.push(this);
 
             this.meshesSelectionPredicate = function (m) {
-                return m.material && m.isVisible && m.isEnabled() && m.checkCollisions;
+                return m.material && m.isVisible && m.isEnabled() && m.checkCollisions && ((m.layerMask & scene.activeCamera.layerMask) != 0);
             };
 
             // VBO

+ 1 - 1
Babylon/LensFlare/babylon.lensFlareSystem.ts

@@ -20,7 +20,7 @@
             this._emitter = emitter;
             scene.lensFlareSystems.push(this);
 
-            this.meshesSelectionPredicate = m => m.material && m.isVisible && m.isEnabled() && m.checkCollisions;
+            this.meshesSelectionPredicate = m => m.material && m.isVisible && m.isEnabled() && m.checkCollisions && ((m.layerMask & scene.activeCamera.layerMask) != 0);
 
             // VBO
             var vertices = [];

+ 64 - 10
Babylon/Lights/Shadows/babylon.shadowGenerator.js

@@ -22,28 +22,67 @@
             this._shadowMap.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
             this._shadowMap.renderParticles = false;
 
+            var effectiveRender = function (useBones, mesh, renderMesh, subMesh) {
+                // World
+                var world = mesh.getWorldMatrix();
+                if (useBones) {
+                    _this._effect.setMatrix("world", world);
+                } else {
+                    world.multiplyToRef(_this.getTransformMatrix(), _this._worldViewProjection);
+                    _this._effect.setMatrix("worldViewProjection", _this._worldViewProjection);
+                }
+
+                // Draw
+                renderMesh._draw(subMesh, true);
+            };
+
             // Custom render function
             var renderSubMesh = function (subMesh) {
                 var mesh = subMesh.getRenderingMesh();
-                var world = mesh.getWorldMatrix();
-                var engine = _this._scene.getEngine();
+                var scene = _this._scene;
+                var engine = scene.getEngine();
 
                 if (_this.isReady(mesh)) {
+                    // Managing instances
+                    var batch = mesh._getInstancesRenderList();
+
+                    if (batch.mustReturn) {
+                        return;
+                    }
+
                     engine.enableEffect(_this._effect);
+                    mesh._bind(subMesh, _this._effect, false);
+
+                    // Alpha test
+                    if (mesh.material && mesh.material.needAlphaTesting()) {
+                        var alphaTexture = mesh.material.getAlphaTestTexture();
+                        _this._effect.setTexture("diffuseSampler", alphaTexture);
+                        _this._effect.setMatrix("diffuseMatrix", alphaTexture.getTextureMatrix());
+                    }
 
                     // Bones
-                    if (mesh.skeleton && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesIndicesKind) && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesWeightsKind)) {
-                        _this._effect.setMatrix("world", world);
+                    var useBones = mesh.skeleton && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesIndicesKind) && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesWeightsKind);
+
+                    if (useBones) {
                         _this._effect.setMatrix("viewProjection", _this.getTransformMatrix());
 
                         _this._effect.setMatrices("mBones", mesh.skeleton.getTransformMatrices());
-                    } else {
-                        world.multiplyToRef(_this.getTransformMatrix(), _this._worldViewProjection);
-                        _this._effect.setMatrix("worldViewProjection", _this._worldViewProjection);
                     }
 
-                    // Bind and draw
-                    mesh.bindAndDraw(subMesh, _this._effect, false);
+                    if (batch.renderSelf) {
+                        effectiveRender(useBones, mesh, mesh, subMesh);
+                    }
+
+                    if (batch.visibleInstances) {
+                        for (var instanceIndex = 0; instanceIndex < batch.visibleInstances.length; instanceIndex++) {
+                            var instance = batch.visibleInstances[instanceIndex];
+
+                            effectiveRender(useBones, instance, mesh, subMesh);
+                        }
+                    }
+                } else {
+                    // Need to reset refresh rate of the shadowMap
+                    _this._shadowMap.resetRefreshCounter();
                 }
             };
 
@@ -73,6 +112,21 @@
             }
 
             var attribs = [BABYLON.VertexBuffer.PositionKind];
+
+            // Alpha test
+            if (mesh.material && mesh.material.needAlphaTesting()) {
+                defines.push("#define ALPHATEST");
+                if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) {
+                    attribs.push(BABYLON.VertexBuffer.UVKind);
+                    defines.push("#define UV1");
+                }
+                if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.UV2Kind)) {
+                    attribs.push(BABYLON.VertexBuffer.UV2Kind);
+                    defines.push("#define UV2");
+                }
+            }
+
+            // Bones
             if (mesh.skeleton && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesIndicesKind) && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesWeightsKind)) {
                 attribs.push(BABYLON.VertexBuffer.MatricesIndicesKind);
                 attribs.push(BABYLON.VertexBuffer.MatricesWeightsKind);
@@ -84,7 +138,7 @@
             var join = defines.join("\n");
             if (this._cachedDefines != join) {
                 this._cachedDefines = join;
-                this._effect = this._scene.getEngine().createEffect("shadowMap", attribs, ["world", "mBones", "viewProjection", "worldViewProjection"], [], join);
+                this._effect = this._scene.getEngine().createEffect("shadowMap", attribs, ["world", "mBones", "viewProjection", "worldViewProjection", "diffuseMatrix"], ["diffuseSampler"], join);
             }
 
             return this._effect.isReady();

+ 65 - 11
Babylon/Lights/Shadows/babylon.shadowGenerator.ts

@@ -30,29 +30,68 @@
             this._shadowMap.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
             this._shadowMap.renderParticles = false;
 
+            var effectiveRender = (useBones: boolean, mesh: AbstractMesh, renderMesh:Mesh, subMesh: SubMesh): void => {
+                // World
+                var world = mesh.getWorldMatrix();
+                if (useBones) {
+                    this._effect.setMatrix("world", world);
+                } else {
+                    world.multiplyToRef(this.getTransformMatrix(), this._worldViewProjection);
+                    this._effect.setMatrix("worldViewProjection", this._worldViewProjection);
+                }
+
+                // Draw
+                renderMesh._draw(subMesh, true);
+            }
 
             // Custom render function
             var renderSubMesh = (subMesh: SubMesh): void => {
                 var mesh = subMesh.getRenderingMesh();
-                var world = mesh.getWorldMatrix();
-                var engine = this._scene.getEngine();
+                var scene = this._scene;
+                var engine = scene.getEngine();
 
                 if (this.isReady(mesh)) {
+
+                    // Managing instances
+                    var batch = mesh._getInstancesRenderList();
+
+                    if (batch.mustReturn) {
+                        return;
+                    }
+
                     engine.enableEffect(this._effect);
+                    mesh._bind(subMesh, this._effect, false);
+
+                    // Alpha test
+                    if (mesh.material && mesh.material.needAlphaTesting()) {
+                        var alphaTexture = mesh.material.getAlphaTestTexture();
+                        this._effect.setTexture("diffuseSampler", alphaTexture);
+                        this._effect.setMatrix("diffuseMatrix", alphaTexture.getTextureMatrix());
+                    }
 
                     // Bones
-                    if (mesh.skeleton && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesIndicesKind) && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesWeightsKind)) {
-                        this._effect.setMatrix("world", world);
+                    var useBones = mesh.skeleton && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesIndicesKind) && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesWeightsKind);
+
+                    if (useBones) {
                         this._effect.setMatrix("viewProjection", this.getTransformMatrix());
 
                         this._effect.setMatrices("mBones", mesh.skeleton.getTransformMatrices());
-                    } else {
-                        world.multiplyToRef(this.getTransformMatrix(), this._worldViewProjection);
-                        this._effect.setMatrix("worldViewProjection", this._worldViewProjection);
                     }
 
-                    // Bind and draw
-                    mesh.bindAndDraw(subMesh, this._effect, false);
+                    if (batch.renderSelf) {
+                        effectiveRender(useBones, mesh, mesh, subMesh);
+                    }
+
+                    if (batch.visibleInstances) {
+                        for (var instanceIndex = 0; instanceIndex < batch.visibleInstances.length; instanceIndex++) {
+                            var instance = batch.visibleInstances[instanceIndex];
+
+                            effectiveRender(useBones, instance, mesh, subMesh);
+                        }
+                    }
+                } else {
+                    // Need to reset refresh rate of the shadowMap
+                    this._shadowMap.resetRefreshCounter();
                 }
             };
 
@@ -84,6 +123,21 @@
             }
 
             var attribs = [BABYLON.VertexBuffer.PositionKind];
+
+            // Alpha test
+            if (mesh.material && mesh.material.needAlphaTesting()) {
+                defines.push("#define ALPHATEST");
+                if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.UVKind)) {
+                    attribs.push(BABYLON.VertexBuffer.UVKind);
+                    defines.push("#define UV1");
+                }
+                if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.UV2Kind)) {
+                    attribs.push(BABYLON.VertexBuffer.UV2Kind);
+                    defines.push("#define UV2");
+                }
+            }
+
+            // Bones
             if (mesh.skeleton && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesIndicesKind) && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesWeightsKind)) {
                 attribs.push(BABYLON.VertexBuffer.MatricesIndicesKind);
                 attribs.push(BABYLON.VertexBuffer.MatricesWeightsKind);
@@ -97,8 +151,8 @@
                 this._cachedDefines = join;
                 this._effect = this._scene.getEngine().createEffect("shadowMap",
                     attribs,
-                    ["world", "mBones", "viewProjection", "worldViewProjection"],
-                    [], join);
+                    ["world", "mBones", "viewProjection", "worldViewProjection", "diffuseMatrix"],
+                    ["diffuseSampler"], join);
             }
 
             return this._effect.isReady();

+ 18 - 19
Babylon/Loading/Plugins/babylon.babylonFileLoader.js

@@ -303,7 +303,7 @@ var BABYLON = BABYLON || {};
     var parseCamera = function (parsedCamera, scene) {
         var camera = new BABYLON.FreeCamera(parsedCamera.name, BABYLON.Vector3.FromArray(parsedCamera.position), scene);
         camera.id = parsedCamera.id;
-        
+
         BABYLON.Tags.AddTagsTo(camera, parsedCamera.tags);
 
         // Parent
@@ -349,14 +349,13 @@ var BABYLON = BABYLON || {};
             scene.beginAnimation(camera, parsedCamera.autoAnimateFrom, parsedCamera.autoAnimateTo, parsedCamera.autoAnimateLoop, 1.0);
         }
 
-        
         // Layer Mask
-        if (parsedCamera.layerMask && (parseInt(parsedCamera.layerMask) != NaN)) {
-          camera.layerMask = Math.abs(parseInt(parsedCamera.layerMask));
+        if (parsedCamera.layerMask && (!isNaN(parsedCamera.layerMask))) {
+            camera.layerMask = Math.abs(parseInt(parsedCamera.layerMask));
         } else {
-          camera.layerMask = 0xFFFFFFFF;
+            camera.layerMask = 0xFFFFFFFF;
         }
-        
+
         return camera;
     };
 
@@ -504,7 +503,7 @@ var BABYLON = BABYLON || {};
     var parseMesh = function (parsedMesh, scene, rootUrl) {
         var mesh = new BABYLON.Mesh(parsedMesh.name, scene);
         mesh.id = parsedMesh.id;
-        
+
         BABYLON.Tags.AddTagsTo(mesh, parsedMesh.tags);
 
         mesh.position = BABYLON.Vector3.FromArray(parsedMesh.position);
@@ -544,7 +543,7 @@ var BABYLON = BABYLON || {};
         if (parsedMesh.parentId) {
             mesh.parent = scene.getLastEntryByID(parsedMesh.parentId);
         }
-        
+
         // Geometry
         if (parsedMesh.delayLoadingFile) {
             mesh.delayLoadState = BABYLON.Engine.DELAYLOADSTATE_NOTLOADED;
@@ -624,10 +623,10 @@ var BABYLON = BABYLON || {};
         }
 
         // Layer Mask
-        if (parsedMesh.layerMask && (parseInt(parsedMesh.layerMask) != NaN)) {
-          mesh.layerMask = Math.abs(parseInt(parsedMesh.layerMask));
+        if (parsedMesh.layerMask && (!isNaN(parsedMesh.layerMask))) {
+            mesh.layerMask = Math.abs(parseInt(parsedMesh.layerMask));
         } else {
-          mesh.layerMask = 0xFFFFFFFF;
+            mesh.layerMask = 0xFFFFFFFF;
         }
 
         return mesh;
@@ -718,19 +717,19 @@ var BABYLON = BABYLON || {};
         }
 
         else if (parsedGeometry.positions && parsedGeometry.normals && parsedGeometry.indices) {
-            mesh.setVerticesData(parsedGeometry.positions, BABYLON.VertexBuffer.PositionKind, false);
-            mesh.setVerticesData(parsedGeometry.normals, BABYLON.VertexBuffer.NormalKind, false);
+            mesh.setVerticesData(BABYLON.VertexBuffer.PositionKind, parsedGeometry.positions, false);
+            mesh.setVerticesData(BABYLON.VertexBuffer.NormalKind, parsedGeometry.normals, false);
 
             if (parsedGeometry.uvs) {
-                mesh.setVerticesData(parsedGeometry.uvs, BABYLON.VertexBuffer.UVKind, false);
+                mesh.setVerticesData(BABYLON.VertexBuffer.UVKind, parsedGeometry.uvs, false);
             }
 
             if (parsedGeometry.uvs2) {
-                mesh.setVerticesData(parsedGeometry.uvs2, BABYLON.VertexBuffer.UV2Kind, false);
+                mesh.setVerticesData(BABYLON.VertexBuffer.UV2Kind, parsedGeometry.uvs2, false);
             }
 
             if (parsedGeometry.colors) {
-                mesh.setVerticesData(parsedGeometry.colors, BABYLON.VertexBuffer.ColorKind, false);
+                mesh.setVerticesData(BABYLON.VertexBuffer.ColorKind, parsedGeometry.colors, false);
             }
 
             if (parsedGeometry.matricesIndices) {
@@ -746,15 +745,15 @@ var BABYLON = BABYLON || {};
                         floatIndices.push(matricesIndex >> 24);
                     }
 
-                    mesh.setVerticesData(floatIndices, BABYLON.VertexBuffer.MatricesIndicesKind, false);
+                    mesh.setVerticesData(BABYLON.VertexBuffer.MatricesIndicesKind, floatIndices, false);
                 } else {
                     delete parsedGeometry.matricesIndices._isExpanded;
-                    mesh.setVerticesData(parsedGeometry.matricesIndices, BABYLON.VertexBuffer.MatricesIndicesKind, false);
+                    mesh.setVerticesData(BABYLON.VertexBuffer.MatricesIndicesKind, parsedGeometry.matricesIndices, false);
                 }
             }
 
             if (parsedGeometry.matricesWeights) {
-                mesh.setVerticesData(parsedGeometry.matricesWeights, BABYLON.VertexBuffer.MatricesWeightsKind, false);
+                mesh.setVerticesData(BABYLON.VertexBuffer.MatricesWeightsKind, parsedGeometry.matricesWeights, false);
             }
 
             mesh.setIndices(parsedGeometry.indices);

+ 1 - 1
Babylon/Materials/babylon.effect.ts

@@ -184,7 +184,7 @@
             this._engine._bindTexture(this._samplers.indexOf(channel), texture);
         }
 
-        public setTexture(channel: string, texture: Texture): void {
+        public setTexture(channel: string, texture: BaseTexture): void {
             this._engine.setTexture(this._samplers.indexOf(channel), texture);
         }
 

+ 4 - 0
Babylon/Materials/babylon.material.js

@@ -37,6 +37,10 @@
             return false;
         };
 
+        Material.prototype.getAlphaTestTexture = function () {
+            return null;
+        };
+
         Material.prototype.trackCreation = function (onCompiled, onError) {
         };
 

+ 4 - 0
Babylon/Materials/babylon.material.ts

@@ -45,6 +45,10 @@
             return false;
         }
 
+        public getAlphaTestTexture(): BaseTexture {
+            return null;
+        }
+
         public trackCreation(onCompiled: (effect: Effect) => void, onError: (effect: Effect, errors: string) => void) {
         }
 

+ 1 - 1
Babylon/Materials/babylon.shaderMaterial.js

@@ -113,7 +113,7 @@ var BABYLON;
             return true;
         };
 
-        ShaderMaterial.prototype.bind = function (world, mesh) {
+        ShaderMaterial.prototype.bind = function (world) {
             // Std values
             if (this._options.uniforms.indexOf("world") !== -1) {
                 this._effect.setMatrix("world", world);

+ 1 - 1
Babylon/Materials/babylon.shaderMaterial.ts

@@ -113,7 +113,7 @@
             return true;
         }
 
-        public bind(world: Matrix, mesh: Mesh): void {
+        public bind(world: Matrix): void {
             // Std values
             if (this._options.uniforms.indexOf("world") !== -1) {
                 this._effect.setMatrix("world", world);

+ 11 - 7
Babylon/Materials/babylon.standardMaterial.js

@@ -50,6 +50,10 @@ var BABYLON;
             return this.diffuseTexture != null && this.diffuseTexture.hasAlpha && this.useAlphaFromDiffuseTexture;
         };
 
+        StandardMaterial.prototype.getAlphaTestTexture = function () {
+            return this.diffuseTexture;
+        };
+
         // Methods
         StandardMaterial.prototype.isReady = function (mesh) {
             if (this.checkReadyOnlyOnce) {
@@ -295,7 +299,7 @@ var BABYLON;
                 this._effect.setTexture("diffuseSampler", this.diffuseTexture);
 
                 this._effect.setFloat2("vDiffuseInfos", this.diffuseTexture.coordinatesIndex, this.diffuseTexture.level);
-                this._effect.setMatrix("diffuseMatrix", this.diffuseTexture._computeTextureMatrix());
+                this._effect.setMatrix("diffuseMatrix", this.diffuseTexture.getTextureMatrix());
 
                 this._baseColor.copyFromFloats(1, 1, 1);
             }
@@ -304,14 +308,14 @@ var BABYLON;
                 this._effect.setTexture("ambientSampler", this.ambientTexture);
 
                 this._effect.setFloat2("vAmbientInfos", this.ambientTexture.coordinatesIndex, this.ambientTexture.level);
-                this._effect.setMatrix("ambientMatrix", this.ambientTexture._computeTextureMatrix());
+                this._effect.setMatrix("ambientMatrix", this.ambientTexture.getTextureMatrix());
             }
 
             if (this.opacityTexture && BABYLON.StandardMaterial.OpacityTextureEnabled) {
                 this._effect.setTexture("opacitySampler", this.opacityTexture);
 
                 this._effect.setFloat2("vOpacityInfos", this.opacityTexture.coordinatesIndex, this.opacityTexture.level);
-                this._effect.setMatrix("opacityMatrix", this.opacityTexture._computeTextureMatrix());
+                this._effect.setMatrix("opacityMatrix", this.opacityTexture.getTextureMatrix());
             }
 
             if (this.reflectionTexture && BABYLON.StandardMaterial.ReflectionTextureEnabled) {
@@ -321,7 +325,7 @@ var BABYLON;
                     this._effect.setTexture("reflection2DSampler", this.reflectionTexture);
                 }
 
-                this._effect.setMatrix("reflectionMatrix", this.reflectionTexture._computeReflectionTextureMatrix());
+                this._effect.setMatrix("reflectionMatrix", this.reflectionTexture.getReflectionTextureMatrix());
                 this._effect.setFloat3("vReflectionInfos", this.reflectionTexture.coordinatesMode, this.reflectionTexture.level, this.reflectionTexture.isCube ? 1 : 0);
             }
 
@@ -329,21 +333,21 @@ var BABYLON;
                 this._effect.setTexture("emissiveSampler", this.emissiveTexture);
 
                 this._effect.setFloat2("vEmissiveInfos", this.emissiveTexture.coordinatesIndex, this.emissiveTexture.level);
-                this._effect.setMatrix("emissiveMatrix", this.emissiveTexture._computeTextureMatrix());
+                this._effect.setMatrix("emissiveMatrix", this.emissiveTexture.getTextureMatrix());
             }
 
             if (this.specularTexture && BABYLON.StandardMaterial.SpecularTextureEnabled) {
                 this._effect.setTexture("specularSampler", this.specularTexture);
 
                 this._effect.setFloat2("vSpecularInfos", this.specularTexture.coordinatesIndex, this.specularTexture.level);
-                this._effect.setMatrix("specularMatrix", this.specularTexture._computeTextureMatrix());
+                this._effect.setMatrix("specularMatrix", this.specularTexture.getTextureMatrix());
             }
 
             if (this.bumpTexture && scene.getEngine().getCaps().standardDerivatives && BABYLON.StandardMaterial.BumpTextureEnabled) {
                 this._effect.setTexture("bumpSampler", this.bumpTexture);
 
                 this._effect.setFloat2("vBumpInfos", this.bumpTexture.coordinatesIndex, this.bumpTexture.level);
-                this._effect.setMatrix("bumpMatrix", this.bumpTexture._computeTextureMatrix());
+                this._effect.setMatrix("bumpMatrix", this.bumpTexture.getTextureMatrix());
             }
 
             // Colors

+ 18 - 14
Babylon/Materials/babylon.standardMaterial.ts

@@ -2,13 +2,13 @@
     var maxSimultaneousLights = 4;
 
     export class StandardMaterial extends Material {
-        public diffuseTexture: Texture;
-        public ambientTexture: Texture;
-        public opacityTexture: Texture;
-        public reflectionTexture: Texture;
-        public emissiveTexture: Texture;
-        public specularTexture: Texture;
-        public bumpTexture: Texture;
+        public diffuseTexture: BaseTexture;
+        public ambientTexture: BaseTexture;
+        public opacityTexture: BaseTexture;
+        public reflectionTexture: BaseTexture;
+        public emissiveTexture: BaseTexture;
+        public specularTexture: BaseTexture;
+        public bumpTexture: BaseTexture;
 
         public ambientColor = new BABYLON.Color3(0, 0, 0);
         public diffuseColor = new BABYLON.Color3(1, 1, 1);
@@ -53,6 +53,10 @@
             return this.diffuseTexture != null && this.diffuseTexture.hasAlpha && this.useAlphaFromDiffuseTexture;
         }
 
+        public getAlphaTestTexture(): BaseTexture {
+            return this.diffuseTexture;
+        }
+
         // Methods   
         public isReady(mesh?: AbstractMesh): boolean {
             if (this.checkReadyOnlyOnce) {
@@ -301,7 +305,7 @@
                 this._effect.setTexture("diffuseSampler", this.diffuseTexture);
 
                 this._effect.setFloat2("vDiffuseInfos", this.diffuseTexture.coordinatesIndex, this.diffuseTexture.level);
-                this._effect.setMatrix("diffuseMatrix", this.diffuseTexture._computeTextureMatrix());
+                this._effect.setMatrix("diffuseMatrix", this.diffuseTexture.getTextureMatrix());
 
                 this._baseColor.copyFromFloats(1, 1, 1);
             }
@@ -310,14 +314,14 @@
                 this._effect.setTexture("ambientSampler", this.ambientTexture);
 
                 this._effect.setFloat2("vAmbientInfos", this.ambientTexture.coordinatesIndex, this.ambientTexture.level);
-                this._effect.setMatrix("ambientMatrix", this.ambientTexture._computeTextureMatrix());
+                this._effect.setMatrix("ambientMatrix", this.ambientTexture.getTextureMatrix());
             }
 
             if (this.opacityTexture && BABYLON.StandardMaterial.OpacityTextureEnabled) {
                 this._effect.setTexture("opacitySampler", this.opacityTexture);
 
                 this._effect.setFloat2("vOpacityInfos", this.opacityTexture.coordinatesIndex, this.opacityTexture.level);
-                this._effect.setMatrix("opacityMatrix", this.opacityTexture._computeTextureMatrix());
+                this._effect.setMatrix("opacityMatrix", this.opacityTexture.getTextureMatrix());
             }
 
             if (this.reflectionTexture && BABYLON.StandardMaterial.ReflectionTextureEnabled) {
@@ -327,7 +331,7 @@
                     this._effect.setTexture("reflection2DSampler", this.reflectionTexture);
                 }
 
-                this._effect.setMatrix("reflectionMatrix", this.reflectionTexture._computeReflectionTextureMatrix());
+                this._effect.setMatrix("reflectionMatrix", this.reflectionTexture.getReflectionTextureMatrix());
                 this._effect.setFloat3("vReflectionInfos", this.reflectionTexture.coordinatesMode, this.reflectionTexture.level, this.reflectionTexture.isCube ? 1 : 0);
             }
 
@@ -335,21 +339,21 @@
                 this._effect.setTexture("emissiveSampler", this.emissiveTexture);
 
                 this._effect.setFloat2("vEmissiveInfos", this.emissiveTexture.coordinatesIndex, this.emissiveTexture.level);
-                this._effect.setMatrix("emissiveMatrix", this.emissiveTexture._computeTextureMatrix());
+                this._effect.setMatrix("emissiveMatrix", this.emissiveTexture.getTextureMatrix());
             }
 
             if (this.specularTexture && BABYLON.StandardMaterial.SpecularTextureEnabled) {
                 this._effect.setTexture("specularSampler", this.specularTexture);
 
                 this._effect.setFloat2("vSpecularInfos", this.specularTexture.coordinatesIndex, this.specularTexture.level);
-                this._effect.setMatrix("specularMatrix", this.specularTexture._computeTextureMatrix());
+                this._effect.setMatrix("specularMatrix", this.specularTexture.getTextureMatrix());
             }
 
             if (this.bumpTexture && scene.getEngine().getCaps().standardDerivatives && BABYLON.StandardMaterial.BumpTextureEnabled) {
                 this._effect.setTexture("bumpSampler", this.bumpTexture);
 
                 this._effect.setFloat2("vBumpInfos", this.bumpTexture.coordinatesIndex, this.bumpTexture.level);
-                this._effect.setMatrix("bumpMatrix", this.bumpTexture._computeTextureMatrix());
+                this._effect.setMatrix("bumpMatrix", this.bumpTexture.getTextureMatrix());
             }
 
             // Colors

+ 19 - 0
Babylon/Materials/textures/babylon.baseTexture.js

@@ -6,6 +6,13 @@
             this.hasAlpha = false;
             this.level = 1;
             this.isCube = false;
+            this.isRenderTarget = false;
+            this.animations = new Array();
+            this.coordinatesIndex = 0;
+            this.coordinatesMode = BABYLON.Texture.EXPLICIT_MODE;
+            this.wrapU = BABYLON.Texture.WRAP_ADDRESSMODE;
+            this.wrapV = BABYLON.Texture.WRAP_ADDRESSMODE;
+            this.anisotropicFilteringLevel = 4;
             this._scene = scene;
             this._scene.textures.push(this);
         }
@@ -13,6 +20,14 @@
             return this._scene;
         };
 
+        BaseTexture.prototype.getTextureMatrix = function () {
+            return null;
+        };
+
+        BaseTexture.prototype.getReflectionTextureMatrix = function () {
+            return null;
+        };
+
         BaseTexture.prototype.getInternalTexture = function () {
             return this._texture;
         };
@@ -87,6 +102,10 @@
             }
         };
 
+        BaseTexture.prototype.clone = function () {
+            return null;
+        };
+
         BaseTexture.prototype.dispose = function () {
             // Remove from scene
             var index = this._scene.textures.indexOf(this);

+ 24 - 3
Babylon/Materials/textures/babylon.baseTexture.ts

@@ -1,13 +1,22 @@
 module BABYLON {
     export class BaseTexture {
+        public name: string;
         public delayLoadState = BABYLON.Engine.DELAYLOADSTATE_NONE;
         public hasAlpha = false;
         public level = 1;
-        public isCube = false;
-        public _texture: WebGLTexture;
+        public isCube = false
+        public isRenderTarget = false;
+        public animations = new Array<Animation>();
         public onDispose: () => void;
+        public coordinatesIndex = 0;
+        public coordinatesMode = BABYLON.Texture.EXPLICIT_MODE;
+        public wrapU = BABYLON.Texture.WRAP_ADDRESSMODE;
+        public wrapV = BABYLON.Texture.WRAP_ADDRESSMODE;
+        public anisotropicFilteringLevel = 4;
+        public _cachedAnisotropicFilteringLevel: number;
 
         private _scene: Scene;
+        public _texture: WebGLTexture;
 
         constructor(scene: Scene) {
             this._scene = scene;
@@ -16,7 +25,15 @@
 
         public getScene(): Scene {
             return this._scene;
-        } 
+        }
+
+        public getTextureMatrix(): Matrix {
+            return null;
+        }
+
+        public getReflectionTextureMatrix(): Matrix {
+            return null;
+        }
 
         public getInternalTexture(): WebGLTexture {
             return this._texture;
@@ -92,6 +109,10 @@
             }
         }
 
+        public clone(): BaseTexture {
+            return null;
+        }
+
         public dispose(): void {
             // Remove from scene
             var index = this._scene.textures.indexOf(this);

+ 14 - 1
Babylon/Materials/textures/babylon.cubeTexture.js

@@ -37,6 +37,19 @@ var BABYLON;
 
             this._textureMatrix = BABYLON.Matrix.Identity();
         }
+        CubeTexture.prototype.clone = function () {
+            var newTexture = new BABYLON.CubeTexture(this.url, this.getScene(), this._extensions, this._noMipmap);
+
+            // Base texture
+            newTexture.level = this.level;
+            newTexture.wrapU = this.wrapU;
+            newTexture.wrapV = this.wrapV;
+            newTexture.coordinatesIndex = this.coordinatesIndex;
+            newTexture.coordinatesMode = this.coordinatesMode;
+
+            return newTexture;
+        };
+
         // Methods
         CubeTexture.prototype.delayLoad = function () {
             if (this.delayLoadState != BABYLON.Engine.DELAYLOADSTATE_NOTLOADED) {
@@ -51,7 +64,7 @@ var BABYLON;
             }
         };
 
-        CubeTexture.prototype._computeReflectionTextureMatrix = function () {
+        CubeTexture.prototype.getReflectionTextureMatrix = function () {
             return this._textureMatrix;
         };
         return CubeTexture;

+ 14 - 2
Babylon/Materials/textures/babylon.cubeTexture.ts

@@ -1,6 +1,5 @@
 module BABYLON {
     export class CubeTexture extends BaseTexture {
-        public name: string;
         public url: string;
         public coordinatesMode = BABYLON.Texture.CUBIC_MODE;
 
@@ -37,6 +36,19 @@
             this._textureMatrix = BABYLON.Matrix.Identity();
         }
 
+        public clone(): CubeTexture {
+            var newTexture = new BABYLON.CubeTexture(this.url, this.getScene(), this._extensions, this._noMipmap);
+
+            // Base texture
+            newTexture.level = this.level;
+            newTexture.wrapU = this.wrapU;
+            newTexture.wrapV = this.wrapV;
+            newTexture.coordinatesIndex = this.coordinatesIndex;
+            newTexture.coordinatesMode = this.coordinatesMode;
+
+            return newTexture;
+        }
+
         // Methods
         public delayLoad(): void {
             if (this.delayLoadState != BABYLON.Engine.DELAYLOADSTATE_NOTLOADED) {
@@ -51,7 +63,7 @@
             }
         }
 
-        public _computeReflectionTextureMatrix(): Matrix {
+        public getReflectionTextureMatrix(): Matrix {
             return this._textureMatrix;
         }
     }

+ 49 - 6
Babylon/Materials/textures/babylon.renderTargetTexture.js

@@ -14,6 +14,8 @@ var BABYLON;
             this.renderParticles = true;
             this.renderSprites = false;
             this.coordinatesMode = BABYLON.Texture.PROJECTION_MODE;
+            this._currentRefreshId = -1;
+            this._refreshRate = 1;
 
             this.name = name;
             this.isRenderTarget = true;
@@ -26,6 +28,39 @@ var BABYLON;
             // Rendering groups
             this._renderingManager = new BABYLON.RenderingManager(scene);
         }
+        RenderTargetTexture.prototype.resetRefreshCounter = function () {
+            this._currentRefreshId = -1;
+        };
+
+        Object.defineProperty(RenderTargetTexture.prototype, "refreshRate", {
+            get: function () {
+                return this._refreshRate;
+            },
+            // Use 0 to render just once, 1 to render on every frame, 2 to render every two frames and so on...
+            set: function (value) {
+                this._refreshRate = value;
+                this.resetRefreshCounter();
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+
+        RenderTargetTexture.prototype._shouldRender = function () {
+            if (this._currentRefreshId === -1) {
+                this._currentRefreshId = 1;
+                return true;
+            }
+
+            if (this.refreshRate == this._currentRefreshId) {
+                this._currentRefreshId = 1;
+                return true;
+            }
+
+            this._currentRefreshId++;
+            return false;
+        };
+
         RenderTargetTexture.prototype.getRenderSize = function () {
             return this._size;
         };
@@ -66,13 +101,21 @@ var BABYLON;
             for (var meshIndex = 0; meshIndex < this.renderList.length; meshIndex++) {
                 var mesh = this.renderList[meshIndex];
 
-                if (mesh && mesh.isEnabled() && mesh.isVisible && mesh.subMeshes && ((mesh.layerMask & scene.activeCamera.layerMask) != 0)) {
-                    mesh._activate(scene.getRenderId());
+                if (mesh) {
+                    if (!mesh.isReady() || (mesh.material && !mesh.material.isReady())) {
+                        // Reset _currentRefreshId
+                        this.resetRefreshCounter();
+                        continue;
+                    }
+
+                    if (mesh.isEnabled() && mesh.isVisible && mesh.subMeshes && ((mesh.layerMask & scene.activeCamera.layerMask) != 0)) {
+                        mesh._activate(scene.getRenderId());
 
-                    for (var subIndex = 0; subIndex < mesh.subMeshes.length; subIndex++) {
-                        var subMesh = mesh.subMeshes[subIndex];
-                        scene._activeVertices += subMesh.verticesCount;
-                        this._renderingManager.dispatch(subMesh);
+                        for (var subIndex = 0; subIndex < mesh.subMeshes.length; subIndex++) {
+                            var subMesh = mesh.subMeshes[subIndex];
+                            scene._activeVertices += subMesh.verticesCount;
+                            this._renderingManager.dispatch(subMesh);
+                        }
                     }
                 }
             }

+ 46 - 8
Babylon/Materials/textures/babylon.renderTargetTexture.ts

@@ -10,9 +10,11 @@
 
         private _size: number;
         public _generateMipMaps: boolean;
-        private _renderingManager
+        private _renderingManager: RenderingManager;
         public _waitingRenderList: string[];
         private _doNotChangeAspectRatio: boolean;
+        private _currentRefreshId = -1;
+        private _refreshRate = 1;
 
         constructor(name: string, size: any, scene: Scene, generateMipMaps?: boolean, doNotChangeAspectRatio?: boolean) {
             super(null, scene, !generateMipMaps);
@@ -29,6 +31,35 @@
             this._renderingManager = new BABYLON.RenderingManager(scene);
         }
 
+        public resetRefreshCounter(): void {
+            this._currentRefreshId = -1;
+        }
+
+        public get refreshRate(): number {
+            return this._refreshRate;
+        }
+
+        // Use 0 to render just once, 1 to render on every frame, 2 to render every two frames and so on...
+        public set refreshRate(value: number) {
+            this._refreshRate = value;
+            this.resetRefreshCounter();
+        }
+
+        public _shouldRender(): boolean {
+            if (this._currentRefreshId === -1) { // At least render once
+                this._currentRefreshId = 1;
+                return true;
+            }
+
+            if (this.refreshRate == this._currentRefreshId) {
+                this._currentRefreshId = 1;
+                return true;
+            }
+
+            this._currentRefreshId++;
+            return false;
+        }
+
         public getRenderSize(): number {
             return this._size;
         }
@@ -69,13 +100,21 @@
             for (var meshIndex = 0; meshIndex < this.renderList.length; meshIndex++) {
                 var mesh = this.renderList[meshIndex];
 
-                if (mesh && mesh.isEnabled() && mesh.isVisible && mesh.subMeshes && ((mesh.layerMask & scene.activeCamera.layerMask) != 0)) {
-                    mesh._activate(scene.getRenderId());
+                if (mesh) {
+                    if (!mesh.isReady() || (mesh.material && !mesh.material.isReady())) {
+                        // Reset _currentRefreshId
+                        this.resetRefreshCounter();
+                        continue;
+                    }
+
+                    if (mesh.isEnabled() && mesh.isVisible && mesh.subMeshes && ((mesh.layerMask & scene.activeCamera.layerMask) != 0)) {
+                        mesh._activate(scene.getRenderId());
 
-                    for (var subIndex = 0; subIndex < mesh.subMeshes.length; subIndex++) {
-                        var subMesh = mesh.subMeshes[subIndex];
-                        scene._activeVertices += subMesh.verticesCount;
-                        this._renderingManager.dispatch(subMesh);
+                        for (var subIndex = 0; subIndex < mesh.subMeshes.length; subIndex++) {
+                            var subMesh = mesh.subMeshes[subIndex];
+                            scene._activeVertices += subMesh.verticesCount;
+                            this._renderingManager.dispatch(subMesh);
+                        }
                     }
                 }
             }
@@ -89,7 +128,6 @@
             }
 
             // Render
-
             this._renderingManager.render(this.customRenderFunction, this.renderList, this.renderParticles, this.renderSprites);
 
             if (useCameraPostProcess) {

+ 6 - 13
Babylon/Materials/textures/babylon.texture.js

@@ -17,13 +17,6 @@ var BABYLON;
             this.uAng = 0;
             this.vAng = 0;
             this.wAng = 0;
-            this.wrapU = BABYLON.Texture.WRAP_ADDRESSMODE;
-            this.wrapV = BABYLON.Texture.WRAP_ADDRESSMODE;
-            this.coordinatesIndex = 0;
-            this.coordinatesMode = BABYLON.Texture.EXPLICIT_MODE;
-            this.anisotropicFilteringLevel = 4;
-            this.animations = new Array();
-            this.isRenderTarget = false;
 
             this.name = url;
             this.url = url;
@@ -72,7 +65,7 @@ var BABYLON;
             t.z += 0.5;
         };
 
-        Texture.prototype._computeTextureMatrix = function () {
+        Texture.prototype.getTextureMatrix = function () {
             if (this.uOffset === this._cachedUOffset && this.vOffset === this._cachedVOffset && this.uScale === this._cachedUScale && this.vScale === this._cachedVScale && this.uAng === this._cachedUAng && this.vAng === this._cachedVAng && this.wAng === this._cachedWAng) {
                 return this._cachedTextureMatrix;
             }
@@ -116,7 +109,7 @@ var BABYLON;
             return this._cachedTextureMatrix;
         };
 
-        Texture.prototype._computeReflectionTextureMatrix = function () {
+        Texture.prototype.getReflectionTextureMatrix = function () {
             if (this.uOffset === this._cachedUOffset && this.vOffset === this._cachedVOffset && this.uScale === this._cachedUScale && this.vScale === this._cachedVScale && this.coordinatesMode === this._cachedCoordinatesMode) {
                 return this._cachedTextureMatrix;
             }
@@ -167,6 +160,10 @@ var BABYLON;
             // Base texture
             newTexture.hasAlpha = this.hasAlpha;
             newTexture.level = this.level;
+            newTexture.wrapU = this.wrapU;
+            newTexture.wrapV = this.wrapV;
+            newTexture.coordinatesIndex = this.coordinatesIndex;
+            newTexture.coordinatesMode = this.coordinatesMode;
 
             // Texture
             newTexture.uOffset = this.uOffset;
@@ -176,10 +173,6 @@ var BABYLON;
             newTexture.uAng = this.uAng;
             newTexture.vAng = this.vAng;
             newTexture.wAng = this.wAng;
-            newTexture.wrapU = this.wrapU;
-            newTexture.wrapV = this.wrapV;
-            newTexture.coordinatesIndex = this.coordinatesIndex;
-            newTexture.coordinatesMode = this.coordinatesMode;
 
             return newTexture;
         };

+ 6 - 15
Babylon/Materials/textures/babylon.texture.ts

@@ -17,7 +17,6 @@
         public static MIRROR_ADDRESSMODE = 2;
 
         // Members
-        public name: string;
         public url: string;
         public uOffset = 0;
         public vOffset = 0;
@@ -26,13 +25,6 @@
         public uAng = 0;
         public vAng = 0;
         public wAng = 0;
-        public wrapU = BABYLON.Texture.WRAP_ADDRESSMODE;
-        public wrapV = BABYLON.Texture.WRAP_ADDRESSMODE;
-        public coordinatesIndex = 0;
-        public coordinatesMode = BABYLON.Texture.EXPLICIT_MODE;
-        public anisotropicFilteringLevel = 4;
-        public animations = new Array<Animation>();
-        public isRenderTarget = false;
 
         private _noMipmap: boolean;
         public _invertY: boolean;
@@ -43,7 +35,6 @@
         private _t1: Vector3;
         private _t2: Vector3;
 
-        public _cachedAnisotropicFilteringLevel: number;
         private _cachedUOffset: number;
         private _cachedVOffset: number;
         private _cachedUScale: number;
@@ -104,7 +95,7 @@
             t.z += 0.5;
         }
 
-        public _computeTextureMatrix(): Matrix {
+        public getTextureMatrix(): Matrix {
             if (
                 this.uOffset === this._cachedUOffset &&
                 this.vOffset === this._cachedVOffset &&
@@ -149,7 +140,7 @@
             return this._cachedTextureMatrix;
         }
 
-        public _computeReflectionTextureMatrix(): Matrix {
+        public getReflectionTextureMatrix(): Matrix {
             if (
                 this.uOffset === this._cachedUOffset &&
                 this.vOffset === this._cachedVOffset &&
@@ -205,6 +196,10 @@
             // Base texture
             newTexture.hasAlpha = this.hasAlpha;
             newTexture.level = this.level;
+            newTexture.wrapU = this.wrapU;
+            newTexture.wrapV = this.wrapV;
+            newTexture.coordinatesIndex = this.coordinatesIndex;
+            newTexture.coordinatesMode = this.coordinatesMode;
 
             // Texture
             newTexture.uOffset = this.uOffset;
@@ -214,10 +209,6 @@
             newTexture.uAng = this.uAng;
             newTexture.vAng = this.vAng;
             newTexture.wAng = this.wAng;
-            newTexture.wrapU = this.wrapU;
-            newTexture.wrapV = this.wrapV;
-            newTexture.coordinatesIndex = this.coordinatesIndex;
-            newTexture.coordinatesMode = this.coordinatesMode;
 
             return newTexture;
         }

+ 14 - 10
Babylon/Math/babylon.math.js

@@ -1837,18 +1837,18 @@
             this.direction = direction;
         }
         // Methods
-        Ray.prototype.intersectsBox = function (box) {
+        Ray.prototype.intersectsBoxMinMax = function (minimum, maximum) {
             var d = 0.0;
             var maxValue = Number.MAX_VALUE;
 
             if (Math.abs(this.direction.x) < 0.0000001) {
-                if (this.origin.x < box.minimum.x || this.origin.x > box.maximum.x) {
+                if (this.origin.x < minimum.x || this.origin.x > maximum.x) {
                     return false;
                 }
             } else {
                 var inv = 1.0 / this.direction.x;
-                var min = (box.minimum.x - this.origin.x) * inv;
-                var max = (box.maximum.x - this.origin.x) * inv;
+                var min = (minimum.x - this.origin.x) * inv;
+                var max = (maximum.x - this.origin.x) * inv;
 
                 if (min > max) {
                     var temp = min;
@@ -1865,13 +1865,13 @@
             }
 
             if (Math.abs(this.direction.y) < 0.0000001) {
-                if (this.origin.y < box.minimum.y || this.origin.y > box.maximum.y) {
+                if (this.origin.y < minimum.y || this.origin.y > maximum.y) {
                     return false;
                 }
             } else {
                 inv = 1.0 / this.direction.y;
-                min = (box.minimum.y - this.origin.y) * inv;
-                max = (box.maximum.y - this.origin.y) * inv;
+                min = (minimum.y - this.origin.y) * inv;
+                max = (maximum.y - this.origin.y) * inv;
 
                 if (min > max) {
                     temp = min;
@@ -1888,13 +1888,13 @@
             }
 
             if (Math.abs(this.direction.z) < 0.0000001) {
-                if (this.origin.z < box.minimum.z || this.origin.z > box.maximum.z) {
+                if (this.origin.z < minimum.z || this.origin.z > maximum.z) {
                     return false;
                 }
             } else {
                 inv = 1.0 / this.direction.z;
-                min = (box.minimum.z - this.origin.z) * inv;
-                max = (box.maximum.z - this.origin.z) * inv;
+                min = (minimum.z - this.origin.z) * inv;
+                max = (maximum.z - this.origin.z) * inv;
 
                 if (min > max) {
                     temp = min;
@@ -1912,6 +1912,10 @@
             return true;
         };
 
+        Ray.prototype.intersectsBox = function (box) {
+            return this.intersectsBoxMinMax(box.minimum, box.maximum);
+        };
+
         Ray.prototype.intersectsSphere = function (sphere) {
             var x = sphere.center.x - this.origin.x;
             var y = sphere.center.y - this.origin.y;

+ 14 - 10
Babylon/Math/babylon.math.ts

@@ -1843,19 +1843,19 @@
         }
 
         // Methods
-        public intersectsBox(box: BoundingBox): boolean {
+        public intersectsBoxMinMax(minimum: Vector3, maximum: Vector3): boolean {
             var d = 0.0;
             var maxValue = Number.MAX_VALUE;
 
             if (Math.abs(this.direction.x) < 0.0000001) {
-                if (this.origin.x < box.minimum.x || this.origin.x > box.maximum.x) {
+                if (this.origin.x < minimum.x || this.origin.x > maximum.x) {
                     return false;
                 }
             }
             else {
                 var inv = 1.0 / this.direction.x;
-                var min = (box.minimum.x - this.origin.x) * inv;
-                var max = (box.maximum.x - this.origin.x) * inv;
+                var min = (minimum.x - this.origin.x) * inv;
+                var max = (maximum.x - this.origin.x) * inv;
 
                 if (min > max) {
                     var temp = min;
@@ -1872,14 +1872,14 @@
             }
 
             if (Math.abs(this.direction.y) < 0.0000001) {
-                if (this.origin.y < box.minimum.y || this.origin.y > box.maximum.y) {
+                if (this.origin.y < minimum.y || this.origin.y > maximum.y) {
                     return false;
                 }
             }
             else {
                 inv = 1.0 / this.direction.y;
-                min = (box.minimum.y - this.origin.y) * inv;
-                max = (box.maximum.y - this.origin.y) * inv;
+                min = (minimum.y - this.origin.y) * inv;
+                max = (maximum.y - this.origin.y) * inv;
 
                 if (min > max) {
                     temp = min;
@@ -1896,14 +1896,14 @@
             }
 
             if (Math.abs(this.direction.z) < 0.0000001) {
-                if (this.origin.z < box.minimum.z || this.origin.z > box.maximum.z) {
+                if (this.origin.z < minimum.z || this.origin.z > maximum.z) {
                     return false;
                 }
             }
             else {
                 inv = 1.0 / this.direction.z;
-                min = (box.minimum.z - this.origin.z) * inv;
-                max = (box.maximum.z - this.origin.z) * inv;
+                min = (minimum.z - this.origin.z) * inv;
+                max = (maximum.z - this.origin.z) * inv;
 
                 if (min > max) {
                     temp = min;
@@ -1921,6 +1921,10 @@
             return true;
         }
 
+        public intersectsBox(box: BoundingBox): boolean {
+            return this.intersectsBoxMinMax(box.minimum, box.maximum);
+        }
+
         public intersectsSphere(sphere): boolean {
             var x = sphere.center.x - this.origin.x;
             var y = sphere.center.y - this.origin.y;

+ 70 - 8
Babylon/Mesh/babylon.abstractMesh.js

@@ -20,10 +20,15 @@ var BABYLON;
             this.isVisible = true;
             this.isPickable = true;
             this.showBoundingBox = false;
+            this.showSubMeshesBoundingBox = false;
             this.onDispose = null;
             this.checkCollisions = false;
             this.renderingGroupId = 0;
             this.receiveShadows = false;
+            this.useOctreeForRenderingSelection = true;
+            this.useOctreeForPicking = true;
+            this.useOctreeForCollisions = true;
+            this.layerMask = 0xFFFFFFFF;
             // Physics
             this._physicImpostor = BABYLON.PhysicsEngine.NoImpostor;
             // Cache
@@ -43,6 +48,8 @@ var BABYLON;
             this._pivotMatrix = BABYLON.Matrix.Identity();
             this._isDisposed = false;
             this._renderId = 0;
+            this._traversalId = -1;
+            this._collisionTraversalId = 0;
 
             scene.meshes.push(this);
         }
@@ -517,6 +524,23 @@ var BABYLON;
             this.getScene().getPhysicsEngine()._createLink(this, otherMesh, pivot1, pivot2);
         };
 
+        // Submeshes octree
+        /**
+        * This function will create an octree to help select the right submeshes for rendering, picking and collisions
+        * Please note that you must have a decent number of submeshes to get performance improvements when using octree
+        */
+        AbstractMesh.prototype.createOrUpdateSubmeshesOctree = function (capacity) {
+            if (!this._submeshesOctree) {
+                this._submeshesOctree = new BABYLON.Octree(BABYLON.Octree.CreationFuncForSubMeshes, capacity);
+            }
+
+            this.computeWorldMatrix(true);
+
+            // Update octree
+            var bbox = this.getBoundingInfo().boundingBox;
+            this._submeshesOctree.update(bbox.minimumWorld, bbox.maximumWorld, this.subMeshes);
+        };
+
         // Collisions
         AbstractMesh.prototype._collideForSubMesh = function (subMesh, transformMatrix, collider) {
             this._generatePointsArray();
@@ -537,12 +561,35 @@ var BABYLON;
             collider._collide(subMesh, subMesh._lastColliderWorldVertices, this.getIndices(), subMesh.indexStart, subMesh.indexStart + subMesh.indexCount, subMesh.verticesStart);
         };
 
-        AbstractMesh.prototype._processCollisionsForSubModels = function (collider, transformMatrix) {
-            for (var index = 0; index < this.subMeshes.length; index++) {
-                var subMesh = this.subMeshes[index];
+        AbstractMesh.prototype._processCollisionsForSubMeshes = function (collider, transformMatrix) {
+            var subMeshes;
+            var len;
+
+            // Octrees
+            if (this._submeshesOctree && this.useOctreeForCollisions) {
+                var radius = collider.velocityWorldLength + Math.max(collider.radius.x, collider.radius.y, collider.radius.z);
+                var intersections = this._submeshesOctree.intersects(collider.basePointWorld, radius, true);
+
+                len = intersections.length;
+                subMeshes = intersections.data;
+            } else {
+                subMeshes = this.subMeshes;
+                len = subMeshes.length;
+            }
+
+            this._collisionTraversalId++;
+
+            for (var index = 0; index < len; index++) {
+                var subMesh = subMeshes[index];
+
+                if (subMesh._collisionTraversalId === this._collisionTraversalId) {
+                    continue;
+                }
+
+                subMesh._collisionTraversalId = this._collisionTraversalId;
 
                 // Bounding test
-                if (this.subMeshes.length > 1 && !subMesh._checkCollision(collider))
+                if (len > 1 && !subMesh._checkCollision(collider))
                     continue;
 
                 this._collideForSubMesh(subMesh, transformMatrix, collider);
@@ -558,7 +605,7 @@ var BABYLON;
             BABYLON.Matrix.ScalingToRef(1.0 / collider.radius.x, 1.0 / collider.radius.y, 1.0 / collider.radius.z, this._collisionsScalingMatrix);
             this.worldMatrixFromCache.multiplyToRef(this._collisionsScalingMatrix, this._collisionsTransformMatrix);
 
-            this._processCollisionsForSubModels(collider, this._collisionsTransformMatrix);
+            this._processCollisionsForSubMeshes(collider, this._collisionsTransformMatrix);
         };
 
         // Picking
@@ -579,11 +626,26 @@ var BABYLON;
 
             var intersectInfo = null;
 
-            for (var index = 0; index < this.subMeshes.length; index++) {
-                var subMesh = this.subMeshes[index];
+            // Octrees
+            var subMeshes;
+            var len;
+
+            if (this._submeshesOctree && this.useOctreeForPicking) {
+                var worldRay = BABYLON.Ray.Transform(ray, this.getWorldMatrix());
+                var intersections = this._submeshesOctree.intersectsRay(worldRay);
+
+                len = intersections.length;
+                subMeshes = intersections.data;
+            } else {
+                subMeshes = this.subMeshes;
+                len = subMeshes.length;
+            }
+
+            for (var index = 0; index < len; index++) {
+                var subMesh = subMeshes[index];
 
                 // Bounding test
-                if (this.subMeshes.length > 1 && !subMesh.canIntersects(ray))
+                if (len > 1 && !subMesh.canIntersects(ray))
                     continue;
 
                 var currentIntersectInfo = subMesh.intersects(ray, this._positions, this.getIndices(), fastCheck);

+ 73 - 8
Babylon/Mesh/babylon.abstractMesh.ts

@@ -38,6 +38,7 @@
         public isVisible = true;
         public isPickable = true;
         public showBoundingBox = false;
+        public showSubMeshesBoundingBox = false;
         public onDispose = null;
         public checkCollisions = false;
         public skeleton: Skeleton;
@@ -45,6 +46,11 @@
         public material: Material;
         public receiveShadows = false;
         public actionManager: ActionManager;
+
+        public useOctreeForRenderingSelection = true;
+        public useOctreeForPicking = true;
+        public useOctreeForCollisions = true;
+
         public layerMask: number = 0xFFFFFFFF;
 
         // Physics
@@ -73,8 +79,11 @@
         private _pivotMatrix = BABYLON.Matrix.Identity();
         public _isDisposed = false;
         public _renderId = 0;
+        public _traversalId = -1;
+        private _collisionTraversalId = 0;
 
         public subMeshes: SubMesh[];
+        public _submeshesOctree: Octree<SubMesh>;
 
         constructor(name: string, scene: Scene) {
             super(name, scene);
@@ -510,6 +519,24 @@
             this.getScene().getPhysicsEngine()._createLink(this, otherMesh, pivot1, pivot2);
         }
 
+        // Submeshes octree
+
+        /**
+        * This function will create an octree to help select the right submeshes for rendering, picking and collisions
+        * Please note that you must have a decent number of submeshes to get performance improvements when using octree
+        */
+        public createOrUpdateSubmeshesOctree(capacity?: number): void {
+            if (!this._submeshesOctree) {
+                this._submeshesOctree = new BABYLON.Octree<SubMesh>(Octree.CreationFuncForSubMeshes, capacity);
+            }
+
+            this.computeWorldMatrix(true);            
+
+            // Update octree
+            var bbox = this.getBoundingInfo().boundingBox;
+            this._submeshesOctree.update(bbox.minimumWorld, bbox.maximumWorld, this.subMeshes);
+        }
+
         // Collisions
         public _collideForSubMesh(subMesh: SubMesh, transformMatrix: Matrix, collider: Collider): void {
             this._generatePointsArray();
@@ -528,12 +555,35 @@
             collider._collide(subMesh, subMesh._lastColliderWorldVertices, this.getIndices(), subMesh.indexStart, subMesh.indexStart + subMesh.indexCount, subMesh.verticesStart);
         }
 
-        public _processCollisionsForSubModels(collider: Collider, transformMatrix: Matrix): void {
-            for (var index = 0; index < this.subMeshes.length; index++) {
-                var subMesh = this.subMeshes[index];
+        public _processCollisionsForSubMeshes(collider: Collider, transformMatrix: Matrix): void {
+            var subMeshes: SubMesh[];
+            var len: number;            
+
+            // Octrees
+            if (this._submeshesOctree && this.useOctreeForCollisions) {
+                var radius = collider.velocityWorldLength + Math.max(collider.radius.x, collider.radius.y, collider.radius.z);
+                var intersections = this._submeshesOctree.intersects(collider.basePointWorld, radius, true);
+
+                len = intersections.length;
+                subMeshes = intersections.data;
+            } else {
+                subMeshes = this.subMeshes;
+                len = subMeshes.length;
+            }
+
+            this._collisionTraversalId++;
+
+            for (var index = 0; index < len; index++) {
+                var subMesh = subMeshes[index];
+
+                if (subMesh._collisionTraversalId === this._collisionTraversalId) {
+                    continue;
+                }
+
+                subMesh._collisionTraversalId = this._collisionTraversalId;
 
                 // Bounding test
-                if (this.subMeshes.length > 1 && !subMesh._checkCollision(collider))
+                if (len > 1 && !subMesh._checkCollision(collider))
                     continue;
 
                 this._collideForSubMesh(subMesh, transformMatrix, collider);
@@ -549,7 +599,7 @@
             BABYLON.Matrix.ScalingToRef(1.0 / collider.radius.x, 1.0 / collider.radius.y, 1.0 / collider.radius.z, this._collisionsScalingMatrix);
             this.worldMatrixFromCache.multiplyToRef(this._collisionsScalingMatrix, this._collisionsTransformMatrix);
 
-            this._processCollisionsForSubModels(collider, this._collisionsTransformMatrix);
+            this._processCollisionsForSubMeshes(collider, this._collisionsTransformMatrix);
         }
 
         // Picking
@@ -570,11 +620,26 @@
 
             var intersectInfo: IntersectionInfo = null;
 
-            for (var index = 0; index < this.subMeshes.length; index++) {
-                var subMesh = this.subMeshes[index];
+            // Octrees
+            var subMeshes: SubMesh[];
+            var len: number;
+
+            if (this._submeshesOctree && this.useOctreeForPicking) {
+                var worldRay = Ray.Transform(ray, this.getWorldMatrix());
+                var intersections = this._submeshesOctree.intersectsRay(worldRay);
+
+                len = intersections.length;
+                subMeshes = intersections.data;
+            } else {
+                subMeshes = this.subMeshes;
+                len = subMeshes.length;
+            }
+
+            for (var index = 0; index < len; index++) {
+                var subMesh = subMeshes[index];
 
                 // Bounding test
-                if (this.subMeshes.length > 1 && !subMesh.canIntersects(ray))
+                if (len > 1 && !subMesh.canIntersects(ray))
                     continue;
 
                 var currentIntersectInfo = subMesh.intersects(ray, this._positions, this.getIndices(), fastCheck);

+ 3 - 3
Babylon/Mesh/babylon.csg.js

@@ -528,9 +528,9 @@
                 }
             }
 
-            mesh.setVerticesData(vertices, BABYLON.VertexBuffer.PositionKind);
-            mesh.setVerticesData(normals, BABYLON.VertexBuffer.NormalKind);
-            mesh.setVerticesData(uvs, BABYLON.VertexBuffer.UVKind);
+            mesh.setVerticesData(BABYLON.VertexBuffer.PositionKind, vertices);
+            mesh.setVerticesData(BABYLON.VertexBuffer.NormalKind, normals);
+            mesh.setVerticesData(BABYLON.VertexBuffer.UVKind, uvs);
             mesh.setIndices(indices);
 
             if (keepSubMeshes) {

+ 3 - 3
Babylon/Mesh/babylon.csg.ts

@@ -553,9 +553,9 @@
 
             }
 
-            mesh.setVerticesData(vertices, BABYLON.VertexBuffer.PositionKind);
-            mesh.setVerticesData(normals, BABYLON.VertexBuffer.NormalKind);
-            mesh.setVerticesData(uvs, BABYLON.VertexBuffer.UVKind);
+            mesh.setVerticesData(BABYLON.VertexBuffer.PositionKind, vertices);
+            mesh.setVerticesData(BABYLON.VertexBuffer.NormalKind, normals);
+            mesh.setVerticesData(BABYLON.VertexBuffer.UVKind, uvs);
             mesh.setIndices(indices);
 
             if (keepSubMeshes) {

+ 3 - 3
Babylon/Mesh/babylon.geometry.js

@@ -40,7 +40,7 @@ var BABYLON;
             vertexData.applyToGeometry(this, updatable);
         };
 
-        Geometry.prototype.setVerticesData = function (data, kind, updatable) {
+        Geometry.prototype.setVerticesData = function (kind, data, updatable) {
             this._vertexBuffers = this._vertexBuffers || {};
 
             if (this._vertexBuffers[kind]) {
@@ -434,11 +434,11 @@ var BABYLON;
                     _super.prototype.setAllVerticesData.call(this, vertexData, false);
                 };
 
-                _Primitive.prototype.setVerticesData = function (data, kind, updatable) {
+                _Primitive.prototype.setVerticesData = function (kind, data, updatable) {
                     if (!this._beingRegenerated) {
                         return;
                     }
-                    _super.prototype.setVerticesData.call(this, data, kind, false);
+                    _super.prototype.setVerticesData.call(this, kind, data, false);
                 };
 
                 // to override

+ 3 - 3
Babylon/Mesh/babylon.geometry.ts

@@ -48,7 +48,7 @@
             vertexData.applyToGeometry(this, updatable);
         }
 
-        public setVerticesData(data: number[], kind: string, updatable?: boolean): void {
+        public setVerticesData(kind: string, data: number[], updatable?: boolean): void {
             this._vertexBuffers = this._vertexBuffers || {};
 
             if (this._vertexBuffers[kind]) {
@@ -445,11 +445,11 @@
                 super.setAllVerticesData(vertexData, false);
             }
 
-            public setVerticesData(data: number[], kind: string, updatable?: boolean): void {
+            public setVerticesData(kind: string, data: number[], updatable?: boolean): void {
                 if (!this._beingRegenerated) {
                     return;
                 }
-                super.setVerticesData(data, kind, false);
+                super.setVerticesData(kind, data, false);
             }
 
             // to override

+ 54 - 0
Babylon/Mesh/babylon.groundMesh.js

@@ -0,0 +1,54 @@
+var __extends = this.__extends || function (d, b) {
+    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
+    function __() { this.constructor = d; }
+    __.prototype = b.prototype;
+    d.prototype = new __();
+};
+var BABYLON;
+(function (BABYLON) {
+    var GroundMesh = (function (_super) {
+        __extends(GroundMesh, _super);
+        function GroundMesh(name, scene) {
+            _super.call(this, name, scene);
+            this.chunkSize = 128;
+            this._worldInverse = new BABYLON.Matrix();
+        }
+        Object.defineProperty(GroundMesh.prototype, "subdivisions", {
+            get: function () {
+                return this._subdivisions;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+        GroundMesh.prototype._setReady = function (state) {
+            if (state) {
+                this.subdivide(this._subdivisions);
+
+                this.createOrUpdateSubmeshesOctree(32);
+            }
+
+            _super.prototype._setReady.call(this, state);
+        };
+
+        GroundMesh.prototype.getHeightAtCoordinates = function (x, z) {
+            var ray = new BABYLON.Ray(new BABYLON.Vector3(x, this.getBoundingInfo().boundingBox.maximumWorld.y + 1, z), new BABYLON.Vector3(0, -1, 0));
+
+            this.getWorldMatrix().invertToRef(this._worldInverse);
+
+            ray = BABYLON.Ray.Transform(ray, this._worldInverse);
+
+            var pickInfo = this.intersects(ray);
+
+            if (pickInfo.hit) {
+                var result = BABYLON.Vector3.TransformCoordinates(pickInfo.pickedPoint, this.getWorldMatrix());
+                return result.y;
+            }
+
+            return 0;
+        };
+        return GroundMesh;
+    })(BABYLON.Mesh);
+    BABYLON.GroundMesh = GroundMesh;
+})(BABYLON || (BABYLON = {}));
+//# sourceMappingURL=babylon.groundMesh.js.map

+ 43 - 0
Babylon/Mesh/babylon.groundMesh.ts

@@ -0,0 +1,43 @@
+module BABYLON {
+    export class GroundMesh extends Mesh {
+        public chunkSize = 128; // Aiming to get around 128 indices per submesh
+        private _worldInverse = new BABYLON.Matrix();
+
+        public _subdivisions: number;
+
+        constructor(name: string, scene: Scene) {
+            super(name, scene);
+        }
+
+        public get subdivisions(): number {
+            return this._subdivisions;
+        }
+
+        public _setReady(state: boolean): void {
+            if (state) {
+                this.subdivide(this._subdivisions);
+
+                this.createOrUpdateSubmeshesOctree(32);
+            }
+
+            super._setReady(state);
+        }
+
+        public getHeightAtCoordinates(x: number, z: number): number {
+            var ray = new BABYLON.Ray(new BABYLON.Vector3(x, this.getBoundingInfo().boundingBox.maximumWorld.y + 1, z), new BABYLON.Vector3(0, -1, 0));
+
+            this.getWorldMatrix().invertToRef(this._worldInverse);
+
+            ray = BABYLON.Ray.Transform(ray, this._worldInverse);
+
+            var pickInfo = this.intersects(ray);
+
+            if (pickInfo.hit) {
+                var result = BABYLON.Vector3.TransformCoordinates(pickInfo.pickedPoint, this.getWorldMatrix());
+                return result.y;
+            }
+
+            return 0;
+        }
+    }
+} 

+ 67 - 32
Babylon/Mesh/babylon.mesh.js

@@ -6,6 +6,15 @@
 };
 var BABYLON;
 (function (BABYLON) {
+    var _InstancesBatch = (function () {
+        function _InstancesBatch() {
+            this.mustReturn = false;
+            this.renderSelf = true;
+        }
+        return _InstancesBatch;
+    })();
+    BABYLON._InstancesBatch = _InstancesBatch;
+
     var Mesh = (function (_super) {
         __extends(Mesh, _super);
         function Mesh(name, scene) {
@@ -16,6 +25,7 @@ var BABYLON;
             this._onBeforeRenderCallbacks = [];
             this._visibleInstances = {};
             this._renderIdForInstances = -1;
+            this._batchCache = new _InstancesBatch();
         }
         Mesh.prototype.getTotalVertices = function () {
             if (!this._geometry) {
@@ -139,11 +149,19 @@ var BABYLON;
             }
 
             var totalIndices = this.getTotalIndices();
-            var subdivisionSize = totalIndices / count;
+            var subdivisionSize = (totalIndices / count) | 0;
             var offset = 0;
 
+            while (subdivisionSize % 3 != 0) {
+                subdivisionSize++;
+            }
+
             this.releaseSubMeshes();
             for (var index = 0; index < count; index++) {
+                if (offset >= totalIndices) {
+                    break;
+                }
+
                 BABYLON.SubMesh.CreateFromIndices(0, offset, Math.min(subdivisionSize, totalIndices - offset), this);
 
                 offset += subdivisionSize;
@@ -152,7 +170,7 @@ var BABYLON;
             this.synchronizeInstances();
         };
 
-        Mesh.prototype.setVerticesData = function (data, kind, updatable) {
+        Mesh.prototype.setVerticesData = function (kind, data, updatable) {
             if (!this._geometry) {
                 var vertexData = new BABYLON.VertexData();
                 vertexData.set(data, kind);
@@ -161,7 +179,7 @@ var BABYLON;
 
                 new BABYLON.Geometry(BABYLON.Geometry.RandomId(), scene.getEngine(), vertexData, updatable, this);
             } else {
-                this._geometry.setVerticesData(data, kind, updatable);
+                this._geometry.setVerticesData(kind, data, updatable);
             }
         };
 
@@ -223,10 +241,10 @@ var BABYLON;
             engine.draw(useTriangles, useTriangles ? subMesh.indexStart : 0, useTriangles ? subMesh.indexCount : subMesh.linesIndexCount);
         };
 
-        Mesh.prototype.bindAndDraw = function (subMesh, effect, wireframe) {
-            this._bind(subMesh, effect, wireframe);
+        Mesh.prototype.bindAndDraw = function (subMesh, effect) {
+            this._bind(subMesh, effect, false);
 
-            this._draw(subMesh, !wireframe);
+            this._draw(subMesh, true);
         };
 
         Mesh.prototype.registerBeforeRender = function (func) {
@@ -241,34 +259,49 @@ var BABYLON;
             }
         };
 
-        Mesh.prototype.render = function (subMesh) {
-            var renderSelf = true;
+        Mesh.prototype._getInstancesRenderList = function () {
             var scene = this.getScene();
+            this._batchCache.mustReturn = false;
+            this._batchCache.renderSelf = true;
+            this._batchCache.visibleInstances = null;
 
-            // Managing instances
             if (this._visibleInstances) {
                 var currentRenderId = scene.getRenderId();
-                var visibleInstances = this._visibleInstances[currentRenderId];
+                this._batchCache.visibleInstances = this._visibleInstances[currentRenderId];
                 var selfRenderId = this._renderId;
 
-                if (!visibleInstances && this._visibleInstances.defaultRenderId) {
-                    visibleInstances = this._visibleInstances[this._visibleInstances.defaultRenderId];
+                if (!this._batchCache.visibleInstances && this._visibleInstances.defaultRenderId) {
+                    this._batchCache.visibleInstances = this._visibleInstances[this._visibleInstances.defaultRenderId];
                     currentRenderId = this._visibleInstances.defaultRenderId;
                     selfRenderId = this._visibleInstances.selfDefaultRenderId;
                 }
 
-                if (visibleInstances && visibleInstances.length) {
+                if (this._batchCache.visibleInstances && this._batchCache.visibleInstances.length) {
                     if (this._renderIdForInstances === currentRenderId) {
-                        return;
+                        this._batchCache.mustReturn = true;
+                        return this._batchCache;
                     }
 
                     if (currentRenderId !== selfRenderId) {
-                        renderSelf = false;
+                        this._batchCache.renderSelf = false;
                     }
                 }
                 this._renderIdForInstances = currentRenderId;
             }
 
+            return this._batchCache;
+        };
+
+        Mesh.prototype.render = function (subMesh) {
+            var scene = this.getScene();
+
+            // Managing instances
+            var batch = this._getInstancesRenderList();
+
+            if (batch.mustReturn) {
+                return;
+            }
+
             // Checking geometry state
             if (!this._geometry || !this._geometry.getVertexBuffers() || !this._geometry.getIndexBuffer()) {
                 return;
@@ -293,7 +326,7 @@ var BABYLON;
             this._bind(subMesh, effect, wireFrame);
             effectiveMaterial._preBind();
 
-            if (renderSelf) {
+            if (batch.renderSelf) {
                 // World
                 var world = this.getWorldMatrix();
                 effectiveMaterial.bind(world, this);
@@ -302,9 +335,9 @@ var BABYLON;
                 this._draw(subMesh, !wireFrame);
             }
 
-            if (visibleInstances) {
-                for (var instanceIndex = 0; instanceIndex < visibleInstances.length; instanceIndex++) {
-                    var instance = visibleInstances[instanceIndex];
+            if (batch.visibleInstances) {
+                for (var instanceIndex = 0; instanceIndex < batch.visibleInstances.length; instanceIndex++) {
+                    var instance = batch.visibleInstances[instanceIndex];
 
                     // World
                     world = instance.getWorldMatrix();
@@ -437,7 +470,7 @@ var BABYLON;
                 BABYLON.Vector3.TransformCoordinates(BABYLON.Vector3.FromArray(data, index), transform).toArray(temp, index);
             }
 
-            this.setVerticesData(temp, BABYLON.VertexBuffer.PositionKind, this.getVertexBuffer(BABYLON.VertexBuffer.PositionKind).isUpdatable());
+            this.setVerticesData(BABYLON.VertexBuffer.PositionKind, temp, this.getVertexBuffer(BABYLON.VertexBuffer.PositionKind).isUpdatable());
 
             // Normals
             if (!this.isVerticesDataPresent(BABYLON.VertexBuffer.NormalKind)) {
@@ -449,7 +482,7 @@ var BABYLON;
                 BABYLON.Vector3.TransformNormal(BABYLON.Vector3.FromArray(data, index), transform).toArray(temp, index);
             }
 
-            this.setVerticesData(temp, BABYLON.VertexBuffer.NormalKind, this.getVertexBuffer(BABYLON.VertexBuffer.NormalKind).isUpdatable());
+            this.setVerticesData(BABYLON.VertexBuffer.NormalKind, temp, this.getVertexBuffer(BABYLON.VertexBuffer.NormalKind).isUpdatable());
         };
 
         // Cache
@@ -486,10 +519,6 @@ var BABYLON;
             // Deep copy
             BABYLON.Tools.DeepCopy(this, result, ["name", "material", "skeleton"], []);
 
-            // Bounding info
-            var extend = BABYLON.Tools.ExtractMinAndMax(this.getVerticesData(BABYLON.VertexBuffer.PositionKind), 0, this.getTotalVertices());
-            result._boundingInfo = new BABYLON.BoundingInfo(extend.minimum, extend.maximum);
-
             // Material
             result.material = this.material;
 
@@ -603,11 +632,11 @@ var BABYLON;
             }
 
             this.setIndices(indices);
-            this.setVerticesData(normals, BABYLON.VertexBuffer.NormalKind, updatableNormals);
+            this.setVerticesData(BABYLON.VertexBuffer.NormalKind, normals, updatableNormals);
 
             for (kindIndex = 0; kindIndex < kinds.length; kindIndex++) {
                 kind = kinds[kindIndex];
-                this.setVerticesData(newdata[kind], kind, vbs[kind].isUpdatable());
+                this.setVerticesData(kind, newdata[kind], vbs[kind].isUpdatable());
             }
 
             // Updating submeshes
@@ -691,16 +720,24 @@ var BABYLON;
         };
 
         Mesh.CreateGround = function (name, width, height, subdivisions, scene, updatable) {
-            var ground = new BABYLON.Mesh(name, scene);
+            var ground = new BABYLON.GroundMesh(name, scene);
+            ground._setReady(false);
+            ground._subdivisions = subdivisions;
+
             var vertexData = BABYLON.VertexData.CreateGround(width, height, subdivisions);
 
             vertexData.applyToMesh(ground, updatable);
 
+            ground._setReady(true);
+
             return ground;
         };
 
         Mesh.CreateGroundFromHeightMap = function (name, url, width, height, subdivisions, minHeight, maxHeight, scene, updatable) {
-            var ground = new BABYLON.Mesh(name, scene);
+            var ground = new BABYLON.GroundMesh(name, scene);
+            ground._subdivisions = subdivisions;
+
+            ground._setReady(false);
 
             var onload = function (img) {
                 // Getting height map data
@@ -719,14 +756,12 @@ var BABYLON;
 
                 vertexData.applyToMesh(ground, updatable);
 
-                ground._isReady = true;
+                ground._setReady(true);
             };
 
             BABYLON.Tools.LoadImage(url, onload, function () {
             }, scene.database);
 
-            ground._isReady = false;
-
             return ground;
         };
 

+ 67 - 34
Babylon/Mesh/babylon.mesh.ts

@@ -1,4 +1,10 @@
 module BABYLON {
+    export class _InstancesBatch {
+        public mustReturn = false;
+        public visibleInstances: InstancedMesh[];
+        public renderSelf = true;
+    }
+
     export class Mesh extends AbstractMesh implements IGetSetVerticesData {
         // Members
         public delayLoadState = BABYLON.Engine.DELAYLOADSTATE_NONE;
@@ -12,6 +18,7 @@
         private _delayLoadingFunction: (any, Mesh) => void;
         public _visibleInstances: any = {};
         private _renderIdForInstances = -1;
+        private _batchCache = new _InstancesBatch();
 
         constructor(name: string, scene: Scene) {
             super(name, scene);
@@ -139,11 +146,20 @@
             }
 
             var totalIndices = this.getTotalIndices();
-            var subdivisionSize = totalIndices / count;
+            var subdivisionSize = (totalIndices / count) | 0;
             var offset = 0;
 
+            // Ensure that subdivisionSize is a multiple of 3
+            while (subdivisionSize % 3 != 0) {
+                subdivisionSize++;
+            }
+
             this.releaseSubMeshes();
             for (var index = 0; index < count; index++) {
+                if (offset >= totalIndices) {
+                    break;
+                }
+
                 BABYLON.SubMesh.CreateFromIndices(0, offset, Math.min(subdivisionSize, totalIndices - offset), this);
 
                 offset += subdivisionSize;
@@ -152,7 +168,7 @@
             this.synchronizeInstances();
         }
 
-        public setVerticesData(data: number[], kind: string, updatable?: boolean): void {
+        public setVerticesData(kind: string, data: number[], updatable?: boolean): void {
             if (!this._geometry) {
                 var vertexData = new BABYLON.VertexData();
                 vertexData.set(data, kind);
@@ -162,7 +178,7 @@
                 new BABYLON.Geometry(Geometry.RandomId(), scene.getEngine(), vertexData, updatable, this);
             }
             else {
-                this._geometry.setVerticesData(data, kind, updatable);
+                this._geometry.setVerticesData(kind, data, updatable);
             }
         }
 
@@ -201,7 +217,7 @@
             }
         }
 
-        private _bind(subMesh: SubMesh, effect: Effect, wireframe?: boolean): void {
+        public _bind(subMesh: SubMesh, effect: Effect, wireframe?: boolean): void {
             var engine = this.getScene().getEngine();
 
             // Wireframe
@@ -215,7 +231,7 @@
             engine.bindMultiBuffers(this._geometry.getVertexBuffers(), indexToBind, effect);
         }
 
-        private _draw(subMesh: SubMesh, useTriangles: boolean): void {
+        public _draw(subMesh: SubMesh, useTriangles: boolean): void {
             if (!this._geometry || !this._geometry.getVertexBuffers() || !this._geometry.getIndexBuffer()) {
                 return;
             }
@@ -226,10 +242,10 @@
             engine.draw(useTriangles, useTriangles ? subMesh.indexStart : 0, useTriangles ? subMesh.indexCount : subMesh.linesIndexCount);
         }
 
-        public bindAndDraw(subMesh: SubMesh, effect: Effect, wireframe?: boolean): void {
-            this._bind(subMesh, effect, wireframe);
+        public bindAndDraw(subMesh: SubMesh, effect: Effect): void {
+            this._bind(subMesh, effect, false);
 
-            this._draw(subMesh, !wireframe);
+            this._draw(subMesh, true);
         }
 
         public registerBeforeRender(func: () => void): void {
@@ -244,35 +260,50 @@
             }
         }
 
-        public render(subMesh: SubMesh): void {
-            var renderSelf = true;
+        public _getInstancesRenderList(): _InstancesBatch {
             var scene = this.getScene();
+            this._batchCache.mustReturn = false;
+            this._batchCache.renderSelf = true;
+            this._batchCache.visibleInstances = null;
 
-            // Managing instances
             if (this._visibleInstances) {
                 var currentRenderId = scene.getRenderId();
-                var visibleInstances = this._visibleInstances[currentRenderId];
+                this._batchCache.visibleInstances = this._visibleInstances[currentRenderId];
                 var selfRenderId = this._renderId;
 
-                if (!visibleInstances && this._visibleInstances.defaultRenderId) {
-                    visibleInstances = this._visibleInstances[this._visibleInstances.defaultRenderId];
+                if (!this._batchCache.visibleInstances && this._visibleInstances.defaultRenderId) {
+                    this._batchCache.visibleInstances = this._visibleInstances[this._visibleInstances.defaultRenderId];
                     currentRenderId = this._visibleInstances.defaultRenderId;
                     selfRenderId = this._visibleInstances.selfDefaultRenderId;
                 }
 
-                if (visibleInstances && visibleInstances.length) {
+                if (this._batchCache.visibleInstances && this._batchCache.visibleInstances.length) {
                     if (this._renderIdForInstances === currentRenderId) {
-                        return;
+                        this._batchCache.mustReturn = true;
+                        return this._batchCache;
                     }
 
                     if (currentRenderId !== selfRenderId) {
-                        renderSelf = false;
+                        this._batchCache.renderSelf = false;
                     }
 
                 }
                 this._renderIdForInstances = currentRenderId;
             }
 
+            return this._batchCache;
+        }
+
+        public render(subMesh: SubMesh): void {
+            var scene = this.getScene();
+
+            // Managing instances
+            var batch = this._getInstancesRenderList();
+
+            if (batch.mustReturn) {
+                return;
+            }
+
             // Checking geometry state
             if (!this._geometry || !this._geometry.getVertexBuffers() || !this._geometry.getIndexBuffer()) {
                 return;
@@ -297,7 +328,7 @@
             this._bind(subMesh, effect, wireFrame);
             effectiveMaterial._preBind();
 
-            if (renderSelf) {
+            if (batch.renderSelf) {
                 // World
                 var world = this.getWorldMatrix();
                 effectiveMaterial.bind(world, this);
@@ -306,9 +337,9 @@
                 this._draw(subMesh, !wireFrame);
             }
 
-            if (visibleInstances) {
-                for (var instanceIndex = 0; instanceIndex < visibleInstances.length; instanceIndex++) {
-                    var instance = visibleInstances[instanceIndex];
+            if (batch.visibleInstances) {
+                for (var instanceIndex = 0; instanceIndex < batch.visibleInstances.length; instanceIndex++) {
+                    var instance = batch.visibleInstances[instanceIndex];
 
                     // World
                     world = instance.getWorldMatrix();
@@ -440,7 +471,7 @@
                 BABYLON.Vector3.TransformCoordinates(BABYLON.Vector3.FromArray(data, index), transform).toArray(temp, index);
             }
 
-            this.setVerticesData(temp, BABYLON.VertexBuffer.PositionKind, this.getVertexBuffer(BABYLON.VertexBuffer.PositionKind).isUpdatable());
+            this.setVerticesData(BABYLON.VertexBuffer.PositionKind, temp, this.getVertexBuffer(BABYLON.VertexBuffer.PositionKind).isUpdatable());
 
             // Normals
             if (!this.isVerticesDataPresent(BABYLON.VertexBuffer.NormalKind)) {
@@ -452,7 +483,7 @@
                 BABYLON.Vector3.TransformNormal(BABYLON.Vector3.FromArray(data, index), transform).toArray(temp, index);
             }
 
-            this.setVerticesData(temp, BABYLON.VertexBuffer.NormalKind, this.getVertexBuffer(BABYLON.VertexBuffer.NormalKind).isUpdatable());
+            this.setVerticesData(BABYLON.VertexBuffer.NormalKind, temp, this.getVertexBuffer(BABYLON.VertexBuffer.NormalKind).isUpdatable());
         }
 
 
@@ -491,10 +522,6 @@
             // Deep copy
             BABYLON.Tools.DeepCopy(this, result, ["name", "material", "skeleton"], []);
 
-            // Bounding info
-            var extend = BABYLON.Tools.ExtractMinAndMax(this.getVerticesData(BABYLON.VertexBuffer.PositionKind), 0, this.getTotalVertices());
-            result._boundingInfo = new BABYLON.BoundingInfo(extend.minimum, extend.maximum);
-
             // Material
             result.material = this.material;
 
@@ -614,12 +641,12 @@
             }
 
             this.setIndices(indices);
-            this.setVerticesData(normals, BABYLON.VertexBuffer.NormalKind, updatableNormals);
+            this.setVerticesData(BABYLON.VertexBuffer.NormalKind, normals, updatableNormals);
 
             // Updating vertex buffers
             for (kindIndex = 0; kindIndex < kinds.length; kindIndex++) {
                 kind = kinds[kindIndex];
-                this.setVerticesData(newdata[kind], kind, vbs[kind].isUpdatable());
+                this.setVerticesData(kind, newdata[kind], vbs[kind].isUpdatable());
             }
 
             // Updating submeshes
@@ -703,16 +730,24 @@
         }
 
         public static CreateGround(name: string, width: number, height: number, subdivisions: number, scene: Scene, updatable?: boolean): Mesh {
-            var ground = new BABYLON.Mesh(name, scene);
+            var ground = new BABYLON.GroundMesh(name, scene);
+            ground._setReady(false);
+            ground._subdivisions = subdivisions;
+
             var vertexData = BABYLON.VertexData.CreateGround(width, height, subdivisions);
 
             vertexData.applyToMesh(ground, updatable);
 
+            ground._setReady(true);
+
             return ground;
         }
 
         public static CreateGroundFromHeightMap(name: string, url: string, width: number, height: number, subdivisions: number, minHeight: number, maxHeight: number, scene: Scene, updatable?: boolean): Mesh {
-            var ground = new BABYLON.Mesh(name, scene);
+            var ground = new BABYLON.GroundMesh(name, scene);
+            ground._subdivisions = subdivisions;
+
+            ground._setReady(false);
 
             var onload = img => {
                 // Getting height map data
@@ -731,13 +766,11 @@
 
                 vertexData.applyToMesh(ground, updatable);
 
-                ground._isReady = true;
+                ground._setReady(true);
             };
 
             Tools.LoadImage(url, onload, () => { }, scene.database);
 
-            ground._isReady = false;
-
             return ground;
         }
 

+ 7 - 7
Babylon/Mesh/babylon.mesh.vertexData.js

@@ -47,31 +47,31 @@
 
         VertexData.prototype._applyTo = function (meshOrGeometry, updatable) {
             if (this.positions) {
-                meshOrGeometry.setVerticesData(this.positions, BABYLON.VertexBuffer.PositionKind, updatable);
+                meshOrGeometry.setVerticesData(BABYLON.VertexBuffer.PositionKind, this.positions, updatable);
             }
 
             if (this.normals) {
-                meshOrGeometry.setVerticesData(this.normals, BABYLON.VertexBuffer.NormalKind, updatable);
+                meshOrGeometry.setVerticesData(BABYLON.VertexBuffer.NormalKind, this.normals, updatable);
             }
 
             if (this.uvs) {
-                meshOrGeometry.setVerticesData(this.uvs, BABYLON.VertexBuffer.UVKind, updatable);
+                meshOrGeometry.setVerticesData(BABYLON.VertexBuffer.UVKind, this.uvs, updatable);
             }
 
             if (this.uv2s) {
-                meshOrGeometry.setVerticesData(this.uv2s, BABYLON.VertexBuffer.UV2Kind, updatable);
+                meshOrGeometry.setVerticesData(BABYLON.VertexBuffer.UV2Kind, this.uv2s, updatable);
             }
 
             if (this.colors) {
-                meshOrGeometry.setVerticesData(this.colors, BABYLON.VertexBuffer.ColorKind, updatable);
+                meshOrGeometry.setVerticesData(BABYLON.VertexBuffer.ColorKind, this.colors, updatable);
             }
 
             if (this.matricesIndices) {
-                meshOrGeometry.setVerticesData(this.matricesIndices, BABYLON.VertexBuffer.MatricesIndicesKind, updatable);
+                meshOrGeometry.setVerticesData(BABYLON.VertexBuffer.MatricesIndicesKind, this.matricesIndices, updatable);
             }
 
             if (this.matricesWeights) {
-                meshOrGeometry.setVerticesData(this.matricesWeights, BABYLON.VertexBuffer.MatricesWeightsKind, updatable);
+                meshOrGeometry.setVerticesData(BABYLON.VertexBuffer.MatricesWeightsKind, this.matricesWeights, updatable);
             }
 
             if (this.indices) {

+ 8 - 8
Babylon/Mesh/babylon.mesh.vertexData.ts

@@ -3,7 +3,7 @@
         isVerticesDataPresent(kind: string): boolean;
         getVerticesData(kind: string): number[];
         getIndices(): number[];
-        setVerticesData(data: number[], kind: string, updatable?: boolean): void;
+        setVerticesData(kind: string, data: number[], updatable?: boolean): void;
         updateVerticesData(kind: string, data: number[], updateExtends?: boolean, makeItUnique?: boolean): void;
         setIndices(indices: number[]): void;
     }
@@ -62,31 +62,31 @@
 
         private _applyTo(meshOrGeometry: IGetSetVerticesData, updatable?: boolean) {
             if (this.positions) {
-                meshOrGeometry.setVerticesData(this.positions, BABYLON.VertexBuffer.PositionKind, updatable);
+                meshOrGeometry.setVerticesData(BABYLON.VertexBuffer.PositionKind, this.positions, updatable);
             }
 
             if (this.normals) {
-                meshOrGeometry.setVerticesData(this.normals, BABYLON.VertexBuffer.NormalKind, updatable);
+                meshOrGeometry.setVerticesData(BABYLON.VertexBuffer.NormalKind, this.normals, updatable);
             }
 
             if (this.uvs) {
-                meshOrGeometry.setVerticesData(this.uvs, BABYLON.VertexBuffer.UVKind, updatable);
+                meshOrGeometry.setVerticesData(BABYLON.VertexBuffer.UVKind, this.uvs, updatable);
             }
 
             if (this.uv2s) {
-                meshOrGeometry.setVerticesData(this.uv2s, BABYLON.VertexBuffer.UV2Kind, updatable);
+                meshOrGeometry.setVerticesData(BABYLON.VertexBuffer.UV2Kind, this.uv2s, updatable);
             }
 
             if (this.colors) {
-                meshOrGeometry.setVerticesData(this.colors, BABYLON.VertexBuffer.ColorKind, updatable);
+                meshOrGeometry.setVerticesData(BABYLON.VertexBuffer.ColorKind, this.colors, updatable);
             }
 
             if (this.matricesIndices) {
-                meshOrGeometry.setVerticesData(this.matricesIndices, BABYLON.VertexBuffer.MatricesIndicesKind, updatable);
+                meshOrGeometry.setVerticesData(BABYLON.VertexBuffer.MatricesIndicesKind, this.matricesIndices, updatable);
             }
 
             if (this.matricesWeights) {
-                meshOrGeometry.setVerticesData(this.matricesWeights, BABYLON.VertexBuffer.MatricesWeightsKind, updatable);
+                meshOrGeometry.setVerticesData(BABYLON.VertexBuffer.MatricesWeightsKind, this.matricesWeights, updatable);
             }
 
             if (this.indices) {

+ 21 - 5
Babylon/Mesh/babylon.subMesh.js

@@ -1,18 +1,23 @@
 var BABYLON;
 (function (BABYLON) {
     var SubMesh = (function () {
-        function SubMesh(materialIndex, verticesStart, verticesCount, indexStart, indexCount, mesh, renderingMesh) {
+        function SubMesh(materialIndex, verticesStart, verticesCount, indexStart, indexCount, mesh, renderingMesh, createBoundingBox) {
+            if (typeof createBoundingBox === "undefined") { createBoundingBox = true; }
             this.materialIndex = materialIndex;
             this.verticesStart = verticesStart;
             this.verticesCount = verticesCount;
             this.indexStart = indexStart;
             this.indexCount = indexCount;
             this._renderId = 0;
+            this._traversalId = -1;
+            this._collisionTraversalId = -1;
             this._mesh = mesh;
             this._renderingMesh = renderingMesh || mesh;
             mesh.subMeshes.push(this);
 
-            this.refreshBoundingInfo();
+            if (createBoundingBox) {
+                this.refreshBoundingInfo();
+            }
         }
         SubMesh.prototype.getBoundingInfo = function () {
             return this._boundingInfo;
@@ -50,7 +55,14 @@
                 return;
             }
 
-            var extend = BABYLON.Tools.ExtractMinAndMax(data, this.verticesStart, this.verticesCount);
+            var indices = this._renderingMesh.getIndices();
+            var extend;
+
+            if (this.indexStart === 0 && this.indexCount === indices.length) {
+                extend = BABYLON.Tools.ExtractMinAndMax(data, this.verticesStart, this.verticesCount);
+            } else {
+                extend = BABYLON.Tools.ExtractMinAndMaxIndexed(data, indices, this.indexStart, this.indexCount);
+            }
             this._boundingInfo = new BABYLON.BoundingInfo(extend.minimum, extend.maximum);
         };
 
@@ -118,7 +130,11 @@
 
         // Clone
         SubMesh.prototype.clone = function (newMesh, newRenderingMesh) {
-            return new SubMesh(this.materialIndex, this.verticesStart, this.verticesCount, this.indexStart, this.indexCount, newMesh, newRenderingMesh);
+            var result = new SubMesh(this.materialIndex, this.verticesStart, this.verticesCount, this.indexStart, this.indexCount, newMesh, newRenderingMesh, false);
+
+            result._boundingInfo = new BABYLON.BoundingInfo(this._boundingInfo.minimum, this._boundingInfo.maximum);
+
+            return result;
         };
 
         // Dispose
@@ -150,7 +166,7 @@
                     maxVertexIndex = vertexIndex;
             }
 
-            return new BABYLON.SubMesh(materialIndex, minVertexIndex, maxVertexIndex - minVertexIndex, startIndex, indexCount, mesh, renderingMesh);
+            return new BABYLON.SubMesh(materialIndex, minVertexIndex, maxVertexIndex - minVertexIndex + 1, startIndex, indexCount, mesh, renderingMesh);
         };
         return SubMesh;
     })();

+ 20 - 5
Babylon/Mesh/babylon.subMesh.ts

@@ -11,14 +11,18 @@
         public _lastColliderTransformMatrix: Matrix;
 
         public _renderId = 0;
+        public _traversalId = -1;
+        public _collisionTraversalId = -1;
         public _distanceToCamera: number;
 
-        constructor(public materialIndex: number, public verticesStart: number, public verticesCount: number, public indexStart, public indexCount: number, mesh: AbstractMesh, renderingMesh?: Mesh) {
+        constructor(public materialIndex: number, public verticesStart: number, public verticesCount: number, public indexStart, public indexCount: number, mesh: AbstractMesh, renderingMesh?: Mesh, createBoundingBox: boolean = true) {
             this._mesh = mesh;
             this._renderingMesh = renderingMesh || <Mesh>mesh;
             mesh.subMeshes.push(this);
 
-            this.refreshBoundingInfo();
+            if (createBoundingBox) {
+                this.refreshBoundingInfo();
+            }
         }
 
         public getBoundingInfo(): BoundingInfo {
@@ -57,7 +61,14 @@
                 return;
             }
 
-            var extend = BABYLON.Tools.ExtractMinAndMax(data, this.verticesStart, this.verticesCount);
+            var indices = this._renderingMesh.getIndices();
+            var extend;
+
+            if (this.indexStart === 0 && this.indexCount === indices.length) {
+                extend = BABYLON.Tools.ExtractMinAndMax(data, this.verticesStart, this.verticesCount);
+            } else {
+                extend = BABYLON.Tools.ExtractMinAndMaxIndexed(data, indices, this.indexStart, this.indexCount);
+            }
             this._boundingInfo = new BoundingInfo(extend.minimum, extend.maximum);
         }
 
@@ -128,7 +139,11 @@
 
         // Clone    
         public clone(newMesh: AbstractMesh, newRenderingMesh?: Mesh): SubMesh {
-            return new SubMesh(this.materialIndex, this.verticesStart, this.verticesCount, this.indexStart, this.indexCount, newMesh, newRenderingMesh);
+            var result = new SubMesh(this.materialIndex, this.verticesStart, this.verticesCount, this.indexStart, this.indexCount, newMesh, newRenderingMesh, false);
+
+            result._boundingInfo = new BoundingInfo(this._boundingInfo.minimum, this._boundingInfo.maximum);
+
+            return result;
         }
 
         // Dispose
@@ -160,7 +175,7 @@
                     maxVertexIndex = vertexIndex;
             }
 
-            return new BABYLON.SubMesh(materialIndex, minVertexIndex, maxVertexIndex - minVertexIndex, startIndex, indexCount, mesh, renderingMesh);
+            return new BABYLON.SubMesh(materialIndex, minVertexIndex, maxVertexIndex - minVertexIndex + 1, startIndex, indexCount, mesh, renderingMesh);
         }
     }
 }

+ 5 - 1
Babylon/Particles/babylon.particleSystem.js

@@ -50,7 +50,7 @@
             this._scaledDirection = BABYLON.Vector3.Zero();
             this._scaledGravity = BABYLON.Vector3.Zero();
             this._currentRenderId = -1;
-            this._started = true;
+            this._started = false;
             this._stopped = false;
             this._actualFrame = 0;
             this.id = name;
@@ -104,6 +104,10 @@
             return this._alive;
         };
 
+        ParticleSystem.prototype.isStarted = function () {
+            return this._started;
+        };
+
         ParticleSystem.prototype.start = function () {
             this._started = true;
             this._stopped = false;

+ 5 - 1
Babylon/Particles/babylon.particleSystem.ts

@@ -76,7 +76,7 @@
         private _currentRenderId = -1;
 
         private _alive: boolean;
-        private _started = true;
+        private _started = false;
         private _stopped = false;
         private _actualFrame = 0;
         private _scaledUpdateSpeed: number;
@@ -134,6 +134,10 @@
             return this._alive;
         }
 
+        public isStarted(): boolean {
+            return this._started;
+        }
+
         public start(): void {
             this._started = true;
             this._stopped = false;

+ 4 - 5
Babylon/Rendering/babylon.boundingBoxRenderer.js

@@ -30,14 +30,13 @@
             engine.setDepthWrite(false);
             this._colorShader._preBind();
             for (var boundingBoxIndex = 0; boundingBoxIndex < this.renderList.length; boundingBoxIndex++) {
-                var mesh = this.renderList.data[boundingBoxIndex];
-                var boundingBox = mesh.getBoundingInfo().boundingBox;
+                var boundingBox = this.renderList.data[boundingBoxIndex];
                 var min = boundingBox.minimum;
                 var max = boundingBox.maximum;
                 var diff = max.subtract(min);
                 var median = min.add(diff.scale(0.5));
 
-                var worldMatrix = BABYLON.Matrix.Scaling(diff.x, diff.y, diff.z).multiply(BABYLON.Matrix.Translation(median.x, median.y, median.z)).multiply(mesh.getWorldMatrix());
+                var worldMatrix = BABYLON.Matrix.Scaling(diff.x, diff.y, diff.z).multiply(BABYLON.Matrix.Translation(median.x, median.y, median.z)).multiply(boundingBox.getWorldMatrix());
 
                 // VBOs
                 engine.bindBuffers(this._vb.getBuffer(), this._ib, [3], 3 * 4, this._colorShader.getEffect());
@@ -46,7 +45,7 @@
                     // Back
                     engine.setDepthFunctionToGreaterOrEqual();
                     this._colorShader.setColor3("color", this.backColor);
-                    this._colorShader.bind(worldMatrix, mesh);
+                    this._colorShader.bind(worldMatrix);
 
                     // Draw order
                     engine.draw(false, 0, 24);
@@ -55,7 +54,7 @@
                 // Front
                 engine.setDepthFunctionToLess();
                 this._colorShader.setColor3("color", this.frontColor);
-                this._colorShader.bind(worldMatrix, mesh);
+                this._colorShader.bind(worldMatrix);
 
                 // Draw order
                 engine.draw(false, 0, 24);

+ 5 - 6
Babylon/Rendering/babylon.boundingBoxRenderer.ts

@@ -3,7 +3,7 @@
         public frontColor = new BABYLON.Color3(1, 1, 1);
         public backColor = new BABYLON.Color3(0.1, 0.1, 0.1);
         public showBackLines = true;
-        public renderList = new BABYLON.SmartArray<Mesh>(32);
+        public renderList = new BABYLON.SmartArray<BoundingBox>(32);
 
         private _scene: Scene;
         private _colorShader: ShaderMaterial;
@@ -39,8 +39,7 @@
             engine.setDepthWrite(false);
             this._colorShader._preBind();
             for (var boundingBoxIndex = 0; boundingBoxIndex < this.renderList.length; boundingBoxIndex++) {
-                var mesh = this.renderList.data[boundingBoxIndex];
-                var boundingBox = mesh.getBoundingInfo().boundingBox;
+                var boundingBox = this.renderList.data[boundingBoxIndex];
                 var min = boundingBox.minimum;
                 var max = boundingBox.maximum;
                 var diff = max.subtract(min);
@@ -48,7 +47,7 @@
 
                 var worldMatrix = BABYLON.Matrix.Scaling(diff.x, diff.y, diff.z)
                     .multiply(BABYLON.Matrix.Translation(median.x, median.y, median.z))
-                    .multiply(mesh.getWorldMatrix());
+                    .multiply(boundingBox.getWorldMatrix());
 
                 // VBOs
                 engine.bindBuffers(this._vb.getBuffer(), this._ib, [3], 3 * 4, this._colorShader.getEffect());
@@ -57,7 +56,7 @@
                     // Back
                     engine.setDepthFunctionToGreaterOrEqual();
                     this._colorShader.setColor3("color", this.backColor);
-                    this._colorShader.bind(worldMatrix, mesh);
+                    this._colorShader.bind(worldMatrix);
 
                     // Draw order
                     engine.draw(false, 0, 24);
@@ -66,7 +65,7 @@
                 // Front
                 engine.setDepthFunctionToLess();
                 this._colorShader.setColor3("color", this.frontColor);
-                this._colorShader.bind(worldMatrix, mesh);
+                this._colorShader.bind(worldMatrix);
 
                 // Draw order
                 engine.draw(false, 0, 24);

+ 2 - 2
Babylon/Rendering/babylon.renderingManager.ts

@@ -10,7 +10,7 @@
             this._scene = scene;
         }
 
-        private _renderParticles(index: number, activeMeshes: Mesh[]): void {
+        private _renderParticles(index: number, activeMeshes: AbstractMesh[]): void {
             if (this._scene._activeParticleSystems.length === 0) {
                 return;
             }
@@ -61,7 +61,7 @@
         }
 
         public render(customRenderFunction: (opaqueSubMeshes: SmartArray<SubMesh>, transparentSubMeshes: SmartArray<SubMesh>, alphaTestSubMeshes: SmartArray<SubMesh>, beforeTransparents: () => void) => void,
-            activeMeshes: Mesh[], renderParticles: boolean, renderSprites: boolean): void {
+            activeMeshes: AbstractMesh[], renderParticles: boolean, renderSprites: boolean): void {
             for (var index = 0; index < BABYLON.RenderingManager.MAX_RENDERINGGROUPS; index++) {
                 this._depthBufferAlreadyCleaned = false;
                 var renderingGroup = this._renderingGroups[index];

+ 2 - 2
Babylon/Shaders/default.fragment.fx

@@ -555,7 +555,7 @@ void main(void) {
 
 	if (vReflectionInfos.z != 0.0)
 	{
-		reflectionColor = textureCube(reflectionCubeSampler, vReflectionUVW).rgb * vReflectionInfos.y;
+		reflectionColor = textureCube(reflectionCubeSampler, vReflectionUVW).rgb * vReflectionInfos.y * shadow;
 	}
 	else
 	{
@@ -568,7 +568,7 @@ void main(void) {
 
 		coords.y = 1.0 - coords.y;
 
-		reflectionColor = texture2D(reflection2DSampler, coords).rgb * vReflectionInfos.y;
+		reflectionColor = texture2D(reflection2DSampler, coords).rgb * vReflectionInfos.y * shadow;
 	}
 #endif
 

+ 10 - 0
Babylon/Shaders/shadowMap.fragment.fx

@@ -26,8 +26,18 @@ vec2 packHalf(float depth)
 varying vec4 vPosition;
 #endif
 
+#ifdef ALPHATEST
+varying vec2 vUV;
+uniform sampler2D diffuseSampler;
+#endif
+
 void main(void)
 {
+#ifdef ALPHATEST
+	if (texture2D(diffuseSampler, vUV).a < 0.4)
+		discard;
+#endif
+
 #ifdef VSM
 	float moment1 = gl_FragCoord.z / gl_FragCoord.w;
 	float moment2 = moment1 * moment1;

+ 20 - 0
Babylon/Shaders/shadowMap.vertex.fx

@@ -22,6 +22,17 @@ uniform mat4 worldViewProjection;
 varying vec4 vPosition;
 #endif
 
+#ifdef ALPHATEST
+varying vec2 vUV;
+uniform mat4 diffuseMatrix;
+#ifdef UV1
+attribute vec2 uv;
+#endif
+#ifdef UV2
+attribute vec2 uv2;
+#endif
+#endif
+
 void main(void)
 {
 #ifdef BONES
@@ -37,4 +48,13 @@ void main(void)
 #endif
 	gl_Position = worldViewProjection * vec4(position, 1.0);
 #endif
+
+#ifdef ALPHATEST
+#ifdef UV1
+	vUV = vec2(diffuseMatrix * vec4(uv, 1.0, 0.0));
+#endif
+#ifdef UV2
+	vUV = vec2(diffuseMatrix * vec4(uv2, 1.0, 0.0));
+#endif
+#endif
 }

+ 3 - 3
Babylon/Tools/babylon.filesInput.js

@@ -1,7 +1,6 @@
 
 var BABYLON;
 (function (BABYLON) {
-    // We're mainly based on the logic defined into the FreeCamera code
     var FilesInput = (function () {
         /// Register to core BabylonJS object: engine, scene, rendering canvas, callback function when the scene will be loaded,
         /// loading progress callback and optionnal addionnal logic to call in the rendering loop
@@ -61,6 +60,7 @@ var BABYLON;
         };
 
         FilesInput.prototype.loadFiles = function (event) {
+            var _this = this;
             var that = this;
             if (this.startingProcessingFilesCallback)
                 this.startingProcessingFilesCallback();
@@ -113,8 +113,8 @@ var BABYLON;
                             });
                         });
                     }, function (progress) {
-                        if (that.progressCallback) {
-                            that.progressCallback(progress);
+                        if (_this.progressCallback) {
+                            _this.progressCallback(progress);
                         }
                     });
                 } else {

+ 7 - 8
Babylon/Tools/babylon.filesInput.ts

@@ -6,7 +6,6 @@ declare module BABYLON {
 }
 
 module BABYLON {
-    // We're mainly based on the logic defined into the FreeCamera code
     export class FilesInput {
         private engine: BABYLON.Engine;
         private currentScene: BABYLON.Scene;
@@ -113,7 +112,7 @@ module BABYLON {
                         that.currentScene = newScene;
 
                         // Wait for textures and shaders to be ready
-                        that.currentScene.executeWhenReady(function () {
+                        that.currentScene.executeWhenReady(() => {
                             // Attach camera to canvas inputs
                             if (that.currentScene.activeCamera) {
                                 that.currentScene.activeCamera.attachControl(that.canvas);
@@ -121,13 +120,13 @@ module BABYLON {
                             if (that.sceneLoadedCallback) {
                                 that.sceneLoadedCallback(sceneFileToLoad, that.currentScene);
                             }
-                            that.engine.runRenderLoop(function () { that.renderFunction() });
-                        });
-                    }, function (progress) {
-                        if (that.progressCallback) {
-                            that.progressCallback(progress);
-                            }
+                            that.engine.runRenderLoop(() => { that.renderFunction(); });
                         });
+                    }, progress => {
+                        if (this.progressCallback) {
+                            this.progressCallback(progress);
+                        }
+                    });
                 }
                 else {
                     BABYLON.Tools.Error("Please provide a valid .babylon file.");

文件差异内容过多而无法显示
+ 573 - 0
Babylon/Tools/babylon.gamepads.js


文件差异内容过多而无法显示
+ 512 - 0
Babylon/Tools/babylon.gamepads.ts


+ 15 - 7
Babylon/Tools/babylon.sceneSerializer.js

@@ -77,6 +77,9 @@
         // Animations
         appendAnimations(camera, serializationObject);
 
+        // Layer mask
+        serializationObject.layerMask = camera.layerMask;
+
         return serializationObject;
     };
 
@@ -232,19 +235,21 @@
             }
         }
 
+        var regularTexture = texture;
+
         serializationObject.name = texture.name;
         serializationObject.hasAlpha = texture.hasAlpha;
         serializationObject.level = texture.level;
 
         serializationObject.coordinatesIndex = texture.coordinatesIndex;
         serializationObject.coordinatesMode = texture.coordinatesMode;
-        serializationObject.uOffset = texture.uOffset;
-        serializationObject.vOffset = texture.vOffset;
-        serializationObject.uScale = texture.uScale;
-        serializationObject.vScale = texture.vScale;
-        serializationObject.uAng = texture.uAng;
-        serializationObject.vAng = texture.vAng;
-        serializationObject.wAng = texture.wAng;
+        serializationObject.uOffset = regularTexture.uOffset;
+        serializationObject.vOffset = regularTexture.vOffset;
+        serializationObject.uScale = regularTexture.uScale;
+        serializationObject.vScale = regularTexture.vScale;
+        serializationObject.uAng = regularTexture.uAng;
+        serializationObject.vAng = regularTexture.vAng;
+        serializationObject.wAng = regularTexture.wAng;
 
         serializationObject.wrapU = texture.wrapU;
         serializationObject.wrapV = texture.wrapV;
@@ -602,6 +607,9 @@
         // Animations
         appendAnimations(mesh, serializationObject);
 
+        // Layer mask
+        serializationObject.layerMask = mesh.layerMask;
+
         return serializationObject;
     };
 

+ 16 - 8
Babylon/Tools/babylon.sceneSerializer.ts

@@ -77,6 +77,9 @@
         // Animations
         appendAnimations(camera, serializationObject);
 
+        // Layer mask
+        serializationObject.layerMask = camera.layerMask;
+
         return serializationObject;
     };
 
@@ -196,7 +199,7 @@
         return serializationObject;
     };
 
-    var serializeTexture = (texture: Texture): any => {
+    var serializeTexture = (texture: BaseTexture): any => {
         var serializationObject:any = {};
 
         if (!texture.name) {
@@ -232,19 +235,21 @@
             }
         }
 
+        var regularTexture = <Texture>texture;
+
         serializationObject.name = texture.name;
         serializationObject.hasAlpha = texture.hasAlpha;
         serializationObject.level = texture.level;
 
         serializationObject.coordinatesIndex = texture.coordinatesIndex;
         serializationObject.coordinatesMode = texture.coordinatesMode;
-        serializationObject.uOffset = texture.uOffset;
-        serializationObject.vOffset = texture.vOffset;
-        serializationObject.uScale = texture.uScale;
-        serializationObject.vScale = texture.vScale;
-        serializationObject.uAng = texture.uAng;
-        serializationObject.vAng = texture.vAng;
-        serializationObject.wAng = texture.wAng;
+        serializationObject.uOffset = regularTexture.uOffset;
+        serializationObject.vOffset = regularTexture.vOffset;
+        serializationObject.uScale = regularTexture.uScale;
+        serializationObject.vScale = regularTexture.vScale;
+        serializationObject.uAng = regularTexture.uAng;
+        serializationObject.vAng = regularTexture.vAng;
+        serializationObject.wAng = regularTexture.wAng;
 
         serializationObject.wrapU = texture.wrapU;
         serializationObject.wrapV = texture.wrapV;
@@ -611,6 +616,9 @@
         // Animations
         appendAnimations(mesh, serializationObject);
 
+        // Layer mask
+        serializationObject.layerMask = mesh.layerMask;
+
         return serializationObject;
     };
 

+ 2 - 2
Babylon/Tools/babylon.smartArray.ts

@@ -30,7 +30,7 @@
             this.length = 0;
         }
 
-        public concat(array: SmartArray<T>): void {
+        public concat(array: any): void {
             if (array.length === 0) {
                 return;
             }
@@ -43,7 +43,7 @@
             }
         }
 
-        public concatWithNoDuplicate(array: SmartArray<T>): void {
+        public concatWithNoDuplicate(array: any): void {
             if (array.length === 0) {
                 return;
             }

+ 33 - 0
Babylon/Tools/babylon.tools.js

@@ -61,6 +61,23 @@ var BABYLON;
             return angle * Math.PI / 180;
         };
 
+        Tools.ExtractMinAndMaxIndexed = function (positions, indices, indexStart, indexCount) {
+            var minimum = new BABYLON.Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
+            var maximum = new BABYLON.Vector3(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE);
+
+            for (var index = indexStart; index < indexStart + indexCount; index++) {
+                var current = new BABYLON.Vector3(positions[indices[index] * 3], positions[indices[index] * 3 + 1], positions[indices[index] * 3 + 2]);
+
+                minimum = BABYLON.Vector3.Minimize(current, minimum);
+                maximum = BABYLON.Vector3.Maximize(current, maximum);
+            }
+
+            return {
+                minimum: minimum,
+                maximum: maximum
+            };
+        };
+
         Tools.ExtractMinAndMax = function (positions, start, count) {
             var minimum = new BABYLON.Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
             var maximum = new BABYLON.Vector3(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE);
@@ -243,6 +260,22 @@ var BABYLON;
         };
 
         // Misc.
+        Tools.CheckExtends = function (v, min, max) {
+            if (v.x < min.x)
+                min.x = v.x;
+            if (v.y < min.y)
+                min.y = v.y;
+            if (v.z < min.z)
+                min.z = v.z;
+
+            if (v.x > max.x)
+                max.x = v.x;
+            if (v.y > max.y)
+                max.y = v.y;
+            if (v.z > max.z)
+                max.z = v.z;
+        };
+
         Tools.WithinEpsilon = function (a, b) {
             var num = a - b;
             return -1.401298E-45 <= num && num <= 1.401298E-45;

+ 36 - 2
Babylon/Tools/babylon.tools.ts

@@ -1,7 +1,7 @@
 // ANY
 declare module BABYLON {
     export class Database {
-        static isUASupportingBlobStorage:  boolean;
+        static isUASupportingBlobStorage: boolean;
     }
 }
 
@@ -76,6 +76,23 @@ module BABYLON {
             return angle * Math.PI / 180;
         }
 
+        public static ExtractMinAndMaxIndexed(positions: number[], indices: number[], indexStart:number, indexCount: number): { minimum: Vector3; maximum: Vector3 } {
+            var minimum = new Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
+            var maximum = new Vector3(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE);
+
+            for (var index = indexStart; index < indexStart + indexCount; index ++) {
+                var current = new Vector3(positions[indices[index] * 3], positions[indices[index] * 3 + 1], positions[indices[index] * 3 + 2]);
+
+                minimum = BABYLON.Vector3.Minimize(current, minimum);
+                maximum = BABYLON.Vector3.Maximize(current, maximum);
+            }
+
+            return {
+                minimum: minimum,
+                maximum: maximum
+            };
+        }
+
         public static ExtractMinAndMax(positions: number[], start: number, count: number): { minimum: Vector3; maximum: Vector3 } {
             var minimum = new Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
             var maximum = new Vector3(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE);
@@ -184,7 +201,7 @@ module BABYLON {
 
 
             //ANY database to do!
-            if (database && database.enableTexturesOffline && BABYLON.Database.isUASupportingBlobStorage) { 
+            if (database && database.enableTexturesOffline && BABYLON.Database.isUASupportingBlobStorage) {
                 database.openAsync(loadFromIndexedDB, noIndexedDB);
             }
             else {
@@ -266,6 +283,23 @@ module BABYLON {
         }
 
         // Misc.        
+
+        public static CheckExtends(v: Vector3, min: Vector3, max: Vector3): void {
+            if (v.x < min.x)
+                min.x = v.x;
+            if (v.y < min.y)
+                min.y = v.y;
+            if (v.z < min.z)
+                min.z = v.z;
+
+            if (v.x > max.x)
+                max.x = v.x;
+            if (v.y > max.y)
+                max.y = v.y;
+            if (v.z > max.z)
+                max.z = v.z;
+        }
+
         public static WithinEpsilon(a: number, b: number): boolean {
             var num = a - b;
             return -1.401298E-45 <= num && num <= 1.401298E-45;

+ 8 - 7
Babylon/babylon.engine.js

@@ -468,16 +468,17 @@
 
         Engine.prototype.updateDynamicVertexBuffer = function (vertexBuffer, vertices, length) {
             this._gl.bindBuffer(this._gl.ARRAY_BUFFER, vertexBuffer);
-            if (length && length != vertices.length) {
-                this._gl.bufferSubData(this._gl.ARRAY_BUFFER, 0, new Float32Array(vertices, 0, length));
+
+            //if (length && length != vertices.length) {
+            //    this._gl.bufferSubData(this._gl.ARRAY_BUFFER, 0, new Float32Array(vertices, 0, length));
+            //} else {
+            if (vertices instanceof Float32Array) {
+                this._gl.bufferSubData(this._gl.ARRAY_BUFFER, 0, vertices);
             } else {
-                if (vertices instanceof Float32Array) {
-                    this._gl.bufferSubData(this._gl.ARRAY_BUFFER, 0, vertices);
-                } else {
-                    this._gl.bufferSubData(this._gl.ARRAY_BUFFER, 0, new Float32Array(vertices));
-                }
+                this._gl.bufferSubData(this._gl.ARRAY_BUFFER, 0, new Float32Array(vertices));
             }
 
+            //  }
             this._resetVertexBufferBinding();
         };
 

+ 7 - 7
Babylon/babylon.engine.ts

@@ -167,7 +167,7 @@
 
         // Cache
         private _loadedTexturesCache = new Array<WebGLTexture>();
-        public _activeTexturesCache = new Array<Texture>();
+        public _activeTexturesCache = new Array<BaseTexture>();
         private _currentEffect: Effect;
         private _cullingState: boolean;
         private _compiledEffects = {};
@@ -499,15 +499,15 @@
 
         public updateDynamicVertexBuffer(vertexBuffer: WebGLBuffer, vertices: any, length?: number): void {
             this._gl.bindBuffer(this._gl.ARRAY_BUFFER, vertexBuffer);
-            if (length && length != vertices.length) {
-                this._gl.bufferSubData(this._gl.ARRAY_BUFFER, 0, new Float32Array(vertices, 0, length));
-            } else {
+            //if (length && length != vertices.length) {
+            //    this._gl.bufferSubData(this._gl.ARRAY_BUFFER, 0, new Float32Array(vertices, 0, length));
+            //} else {
                 if (vertices instanceof Float32Array) {
                     this._gl.bufferSubData(this._gl.ARRAY_BUFFER, 0, vertices);
                 } else {
                     this._gl.bufferSubData(this._gl.ARRAY_BUFFER, 0, new Float32Array(vertices));
                 }
-            }
+          //  }
 
             this._resetVertexBufferBinding();
         }
@@ -1147,7 +1147,7 @@
             this._bindTexture(channel, postProcess._textures.data[postProcess._currentRenderTextureInd]);
         }
 
-        public setTexture(channel: number, texture: Texture): void {
+        public setTexture(channel: number, texture: BaseTexture): void {
             if (channel < 0) {
                 return;
             }
@@ -1230,7 +1230,7 @@
             }
         }
 
-        public _setAnisotropicLevel(key: number, texture: Texture) {
+        public _setAnisotropicLevel(key: number, texture: BaseTexture) {
             var anisotropicFilterExtension = this._caps.textureAnisotropicFilterExtension;
 
             if (anisotropicFilterExtension && texture._cachedAnisotropicFilteringLevel !== texture.anisotropicFilteringLevel) {

+ 16 - 0
Babylon/babylon.node.js

@@ -126,6 +126,22 @@
 
             return results;
         };
+
+        Node.prototype._setReady = function (state) {
+            if (state == this._isReady) {
+                return;
+            }
+
+            if (!state) {
+                this._isReady = false;
+                return;
+            }
+
+            this._isReady = true;
+            if (this.onReady) {
+                this.onReady(this);
+            }
+        };
         return Node;
     })();
     BABYLON.Node = Node;

+ 19 - 1
Babylon/babylon.node.ts

@@ -6,9 +6,11 @@
 
         public animations = new Array<Animation>();
 
+        public onReady: (node: Node) => void;
+
         private _childrenFlag = -1;
         private _isEnabled = true;
-        public _isReady = true;
+        private _isReady = true;
         public _currentRenderId = -1;
 
         private _scene: Scene;
@@ -136,5 +138,21 @@
 
             return results;
         }
+
+        public _setReady(state: boolean): void {
+            if (state == this._isReady) {
+                return;
+            }
+
+            if (!state) {
+                this._isReady = false;
+                return;
+            }
+
+            this._isReady = true;
+            if (this.onReady) {
+                this.onReady(this);
+            }
+        }
     }
 } 

+ 114 - 99
Babylon/babylon.scene.js

@@ -1,21 +1,5 @@
 var BABYLON;
 (function (BABYLON) {
-    var checkExtends = function (v, min, max) {
-        if (v.x < min.x)
-            min.x = v.x;
-        if (v.y < min.y)
-            min.y = v.y;
-        if (v.z < min.z)
-            min.z = v.z;
-
-        if (v.x > max.x)
-            max.x = v.x;
-        if (v.y > max.y)
-            max.y = v.y;
-        if (v.z > max.z)
-            max.z = v.z;
-    };
-
     var Scene = (function () {
         // Constructor
         function Scene(engine) {
@@ -78,6 +62,7 @@
             this._spritesDuration = 0;
             this._animationRatio = 0;
             this._renderId = 0;
+            this._traversalId = 0;
             this._executeWhenReadyTimeoutId = -1;
             this._toBeDisposed = new BABYLON.SmartArray(256);
             this._onReadyCallbacks = new Array();
@@ -104,7 +89,31 @@
 
             this.attachControl();
         }
-        // Properties
+        Object.defineProperty(Scene.prototype, "meshUnderPointer", {
+            // Properties
+            get: function () {
+                return this._meshUnderPointer;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+        Object.defineProperty(Scene.prototype, "pointerX", {
+            get: function () {
+                return this._pointerX;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+        Object.defineProperty(Scene.prototype, "pointerY", {
+            get: function () {
+                return this._pointerY;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
         Scene.prototype.getBoundingBoxRenderer = function () {
             return this._boundingBoxRenderer;
         };
@@ -167,16 +176,22 @@
             var _this = this;
             this._onPointerMove = function (evt) {
                 var canvas = _this._engine.getRenderingCanvas();
-                var pickResult = _this.pick(evt.offsetX || evt.layerX, evt.offsetY || evt.layerY, function (mesh) {
+
+                _this._pointerX = evt.offsetX || evt.layerX;
+                _this._pointerY = evt.offsetY || evt.layerY;
+                var pickResult = _this.pick(_this._pointerX, _this._pointerY, function (mesh) {
                     return mesh.actionManager && mesh.isPickable;
                 });
 
                 if (pickResult.hit) {
                     _this.setPointerOverMesh(pickResult.pickedMesh);
                     canvas.style.cursor = "pointer";
+
+                    _this._meshUnderPointer = pickResult.pickedMesh;
                 } else {
                     _this.setPointerOverMesh(null);
                     canvas.style.cursor = "";
+                    _this._meshUnderPointer = null;
                 }
             };
 
@@ -583,6 +598,10 @@
             if (mesh.subMeshes.length == 1 || subMesh.isInFrustum(this._frustumPlanes)) {
                 var material = subMesh.getMaterial();
 
+                if (mesh.showSubMeshesBoundingBox) {
+                    this._boundingBoxRenderer.renderList.push(subMesh.getBoundingInfo().boundingBox);
+                }
+
                 if (material) {
                     // Render targets
                     if (material.getRenderTargetTextures) {
@@ -615,91 +634,42 @@
             }
 
             // Meshes
-            if (this._selectionOctree) {
-                var selection = this._selectionOctree.select(this._frustumPlanes);
+            var meshes;
+            var len;
 
-                for (var blockIndex = 0; blockIndex < selection.length; blockIndex++) {
-                    var block = selection.data[blockIndex];
-
-                    for (var meshIndex = 0; meshIndex < block.meshes.length; meshIndex++) {
-                        var mesh = block.meshes[meshIndex];
-
-                        if (Math.abs(mesh._renderId) !== this._renderId) {
-                            this._totalVertices += mesh.getTotalVertices();
-
-                            if (!mesh.isReady()) {
-                                continue;
-                            }
+            if (this._selectionOctree) {
+                var selection = this._selectionOctree.select(this._frustumPlanes, true);
+                meshes = selection.data;
+                len = selection.length;
+            } else {
+                len = this.meshes.length;
+                meshes = this.meshes;
+            }
 
-                            mesh.computeWorldMatrix();
-                            mesh._renderId = 0;
-                            mesh._preActivate();
-                        }
+            this._traversalId++;
+            for (var meshIndex = 0; meshIndex < len; meshIndex++) {
+                var mesh = meshes[meshIndex];
 
-                        if (mesh._renderId === this._renderId || (mesh._renderId === 0 && mesh.isEnabled() && mesh.isVisible && mesh.visibility > 0 && mesh.isInFrustum(this._frustumPlanes) && ((mesh.layerMask & this.activeCamera.layerMask) != 0))) {
-                            if (mesh._renderId === 0) {
-                                this._activeMeshes.push(mesh);
-                                mesh._activate(this._renderId);
-                            }
-                            mesh._renderId = this._renderId;
-
-                            if (mesh.showBoundingBox) {
-                                this._boundingBoxRenderer.renderList.push(mesh);
-                            }
-
-                            if (mesh.skeleton) {
-                                this._activeSkeletons.pushNoDuplicate(mesh.skeleton);
-                            }
-
-                            var subMeshes = block.subMeshes[meshIndex];
-                            for (subIndex = 0; subIndex < subMeshes.length; subIndex++) {
-                                subMesh = subMeshes[subIndex];
-
-                                if (subMesh._renderId === this._renderId) {
-                                    continue;
-                                }
-                                subMesh._renderId = this._renderId;
-
-                                this._evaluateSubMesh(subMesh, mesh);
-                            }
-                        } else {
-                            mesh._renderId = -this._renderId;
-                        }
-                    }
+                if (mesh._traversalId === this._traversalId) {
+                    continue;
                 }
-            } else {
-                for (meshIndex = 0; meshIndex < this.meshes.length; meshIndex++) {
-                    mesh = this.meshes[meshIndex];
 
-                    this._totalVertices += mesh.getTotalVertices();
+                mesh._traversalId = this._traversalId;
 
-                    if (!mesh.isReady()) {
-                        continue;
-                    }
+                this._totalVertices += mesh.getTotalVertices();
 
-                    mesh.computeWorldMatrix();
-                    mesh._preActivate();
-
-                    if (mesh.isEnabled() && ((mesh.layerMask & this.activeCamera.layerMask) != 0) && mesh.isVisible && mesh.visibility > 0 && mesh.isInFrustum(this._frustumPlanes)) {
-                        this._activeMeshes.push(mesh);
-                        mesh._activate(this._renderId);
+                if (!mesh.isReady()) {
+                    continue;
+                }
 
-                        if (mesh.skeleton) {
-                            this._activeSkeletons.pushNoDuplicate(mesh.skeleton);
-                        }
+                mesh.computeWorldMatrix();
+                mesh._preActivate();
 
-                        if (mesh.showBoundingBox) {
-                            this._boundingBoxRenderer.renderList.push(mesh);
-                        }
+                if (mesh.isEnabled() && mesh.isVisible && mesh.visibility > 0 && ((mesh.layerMask & this.activeCamera.layerMask) != 0) && mesh.isInFrustum(this._frustumPlanes)) {
+                    this._activeMeshes.push(mesh);
+                    mesh._activate(this._renderId);
 
-                        if (mesh.subMeshes) {
-                            for (var subIndex = 0; subIndex < mesh.subMeshes.length; subIndex++) {
-                                var subMesh = mesh.subMeshes[subIndex];
-
-                                this._evaluateSubMesh(subMesh, mesh);
-                            }
-                        }
-                    }
+                    this._activeMesh(mesh);
                 }
             }
 
@@ -709,6 +679,10 @@
                 for (var particleIndex = 0; particleIndex < this.particleSystems.length; particleIndex++) {
                     var particleSystem = this.particleSystems[particleIndex];
 
+                    if (!particleSystem.isStarted()) {
+                        continue;
+                    }
+
                     if (!particleSystem.emitter.position || (particleSystem.emitter && particleSystem.emitter.isEnabled())) {
                         this._activeParticleSystems.push(particleSystem);
                         particleSystem.animate();
@@ -718,6 +692,44 @@
             this._particlesDuration += new Date().getTime() - beforeParticlesDate;
         };
 
+        Scene.prototype._activeMesh = function (mesh) {
+            if (mesh.skeleton) {
+                this._activeSkeletons.pushNoDuplicate(mesh.skeleton);
+            }
+
+            if (mesh.showBoundingBox) {
+                this._boundingBoxRenderer.renderList.push(mesh.getBoundingInfo().boundingBox);
+            }
+
+            if (mesh.subMeshes) {
+                // Submeshes Octrees
+                var len;
+                var subMeshes;
+
+                if (mesh._submeshesOctree && mesh.useOctreeForRenderingSelection) {
+                    var intersections = mesh._submeshesOctree.select(this._frustumPlanes, true);
+
+                    len = intersections.length;
+                    subMeshes = intersections.data;
+                } else {
+                    subMeshes = mesh.subMeshes;
+                    len = subMeshes.length;
+                }
+
+                for (var subIndex = 0; subIndex < len; subIndex++) {
+                    var subMesh = subMeshes[subIndex];
+
+                    if (mesh._traversalId === subMesh._traversalId) {
+                        continue;
+                    }
+
+                    subMesh._traversalId = mesh._traversalId;
+
+                    this._evaluateSubMesh(subMesh, mesh);
+                }
+            }
+        };
+
         Scene.prototype.updateTransformMatrix = function (force) {
             this.setTransformMatrix(this.activeCamera.getViewMatrix(), this.activeCamera.getProjectionMatrix(force));
         };
@@ -753,7 +765,8 @@
             }
 
             for (var customIndex = 0; customIndex < this.customRenderTargets.length; customIndex++) {
-                this._renderTargets.push(this.customRenderTargets[customIndex]);
+                var renderTarget = this.customRenderTargets[customIndex];
+                this._renderTargets.push(renderTarget);
             }
 
             // Render targets
@@ -761,8 +774,10 @@
             if (this.renderTargetsEnabled) {
                 for (var renderIndex = 0; renderIndex < this._renderTargets.length; renderIndex++) {
                     var renderTarget = this._renderTargets.data[renderIndex];
-                    this._renderId++;
-                    renderTarget.render();
+                    if (renderTarget._shouldRender()) {
+                        this._renderId++;
+                        renderTarget.render();
+                    }
                 }
                 this._renderId++;
             }
@@ -1034,7 +1049,7 @@
         // Octrees
         Scene.prototype.createOrUpdateSelectionOctree = function () {
             if (!this._selectionOctree) {
-                this._selectionOctree = new BABYLON.Octree();
+                this._selectionOctree = new BABYLON.Octree(BABYLON.Octree.CreationFuncForMeshes);
             }
 
             var min = new BABYLON.Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
@@ -1046,8 +1061,8 @@
                 var minBox = mesh.getBoundingInfo().boundingBox.minimumWorld;
                 var maxBox = mesh.getBoundingInfo().boundingBox.maximumWorld;
 
-                checkExtends(minBox, min, max);
-                checkExtends(maxBox, min, max);
+                BABYLON.Tools.CheckExtends(minBox, min, max);
+                BABYLON.Tools.CheckExtends(maxBox, min, max);
             }
 
             // Update octree

+ 107 - 101
Babylon/babylon.scene.ts

@@ -1,20 +1,4 @@
 module BABYLON {
-    var checkExtends = (v: Vector3, min: Vector3, max: Vector3) => {
-        if (v.x < min.x)
-            min.x = v.x;
-        if (v.y < min.y)
-            min.y = v.y;
-        if (v.z < min.z)
-            min.z = v.z;
-
-        if (v.x > max.x)
-            max.x = v.x;
-        if (v.y > max.y)
-            max.y = v.y;
-        if (v.z > max.z)
-            max.z = v.z;
-    };
-
     export interface IDisposable {
         dispose(): void;
     }
@@ -41,6 +25,9 @@
         private _onPointerMove: (evt: PointerEvent) => void;
         private _onPointerDown: (evt: PointerEvent) => void;
         public onPointerDown: (evt: PointerEvent, pickInfo: PickingInfo) => void;
+        private _pointerX: number;
+        private _pointerY: number;
+        private _meshUnderPointer: AbstractMesh;
 
         // Fog
         public fogMode = BABYLON.Scene.FOGMODE_NONE;
@@ -127,6 +114,7 @@
         private _animationStartDate: number;
 
         private _renderId = 0;
+        private _traversalId = 0;
         private _executeWhenReadyTimeoutId = -1;
 
         public _toBeDisposed = new SmartArray<IDisposable>(256);
@@ -159,7 +147,7 @@
         private _projectionMatrix: Matrix;
         private _frustumPlanes: Plane[];
 
-        private _selectionOctree: Octree;
+        private _selectionOctree: Octree<AbstractMesh>;
 
         private _pointerOverMesh: Mesh;
 
@@ -179,6 +167,18 @@
         }
 
         // Properties 
+        public get meshUnderPointer(): AbstractMesh {
+            return this._meshUnderPointer;
+        }
+
+        public get pointerX(): number {
+            return this._pointerX;
+        }
+
+        public get pointerY(): number {
+            return this._pointerY;
+        }
+
         public getBoundingBoxRenderer(): BoundingBoxRenderer {
             return this._boundingBoxRenderer;
         }
@@ -240,14 +240,20 @@
         public attachControl() {
             this._onPointerMove = (evt: PointerEvent) => {
                 var canvas = this._engine.getRenderingCanvas();
-                var pickResult = this.pick(evt.offsetX || evt.layerX, evt.offsetY || evt.layerY, mesh => mesh.actionManager && mesh.isPickable);
+
+                this._pointerX = evt.offsetX || evt.layerX;
+                this._pointerY = evt.offsetY || evt.layerY;
+                var pickResult = this.pick(this._pointerX, this._pointerY, mesh => mesh.actionManager && mesh.isPickable);
 
                 if (pickResult.hit) {
                     this.setPointerOverMesh(pickResult.pickedMesh);
                     canvas.style.cursor = "pointer";
+
+                    this._meshUnderPointer = pickResult.pickedMesh;
                 } else {
                     this.setPointerOverMesh(null);
                     canvas.style.cursor = "";
+                    this._meshUnderPointer = null;
                 }
             };
 
@@ -293,7 +299,7 @@
 
             for (index = 0; index < this.meshes.length; index++) {
                 var mesh = this.meshes[index];
-                
+
                 if (!mesh.isReady()) {
                     return false;
                 }
@@ -653,6 +659,10 @@
             if (mesh.subMeshes.length == 1 || subMesh.isInFrustum(this._frustumPlanes)) {
                 var material = subMesh.getMaterial();
 
+                if (mesh.showSubMeshesBoundingBox) {
+                    this._boundingBoxRenderer.renderList.push(subMesh.getBoundingInfo().boundingBox);
+                }
+
                 if (material) {
                     // Render targets
                     if (material.getRenderTargetTextures) {
@@ -685,91 +695,42 @@
             }
 
             // Meshes
-            if (this._selectionOctree) { // Octree
-                var selection = this._selectionOctree.select(this._frustumPlanes);
-
-                for (var blockIndex = 0; blockIndex < selection.length; blockIndex++) {
-                    var block = selection.data[blockIndex];
-
-                    for (var meshIndex = 0; meshIndex < block.meshes.length; meshIndex++) {
-                        var mesh = block.meshes[meshIndex];
+            var meshes: AbstractMesh[];
+            var len: number;
 
-                        if (Math.abs(mesh._renderId) !== this._renderId) {
-                            this._totalVertices += mesh.getTotalVertices();
-
-                            if (!mesh.isReady()) {
-                                continue;
-                            }
-
-                            mesh.computeWorldMatrix();
-                            mesh._renderId = 0;
-                            mesh._preActivate();
-                        }
-
-						if (mesh._renderId === this._renderId || (mesh._renderId === 0 && mesh.isEnabled() && mesh.isVisible && mesh.visibility > 0 && mesh.isInFrustum(this._frustumPlanes) && ((mesh.layerMask & this.activeCamera.layerMask)!=0))) {
-                            if (mesh._renderId === 0) {
-                                this._activeMeshes.push(mesh);
-                                mesh._activate(this._renderId);
-                            }
-                            mesh._renderId = this._renderId;
-
-                            if (mesh.showBoundingBox) {
-                                this._boundingBoxRenderer.renderList.push(mesh);
-                            }
-
-                            if (mesh.skeleton) {
-                                this._activeSkeletons.pushNoDuplicate(mesh.skeleton);
-                            }
-
-                            var subMeshes = block.subMeshes[meshIndex];
-                            for (subIndex = 0; subIndex < subMeshes.length; subIndex++) {
-                                subMesh = subMeshes[subIndex];
-
-                                if (subMesh._renderId === this._renderId) {
-                                    continue;
-                                }
-                                subMesh._renderId = this._renderId;
-
-                                this._evaluateSubMesh(subMesh, mesh);
-                            }
-                        } else {
-                            mesh._renderId = -this._renderId;
-                        }
-                    }
-                }
+            if (this._selectionOctree) { // Octree
+                var selection = this._selectionOctree.select(this._frustumPlanes, true);
+                meshes = selection.data;
+                len = selection.length;
             } else { // Full scene traversal
-                for (meshIndex = 0; meshIndex < this.meshes.length; meshIndex++) {
-                    mesh = this.meshes[meshIndex];
+                len = this.meshes.length;
+                meshes = this.meshes;
+            }
 
-                    this._totalVertices += mesh.getTotalVertices();
+            this._traversalId++;
+            for (var meshIndex = 0; meshIndex < len; meshIndex++) {
+                var mesh = meshes[meshIndex];
 
-                    if (!mesh.isReady()) {
-                        continue;
-                    }
+                if (mesh._traversalId === this._traversalId) {
+                    continue;
+                }
 
-                    mesh.computeWorldMatrix();
-                    mesh._preActivate();
+                mesh._traversalId = this._traversalId;
 
-                    if (mesh.isEnabled() && ((mesh.layerMask & this.activeCamera.layerMask) != 0) && mesh.isVisible && mesh.visibility > 0 && mesh.isInFrustum(this._frustumPlanes)) {
-                        this._activeMeshes.push(mesh);
-                        mesh._activate(this._renderId);
+                this._totalVertices += mesh.getTotalVertices();
 
-                        if (mesh.skeleton) {
-                            this._activeSkeletons.pushNoDuplicate(mesh.skeleton);
-                        }
+                if (!mesh.isReady()) {
+                    continue;
+                }
 
-                        if (mesh.showBoundingBox) {
-                            this._boundingBoxRenderer.renderList.push(mesh);
-                        }
+                mesh.computeWorldMatrix();
+                mesh._preActivate();
 
-                        if (mesh.subMeshes) {
-                            for (var subIndex = 0; subIndex < mesh.subMeshes.length; subIndex++) {
-                                var subMesh = mesh.subMeshes[subIndex];
+                if (mesh.isEnabled() && mesh.isVisible && mesh.visibility > 0 && ((mesh.layerMask & this.activeCamera.layerMask) != 0) && mesh.isInFrustum(this._frustumPlanes)) {
+                    this._activeMeshes.push(mesh);
+                    mesh._activate(this._renderId);
 
-                                this._evaluateSubMesh(subMesh, mesh);
-                            }
-                        }
-                    }
+                    this._activeMesh(mesh);
                 }
             }
 
@@ -779,6 +740,10 @@
                 for (var particleIndex = 0; particleIndex < this.particleSystems.length; particleIndex++) {
                     var particleSystem = this.particleSystems[particleIndex];
 
+                    if (!particleSystem.isStarted()) {
+                        continue;
+                    }
+
                     if (!particleSystem.emitter.position || (particleSystem.emitter && particleSystem.emitter.isEnabled())) {
                         this._activeParticleSystems.push(particleSystem);
                         particleSystem.animate();
@@ -788,6 +753,44 @@
             this._particlesDuration += new Date().getTime() - beforeParticlesDate;
         }
 
+        private _activeMesh(mesh: AbstractMesh): void {
+            if (mesh.skeleton) {
+                this._activeSkeletons.pushNoDuplicate(mesh.skeleton);
+            }
+
+            if (mesh.showBoundingBox) {
+                this._boundingBoxRenderer.renderList.push(mesh.getBoundingInfo().boundingBox);
+            }
+
+            if (mesh.subMeshes) {
+                // Submeshes Octrees
+                var len: number;
+                var subMeshes: SubMesh[];
+
+                if (mesh._submeshesOctree && mesh.useOctreeForRenderingSelection) {
+                    var intersections = mesh._submeshesOctree.select(this._frustumPlanes, true);
+
+                    len = intersections.length;
+                    subMeshes = intersections.data;
+                } else {
+                    subMeshes = mesh.subMeshes;
+                    len = subMeshes.length;
+                }
+
+                for (var subIndex = 0; subIndex < len; subIndex++) {
+                    var subMesh = subMeshes[subIndex];
+
+                    if (mesh._traversalId === subMesh._traversalId) {
+                        continue;
+                    }
+
+                    subMesh._traversalId = mesh._traversalId;
+
+                    this._evaluateSubMesh(subMesh, mesh);
+                }
+            }
+        }
+
         public updateTransformMatrix(force?: boolean): void {
             this.setTransformMatrix(this.activeCamera.getViewMatrix(), this.activeCamera.getProjectionMatrix(force));
         }
@@ -825,7 +828,8 @@
 
             // Customs render targets registration
             for (var customIndex = 0; customIndex < this.customRenderTargets.length; customIndex++) {
-                this._renderTargets.push(this.customRenderTargets[customIndex]);
+                var renderTarget = this.customRenderTargets[customIndex];
+                this._renderTargets.push(renderTarget);
             }
 
             // Render targets
@@ -833,8 +837,10 @@
             if (this.renderTargetsEnabled) {
                 for (var renderIndex = 0; renderIndex < this._renderTargets.length; renderIndex++) {
                     var renderTarget = this._renderTargets.data[renderIndex];
-                    this._renderId++;
-                    renderTarget.render();
+                    if (renderTarget._shouldRender()) {
+                        this._renderId++;
+                        renderTarget.render();
+                    }
                 }
                 this._renderId++;
             }
@@ -1119,7 +1125,7 @@
         // Octrees
         public createOrUpdateSelectionOctree(): void {
             if (!this._selectionOctree) {
-                this._selectionOctree = new BABYLON.Octree();
+                this._selectionOctree = new BABYLON.Octree<AbstractMesh>(Octree.CreationFuncForMeshes);
             }
 
             var min = new BABYLON.Vector3(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
@@ -1131,8 +1137,8 @@
                 var minBox = mesh.getBoundingInfo().boundingBox.minimumWorld;
                 var maxBox = mesh.getBoundingInfo().boundingBox.maximumWorld;
 
-                checkExtends(minBox, min, max);
-                checkExtends(maxBox, min, max);
+                Tools.CheckExtends(minBox, min, max);
+                Tools.CheckExtends(maxBox, min, max);
             }
 
             // Update octree
@@ -1178,7 +1184,7 @@
                 var ray = rayFunction(world);
 
                 var result = mesh.intersects(ray, fastCheck);
-                if (! result || !result.hit)
+                if (!result || !result.hit)
                     continue;
 
                 if (!fastCheck && pickingInfo != null && result.distance >= pickingInfo.distance)

+ 3 - 0
Tools/BuildOurOwnBabylonJS/BuildOurOwnBabylonJS/babylonJS.xml

@@ -1,5 +1,7 @@
 <?xml version="1.0" encoding="utf-8" ?>
 <files xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="babylonJS.xsd">
+  <script src="Babylon/Tools/babylon.gamepads.js"></script>
+  <script src="Babylon/Cameras/babylon.gamepadCamera.js"></script>
   <script src="Babylon/Materials/babylon.shaderMaterial.js"></script>
   <script src="Babylon/Cameras/babylon.virtualJoysticksCamera.js"></script>
   <script src="Babylon/Tools/babylon.virtualJoystick.js"></script>
@@ -60,6 +62,7 @@
   <script src="Babylon/Materials/textures/babylon.baseTexture.js"></script>
   <script src="Babylon/Mesh/babylon.subMesh.js"></script>
   <script src="Babylon/Mesh/babylon.mesh.js"></script>
+  <script src="Babylon/Mesh/babylon.GroundMesh.js"></script>
   <script src="Babylon/Mesh/babylon.InstancedMesh.js"></script>
   <script src="Babylon/Mesh/babylon.AbstractMesh.js"></script>
   <script src="Babylon/Mesh/babylon.geometry.js"></script>

二进制
Tools/BuildOurOwnBabylonJS/BuildOurOwnBabylonJS/executables/JSKompactor.exe


文件差异内容过多而无法显示
+ 15 - 13
babylon.1.12-beta.js