ソースを参照

Finalizing bones export from 3dsmax

David Catuhe 10 年 前
コミット
834d39ee17
42 ファイル変更1059 行追加748 行削除
  1. 1 1
      Babylon/Actions/babylon.actionManager.js
  2. 51 6
      Babylon/Animations/babylon.animation.js
  3. 3 2
      Babylon/Lights/Shadows/babylon.shadowGenerator.js
  4. 8 0
      Babylon/Loading/Plugins/babylon.babylonFileLoader.js
  5. 2 2
      Babylon/Loading/babylon.sceneLoader.js
  6. 13 14
      Babylon/Materials/babylon.effect.js
  7. 5 0
      Babylon/Materials/babylon.material.js
  8. 65 37
      Babylon/Materials/babylon.shaderMaterial.js
  9. 136 113
      Babylon/Materials/babylon.standardMaterial.js
  10. 69 51
      Babylon/Materials/textures/Procedurals/babylon.customProceduralTexture.js
  11. 43 6
      Babylon/Materials/textures/Procedurals/babylon.proceduralTexture.js
  12. 166 80
      Babylon/Materials/textures/Procedurals/babylon.standardProceduralTexture.js
  13. 1 1
      Babylon/Materials/textures/babylon.baseTexture.js
  14. 1 1
      Babylon/Materials/textures/babylon.renderTargetTexture.js
  15. 2 0
      Babylon/Materials/textures/babylon.texture.js
  16. 54 0
      Babylon/Math/babylon.math.js
  17. 12 2
      Babylon/Mesh/babylon.InstancedMesh.js
  18. 45 4
      Babylon/Mesh/babylon.abstractMesh.js
  19. 1 1
      Babylon/Mesh/babylon.abstractMesh.ts
  20. 10 5
      Babylon/Mesh/babylon.geometry.js
  21. 45 34
      Babylon/Mesh/babylon.mesh.js
  22. 2 2
      Babylon/Mesh/babylon.vertexBuffer.js
  23. 7 6
      Babylon/Particles/babylon.particleSystem.js
  24. 2 0
      Babylon/Physics/Plugins/babylon.oimoJSPlugin.js
  25. 3 1
      Babylon/Rendering/babylon.boundingBoxRenderer.js
  26. 6 5
      Babylon/Rendering/babylon.outlineRenderer.js
  27. 11 6
      Babylon/Rendering/babylon.renderingGroup.js
  28. 2 3
      Babylon/Rendering/babylon.renderingManager.js
  29. 2 2
      Babylon/Sprites/babylon.spriteManager.js
  30. 44 4
      Babylon/Tools/babylon.tools.js
  31. 39 9
      Babylon/babylon.engine.js
  32. 129 24
      Babylon/babylon.scene.js
  33. BIN
      Exporters/3ds Max/Max2Babylon-0.8.5.zip
  34. 4 6
      Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Animation.cs
  35. 32 39
      Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Light.cs
  36. 0 1
      Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Material.cs
  37. 29 70
      Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Mesh.cs
  38. 2 198
      Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Skeleton.cs
  39. 8 9
      Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.cs
  40. 1 0
      Exporters/3ds Max/readme.md
  41. 1 1
      babylon.2.0-alpha.debug.js
  42. 2 2
      babylon.2.0-alpha.js

+ 1 - 1
Babylon/Actions/babylon.actionManager.js

@@ -202,7 +202,7 @@
                 var action = this.actions[index];
 
                 if (action.trigger === trigger) {
-                    if (trigger == ActionManager.OnKeyUpTrigger || trigger == ActionManager.OnKeyDownTrigger) {
+                    if (trigger === ActionManager.OnKeyUpTrigger || trigger === ActionManager.OnKeyDownTrigger) {
                         var parameter = action.getTriggerParameter();
 
                         if (parameter) {

+ 51 - 6
Babylon/Animations/babylon.animation.js

@@ -14,6 +14,37 @@
             this.dataType = dataType;
             this.loopMode = loopMode === undefined ? Animation.ANIMATIONLOOPMODE_CYCLE : loopMode;
         }
+        Animation.CreateAndStartAnimation = function (name, mesh, tartgetProperty, framePerSecond, totalFrame, from, to, loopMode) {
+            var dataType = undefined;
+
+            if (!isNaN(parseFloat(from)) && isFinite(from)) {
+                dataType = Animation.ANIMATIONTYPE_FLOAT;
+            } else if (from instanceof BABYLON.Quaternion) {
+                dataType = Animation.ANIMATIONTYPE_QUATERNION;
+            } else if (from instanceof BABYLON.Vector3) {
+                dataType = Animation.ANIMATIONTYPE_VECTOR3;
+            } else if (from instanceof BABYLON.Vector2) {
+                dataType = Animation.ANIMATIONTYPE_VECTOR2;
+            } else if (from instanceof BABYLON.Color3) {
+                dataType = Animation.ANIMATIONTYPE_COLOR3;
+            }
+
+            if (dataType == undefined) {
+                return;
+            }
+
+            var animation = new Animation(name, tartgetProperty, framePerSecond, dataType, loopMode);
+
+            var keys = [];
+            keys.push({ frame: 0, value: from });
+            keys.push({ frame: totalFrame, value: to });
+            animation.setKeys(keys);
+
+            mesh.animations.push(animation);
+
+            mesh.getScene().beginAnimation(mesh, 0, totalFrame, (animation.loopMode == 1));
+        };
+
         // Methods
         Animation.prototype.isStopped = function () {
             return this._stopped;
@@ -23,6 +54,14 @@
             return this._keys;
         };
 
+        Animation.prototype.getEasingFunction = function () {
+            return this._easingFunction;
+        };
+
+        Animation.prototype.setEasingFunction = function (easingFunction) {
+            this._easingFunction = easingFunction;
+        };
+
         Animation.prototype.floatInterpolateFunction = function (startValue, endValue, gradient) {
             return startValue + (endValue - startValue) * gradient;
         };
@@ -65,11 +104,19 @@
             this.currentFrame = currentFrame;
 
             for (var key = 0; key < this._keys.length; key++) {
+                // for each frame, we need the key just before the frame superior
                 if (this._keys[key + 1].frame >= currentFrame) {
                     var startValue = this._keys[key].value;
                     var endValue = this._keys[key + 1].value;
+
+                    // gradient : percent of currentFrame between the frame inf and the frame sup
                     var gradient = (currentFrame - this._keys[key].frame) / (this._keys[key + 1].frame - this._keys[key].frame);
 
+                    // check for easingFunction and correction of gradient
+                    if (this._easingFunction != null) {
+                        gradient = this._easingFunction.ease(gradient);
+                    }
+
                     switch (this.dataType) {
                         case Animation.ANIMATIONTYPE_FLOAT:
                             switch (loopMode) {
@@ -143,16 +190,11 @@
                 this._stopped = true;
                 return false;
             }
-
             var returnValue = true;
 
             // Adding a start key at frame 0 if missing
             if (this._keys[0].frame != 0) {
-                var newKey = {
-                    frame: 0,
-                    value: this._keys[0].value
-                };
-
+                var newKey = { frame: 0, value: this._keys[0].value };
                 this._keys.splice(0, 0, newKey);
             }
 
@@ -167,6 +209,8 @@
             // Compute ratio
             var range = to - from;
             var offsetValue;
+
+            // ratio represents the frame delta between from and to
             var ratio = delay * (this.framePerSecond * speedRatio) / 1000.0;
 
             if (ratio > range && !loop) {
@@ -175,6 +219,7 @@
             } else {
                 // Get max value if required
                 var highLimitValue = 0;
+
                 if (this.loopMode != Animation.ANIMATIONLOOPMODE_CYCLE) {
                     var keyOffset = to.toString() + from.toString();
                     if (!this._offsetsCache[keyOffset]) {

+ 3 - 2
Babylon/Lights/Shadows/babylon.shadowGenerator.js

@@ -55,7 +55,7 @@
                     }
 
                     // Bones
-                    var useBones = mesh.skeleton && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesIndicesKind) && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesWeightsKind);
+                    var useBones = mesh.skeleton && scene.skeletonsEnabled && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesIndicesKind) && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesWeightsKind);
 
                     if (useBones) {
                         _this._effect.setMatrices("mBones", mesh.skeleton.getTransformMatrices());
@@ -163,6 +163,7 @@
             var attribs = [BABYLON.VertexBuffer.PositionKind];
 
             var mesh = subMesh.getMesh();
+            var scene = mesh.getScene();
             var material = subMesh.getMaterial();
 
             // Alpha test
@@ -179,7 +180,7 @@
             }
 
             // Bones
-            if (mesh.skeleton && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesIndicesKind) && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesWeightsKind)) {
+            if (mesh.skeleton && scene.skeletonsEnabled && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesIndicesKind) && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesWeightsKind)) {
                 attribs.push(BABYLON.VertexBuffer.MatricesIndicesKind);
                 attribs.push(BABYLON.VertexBuffer.MatricesWeightsKind);
                 defines.push("#define BONES");

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

@@ -647,10 +647,18 @@
             mesh.showBoundingBox = parsedMesh.showBoundingBox;
             mesh.showSubMeshesBoundingBox = parsedMesh.showSubMeshesBoundingBox;
 
+            if (parsedMesh.applyFog !== undefined) {
+                mesh.applyFog = parsedMesh.applyFog;
+            }
+
             if (parsedMesh.pickable !== undefined) {
                 mesh.isPickable = parsedMesh.pickable;
             }
 
+            if (parsedMesh.alphaIndex !== undefined) {
+                mesh.alphaIndex = parsedMesh.alphaIndex;
+            }
+
             mesh.receiveShadows = parsedMesh.receiveShadows;
 
             mesh.billboardMode = parsedMesh.billboardMode;

+ 2 - 2
Babylon/Loading/babylon.sceneLoader.js

@@ -64,14 +64,14 @@
                     try  {
                         if (!plugin.importMesh(meshesNames, scene, data, rootUrl, meshes, particleSystems, skeletons)) {
                             if (onerror) {
-                                onerror(scene);
+                                onerror(scene, 'unable to load the scene');
                             }
 
                             return;
                         }
                     } catch (e) {
                         if (onerror) {
-                            onerror(scene);
+                            onerror(scene, e);
                         }
 
                         return;

+ 13 - 14
Babylon/Materials/babylon.effect.js

@@ -143,8 +143,8 @@
             }
 
             // Is in local store ?
-            if (BABYLON.Effect.ShadersStore[vertex + "VertexShader"]) {
-                callback(BABYLON.Effect.ShadersStore[vertex + "VertexShader"]);
+            if (Effect.ShadersStore[vertex + "VertexShader"]) {
+                callback(Effect.ShadersStore[vertex + "VertexShader"]);
                 return;
             }
 
@@ -169,13 +169,13 @@
             }
 
             // Is in local store ?
-            if (BABYLON.Effect.ShadersStore[fragment + "PixelShader"]) {
-                callback(BABYLON.Effect.ShadersStore[fragment + "PixelShader"]);
+            if (Effect.ShadersStore[fragment + "PixelShader"]) {
+                callback(Effect.ShadersStore[fragment + "PixelShader"]);
                 return;
             }
 
-            if (BABYLON.Effect.ShadersStore[fragment + "FragmentShader"]) {
-                callback(BABYLON.Effect.ShadersStore[fragment + "FragmentShader"]);
+            if (Effect.ShadersStore[fragment + "FragmentShader"]) {
+                callback(Effect.ShadersStore[fragment + "FragmentShader"]);
                 return;
             }
 
@@ -208,7 +208,6 @@
                         index--;
                     }
                 }
-
                 engine.bindSamplers(this);
 
                 this._isReady = true;
@@ -340,7 +339,7 @@
         };
 
         Effect.prototype.setVector2 = function (uniformName, vector2) {
-            if (this._valueCache[uniformName] && this._valueCache[uniformName][0] == vector2.x && this._valueCache[uniformName][1] == vector2.y)
+            if (this._valueCache[uniformName] && this._valueCache[uniformName][0] === vector2.x && this._valueCache[uniformName][1] === vector2.y)
                 return this;
 
             this._cacheFloat2(uniformName, vector2.x, vector2.y);
@@ -350,7 +349,7 @@
         };
 
         Effect.prototype.setFloat2 = function (uniformName, x, y) {
-            if (this._valueCache[uniformName] && this._valueCache[uniformName][0] == x && this._valueCache[uniformName][1] == y)
+            if (this._valueCache[uniformName] && this._valueCache[uniformName][0] === x && this._valueCache[uniformName][1] === y)
                 return this;
 
             this._cacheFloat2(uniformName, x, y);
@@ -360,7 +359,7 @@
         };
 
         Effect.prototype.setVector3 = function (uniformName, vector3) {
-            if (this._valueCache[uniformName] && this._valueCache[uniformName][0] == vector3.x && this._valueCache[uniformName][1] == vector3.y && this._valueCache[uniformName][2] == vector3.z)
+            if (this._valueCache[uniformName] && this._valueCache[uniformName][0] === vector3.x && this._valueCache[uniformName][1] === vector3.y && this._valueCache[uniformName][2] === vector3.z)
                 return this;
 
             this._cacheFloat3(uniformName, vector3.x, vector3.y, vector3.z);
@@ -371,7 +370,7 @@
         };
 
         Effect.prototype.setFloat3 = function (uniformName, x, y, z) {
-            if (this._valueCache[uniformName] && this._valueCache[uniformName][0] == x && this._valueCache[uniformName][1] == y && this._valueCache[uniformName][2] == z)
+            if (this._valueCache[uniformName] && this._valueCache[uniformName][0] === x && this._valueCache[uniformName][1] === y && this._valueCache[uniformName][2] === z)
                 return this;
 
             this._cacheFloat3(uniformName, x, y, z);
@@ -381,7 +380,7 @@
         };
 
         Effect.prototype.setFloat4 = function (uniformName, x, y, z, w) {
-            if (this._valueCache[uniformName] && this._valueCache[uniformName][0] == x && this._valueCache[uniformName][1] == y && this._valueCache[uniformName][2] == z && this._valueCache[uniformName][3] == w)
+            if (this._valueCache[uniformName] && this._valueCache[uniformName][0] === x && this._valueCache[uniformName][1] === y && this._valueCache[uniformName][2] === z && this._valueCache[uniformName][3] === w)
                 return this;
 
             this._cacheFloat4(uniformName, x, y, z, w);
@@ -391,7 +390,7 @@
         };
 
         Effect.prototype.setColor3 = function (uniformName, color3) {
-            if (this._valueCache[uniformName] && this._valueCache[uniformName][0] == color3.r && this._valueCache[uniformName][1] == color3.g && this._valueCache[uniformName][2] == color3.b)
+            if (this._valueCache[uniformName] && this._valueCache[uniformName][0] === color3.r && this._valueCache[uniformName][1] === color3.g && this._valueCache[uniformName][2] === color3.b)
                 return this;
 
             this._cacheFloat3(uniformName, color3.r, color3.g, color3.b);
@@ -401,7 +400,7 @@
         };
 
         Effect.prototype.setColor4 = function (uniformName, color3, alpha) {
-            if (this._valueCache[uniformName] && this._valueCache[uniformName][0] == color3.r && this._valueCache[uniformName][1] == color3.g && this._valueCache[uniformName][2] == color3.b && this._valueCache[uniformName][3] == alpha)
+            if (this._valueCache[uniformName] && this._valueCache[uniformName][0] === color3.r && this._valueCache[uniformName][1] === color3.g && this._valueCache[uniformName][2] === color3.b && this._valueCache[uniformName][3] === alpha)
                 return this;
 
             this._cacheFloat4(uniformName, color3.r, color3.g, color3.b, alpha);

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

@@ -114,6 +114,11 @@
         };
 
         Material.prototype.bind = function (world, mesh) {
+            this._scene._cachedMaterial = this;
+
+            if (this.onBind) {
+                this.onBind(this);
+            }
         };
 
         Material.prototype.bindOnlyWorldMatrix = function (world) {

+ 65 - 37
Babylon/Materials/babylon.shaderMaterial.js

@@ -102,72 +102,100 @@ var BABYLON;
         };
 
         ShaderMaterial.prototype.isReady = function () {
-            var engine = this.getScene().getEngine();
+            var scene = this.getScene();
+            var engine = scene.getEngine();
 
+            if (!this.checkReadyOnEveryCall) {
+                if (this._renderId === scene.getRenderId()) {
+                    return true;
+                }
+            }
+
+            var previousEffect = this._effect;
             this._effect = engine.createEffect(this._shaderPath, this._options.attributes, this._options.uniforms, this._options.samplers, "", null, this.onCompiled, this.onError);
 
             if (!this._effect.isReady()) {
                 return false;
             }
 
+            if (previousEffect !== this._effect) {
+                scene.resetCachedMaterial();
+            }
+
+            this._renderId = scene.getRenderId();
+
             return true;
         };
 
-        ShaderMaterial.prototype.bind = function (world) {
-            // Std values
+        ShaderMaterial.prototype.bindOnlyWorldMatrix = function (world) {
+            var scene = this.getScene();
+
             if (this._options.uniforms.indexOf("world") !== -1) {
                 this._effect.setMatrix("world", world);
             }
 
-            if (this._options.uniforms.indexOf("view") !== -1) {
-                this._effect.setMatrix("view", this.getScene().getViewMatrix());
-            }
-
             if (this._options.uniforms.indexOf("worldView") !== -1) {
-                world.multiplyToRef(this.getScene().getViewMatrix(), this._cachedWorldViewMatrix);
+                world.multiplyToRef(scene.getViewMatrix(), this._cachedWorldViewMatrix);
                 this._effect.setMatrix("worldView", this._cachedWorldViewMatrix);
             }
 
-            if (this._options.uniforms.indexOf("projection") !== -1) {
-                this._effect.setMatrix("projection", this.getScene().getProjectionMatrix());
-            }
-
             if (this._options.uniforms.indexOf("worldViewProjection") !== -1) {
-                this._effect.setMatrix("worldViewProjection", world.multiply(this.getScene().getTransformMatrix()));
+                this._effect.setMatrix("worldViewProjection", world.multiply(scene.getTransformMatrix()));
             }
+        };
 
-            for (var name in this._textures) {
-                this._effect.setTexture(name, this._textures[name]);
-            }
+        ShaderMaterial.prototype.bind = function (world) {
+            // Std values
+            this.bindOnlyWorldMatrix(world);
 
-            for (name in this._floats) {
-                this._effect.setFloat(name, this._floats[name]);
-            }
+            if (this.getScene().getCachedMaterial() !== this) {
+                if (this._options.uniforms.indexOf("view") !== -1) {
+                    this._effect.setMatrix("view", this.getScene().getViewMatrix());
+                }
 
-            for (name in this._floatsArrays) {
-                this._effect.setArray(name, this._floatsArrays[name]);
-            }
+                if (this._options.uniforms.indexOf("projection") !== -1) {
+                    this._effect.setMatrix("projection", this.getScene().getProjectionMatrix());
+                }
 
-            for (name in this._colors3) {
-                this._effect.setColor3(name, this._colors3[name]);
-            }
+                if (this._options.uniforms.indexOf("viewProjection") !== -1) {
+                    this._effect.setMatrix("viewProjection", this.getScene().getTransformMatrix());
+                }
 
-            for (name in this._colors4) {
-                var color = this._colors4[name];
-                this._effect.setFloat4(name, color.r, color.g, color.b, color.a);
-            }
+                for (var name in this._textures) {
+                    this._effect.setTexture(name, this._textures[name]);
+                }
 
-            for (name in this._vectors2) {
-                this._effect.setVector2(name, this._vectors2[name]);
-            }
+                for (name in this._floats) {
+                    this._effect.setFloat(name, this._floats[name]);
+                }
 
-            for (name in this._vectors3) {
-                this._effect.setVector3(name, this._vectors3[name]);
-            }
+                for (name in this._floatsArrays) {
+                    this._effect.setArray(name, this._floatsArrays[name]);
+                }
+
+                for (name in this._colors3) {
+                    this._effect.setColor3(name, this._colors3[name]);
+                }
+
+                for (name in this._colors4) {
+                    var color = this._colors4[name];
+                    this._effect.setFloat4(name, color.r, color.g, color.b, color.a);
+                }
 
-            for (name in this._matrices) {
-                this._effect.setMatrix(name, this._matrices[name]);
+                for (name in this._vectors2) {
+                    this._effect.setVector2(name, this._vectors2[name]);
+                }
+
+                for (name in this._vectors3) {
+                    this._effect.setVector3(name, this._vectors3[name]);
+                }
+
+                for (name in this._matrices) {
+                    this._effect.setMatrix(name, this._matrices[name]);
+                }
             }
+
+            _super.prototype.bind.call(this, world, null);
         };
 
         ShaderMaterial.prototype.dispose = function (forceDisposeEffect) {

+ 136 - 113
Babylon/Materials/babylon.standardMaterial.js

@@ -88,7 +88,7 @@ var BABYLON;
 
             // Textures
             if (scene.texturesEnabled) {
-                if (this.diffuseTexture && BABYLON.StandardMaterial.DiffuseTextureEnabled) {
+                if (this.diffuseTexture && StandardMaterial.DiffuseTextureEnabled) {
                     if (!this.diffuseTexture.isReady()) {
                         return false;
                     } else {
@@ -96,7 +96,7 @@ var BABYLON;
                     }
                 }
 
-                if (this.ambientTexture && BABYLON.StandardMaterial.AmbientTextureEnabled) {
+                if (this.ambientTexture && StandardMaterial.AmbientTextureEnabled) {
                     if (!this.ambientTexture.isReady()) {
                         return false;
                     } else {
@@ -104,7 +104,7 @@ var BABYLON;
                     }
                 }
 
-                if (this.opacityTexture && BABYLON.StandardMaterial.OpacityTextureEnabled) {
+                if (this.opacityTexture && StandardMaterial.OpacityTextureEnabled) {
                     if (!this.opacityTexture.isReady()) {
                         return false;
                     } else {
@@ -116,7 +116,7 @@ var BABYLON;
                     }
                 }
 
-                if (this.reflectionTexture && BABYLON.StandardMaterial.ReflectionTextureEnabled) {
+                if (this.reflectionTexture && StandardMaterial.ReflectionTextureEnabled) {
                     if (!this.reflectionTexture.isReady()) {
                         return false;
                     } else {
@@ -125,7 +125,7 @@ var BABYLON;
                     }
                 }
 
-                if (this.emissiveTexture && BABYLON.StandardMaterial.EmissiveTextureEnabled) {
+                if (this.emissiveTexture && StandardMaterial.EmissiveTextureEnabled) {
                     if (!this.emissiveTexture.isReady()) {
                         return false;
                     } else {
@@ -133,7 +133,7 @@ var BABYLON;
                     }
                 }
 
-                if (this.specularTexture && BABYLON.StandardMaterial.SpecularTextureEnabled) {
+                if (this.specularTexture && StandardMaterial.SpecularTextureEnabled) {
                     if (!this.specularTexture.isReady()) {
                         return false;
                     } else {
@@ -143,7 +143,7 @@ var BABYLON;
                 }
             }
 
-            if (scene.getEngine().getCaps().standardDerivatives && this.bumpTexture && BABYLON.StandardMaterial.BumpTextureEnabled) {
+            if (scene.getEngine().getCaps().standardDerivatives && this.bumpTexture && StandardMaterial.BumpTextureEnabled) {
                 if (!this.bumpTexture.isReady()) {
                     return false;
                 } else {
@@ -171,12 +171,12 @@ var BABYLON;
             }
 
             // Point size
-            if (this.pointsCloud) {
+            if (this.pointsCloud || scene.forcePointsCloud) {
                 defines.push("#define POINTSIZE");
             }
 
             // Fog
-            if (scene.fogMode !== BABYLON.Scene.FOGMODE_NONE && this.fogEnabled) {
+            if (scene.fogEnabled && mesh && mesh.applyFog && scene.fogMode !== BABYLON.Scene.FOGMODE_NONE && this.fogEnabled) {
                 defines.push("#define FOG");
                 fallbacks.addFallback(1, "FOG");
             }
@@ -270,41 +270,43 @@ var BABYLON;
                     }
 
                     lightIndex++;
-                    if (lightIndex == maxSimultaneousLights)
+                    if (lightIndex === maxSimultaneousLights)
                         break;
                 }
             }
 
-            // Fresnel
-            if (this.diffuseFresnelParameters && this.diffuseFresnelParameters.isEnabled || this.opacityFresnelParameters && this.opacityFresnelParameters.isEnabled || this.emissiveFresnelParameters && this.emissiveFresnelParameters.isEnabled || this.reflectionFresnelParameters && this.reflectionFresnelParameters.isEnabled) {
-                var fresnelRank = 1;
+            if (StandardMaterial.FresnelEnabled) {
+                // Fresnel
+                if (this.diffuseFresnelParameters && this.diffuseFresnelParameters.isEnabled || this.opacityFresnelParameters && this.opacityFresnelParameters.isEnabled || this.emissiveFresnelParameters && this.emissiveFresnelParameters.isEnabled || this.reflectionFresnelParameters && this.reflectionFresnelParameters.isEnabled) {
+                    var fresnelRank = 1;
 
-                if (this.diffuseFresnelParameters && this.diffuseFresnelParameters.isEnabled) {
-                    defines.push("#define DIFFUSEFRESNEL");
-                    fallbacks.addFallback(fresnelRank, "DIFFUSEFRESNEL");
-                    fresnelRank++;
-                }
+                    if (this.diffuseFresnelParameters && this.diffuseFresnelParameters.isEnabled) {
+                        defines.push("#define DIFFUSEFRESNEL");
+                        fallbacks.addFallback(fresnelRank, "DIFFUSEFRESNEL");
+                        fresnelRank++;
+                    }
 
-                if (this.opacityFresnelParameters && this.opacityFresnelParameters.isEnabled) {
-                    defines.push("#define OPACITYFRESNEL");
-                    fallbacks.addFallback(fresnelRank, "OPACITYFRESNEL");
-                    fresnelRank++;
-                }
+                    if (this.opacityFresnelParameters && this.opacityFresnelParameters.isEnabled) {
+                        defines.push("#define OPACITYFRESNEL");
+                        fallbacks.addFallback(fresnelRank, "OPACITYFRESNEL");
+                        fresnelRank++;
+                    }
 
-                if (this.reflectionFresnelParameters && this.reflectionFresnelParameters.isEnabled) {
-                    defines.push("#define REFLECTIONFRESNEL");
-                    fallbacks.addFallback(fresnelRank, "REFLECTIONFRESNEL");
-                    fresnelRank++;
-                }
+                    if (this.reflectionFresnelParameters && this.reflectionFresnelParameters.isEnabled) {
+                        defines.push("#define REFLECTIONFRESNEL");
+                        fallbacks.addFallback(fresnelRank, "REFLECTIONFRESNEL");
+                        fresnelRank++;
+                    }
 
-                if (this.emissiveFresnelParameters && this.emissiveFresnelParameters.isEnabled) {
-                    defines.push("#define EMISSIVEFRESNEL");
-                    fallbacks.addFallback(fresnelRank, "EMISSIVEFRESNEL");
-                    fresnelRank++;
-                }
+                    if (this.emissiveFresnelParameters && this.emissiveFresnelParameters.isEnabled) {
+                        defines.push("#define EMISSIVEFRESNEL");
+                        fallbacks.addFallback(fresnelRank, "EMISSIVEFRESNEL");
+                        fresnelRank++;
+                    }
 
-                defines.push("#define FRESNEL");
-                fallbacks.addFallback(fresnelRank - 1, "FRESNEL");
+                    defines.push("#define FRESNEL");
+                    fallbacks.addFallback(fresnelRank - 1, "FRESNEL");
+                }
             }
 
             // Attribs
@@ -318,7 +320,7 @@ var BABYLON;
                     attribs.push(BABYLON.VertexBuffer.UV2Kind);
                     defines.push("#define UV2");
                 }
-                if (mesh.isVerticesDataPresent(BABYLON.VertexBuffer.ColorKind)) {
+                if (mesh.useVertexColors && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.ColorKind)) {
                     attribs.push(BABYLON.VertexBuffer.ColorKind);
                     defines.push("#define VERTEXCOLOR");
 
@@ -326,7 +328,7 @@ var BABYLON;
                         defines.push("#define VERTEXALPHA");
                     }
                 }
-                if (mesh.skeleton && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesIndicesKind) && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesWeightsKind)) {
+                if (mesh.skeleton && scene.skeletonsEnabled && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesIndicesKind) && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesWeightsKind)) {
                     attribs.push(BABYLON.VertexBuffer.MatricesIndicesKind);
                     attribs.push(BABYLON.VertexBuffer.MatricesWeightsKind);
                     defines.push("#define BONES");
@@ -347,9 +349,11 @@ var BABYLON;
 
             // Get correct effect
             var join = defines.join("\n");
-            if (this._cachedDefines != join) {
+            if (this._cachedDefines !== join) {
                 this._cachedDefines = join;
 
+                scene.resetCachedMaterial();
+
                 // Legacy browser patch
                 var shaderName = "default";
                 if (!scene.getEngine().getCaps().standardDerivatives) {
@@ -400,92 +404,118 @@ var BABYLON;
             this._effect.setMatrix("viewProjection", scene.getTransformMatrix());
 
             // Bones
-            if (mesh.skeleton && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesIndicesKind) && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesWeightsKind)) {
+            if (mesh.skeleton && scene.skeletonsEnabled && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesIndicesKind) && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesWeightsKind)) {
                 this._effect.setMatrices("mBones", mesh.skeleton.getTransformMatrices());
             }
 
-            // Fresnel
-            if (this.diffuseFresnelParameters && this.diffuseFresnelParameters.isEnabled) {
-                this._effect.setColor4("diffuseLeftColor", this.diffuseFresnelParameters.leftColor, this.diffuseFresnelParameters.power);
-                this._effect.setColor4("diffuseRightColor", this.diffuseFresnelParameters.rightColor, this.diffuseFresnelParameters.bias);
-            }
+            if (scene.getCachedMaterial() !== this) {
+                if (StandardMaterial.FresnelEnabled) {
+                    // Fresnel
+                    if (this.diffuseFresnelParameters && this.diffuseFresnelParameters.isEnabled) {
+                        this._effect.setColor4("diffuseLeftColor", this.diffuseFresnelParameters.leftColor, this.diffuseFresnelParameters.power);
+                        this._effect.setColor4("diffuseRightColor", this.diffuseFresnelParameters.rightColor, this.diffuseFresnelParameters.bias);
+                    }
 
-            if (this.opacityFresnelParameters && this.opacityFresnelParameters.isEnabled) {
-                this._effect.setColor4("opacityParts", new BABYLON.Color3(this.opacityFresnelParameters.leftColor.toLuminance(), this.opacityFresnelParameters.rightColor.toLuminance(), this.opacityFresnelParameters.bias), this.opacityFresnelParameters.power);
-            }
+                    if (this.opacityFresnelParameters && this.opacityFresnelParameters.isEnabled) {
+                        this._effect.setColor4("opacityParts", new BABYLON.Color3(this.opacityFresnelParameters.leftColor.toLuminance(), this.opacityFresnelParameters.rightColor.toLuminance(), this.opacityFresnelParameters.bias), this.opacityFresnelParameters.power);
+                    }
 
-            if (this.reflectionFresnelParameters && this.reflectionFresnelParameters.isEnabled) {
-                this._effect.setColor4("reflectionLeftColor", this.reflectionFresnelParameters.leftColor, this.reflectionFresnelParameters.power);
-                this._effect.setColor4("reflectionRightColor", this.reflectionFresnelParameters.rightColor, this.reflectionFresnelParameters.bias);
-            }
+                    if (this.reflectionFresnelParameters && this.reflectionFresnelParameters.isEnabled) {
+                        this._effect.setColor4("reflectionLeftColor", this.reflectionFresnelParameters.leftColor, this.reflectionFresnelParameters.power);
+                        this._effect.setColor4("reflectionRightColor", this.reflectionFresnelParameters.rightColor, this.reflectionFresnelParameters.bias);
+                    }
 
-            if (this.emissiveFresnelParameters && this.emissiveFresnelParameters.isEnabled) {
-                this._effect.setColor4("emissiveLeftColor", this.emissiveFresnelParameters.leftColor, this.emissiveFresnelParameters.power);
-                this._effect.setColor4("emissiveRightColor", this.emissiveFresnelParameters.rightColor, this.emissiveFresnelParameters.bias);
-            }
+                    if (this.emissiveFresnelParameters && this.emissiveFresnelParameters.isEnabled) {
+                        this._effect.setColor4("emissiveLeftColor", this.emissiveFresnelParameters.leftColor, this.emissiveFresnelParameters.power);
+                        this._effect.setColor4("emissiveRightColor", this.emissiveFresnelParameters.rightColor, this.emissiveFresnelParameters.bias);
+                    }
+                }
 
-            // Textures
-            if (this.diffuseTexture && BABYLON.StandardMaterial.DiffuseTextureEnabled) {
-                this._effect.setTexture("diffuseSampler", this.diffuseTexture);
+                // Textures
+                if (this.diffuseTexture && StandardMaterial.DiffuseTextureEnabled) {
+                    this._effect.setTexture("diffuseSampler", this.diffuseTexture);
 
-                this._effect.setFloat2("vDiffuseInfos", this.diffuseTexture.coordinatesIndex, this.diffuseTexture.level);
-                this._effect.setMatrix("diffuseMatrix", this.diffuseTexture.getTextureMatrix());
-            }
+                    this._effect.setFloat2("vDiffuseInfos", this.diffuseTexture.coordinatesIndex, this.diffuseTexture.level);
+                    this._effect.setMatrix("diffuseMatrix", this.diffuseTexture.getTextureMatrix());
+                }
 
-            if (this.ambientTexture && BABYLON.StandardMaterial.AmbientTextureEnabled) {
-                this._effect.setTexture("ambientSampler", this.ambientTexture);
+                if (this.ambientTexture && StandardMaterial.AmbientTextureEnabled) {
+                    this._effect.setTexture("ambientSampler", this.ambientTexture);
 
-                this._effect.setFloat2("vAmbientInfos", this.ambientTexture.coordinatesIndex, this.ambientTexture.level);
-                this._effect.setMatrix("ambientMatrix", this.ambientTexture.getTextureMatrix());
-            }
+                    this._effect.setFloat2("vAmbientInfos", this.ambientTexture.coordinatesIndex, this.ambientTexture.level);
+                    this._effect.setMatrix("ambientMatrix", this.ambientTexture.getTextureMatrix());
+                }
 
-            if (this.opacityTexture && BABYLON.StandardMaterial.OpacityTextureEnabled) {
-                this._effect.setTexture("opacitySampler", this.opacityTexture);
+                if (this.opacityTexture && StandardMaterial.OpacityTextureEnabled) {
+                    this._effect.setTexture("opacitySampler", this.opacityTexture);
 
-                this._effect.setFloat2("vOpacityInfos", this.opacityTexture.coordinatesIndex, this.opacityTexture.level);
-                this._effect.setMatrix("opacityMatrix", this.opacityTexture.getTextureMatrix());
-            }
+                    this._effect.setFloat2("vOpacityInfos", this.opacityTexture.coordinatesIndex, this.opacityTexture.level);
+                    this._effect.setMatrix("opacityMatrix", this.opacityTexture.getTextureMatrix());
+                }
 
-            if (this.reflectionTexture && BABYLON.StandardMaterial.ReflectionTextureEnabled) {
-                if (this.reflectionTexture.isCube) {
-                    this._effect.setTexture("reflectionCubeSampler", this.reflectionTexture);
-                } else {
-                    this._effect.setTexture("reflection2DSampler", this.reflectionTexture);
+                if (this.reflectionTexture && StandardMaterial.ReflectionTextureEnabled) {
+                    if (this.reflectionTexture.isCube) {
+                        this._effect.setTexture("reflectionCubeSampler", this.reflectionTexture);
+                    } else {
+                        this._effect.setTexture("reflection2DSampler", this.reflectionTexture);
+                    }
+
+                    this._effect.setMatrix("reflectionMatrix", this.reflectionTexture.getReflectionTextureMatrix());
+                    this._effect.setFloat3("vReflectionInfos", this.reflectionTexture.coordinatesMode, this.reflectionTexture.level, this.reflectionTexture.isCube ? 1 : 0);
                 }
 
-                this._effect.setMatrix("reflectionMatrix", this.reflectionTexture.getReflectionTextureMatrix());
-                this._effect.setFloat3("vReflectionInfos", this.reflectionTexture.coordinatesMode, this.reflectionTexture.level, this.reflectionTexture.isCube ? 1 : 0);
-            }
+                if (this.emissiveTexture && StandardMaterial.EmissiveTextureEnabled) {
+                    this._effect.setTexture("emissiveSampler", this.emissiveTexture);
 
-            if (this.emissiveTexture && BABYLON.StandardMaterial.EmissiveTextureEnabled) {
-                this._effect.setTexture("emissiveSampler", this.emissiveTexture);
+                    this._effect.setFloat2("vEmissiveInfos", this.emissiveTexture.coordinatesIndex, this.emissiveTexture.level);
+                    this._effect.setMatrix("emissiveMatrix", this.emissiveTexture.getTextureMatrix());
+                }
 
-                this._effect.setFloat2("vEmissiveInfos", this.emissiveTexture.coordinatesIndex, this.emissiveTexture.level);
-                this._effect.setMatrix("emissiveMatrix", this.emissiveTexture.getTextureMatrix());
-            }
+                if (this.specularTexture && StandardMaterial.SpecularTextureEnabled) {
+                    this._effect.setTexture("specularSampler", this.specularTexture);
 
-            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.getTextureMatrix());
+                }
 
-                this._effect.setFloat2("vSpecularInfos", this.specularTexture.coordinatesIndex, this.specularTexture.level);
-                this._effect.setMatrix("specularMatrix", this.specularTexture.getTextureMatrix());
-            }
+                if (this.bumpTexture && scene.getEngine().getCaps().standardDerivatives && StandardMaterial.BumpTextureEnabled) {
+                    this._effect.setTexture("bumpSampler", this.bumpTexture);
 
-            if (this.bumpTexture && scene.getEngine().getCaps().standardDerivatives && BABYLON.StandardMaterial.BumpTextureEnabled) {
-                this._effect.setTexture("bumpSampler", this.bumpTexture);
+                    this._effect.setFloat2("vBumpInfos", this.bumpTexture.coordinatesIndex, 1.0 / this.bumpTexture.level);
+                    this._effect.setMatrix("bumpMatrix", this.bumpTexture.getTextureMatrix());
+                }
 
-                this._effect.setFloat2("vBumpInfos", this.bumpTexture.coordinatesIndex, this.bumpTexture.level);
-                this._effect.setMatrix("bumpMatrix", this.bumpTexture.getTextureMatrix());
+                // Clip plane
+                if (scene.clipPlane) {
+                    var clipPlane = scene.clipPlane;
+                    this._effect.setFloat4("vClipPlane", clipPlane.normal.x, clipPlane.normal.y, clipPlane.normal.z, clipPlane.d);
+                }
+
+                // Point size
+                if (this.pointsCloud) {
+                    this._effect.setFloat("pointSize", this.pointSize);
+                }
+
+                // Colors
+                scene.ambientColor.multiplyToRef(this.ambientColor, this._globalAmbientColor);
+
+                // Scaling down color according to emissive
+                this._scaledSpecular.r = this.specularColor.r * BABYLON.Tools.Clamp(1.0 - this.emissiveColor.r);
+                this._scaledSpecular.g = this.specularColor.g * BABYLON.Tools.Clamp(1.0 - this.emissiveColor.g);
+                this._scaledSpecular.b = this.specularColor.b * BABYLON.Tools.Clamp(1.0 - this.emissiveColor.b);
+
+                this._effect.setVector3("vEyePosition", scene.activeCamera.position);
+                this._effect.setColor3("vAmbientColor", this._globalAmbientColor);
+                this._effect.setColor4("vSpecularColor", this._scaledSpecular, this.specularPower);
+                this._effect.setColor3("vEmissiveColor", this.emissiveColor);
             }
 
-            // Colors
-            scene.ambientColor.multiplyToRef(this.ambientColor, this._globalAmbientColor);
+            // Scaling down color according to emissive
+            this._scaledDiffuse.r = this.diffuseColor.r * BABYLON.Tools.Clamp(1.0 - this.emissiveColor.r);
+            this._scaledDiffuse.g = this.diffuseColor.g * BABYLON.Tools.Clamp(1.0 - this.emissiveColor.g);
+            this._scaledDiffuse.b = this.diffuseColor.b * BABYLON.Tools.Clamp(1.0 - this.emissiveColor.b);
 
-            this._effect.setVector3("vEyePosition", scene.activeCamera.position);
-            this._effect.setColor3("vAmbientColor", this._globalAmbientColor);
-            this._effect.setColor4("vDiffuseColor", this.diffuseColor, this.alpha * mesh.visibility);
-            this._effect.setColor4("vSpecularColor", this.specularColor, this.specularPower);
-            this._effect.setColor3("vEmissiveColor", this.emissiveColor);
+            this._effect.setColor4("vDiffuseColor", this._scaledDiffuse, this.alpha * mesh.visibility);
 
             if (scene.lightsEnabled) {
                 var lightIndex = 0;
@@ -531,31 +561,23 @@ var BABYLON;
 
                     lightIndex++;
 
-                    if (lightIndex == maxSimultaneousLights)
+                    if (lightIndex === maxSimultaneousLights)
                         break;
                 }
             }
 
-            if (scene.clipPlane) {
-                var clipPlane = scene.clipPlane;
-                this._effect.setFloat4("vClipPlane", clipPlane.normal.x, clipPlane.normal.y, clipPlane.normal.z, clipPlane.d);
-            }
-
             // View
-            if (scene.fogMode !== BABYLON.Scene.FOGMODE_NONE || this.reflectionTexture) {
+            if (scene.fogEnabled && mesh.applyFog && scene.fogMode !== BABYLON.Scene.FOGMODE_NONE || this.reflectionTexture) {
                 this._effect.setMatrix("view", scene.getViewMatrix());
             }
 
             // Fog
-            if (scene.fogMode !== BABYLON.Scene.FOGMODE_NONE) {
+            if (scene.fogEnabled && mesh.applyFog && scene.fogMode !== BABYLON.Scene.FOGMODE_NONE) {
                 this._effect.setFloat4("vFogInfos", scene.fogMode, scene.fogStart, scene.fogEnd, scene.fogDensity);
                 this._effect.setColor3("vFogColor", scene.fogColor);
             }
 
-            // Point size
-            if (this.pointsCloud) {
-                this._effect.setFloat("pointSize", this.pointSize);
-            }
+            _super.prototype.bind.call(this, world, mesh);
         };
 
         StandardMaterial.prototype.getAnimatables = function () {
@@ -625,7 +647,7 @@ var BABYLON;
         };
 
         StandardMaterial.prototype.clone = function (name) {
-            var newStandardMaterial = new BABYLON.StandardMaterial(name, this.getScene());
+            var newStandardMaterial = new StandardMaterial(name, this.getScene());
 
             // Base material
             newStandardMaterial.checkReadyOnEveryCall = this.checkReadyOnEveryCall;
@@ -672,6 +694,7 @@ var BABYLON;
         StandardMaterial.EmissiveTextureEnabled = true;
         StandardMaterial.SpecularTextureEnabled = true;
         StandardMaterial.BumpTextureEnabled = true;
+        StandardMaterial.FresnelEnabled = true;
         return StandardMaterial;
     })(BABYLON.Material);
     BABYLON.StandardMaterial = StandardMaterial;

+ 69 - 51
Babylon/Materials/textures/Procedurals/babylon.customProceduralTexture.js

@@ -9,42 +9,43 @@ var BABYLON;
     var CustomProceduralTexture = (function (_super) {
         __extends(CustomProceduralTexture, _super);
         function CustomProceduralTexture(name, texturePath, size, scene, fallbackTexture, generateMipMaps) {
-            _super.call(this, name, size, "empty", scene, fallbackTexture, generateMipMaps);
-            this._generateTime = true;
+            _super.call(this, name, size, null, scene, fallbackTexture, generateMipMaps);
+            this._animate = true;
             this._time = 0;
-            this._shaderLoaded = false;
-
             this._texturePath = texturePath;
 
-            //readJson
+            //Try to load json
             this.loadJson(texturePath);
-
-            // Use 0 to render just once, 1 to render on every frame, 2 to render every two frames and so on...
-            this.refreshRate = 0;
+            this.refreshRate = 1;
         }
         CustomProceduralTexture.prototype.loadJson = function (jsonUrl) {
             var _this = this;
+            var that = this;
+
             function noConfigFile() {
-                BABYLON.Tools.Log("No config file found in " + jsonUrl);
+                BABYLON.Tools.Log("No config file found in " + jsonUrl + " trying to use ShaderStore or DOM element");
+                try  {
+                    that.setFragment(that._texturePath);
+                } catch (ex) {
+                    BABYLON.Tools.Error("No json or ShaderStore or DOM element found for CustomProceduralTexture");
+                }
             }
 
-            var that = this;
             var configFileUrl = jsonUrl + "/config.json";
-
             var xhr = new XMLHttpRequest();
 
             xhr.open("GET", configFileUrl, true);
             xhr.addEventListener("load", function () {
                 if (xhr.status === 200 || BABYLON.Tools.ValidateXHRData(xhr, 1)) {
                     try  {
-                        that._config = JSON.parse(xhr.response);
-                        that.updateShaderUniforms();
-                        that.setFragment(jsonUrl + "/custom");
-                        that._generateTime = that._config.generateTime;
-                        if (that._generateTime)
-                            _this.refreshRate = 1;
-                        that._shaderLoaded = true;
-                        that.render();
+                        _this._config = JSON.parse(xhr.response);
+
+                        _this.updateShaderUniforms();
+                        _this.updateTextures();
+                        _this.setFragment(_this._texturePath + "/custom");
+
+                        _this._animate = _this._config.animate;
+                        _this.refreshRate = _this._config.refreshrate;
                     } catch (ex) {
                         noConfigFile();
                     }
@@ -60,16 +61,28 @@ var BABYLON;
             try  {
                 xhr.send();
             } catch (ex) {
-                BABYLON.Tools.Error("Error on XHR send request.");
+                BABYLON.Tools.Error("CustomProceduralTexture: Error on XHR send request.");
             }
         };
 
-        CustomProceduralTexture.prototype.render = function (useCameraPostProcess) {
-            //if config and shader not loaded, do not render
-            if (!this._shaderLoaded)
-                return;
+        CustomProceduralTexture.prototype.isReady = function () {
+            if (!_super.prototype.isReady.call(this)) {
+                return false;
+            }
+
+            for (var name in this._textures) {
+                var texture = this._textures[name];
 
-            if (this._generateTime) {
+                if (!texture.isReady()) {
+                    return false;
+                }
+            }
+
+            return true;
+        };
+
+        CustomProceduralTexture.prototype.render = function (useCameraPostProcess) {
+            if (this._animate) {
                 this._time += this.getScene().getAnimationRatio() * 0.03;
                 this.updateShaderUniforms();
             }
@@ -77,41 +90,46 @@ var BABYLON;
             _super.prototype.render.call(this, useCameraPostProcess);
         };
 
-        CustomProceduralTexture.prototype.updateShaderUniforms = function () {
-            for (var i = 0; i < this._config.texture2Ds.length; i++) {
-                this.setTexture(this._config.texture2Ds[i].textureName, new BABYLON.Texture(this._texturePath + "/" + this._config.texture2Ds[i].textureRelativeUrl, this.getScene()));
+        CustomProceduralTexture.prototype.updateTextures = function () {
+            for (var i = 0; i < this._config.sampler2Ds.length; i++) {
+                this.setTexture(this._config.sampler2Ds[i].sample2Dname, new BABYLON.Texture(this._texturePath + "/" + this._config.sampler2Ds[i].textureRelativeUrl, this.getScene()));
             }
+        };
 
-            for (var j = 0; j < this._config.uniforms.length; j++) {
-                var uniform = this._config.uniforms[j];
-
-                switch (uniform.type) {
-                    case "float":
-                        this.setFloat(uniform.name, uniform.value);
-                        break;
-                    case "color3":
-                        this.setColor3(uniform.name, new BABYLON.Color3(uniform.r, uniform.g, uniform.b));
-                        break;
-                    case "color4":
-                        this.setColor4(uniform.name, new BABYLON.Color4(uniform.r, uniform.g, uniform.b, uniform.a));
-                        break;
-                    case "vector2":
-                        this.setVector2(uniform.name, new BABYLON.Vector2(uniform.x, uniform.y));
-                        break;
-                    case "vector3":
-                        this.setVector3(uniform.name, new BABYLON.Vector3(uniform.x, uniform.y, uniform.z));
-                        break;
+        CustomProceduralTexture.prototype.updateShaderUniforms = function () {
+            if (this._config) {
+                for (var j = 0; j < this._config.uniforms.length; j++) {
+                    var uniform = this._config.uniforms[j];
+
+                    switch (uniform.type) {
+                        case "float":
+                            this.setFloat(uniform.name, uniform.value);
+                            break;
+                        case "color3":
+                            this.setColor3(uniform.name, new BABYLON.Color3(uniform.r, uniform.g, uniform.b));
+                            break;
+                        case "color4":
+                            this.setColor4(uniform.name, new BABYLON.Color4(uniform.r, uniform.g, uniform.b, uniform.a));
+                            break;
+                        case "vector2":
+                            this.setVector2(uniform.name, new BABYLON.Vector2(uniform.x, uniform.y));
+                            break;
+                        case "vector3":
+                            this.setVector3(uniform.name, new BABYLON.Vector3(uniform.x, uniform.y, uniform.z));
+                            break;
+                    }
                 }
             }
+
+            this.setFloat("time", this._time);
         };
 
-        Object.defineProperty(CustomProceduralTexture.prototype, "generateTime", {
+        Object.defineProperty(CustomProceduralTexture.prototype, "animate", {
             get: function () {
-                return this.generateTime;
+                return this._animate;
             },
             set: function (value) {
-                this.generateTime = value;
-                this.updateShaderUniforms();
+                this._animate = value;
             },
             enumerable: true,
             configurable: true

+ 43 - 6
Babylon/Materials/textures/Procedurals/babylon.proceduralTexture.js

@@ -9,6 +9,7 @@ var BABYLON;
     var ProceduralTexture = (function (_super) {
         __extends(ProceduralTexture, _super);
         function ProceduralTexture(name, size, fragment, scene, fallbackTexture, generateMipMaps) {
+            if (typeof generateMipMaps === "undefined") { generateMipMaps = true; }
             _super.call(this, null, scene, !generateMipMaps);
             this._currentRefreshId = -1;
             this._refreshRate = 1;
@@ -24,6 +25,7 @@ var BABYLON;
             this._vectors2 = new Array();
             this._vectors3 = new Array();
             this._matrices = new Array();
+            this._fallbackTextureUsed = false;
 
             scene._proceduralTextures.push(this);
 
@@ -32,7 +34,7 @@ var BABYLON;
             this._size = size;
             this._generateMipMaps = generateMipMaps;
 
-            this._fragment = fragment;
+            this.setFragment(fragment);
 
             this._fallbackTexture = fallbackTexture;
 
@@ -59,15 +61,42 @@ var BABYLON;
 
             this._indexBuffer = scene.getEngine().createIndexBuffer(indices);
         }
+        ProceduralTexture.prototype.reset = function () {
+            if (this._effect === undefined) {
+                return;
+            }
+            var engine = this.getScene().getEngine();
+            engine._releaseEffect(this._effect);
+        };
+
         ProceduralTexture.prototype.isReady = function () {
             var _this = this;
             var engine = this.getScene().getEngine();
+            var shaders;
 
-            this._effect = engine.createEffect({ vertex: "procedural", fragment: this._fragment }, ["position"], this._uniforms, this._samplers, "", null, null, function () {
+            if (!this._fragment) {
+                return false;
+            }
+
+            if (this._fallbackTextureUsed) {
+                return true;
+            }
+
+            if (this._fragment.fragmentElement !== undefined) {
+                shaders = { vertex: "procedural", fragmentElement: this._fragment.fragmentElement };
+            } else {
+                shaders = { vertex: "procedural", fragment: this._fragment };
+            }
+
+            this._effect = engine.createEffect(shaders, ["position"], this._uniforms, this._samplers, "", null, null, function () {
                 _this.releaseInternalTexture();
 
-                _this._texture = _this._fallbackTexture._texture;
-                _this._texture.references++;
+                if (_this._fallbackTexture) {
+                    _this._texture = _this._fallbackTexture._texture;
+                    _this._texture.references++;
+                }
+
+                _this._fallbackTextureUsed = true;
             });
 
             return this._effect.isReady();
@@ -100,12 +129,16 @@ var BABYLON;
                 return false;
             }
 
+            if (this._fallbackTextureUsed) {
+                return false;
+            }
+
             if (this._currentRefreshId === -1) {
                 this._currentRefreshId = 1;
                 return true;
             }
 
-            if (this.refreshRate == this._currentRefreshId) {
+            if (this.refreshRate === this._currentRefreshId) {
                 this._currentRefreshId = 1;
                 return true;
             }
@@ -119,6 +152,10 @@ var BABYLON;
         };
 
         ProceduralTexture.prototype.resize = function (size, generateMipMaps) {
+            if (this._fallbackTextureUsed) {
+                return;
+            }
+
             this.releaseInternalTexture();
             this._texture = this.getScene().getEngine().createRenderTargetTexture(size, generateMipMaps);
         };
@@ -245,7 +282,7 @@ var BABYLON;
 
         ProceduralTexture.prototype.clone = function () {
             var textureSize = this.getSize();
-            var newTexture = new BABYLON.ProceduralTexture(this.name, textureSize.width, this._fragment, this.getScene(), this._fallbackTexture, this._generateMipMaps);
+            var newTexture = new ProceduralTexture(this.name, textureSize.width, this._fragment, this.getScene(), this._fallbackTexture, this._generateMipMaps);
 
             // Base texture
             newTexture.hasAlpha = this.hasAlpha;

+ 166 - 80
Babylon/Materials/textures/Procedurals/babylon.standardProceduralTexture.js

@@ -12,10 +12,7 @@ var BABYLON;
             _super.call(this, name, size, "wood", scene, fallbackTexture, generateMipMaps);
             this._ampScale = 100.0;
             this._woodColor = new BABYLON.Color3(0.32, 0.17, 0.09);
-
             this.updateShaderUniforms();
-
-            // Use 0 to render just once, 1 to render on every frame, 2 to render every two frames and so on...
             this.refreshRate = 0;
         }
         WoodProceduralTexture.prototype.updateShaderUniforms = function () {
@@ -59,27 +56,23 @@ var BABYLON;
             this._time = 0.0;
             this._speed = new BABYLON.Vector2(0.5, 0.3);
             this._shift = 1.6;
-            this._alpha = 1.0;
             this._autoGenerateTime = true;
-
+            this._alphaThreshold = 0.5;
             this._fireColors = FireProceduralTexture.RedFireColors;
             this.updateShaderUniforms();
-
-            // Use 0 to render just once, 1 to render on every frame, 2 to render every two frames and so on...
             this.refreshRate = 1;
         }
         FireProceduralTexture.prototype.updateShaderUniforms = function () {
-            this.setFloat("iGlobalTime", this._time);
+            this.setFloat("time", this._time);
             this.setVector2("speed", this._speed);
             this.setFloat("shift", this._shift);
-            this.setFloat("alpha", this._alpha);
-
-            this.setColor3("c1", new BABYLON.Color3(this._fireColors[0][0], this._fireColors[0][1], this._fireColors[0][2]));
-            this.setColor3("c2", new BABYLON.Color3(this._fireColors[1][0], this._fireColors[1][1], this._fireColors[1][2]));
-            this.setColor3("c3", new BABYLON.Color3(this._fireColors[2][0], this._fireColors[2][1], this._fireColors[2][2]));
-            this.setColor3("c4", new BABYLON.Color3(this._fireColors[3][0], this._fireColors[3][1], this._fireColors[3][2]));
-            this.setColor3("c5", new BABYLON.Color3(this._fireColors[4][0], this._fireColors[4][1], this._fireColors[4][2]));
-            this.setColor3("c6", new BABYLON.Color3(this._fireColors[5][0], this._fireColors[5][1], this._fireColors[5][2]));
+            this.setColor3("c1", this._fireColors[0]);
+            this.setColor3("c2", this._fireColors[1]);
+            this.setColor3("c3", this._fireColors[2]);
+            this.setColor3("c4", this._fireColors[3]);
+            this.setColor3("c5", this._fireColors[4]);
+            this.setColor3("c6", this._fireColors[5]);
+            this.setFloat("alphaThreshold", this._alphaThreshold);
         };
 
         FireProceduralTexture.prototype.render = function (useCameraPostProcess) {
@@ -87,19 +80,18 @@ var BABYLON;
                 this._time += this.getScene().getAnimationRatio() * 0.03;
                 this.updateShaderUniforms();
             }
-
             _super.prototype.render.call(this, useCameraPostProcess);
         };
 
         Object.defineProperty(FireProceduralTexture, "PurpleFireColors", {
             get: function () {
                 return [
-                    [0.5, 0.0, 1.0],
-                    [0.9, 0.0, 1.0],
-                    [0.2, 0.0, 1.0],
-                    [1.0, 0.9, 1.0],
-                    [0.1, 0.1, 1.0],
-                    [0.9, 0.9, 1.0]
+                    new BABYLON.Color3(0.5, 0.0, 1.0),
+                    new BABYLON.Color3(0.9, 0.0, 1.0),
+                    new BABYLON.Color3(0.2, 0.0, 1.0),
+                    new BABYLON.Color3(1.0, 0.9, 1.0),
+                    new BABYLON.Color3(0.1, 0.1, 1.0),
+                    new BABYLON.Color3(0.9, 0.9, 1.0)
                 ];
             },
             enumerable: true,
@@ -109,12 +101,12 @@ var BABYLON;
         Object.defineProperty(FireProceduralTexture, "GreenFireColors", {
             get: function () {
                 return [
-                    [0.5, 1.0, 0.0],
-                    [0.5, 1.0, 0.0],
-                    [0.3, 0.4, 0.0],
-                    [0.5, 1.0, 0.0],
-                    [0.2, 0.0, 0.0],
-                    [0.5, 1.0, 0.0]
+                    new BABYLON.Color3(0.5, 1.0, 0.0),
+                    new BABYLON.Color3(0.5, 1.0, 0.0),
+                    new BABYLON.Color3(0.3, 0.4, 0.0),
+                    new BABYLON.Color3(0.5, 1.0, 0.0),
+                    new BABYLON.Color3(0.2, 0.0, 0.0),
+                    new BABYLON.Color3(0.5, 1.0, 0.0)
                 ];
             },
             enumerable: true,
@@ -124,12 +116,12 @@ var BABYLON;
         Object.defineProperty(FireProceduralTexture, "RedFireColors", {
             get: function () {
                 return [
-                    [0.5, 0.0, 0.1],
-                    [0.9, 0.0, 0.0],
-                    [0.2, 0.0, 0.0],
-                    [1.0, 0.9, 0.0],
-                    [0.1, 0.1, 0.1],
-                    [0.9, 0.9, 0.9]
+                    new BABYLON.Color3(0.5, 0.0, 0.1),
+                    new BABYLON.Color3(0.9, 0.0, 0.0),
+                    new BABYLON.Color3(0.2, 0.0, 0.0),
+                    new BABYLON.Color3(1.0, 0.9, 0.0),
+                    new BABYLON.Color3(0.1, 0.1, 0.1),
+                    new BABYLON.Color3(0.9, 0.9, 0.9)
                 ];
             },
             enumerable: true,
@@ -139,12 +131,12 @@ var BABYLON;
         Object.defineProperty(FireProceduralTexture, "BlueFireColors", {
             get: function () {
                 return [
-                    [0.1, 0.0, 0.5],
-                    [0.0, 0.0, 0.5],
-                    [0.1, 0.0, 0.2],
-                    [0.0, 0.0, 1.0],
-                    [0.1, 0.2, 0.3],
-                    [0.0, 0.2, 0.9]
+                    new BABYLON.Color3(0.1, 0.0, 0.5),
+                    new BABYLON.Color3(0.0, 0.0, 0.5),
+                    new BABYLON.Color3(0.1, 0.0, 0.2),
+                    new BABYLON.Color3(0.0, 0.0, 1.0),
+                    new BABYLON.Color3(0.1, 0.2, 0.3),
+                    new BABYLON.Color3(0.0, 0.2, 0.9)
                 ];
             },
             enumerable: true,
@@ -203,12 +195,12 @@ var BABYLON;
         });
 
 
-        Object.defineProperty(FireProceduralTexture.prototype, "alpha", {
+        Object.defineProperty(FireProceduralTexture.prototype, "alphaThreshold", {
             get: function () {
-                return this._alpha;
+                return this._alphaThreshold;
             },
             set: function (value) {
-                this._alpha = value;
+                this._alphaThreshold = value;
                 this.updateShaderUniforms();
             },
             enumerable: true,
@@ -225,12 +217,8 @@ var BABYLON;
             _super.call(this, name, size, "cloud", scene, fallbackTexture, generateMipMaps);
             this._skyColor = new BABYLON.Color3(0.15, 0.68, 1.0);
             this._cloudColor = new BABYLON.Color3(1, 1, 1);
-
             this.updateShaderUniforms();
-
-            // Use 0 to render just once, 1 to render on every frame, 2 to render every two frames and so on...
             this.refreshRate = 0;
-            // https://www.shadertoy.com/view/XsjSRt
         }
         CloudProceduralTexture.prototype.updateShaderUniforms = function () {
             this.setColor3("skyColor", this._skyColor);
@@ -270,34 +258,80 @@ var BABYLON;
         __extends(GrassProceduralTexture, _super);
         function GrassProceduralTexture(name, size, scene, fallbackTexture, generateMipMaps) {
             _super.call(this, name, size, "grass", scene, fallbackTexture, generateMipMaps);
+            this._herb1 = new BABYLON.Color3(0.29, 0.38, 0.02);
+            this._herb2 = new BABYLON.Color3(0.36, 0.49, 0.09);
+            this._herb3 = new BABYLON.Color3(0.51, 0.6, 0.28);
+            this._groundColor = new BABYLON.Color3(1, 1, 1);
+
+            this._grassColors = [
+                new BABYLON.Color3(0.29, 0.38, 0.02),
+                new BABYLON.Color3(0.36, 0.49, 0.09),
+                new BABYLON.Color3(0.51, 0.6, 0.28)
+            ];
 
-            // Use 0 to render just once, 1 to render on every frame, 2 to render every two frames and so on...
+            this.updateShaderUniforms();
             this.refreshRate = 0;
         }
-        return GrassProceduralTexture;
-    })(BABYLON.ProceduralTexture);
-    BABYLON.GrassProceduralTexture = GrassProceduralTexture;
+        GrassProceduralTexture.prototype.updateShaderUniforms = function () {
+            this.setColor3("herb1Color", this._grassColors[0]);
+            this.setColor3("herb2Color", this._grassColors[1]);
+            this.setColor3("herb3Color", this._grassColors[2]);
+            this.setColor3("groundColor", this._groundColor);
+        };
+
+        Object.defineProperty(GrassProceduralTexture.prototype, "grassColors", {
+            get: function () {
+                return this._grassColors;
+            },
+            set: function (value) {
+                this._grassColors = value;
+                this.updateShaderUniforms();
+            },
+            enumerable: true,
+            configurable: true
+        });
 
-    var RockProceduralTexture = (function (_super) {
-        __extends(RockProceduralTexture, _super);
-        function RockProceduralTexture(name, size, scene, fallbackTexture, generateMipMaps) {
-            _super.call(this, name, size, "rock", scene, fallbackTexture, generateMipMaps);
 
-            // Use 0 to render just once, 1 to render on every frame, 2 to render every two frames and so on...
-            this.refreshRate = 0;
-        }
-        return RockProceduralTexture;
+        Object.defineProperty(GrassProceduralTexture.prototype, "groundColor", {
+            get: function () {
+                return this._groundColor;
+            },
+            set: function (value) {
+                this.groundColor = value;
+                this.updateShaderUniforms();
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+        return GrassProceduralTexture;
     })(BABYLON.ProceduralTexture);
-    BABYLON.RockProceduralTexture = RockProceduralTexture;
+    BABYLON.GrassProceduralTexture = GrassProceduralTexture;
 
     var RoadProceduralTexture = (function (_super) {
         __extends(RoadProceduralTexture, _super);
         function RoadProceduralTexture(name, size, scene, fallbackTexture, generateMipMaps) {
             _super.call(this, name, size, "road", scene, fallbackTexture, generateMipMaps);
-
-            // Use 0 to render just once, 1 to render on every frame, 2 to render every two frames and so on...
+            this._roadColor = new BABYLON.Color3(0.53, 0.53, 0.53);
+            this.updateShaderUniforms();
             this.refreshRate = 0;
         }
+        RoadProceduralTexture.prototype.updateShaderUniforms = function () {
+            this.setColor3("roadColor", this._roadColor);
+        };
+
+        Object.defineProperty(RoadProceduralTexture.prototype, "roadColor", {
+            get: function () {
+                return this._roadColor;
+            },
+            set: function (value) {
+                this._roadColor = value;
+                this.updateShaderUniforms();
+            },
+            enumerable: true,
+            configurable: true
+        });
+
         return RoadProceduralTexture;
     })(BABYLON.ProceduralTexture);
     BABYLON.RoadProceduralTexture = RoadProceduralTexture;
@@ -308,15 +342,16 @@ var BABYLON;
             _super.call(this, name, size, "brick", scene, fallbackTexture, generateMipMaps);
             this._numberOfBricksHeight = 15;
             this._numberOfBricksWidth = 5;
-
+            this._jointColor = new BABYLON.Color3(0.72, 0.72, 0.72);
+            this._brickColor = new BABYLON.Color3(0.77, 0.47, 0.40);
             this.updateShaderUniforms();
-
-            // Use 0 to render just once, 1 to render on every frame, 2 to render every two frames and so on...
             this.refreshRate = 0;
         }
         BrickProceduralTexture.prototype.updateShaderUniforms = function () {
             this.setFloat("numberOfBricksHeight", this._numberOfBricksHeight);
             this.setFloat("numberOfBricksWidth", this._numberOfBricksWidth);
+            this.setColor3("brickColor", this._brickColor);
+            this.setColor3("jointColor", this._jointColor);
         };
 
         Object.defineProperty(BrickProceduralTexture.prototype, "numberOfBricksHeight", {
@@ -348,6 +383,32 @@ var BABYLON;
             configurable: true
         });
 
+
+        Object.defineProperty(BrickProceduralTexture.prototype, "jointColor", {
+            get: function () {
+                return this._jointColor;
+            },
+            set: function (value) {
+                this._jointColor = value;
+                this.updateShaderUniforms();
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+
+        Object.defineProperty(BrickProceduralTexture.prototype, "brickColor", {
+            get: function () {
+                return this._brickColor;
+            },
+            set: function (value) {
+                this._brickColor = value;
+                this.updateShaderUniforms();
+            },
+            enumerable: true,
+            configurable: true
+        });
+
         return BrickProceduralTexture;
     })(BABYLON.ProceduralTexture);
     BABYLON.BrickProceduralTexture = BrickProceduralTexture;
@@ -356,42 +417,67 @@ var BABYLON;
         __extends(MarbleProceduralTexture, _super);
         function MarbleProceduralTexture(name, size, scene, fallbackTexture, generateMipMaps) {
             _super.call(this, name, size, "marble", scene, fallbackTexture, generateMipMaps);
-            this._numberOfBricksHeight = 3;
-            this._numberOfBricksWidth = 3;
-
+            this._numberOfTilesHeight = 3;
+            this._numberOfTilesWidth = 3;
+            this._amplitude = 9.0;
+            this._marbleColor = new BABYLON.Color3(0.77, 0.47, 0.40);
+            this._jointColor = new BABYLON.Color3(0.72, 0.72, 0.72);
             this.updateShaderUniforms();
-
-            // Use 0 to render just once, 1 to render on every frame, 2 to render every two frames and so on...
             this.refreshRate = 0;
         }
         MarbleProceduralTexture.prototype.updateShaderUniforms = function () {
-            this.setFloat("numberOfBricksHeight", this._numberOfBricksHeight);
-            this.setFloat("numberOfBricksWidth", this._numberOfBricksWidth);
+            this.setFloat("numberOfTilesHeight", this._numberOfTilesHeight);
+            this.setFloat("numberOfTilesWidth", this._numberOfTilesWidth);
+            this.setFloat("amplitude", this._amplitude);
+            this.setColor3("marbleColor", this._marbleColor);
+            this.setColor3("jointColor", this._jointColor);
         };
 
-        Object.defineProperty(MarbleProceduralTexture.prototype, "numberOfBricksHeight", {
+        Object.defineProperty(MarbleProceduralTexture.prototype, "numberOfTilesHeight", {
             get: function () {
-                return this._numberOfBricksHeight;
+                return this._numberOfTilesHeight;
+            },
+            set: function (value) {
+                this._numberOfTilesHeight = value;
+                this.updateShaderUniforms();
             },
             enumerable: true,
             configurable: true
         });
 
-        Object.defineProperty(MarbleProceduralTexture.prototype, "cloudColor", {
+
+        Object.defineProperty(MarbleProceduralTexture.prototype, "numberOfTilesWidth", {
+            get: function () {
+                return this._numberOfTilesWidth;
+            },
             set: function (value) {
-                this._numberOfBricksHeight = value;
+                this._numberOfTilesWidth = value;
                 this.updateShaderUniforms();
             },
             enumerable: true,
             configurable: true
         });
 
-        Object.defineProperty(MarbleProceduralTexture.prototype, "numberOfBricksWidth", {
+
+        Object.defineProperty(MarbleProceduralTexture.prototype, "jointColor", {
             get: function () {
-                return this._numberOfBricksWidth;
+                return this._jointColor;
             },
             set: function (value) {
-                this._numberOfBricksHeight = value;
+                this._jointColor = value;
+                this.updateShaderUniforms();
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+
+        Object.defineProperty(MarbleProceduralTexture.prototype, "marbleColor", {
+            get: function () {
+                return this._marbleColor;
+            },
+            set: function (value) {
+                this._marbleColor = value;
                 this.updateShaderUniforms();
             },
             enumerable: true,

+ 1 - 1
Babylon/Materials/textures/babylon.baseTexture.js

@@ -116,7 +116,7 @@
             this._texture.references--;
 
             // Final reference ?
-            if (this._texture.references == 0) {
+            if (this._texture.references === 0) {
                 var index = texturesCache.indexOf(this._texture);
                 texturesCache.splice(index, 1);
 

+ 1 - 1
Babylon/Materials/textures/babylon.renderTargetTexture.js

@@ -135,7 +135,7 @@ var BABYLON;
 
                         for (var subIndex = 0; subIndex < mesh.subMeshes.length; subIndex++) {
                             var subMesh = mesh.subMeshes[subIndex];
-                            scene._activeVertices += subMesh.verticesCount;
+                            scene._activeVertices += subMesh.indexCount;
                             this._renderingManager.dispatch(subMesh);
                         }
                     }

+ 2 - 0
Babylon/Materials/textures/babylon.texture.js

@@ -133,6 +133,8 @@ var BABYLON;
                 this._projectionModeMatrix = BABYLON.Matrix.Zero();
             }
 
+            this._cachedCoordinatesMode = this.coordinatesMode;
+
             switch (this.coordinatesMode) {
                 case BABYLON.Texture.SPHERICAL_MODE:
                     BABYLON.Matrix.IdentityToRef(this._cachedTextureMatrix);

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

@@ -850,6 +850,21 @@
             return Vector3.TransformCoordinates(vector, finalMatrix);
         };
 
+        Vector3.UnprojectFromTransform = function (source, viewportWidth, viewportHeight, world, transform) {
+            var matrix = world.multiply(transform);
+            matrix.invert();
+            source.x = source.x / viewportWidth * 2 - 1;
+            source.y = -(source.y / viewportHeight * 2 - 1);
+            var vector = BABYLON.Vector3.TransformCoordinates(source, matrix);
+            var num = source.x * matrix.m[3] + source.y * matrix.m[7] + source.z * matrix.m[11] + matrix.m[15];
+
+            if (BABYLON.Tools.WithinEpsilon(num, 1.0)) {
+                vector = vector.scale(1.0 / num);
+            }
+
+            return vector;
+        };
+
         Vector3.Unproject = function (source, viewportWidth, viewportHeight, world, view, projection) {
             var matrix = world.multiply(view).multiply(projection);
             matrix.invert();
@@ -2309,6 +2324,10 @@
                 var min = (minimum.x - this.origin.x) * inv;
                 var max = (maximum.x - this.origin.x) * inv;
 
+                if (max == -Infinity) {
+                    max = Infinity;
+                }
+
                 if (min > max) {
                     var temp = min;
                     min = max;
@@ -2332,6 +2351,10 @@
                 min = (minimum.y - this.origin.y) * inv;
                 max = (maximum.y - this.origin.y) * inv;
 
+                if (max == -Infinity) {
+                    max = Infinity;
+                }
+
                 if (min > max) {
                     temp = min;
                     min = max;
@@ -2355,6 +2378,10 @@
                 min = (minimum.z - this.origin.z) * inv;
                 max = (maximum.z - this.origin.z) * inv;
 
+                if (max == -Infinity) {
+                    max = Infinity;
+                }
+
                 if (min > max) {
                     temp = min;
                     min = max;
@@ -2494,5 +2521,32 @@
     })();
     BABYLON.Axis = Axis;
     ;
+
+    var BezierCurve = (function () {
+        function BezierCurve() {
+        }
+        BezierCurve.interpolate = function (t, x1, y1, x2, y2) {
+            // Extract X (which is equal to time here)
+            var f0 = 1 - 3 * x2 + 3 * x1;
+            var f1 = 3 * x2 - 6 * x1;
+            var f2 = 3 * x1;
+
+            var refinedT = t;
+            for (var i = 0; i < 5; i++) {
+                var refinedT2 = refinedT * refinedT;
+                var refinedT3 = refinedT2 * refinedT;
+
+                var x = f0 * refinedT3 + f1 * refinedT2 + f2 * refinedT;
+                var slope = 1.0 / (3.0 * f0 * refinedT2 + 2.0 * f1 * refinedT + f2);
+                refinedT -= (x - t) * slope;
+                refinedT = Math.min(1, Math.max(0, refinedT));
+            }
+
+            // Resolve cubic bezier for the given x
+            return 3 * Math.pow(1 - refinedT, 2) * refinedT * y1 + 3 * (1 - refinedT) * Math.pow(refinedT, 2) * y2 + Math.pow(refinedT, 3);
+        };
+        return BezierCurve;
+    })();
+    BABYLON.BezierCurve = BezierCurve;
 })(BABYLON || (BABYLON = {}));
 //# sourceMappingURL=babylon.math.js.map

+ 12 - 2
Babylon/Mesh/babylon.InstancedMesh.js

@@ -107,11 +107,21 @@ var BABYLON;
         };
 
         InstancedMesh.prototype._preActivate = function () {
-            this.sourceMesh._preActivate();
+            if (this._currentLOD) {
+                this._currentLOD._preActivate();
+            }
         };
 
         InstancedMesh.prototype._activate = function (renderId) {
-            this.sourceMesh._registerInstanceForRenderId(this, renderId);
+            if (this._currentLOD) {
+                this._currentLOD._registerInstanceForRenderId(this, renderId);
+            }
+        };
+
+        InstancedMesh.prototype.getLOD = function (camera) {
+            this._currentLOD = this.sourceMesh.getLOD(this.getScene().activeCamera, this.getBoundingInfo().boundingSphere);
+
+            return this._currentLOD;
         };
 
         InstancedMesh.prototype._syncSubMeshes = function () {

+ 45 - 4
Babylon/Mesh/babylon.abstractMesh.js

@@ -14,8 +14,9 @@ var BABYLON;
             this.position = new BABYLON.Vector3(0, 0, 0);
             this.rotation = new BABYLON.Vector3(0, 0, 0);
             this.scaling = new BABYLON.Vector3(1, 1, 1);
-            this.billboardMode = BABYLON.AbstractMesh.BILLBOARDMODE_NONE;
+            this.billboardMode = AbstractMesh.BILLBOARDMODE_NONE;
             this.visibility = 1.0;
+            this.alphaIndex = Number.MAX_VALUE;
             this.infiniteDistance = false;
             this.isVisible = true;
             this.isPickable = true;
@@ -29,7 +30,12 @@ var BABYLON;
             this.renderOutline = false;
             this.outlineColor = BABYLON.Color3.Red();
             this.outlineWidth = 0.02;
+            this.renderOverlay = false;
+            this.overlayColor = BABYLON.Color3.Red();
+            this.overlayAlpha = 0.5;
             this.hasVertexAlpha = false;
+            this.useVertexColors = true;
+            this.applyFog = true;
             this.useOctreeForRenderingSelection = true;
             this.useOctreeForPicking = true;
             this.useOctreeForCollisions = true;
@@ -61,6 +67,7 @@ var BABYLON;
             this._isDisposed = false;
             this._renderId = 0;
             this._intersectionsInProgress = new Array();
+            this._onAfterWorldMatrixUpdate = new Array();
 
             scene.meshes.push(this);
         }
@@ -134,6 +141,10 @@ var BABYLON;
         };
 
         AbstractMesh.prototype.getBoundingInfo = function () {
+            if (this._masterMesh) {
+                return this._masterMesh.getBoundingInfo();
+            }
+
             if (!this._boundingInfo) {
                 this._updateBoundingInfo();
             }
@@ -148,6 +159,10 @@ var BABYLON;
         };
 
         AbstractMesh.prototype.getWorldMatrix = function () {
+            if (this._masterMesh) {
+                return this._masterMesh.getWorldMatrix();
+            }
+
             if (this._currentRenderId !== this.getScene().getRenderId()) {
                 this.computeWorldMatrix();
             }
@@ -308,6 +323,10 @@ var BABYLON;
 
             this._boundingInfo._update(this.worldMatrixFromCache);
 
+            this._updateSubMeshesBoundingInfo(this.worldMatrixFromCache);
+        };
+
+        AbstractMesh.prototype._updateSubMeshesBoundingInfo = function (matrix) {
             if (!this.subMeshes) {
                 return;
             }
@@ -315,7 +334,7 @@ var BABYLON;
             for (var subIndex = 0; subIndex < this.subMeshes.length; subIndex++) {
                 var subMesh = this.subMeshes[subIndex];
 
-                subMesh.updateBoundingInfo(this.worldMatrixFromCache);
+                subMesh.updateBoundingInfo(matrix);
             }
         };
 
@@ -404,9 +423,29 @@ var BABYLON;
             // Absolute position
             this._absolutePosition.copyFromFloats(this._worldMatrix.m[12], this._worldMatrix.m[13], this._worldMatrix.m[14]);
 
+            for (var callbackIndex = 0; callbackIndex < this._onAfterWorldMatrixUpdate.length; callbackIndex++) {
+                this._onAfterWorldMatrixUpdate[callbackIndex](this);
+            }
+
             return this._worldMatrix;
         };
 
+        /**
+        * If you'd like to be callbacked after the mesh position, rotation or scaling has been updated
+        * @param func: callback function to add
+        */
+        AbstractMesh.prototype.registerAfterWorldMatrixUpdate = function (func) {
+            this._onAfterWorldMatrixUpdate.push(func);
+        };
+
+        AbstractMesh.prototype.unregisterAfterWorldMatrixUpdate = function (func) {
+            var index = this._onAfterWorldMatrixUpdate.indexOf(func);
+
+            if (index > -1) {
+                this._onAfterWorldMatrixUpdate.splice(index, 1);
+            }
+        };
+
         AbstractMesh.prototype.setPositionWithLocalVector = function (vector3) {
             this.computeWorldMatrix();
 
@@ -513,7 +552,7 @@ var BABYLON;
             this._physicsFriction = options.friction;
             this._physicRestitution = options.restitution;
 
-            physicsEngine._registerMesh(this, impostor, options);
+            return physicsEngine._registerMesh(this, impostor, options);
         };
 
         AbstractMesh.prototype.getPhysicsImpostor = function () {
@@ -561,7 +600,7 @@ var BABYLON;
                 camera = this.getScene().activeCamera;
             }
 
-            return this.absolutePosition.subtract(camera.position);
+            return this.absolutePosition.subtract(camera.position).length();
         };
 
         AbstractMesh.prototype.applyImpulse = function (force, contactPoint) {
@@ -825,6 +864,8 @@ var BABYLON;
                 }
             }
 
+            this._onAfterWorldMatrixUpdate = [];
+
             this._isDisposed = true;
 
             // Callback

+ 1 - 1
Babylon/Mesh/babylon.abstractMesh.ts

@@ -361,7 +361,7 @@
                 var cameraGlobalPosition = new BABYLON.Vector3(cameraWorldMatrix.m[12], cameraWorldMatrix.m[13], cameraWorldMatrix.m[14]);
 
                 BABYLON.Matrix.TranslationToRef(this.position.x + cameraGlobalPosition.x, this.position.y + cameraGlobalPosition.y,
-                                                this.position.z + cameraGlobalPosition.z, this._localTranslation);
+                    this.position.z + cameraGlobalPosition.z, this._localTranslation);
             } else {
                 BABYLON.Matrix.TranslationToRef(this.position.x, this.position.y, this.position.z, this._localTranslation);
             }

+ 10 - 5
Babylon/Mesh/babylon.geometry.js

@@ -74,14 +74,14 @@ var BABYLON;
             }
         };
 
-        Geometry.prototype.updateVerticesDataDirectly = function (kind, data) {
+        Geometry.prototype.updateVerticesDataDirectly = function (kind, data, offset) {
             var vertexBuffer = this.getVertexBuffer(kind);
 
             if (!vertexBuffer) {
                 return;
             }
 
-            vertexBuffer.updateDirectly(data);
+            vertexBuffer.updateDirectly(data, offset);
         };
 
         Geometry.prototype.updateVerticesData = function (kind, data, updateExtends) {
@@ -96,9 +96,10 @@ var BABYLON;
             if (kind === BABYLON.VertexBuffer.PositionKind) {
                 var extend;
 
+                var stride = vertexBuffer.getStrideSize();
+                this._totalVertices = data.length / stride;
+
                 if (updateExtends) {
-                    var stride = vertexBuffer.getStrideSize();
-                    this._totalVertices = data.length / stride;
                     extend = BABYLON.Tools.ExtractMinAndMax(data, 0, this._totalVertices);
                 }
 
@@ -170,7 +171,7 @@ var BABYLON;
             return result;
         };
 
-        Geometry.prototype.setIndices = function (indices) {
+        Geometry.prototype.setIndices = function (indices, totalVertices) {
             if (this._indexBuffer) {
                 this._engine._releaseBuffer(this._indexBuffer);
             }
@@ -180,6 +181,10 @@ var BABYLON;
                 this._indexBuffer = this._engine.createIndexBuffer(this._indices);
             }
 
+            if (totalVertices !== undefined) {
+                this._totalVertices = totalVertices;
+            }
+
             var meshes = this._meshes;
             var numOfMeshes = meshes.length;
 

+ 45 - 34
Babylon/Mesh/babylon.mesh.js

@@ -31,7 +31,15 @@ var BABYLON;
             this._batchCache = new _InstancesBatch();
             this._instancesBufferSize = 32 * 16 * 4;
         }
-        // Methods
+        Object.defineProperty(Mesh.prototype, "hasLODLevels", {
+            // Methods
+            get: function () {
+                return this._LODLevels.length > 0;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
         Mesh.prototype._sortLODLevels = function () {
             this._LODLevels.sort(function (a, b) {
                 if (a.distance < b.distance) {
@@ -46,11 +54,16 @@ var BABYLON;
         };
 
         Mesh.prototype.addLODLevel = function (distance, mesh) {
+            if (mesh && mesh._masterMesh) {
+                BABYLON.Tools.Warn("You cannot use a mesh as LOD level twice");
+                return this;
+            }
+
             var level = new BABYLON.Internals.MeshLODLevel(distance, mesh);
             this._LODLevels.push(level);
 
             if (mesh) {
-                mesh._attachedLODLevel = level;
+                mesh._masterMesh = this;
             }
 
             this._sortLODLevels();
@@ -59,37 +72,25 @@ var BABYLON;
         };
 
         Mesh.prototype.removeLODLevel = function (mesh) {
-            if (mesh && !mesh._attachedLODLevel) {
-                return this;
-            }
-
-            var index;
-
-            if (mesh) {
-                index = this._LODLevels.indexOf(mesh._attachedLODLevel);
-                mesh._attachedLODLevel = null;
-
-                this._LODLevels.splice(index, 1);
-
-                this._sortLODLevels();
-            } else {
-                for (index = 0; index < this._LODLevels.length; index++) {
-                    if (this._LODLevels[index].mesh === null) {
-                        this._LODLevels.splice(index, 1);
-                        break;
+            for (var index = 0; index < this._LODLevels.length; index++) {
+                if (this._LODLevels[index].mesh === mesh) {
+                    this._LODLevels.splice(index, 1);
+                    if (mesh) {
+                        mesh._masterMesh = null;
                     }
                 }
             }
 
+            this._sortLODLevels();
             return this;
         };
 
-        Mesh.prototype.getLOD = function (camera) {
+        Mesh.prototype.getLOD = function (camera, boundingSphere) {
             if (!this._LODLevels || this._LODLevels.length === 0) {
                 return this;
             }
 
-            var distanceToCamera = this.getBoundingInfo().boundingSphere.centerWorld.subtract(camera.position).length();
+            var distanceToCamera = (boundingSphere ? boundingSphere : this.getBoundingInfo().boundingSphere).centerWorld.subtract(camera.position).length();
 
             if (this._LODLevels[this._LODLevels.length - 1].distance > distanceToCamera) {
                 return this;
@@ -100,7 +101,8 @@ var BABYLON;
 
                 if (level.distance < distanceToCamera) {
                     if (level.mesh) {
-                        level.mesh._worldMatrix = this._worldMatrix;
+                        level.mesh._preActivate();
+                        level.mesh._updateSubMeshesBoundingInfo(this.worldMatrixFromCache);
                     }
                     return level.mesh;
                 }
@@ -177,7 +179,7 @@ var BABYLON;
 
         Object.defineProperty(Mesh.prototype, "isBlocked", {
             get: function () {
-                return this._attachedLODLevel !== null && this._attachedLODLevel !== undefined;
+                return this._masterMesh !== null && this._masterMesh !== undefined;
             },
             enumerable: true,
             configurable: true
@@ -307,15 +309,15 @@ var BABYLON;
             }
         };
 
-        Mesh.prototype.updateVerticesDataDirectly = function (kind, data, makeItUnique) {
+        Mesh.prototype.updateVerticesDataDirectly = function (kind, data, offset, makeItUnique) {
             if (!this._geometry) {
                 return;
             }
             if (!makeItUnique) {
-                this._geometry.updateVerticesDataDirectly(kind, data);
+                this._geometry.updateVerticesDataDirectly(kind, data, offset);
             } else {
                 this.makeGeometryUnique();
-                this.updateVerticesDataDirectly(kind, data, false);
+                this.updateVerticesDataDirectly(kind, data, offset, false);
             }
         };
 
@@ -327,7 +329,7 @@ var BABYLON;
             geometry.applyToMesh(this);
         };
 
-        Mesh.prototype.setIndices = function (indices) {
+        Mesh.prototype.setIndices = function (indices, totalVertices) {
             if (!this._geometry) {
                 var vertexData = new BABYLON.VertexData();
                 vertexData.indices = indices;
@@ -336,7 +338,7 @@ var BABYLON;
 
                 new BABYLON.Geometry(BABYLON.Geometry.RandomId(), scene, vertexData, false, this);
             } else {
-                this._geometry.setIndices(indices);
+                this._geometry.setIndices(indices, totalVertices);
             }
         };
 
@@ -441,7 +443,8 @@ var BABYLON;
         };
 
         Mesh.prototype._renderWithInstances = function (subMesh, fillMode, batch, effect, engine) {
-            var matricesCount = this.instances.length + 1;
+            var visibleInstances = batch.visibleInstances[subMesh._id];
+            var matricesCount = visibleInstances.length + 1;
             var bufferSize = matricesCount * 16 * 4;
 
             while (this._instancesBufferSize < bufferSize) {
@@ -467,8 +470,6 @@ var BABYLON;
                 instancesCount++;
             }
 
-            var visibleInstances = batch.visibleInstances[subMesh._id];
-
             if (visibleInstances) {
                 for (var instanceIndex = 0; instanceIndex < visibleInstances.length; instanceIndex++) {
                     var instance = visibleInstances[instanceIndex];
@@ -512,7 +513,7 @@ var BABYLON;
             }
 
             var engine = scene.getEngine();
-            var hardwareInstancedRendering = (engine.getCaps().instancedArrays !== null) && (batch.visibleInstances[subMesh._id] !== null);
+            var hardwareInstancedRendering = (engine.getCaps().instancedArrays !== null) && (batch.visibleInstances[subMesh._id] !== null) && (batch.visibleInstances[subMesh._id] !== undefined);
 
             // Material
             var effectiveMaterial = subMesh.getMaterial();
@@ -526,16 +527,18 @@ var BABYLON;
             if (this.renderOutline) {
                 engine.setDepthWrite(false);
                 scene.getOutlineRenderer().render(subMesh, batch);
+                engine.setDepthWrite(savedDepthWrite);
             }
 
             effectiveMaterial._preBind();
             var effect = effectiveMaterial.getEffect();
 
             // Bind
-            var fillMode = engine.forceWireframe ? BABYLON.Material.WireFrameFillMode : effectiveMaterial.fillMode;
+            var fillMode = scene.forcePointsCloud ? BABYLON.Material.PointFillMode : (scene.forceWireframe ? BABYLON.Material.WireFrameFillMode : effectiveMaterial.fillMode);
             this._bind(subMesh, effect, fillMode);
 
             var world = this.getWorldMatrix();
+
             effectiveMaterial.bind(world, this);
 
             // Instances rendering
@@ -572,6 +575,14 @@ var BABYLON;
                 engine.setColorWrite(true);
             }
 
+            // Overlay
+            if (this.renderOverlay) {
+                var currentMode = engine.getAlphaMode();
+                engine.setAlphaMode(BABYLON.Engine.ALPHA_COMBINE);
+                scene.getOutlineRenderer().render(subMesh, batch, true);
+                engine.setAlphaMode(currentMode);
+            }
+
             for (callbackIndex = 0; callbackIndex < this._onAfterRenderCallbacks.length; callbackIndex++) {
                 this._onAfterRenderCallbacks[callbackIndex]();
             }

+ 2 - 2
Babylon/Mesh/babylon.vertexBuffer.js

@@ -90,13 +90,13 @@
             this.create(data);
         };
 
-        VertexBuffer.prototype.updateDirectly = function (data) {
+        VertexBuffer.prototype.updateDirectly = function (data, offset) {
             if (!this._buffer) {
                 return;
             }
 
             if (this._updatable) {
-                this._engine.updateDynamicVertexBuffer(this._buffer, data);
+                this._engine.updateDynamicVertexBuffer(this._buffer, data, offset);
                 this._data = null;
             }
         };

+ 7 - 6
Babylon/Particles/babylon.particleSystem.js

@@ -1,7 +1,7 @@
 var BABYLON;
 (function (BABYLON) {
     var randomNumber = function (min, max) {
-        if (min == max) {
+        if (min === max) {
             return (min);
         }
 
@@ -29,7 +29,7 @@
             this.maxSize = 1;
             this.minAngularSpeed = 0;
             this.maxAngularSpeed = 0;
-            this.blendMode = BABYLON.ParticleSystem.BLENDMODE_ONEONE;
+            this.blendMode = ParticleSystem.BLENDMODE_ONEONE;
             this.forceDepthWrite = false;
             this.gravity = BABYLON.Vector3.Zero();
             this.direction1 = new BABYLON.Vector3(0, 1.0, 0);
@@ -173,7 +173,7 @@
             }
 
             for (index = 0; index < newParticles; index++) {
-                if (this.particles.length == this._capacity) {
+                if (this.particles.length === this._capacity) {
                     break;
                 }
 
@@ -219,7 +219,7 @@
 
             // Effect
             var join = defines.join("\n");
-            if (this._cachedDefines != join) {
+            if (this._cachedDefines !== join) {
                 this._cachedDefines = join;
 
                 this._effect = this._scene.getEngine().createEffect("particles", ["position", "color", "options"], ["invView", "view", "projection", "vClipPlane", "textureMask"], ["diffuseSampler"], join);
@@ -312,6 +312,7 @@
 
             // Render
             engine.enableEffect(effect);
+            engine.setState(false);
 
             var viewMatrix = this._scene.getViewMatrix();
             effect.setTexture("diffuseSampler", this.particleTexture);
@@ -331,7 +332,7 @@
             engine.bindBuffers(this._vertexBuffer, this._indexBuffer, this._vertexDeclaration, this._vertexStrideSize, effect);
 
             // Draw order
-            if (this.blendMode === BABYLON.ParticleSystem.BLENDMODE_ONEONE) {
+            if (this.blendMode === ParticleSystem.BLENDMODE_ONEONE) {
                 engine.setAlphaMode(BABYLON.Engine.ALPHA_ADD);
             } else {
                 engine.setAlphaMode(BABYLON.Engine.ALPHA_COMBINE);
@@ -375,7 +376,7 @@
 
         // Clone
         ParticleSystem.prototype.clone = function (name, newEmitter) {
-            var result = new BABYLON.ParticleSystem(name, this._capacity, this._scene);
+            var result = new ParticleSystem(name, this._capacity, this._scene);
 
             BABYLON.Tools.DeepCopy(this, result, ["particles"], ["_vertexDeclaration", "_vertexStrideSize"]);
 

+ 2 - 0
Babylon/Physics/Plugins/babylon.oimoJSPlugin.js

@@ -304,6 +304,7 @@ var BABYLON;
                             mesh.rotationQuaternion = new BABYLON.Quaternion(0, 0, 0, 1);
                         }
                         mesh.rotationQuaternion.fromRotationMatrix(mtx);
+                        mesh.computeWorldMatrix();
                     } else {
                         m = body.getMatrix();
                         mtx = BABYLON.Matrix.FromArray(m);
@@ -325,6 +326,7 @@ var BABYLON;
                             mesh.rotationQuaternion = new BABYLON.Quaternion(0, 0, 0, 1);
                         }
                         mesh.rotationQuaternion.fromRotationMatrix(mtx);
+                        mesh.computeWorldMatrix();
                     }
                 }
             }

+ 3 - 1
Babylon/Rendering/babylon.boundingBoxRenderer.js

@@ -22,7 +22,7 @@
         };
 
         BoundingBoxRenderer.prototype.render = function () {
-            if (this.renderList.length == 0 || !this._colorShader.isReady()) {
+            if (this.renderList.length === 0 || !this._colorShader.isReady()) {
                 return;
             }
 
@@ -44,6 +44,7 @@
                 if (this.showBackLines) {
                     // Back
                     engine.setDepthFunctionToGreaterOrEqual();
+                    this._scene.resetCachedMaterial();
                     this._colorShader.setColor4("color", this.backColor.toColor4());
                     this._colorShader.bind(worldMatrix);
 
@@ -53,6 +54,7 @@
 
                 // Front
                 engine.setDepthFunctionToLess();
+                this._scene.resetCachedMaterial();
                 this._colorShader.setColor4("color", this.frontColor.toColor4());
                 this._colorShader.bind(worldMatrix);
 

+ 6 - 5
Babylon/Rendering/babylon.outlineRenderer.js

@@ -4,11 +4,12 @@
         function OutlineRenderer(scene) {
             this._scene = scene;
         }
-        OutlineRenderer.prototype.render = function (subMesh, batch) {
+        OutlineRenderer.prototype.render = function (subMesh, batch, useOverlay) {
+            if (typeof useOverlay === "undefined") { useOverlay = false; }
             var scene = this._scene;
             var engine = this._scene.getEngine();
 
-            var hardwareInstancedRendering = (engine.getCaps().instancedArrays !== null) && (batch.visibleInstances !== null);
+            var hardwareInstancedRendering = (engine.getCaps().instancedArrays !== null) && (batch.visibleInstances[subMesh._id] !== null) && (batch.visibleInstances[subMesh._id] !== undefined);
 
             if (!this.isReady(subMesh, hardwareInstancedRendering)) {
                 return;
@@ -18,12 +19,12 @@
             var material = subMesh.getMaterial();
 
             engine.enableEffect(this._effect);
-            this._effect.setFloat("offset", mesh.outlineWidth);
-            this._effect.setColor3("color", mesh.outlineColor);
+            this._effect.setFloat("offset", useOverlay ? 0 : mesh.outlineWidth);
+            this._effect.setColor4("color", useOverlay ? mesh.overlayColor : mesh.outlineColor, useOverlay ? mesh.overlayAlpha : 1.0);
             this._effect.setMatrix("viewProjection", scene.getTransformMatrix());
 
             // Bones
-            var useBones = mesh.skeleton && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesIndicesKind) && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesWeightsKind);
+            var useBones = mesh.skeleton && scene.skeletonsEnabled && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesIndicesKind) && mesh.isVerticesDataPresent(BABYLON.VertexBuffer.MatricesWeightsKind);
             if (useBones) {
                 this._effect.setMatrices("mBones", mesh.skeleton.getTransformMatrices());
             }

+ 11 - 6
Babylon/Rendering/babylon.renderingGroup.js

@@ -25,7 +25,6 @@
 
             for (subIndex = 0; subIndex < this._opaqueSubMeshes.length; subIndex++) {
                 submesh = this._opaqueSubMeshes.data[subIndex];
-                this._activeVertices += submesh.verticesCount;
 
                 submesh.render();
             }
@@ -34,7 +33,6 @@
             engine.setAlphaTesting(true);
             for (subIndex = 0; subIndex < this._alphaTestSubMeshes.length; subIndex++) {
                 submesh = this._alphaTestSubMeshes.data[subIndex];
-                this._activeVertices += submesh.verticesCount;
 
                 submesh.render();
             }
@@ -48,12 +46,22 @@
             if (this._transparentSubMeshes.length) {
                 for (subIndex = 0; subIndex < this._transparentSubMeshes.length; subIndex++) {
                     submesh = this._transparentSubMeshes.data[subIndex];
+                    submesh._alphaIndex = submesh.getMesh().alphaIndex;
                     submesh._distanceToCamera = submesh.getBoundingInfo().boundingSphere.centerWorld.subtract(this._scene.activeCamera.position).length();
                 }
 
                 var sortedArray = this._transparentSubMeshes.data.slice(0, this._transparentSubMeshes.length);
 
                 sortedArray.sort(function (a, b) {
+                    // Alpha index first
+                    if (a._alphaIndex > b._alphaIndex) {
+                        return 1;
+                    }
+                    if (a._alphaIndex < b._alphaIndex) {
+                        return -1;
+                    }
+
+                    // Then distance to camera
                     if (a._distanceToCamera < b._distanceToCamera) {
                         return 1;
                     }
@@ -68,7 +76,6 @@
                 engine.setAlphaMode(BABYLON.Engine.ALPHA_COMBINE);
                 for (subIndex = 0; subIndex < sortedArray.length; subIndex++) {
                     submesh = sortedArray[subIndex];
-                    this._activeVertices += submesh.verticesCount;
 
                     submesh.render();
                 }
@@ -88,9 +95,7 @@
             var mesh = subMesh.getMesh();
 
             if (material.needAlphaBlending() || mesh.visibility < 1.0 || mesh.hasVertexAlpha) {
-                if (material.alpha > 0 || mesh.visibility < 1.0) {
-                    this._transparentSubMeshes.push(subMesh);
-                }
+                this._transparentSubMeshes.push(subMesh);
             } else if (material.needAlphaTesting()) {
                 this._alphaTestSubMeshes.push(subMesh);
             } else {

+ 2 - 3
Babylon/Rendering/babylon.renderingManager.js

@@ -69,11 +69,10 @@
                         }
                     })) {
                         this._renderingGroups.splice(index, 1);
+                    } else if (renderSprites) {
+                        this._renderSprites(index);
                     }
-                } else if (renderSprites) {
-                    this._renderSprites(index);
                 }
-
                 if (renderParticles) {
                     this._renderParticles(index, activeMeshes);
                 }

+ 2 - 2
Babylon/Sprites/babylon.spriteManager.js

@@ -108,7 +108,7 @@
             // Render
             var effect = this._effectBase;
 
-            if (this._scene.fogMode !== BABYLON.Scene.FOGMODE_NONE && this.fogEnabled) {
+            if (this._scene.fogEnabled && this._scene.fogMode !== BABYLON.Scene.FOGMODE_NONE && this.fogEnabled) {
                 effect = this._effectFog;
             }
 
@@ -122,7 +122,7 @@
             effect.setFloat2("textureInfos", this.cellSize / baseSize.width, this.cellSize / baseSize.height);
 
             // Fog
-            if (this._scene.fogMode !== BABYLON.Scene.FOGMODE_NONE && this.fogEnabled) {
+            if (this._scene.fogEnabled && this._scene.fogMode !== BABYLON.Scene.FOGMODE_NONE && this.fogEnabled) {
                 effect.setFloat4("vFogInfos", this._scene.fogMode, this._scene.fogStart, this._scene.fogEnd, this._scene.fogDensity);
                 effect.setColor3("vFogColor", this._scene.fogColor);
             }

+ 44 - 4
Babylon/Tools/babylon.tools.js

@@ -280,6 +280,17 @@
         };
 
         // Misc.
+        Tools.Clamp = function (value, min, max) {
+            if (typeof min === "undefined") { min = 0; }
+            if (typeof max === "undefined") { max = 1; }
+            return Math.min(max, Math.max(min, value));
+        };
+
+        Tools.Format = function (value, decimals) {
+            if (typeof decimals === "undefined") { decimals = 2; }
+            return value.toFixed(decimals);
+        };
+
         Tools.CheckExtends = function (v, min, max) {
             if (v.x < min.x)
                 min.x = v.x;
@@ -597,36 +608,64 @@
             configurable: true
         });
 
+        Tools._AddLogEntry = function (entry) {
+            Tools._LogCache = entry + Tools._LogCache;
+
+            if (Tools.OnNewCacheEntry) {
+                Tools.OnNewCacheEntry(entry);
+            }
+        };
+
         Tools._FormatMessage = function (message) {
             var padStr = function (i) {
                 return (i < 10) ? "0" + i : "" + i;
             };
 
             var date = new Date();
-            return "BJS - [" + padStr(date.getHours()) + ":" + padStr(date.getMinutes()) + ":" + padStr(date.getSeconds()) + "]: " + message;
+            return "[" + padStr(date.getHours()) + ":" + padStr(date.getMinutes()) + ":" + padStr(date.getSeconds()) + "]: " + message;
         };
 
         Tools._LogDisabled = function (message) {
             // nothing to do
         };
         Tools._LogEnabled = function (message) {
-            console.log(Tools._FormatMessage(message));
+            var formattedMessage = Tools._FormatMessage(message);
+            console.log("BJS - " + formattedMessage);
+
+            var entry = "<div style='color:white'>" + formattedMessage + "</div><br>";
+            Tools._AddLogEntry(entry);
         };
 
         Tools._WarnDisabled = function (message) {
             // nothing to do
         };
         Tools._WarnEnabled = function (message) {
-            console.warn(Tools._FormatMessage(message));
+            var formattedMessage = Tools._FormatMessage(message);
+            console.warn("BJS - " + formattedMessage);
+
+            var entry = "<div style='color:orange'>" + formattedMessage + "</div><br>";
+            Tools._AddLogEntry(entry);
         };
 
         Tools._ErrorDisabled = function (message) {
             // nothing to do
         };
         Tools._ErrorEnabled = function (message) {
-            console.error(Tools._FormatMessage(message));
+            var formattedMessage = Tools._FormatMessage(message);
+            console.error("BJS - " + formattedMessage);
+
+            var entry = "<div style='color:red'>" + formattedMessage + "</div><br>";
+            Tools._AddLogEntry(entry);
         };
 
+        Object.defineProperty(Tools, "LogCache", {
+            get: function () {
+                return Tools._LogCache;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
         Object.defineProperty(Tools, "LogLevels", {
             set: function (level) {
                 if ((level & Tools.MessageLogLevel) === Tools.MessageLogLevel) {
@@ -775,6 +814,7 @@
         Tools._MessageLogLevel = 1;
         Tools._WarningLogLevel = 2;
         Tools._ErrorLogLevel = 4;
+        Tools._LogCache = "";
 
         Tools.Log = Tools._LogEnabled;
 

+ 39 - 9
Babylon/babylon.engine.js

@@ -364,16 +364,17 @@
             // Public members
             this.isFullscreen = false;
             this.isPointerLock = false;
-            this.forceWireframe = false;
             this.cullBackFaces = true;
             this.renderEvenInBackground = true;
             this.scenes = new Array();
             this._windowIsBackground = false;
             this._runningLoop = false;
             this._loadingDivBackgroundColor = "black";
+            this._drawCalls = 0;
             // States
             this._depthCullingState = new _DepthCullingState();
             this._alphaState = new _AlphaState();
+            this._alphaMode = Engine.ALPHA_DISABLE;
             // Cache
             this._loadedTexturesCache = new Array();
             this._activeTexturesCache = new Array();
@@ -471,6 +472,10 @@
             document.addEventListener("mspointerlockchange", this._onPointerLockChange, false);
             document.addEventListener("mozpointerlockchange", this._onPointerLockChange, false);
             document.addEventListener("webkitpointerlockchange", this._onPointerLockChange, false);
+
+            this._audioEngine = new BABYLON.AudioEngine();
+
+            BABYLON.Tools.Log("Babylon.js engine (v" + Engine.Version + ") launched");
         }
         Object.defineProperty(Engine, "ALPHA_DISABLE", {
             get: function () {
@@ -536,6 +541,10 @@
             configurable: true
         });
 
+        Engine.prototype.getAudioEngine = function () {
+            return this._audioEngine;
+        };
+
         Engine.prototype.getAspectRatio = function (camera) {
             var viewport = camera.viewport;
             return (this.getRenderWidth() * viewport.width) / (this.getRenderHeight() * viewport.height);
@@ -582,7 +591,19 @@
             return this._caps;
         };
 
+        Object.defineProperty(Engine.prototype, "drawCalls", {
+            get: function () {
+                return this._drawCalls;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
         // Methods
+        Engine.prototype.resetDrawCalls = function () {
+            this._drawCalls = 0;
+        };
+
         Engine.prototype.setDepthFunctionToGreater = function () {
             this._depthCullingState.depthFunc = this._gl.GREATER;
         };
@@ -728,7 +749,7 @@
         };
 
         Engine.prototype.flushFramebuffer = function () {
-            this._gl.flush();
+            //   this._gl.flush();
         };
 
         Engine.prototype.restoreDefaultFramebuffer = function () {
@@ -764,19 +785,19 @@
             return vbo;
         };
 
-        Engine.prototype.updateDynamicVertexBuffer = function (vertexBuffer, vertices, length) {
+        Engine.prototype.updateDynamicVertexBuffer = function (vertexBuffer, vertices, offset) {
             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 (offset === undefined) {
+                offset = 0;
+            }
+
             if (vertices instanceof Float32Array) {
-                this._gl.bufferSubData(this._gl.ARRAY_BUFFER, 0, vertices);
+                this._gl.bufferSubData(this._gl.ARRAY_BUFFER, offset, vertices);
             } else {
-                this._gl.bufferSubData(this._gl.ARRAY_BUFFER, 0, new Float32Array(vertices));
+                this._gl.bufferSubData(this._gl.ARRAY_BUFFER, offset, new Float32Array(vertices));
             }
 
-            //  }
             this._resetVertexBufferBinding();
         };
 
@@ -930,6 +951,8 @@
             }
 
             this._gl.drawElements(useTriangles ? this._gl.TRIANGLES : this._gl.LINES, indexCount, indexFormat, indexStart * 2);
+
+            this._drawCalls++;
         };
 
         Engine.prototype.drawPointClouds = function (verticesStart, verticesCount, instancesCount) {
@@ -942,6 +965,7 @@
             }
 
             this._gl.drawArrays(this._gl.POINTS, verticesStart, verticesCount);
+            this._drawCalls++;
         };
 
         // Shaders
@@ -1183,6 +1207,12 @@
                     this._alphaState.alphaBlend = true;
                     break;
             }
+
+            this._alphaMode = mode;
+        };
+
+        Engine.prototype.getAlphaMode = function () {
+            return this._alphaMode;
         };
 
         Engine.prototype.setAlphaTesting = function (enable) {

+ 129 - 24
Babylon/babylon.scene.js

@@ -8,9 +8,13 @@
             this.clearColor = new BABYLON.Color3(0.2, 0.2, 0.3);
             this.ambientColor = new BABYLON.Color3(0, 0, 0);
             this.forceWireframe = false;
+            this.forcePointsCloud = false;
+            this.forceShowBoundingBoxes = false;
+            this.animationsEnabled = true;
             this.cameraToUseForPointers = null;
             // Fog
-            this.fogMode = BABYLON.Scene.FOGMODE_NONE;
+            this.fogEnabled = true;
+            this.fogMode = Scene.FOGMODE_NONE;
             this.fogColor = new BABYLON.Color3(0.2, 0.2, 0.3);
             this.fogDensity = 0.1;
             this.fogStart = 0;
@@ -40,6 +44,7 @@
             // Layers
             this.layers = new Array();
             // Skeletons
+            this.skeletonsEnabled = true;
             this.skeletons = new Array();
             // Lens flares
             this.lensFlaresEnabled = true;
@@ -59,6 +64,7 @@
             // Procedural textures
             this.proceduralTexturesEnabled = true;
             this._proceduralTextures = new Array();
+            this.soundTracks = new Array();
             this._totalVertices = 0;
             this._activeVertices = 0;
             this._activeParticles = 0;
@@ -75,11 +81,13 @@
             this._onReadyCallbacks = new Array();
             this._pendingData = [];
             this._onBeforeRenderCallbacks = new Array();
+            this._onAfterRenderCallbacks = new Array();
             this._activeMeshes = new BABYLON.SmartArray(256);
             this._processedMaterials = new BABYLON.SmartArray(256);
             this._renderTargets = new BABYLON.SmartArray(256);
             this._activeParticleSystems = new BABYLON.SmartArray(256);
             this._activeSkeletons = new BABYLON.SmartArray(32);
+            this._activeBones = 0;
             this._activeAnimatables = new Array();
             this._transformMatrix = BABYLON.Matrix.Zero();
             this._scaledPosition = BABYLON.Vector3.Zero();
@@ -98,10 +106,21 @@
             this._outlineRenderer = new BABYLON.OutlineRenderer(this);
 
             this.attachControl();
+
+            this._debugLayer = new BABYLON.DebugLayer(this);
+            this.mainSoundTrack = new BABYLON.SoundTrack(this, { mainTrack: true });
         }
-        Object.defineProperty(Scene.prototype, "meshUnderPointer", {
+        Object.defineProperty(Scene.prototype, "debugLayer", {
             // Properties
             get: function () {
+                return this._debugLayer;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+        Object.defineProperty(Scene.prototype, "meshUnderPointer", {
+            get: function () {
                 return this._meshUnderPointer;
             },
             enumerable: true,
@@ -124,6 +143,10 @@
             configurable: true
         });
 
+        Scene.prototype.getCachedMaterial = function () {
+            return this._cachedMaterial;
+        };
+
         Scene.prototype.getBoundingBoxRenderer = function () {
             return this._boundingBoxRenderer;
         };
@@ -148,6 +171,10 @@
             return this._activeParticles;
         };
 
+        Scene.prototype.getActiveBones = function () {
+            return this._activeBones;
+        };
+
         // Stats
         Scene.prototype.getLastFrameDuration = function () {
             return this._lastFrameDuration;
@@ -317,6 +344,10 @@
             return true;
         };
 
+        Scene.prototype.resetCachedMaterial = function () {
+            this._cachedMaterial = null;
+        };
+
         Scene.prototype.registerBeforeRender = function (func) {
             this._onBeforeRenderCallbacks.push(func);
         };
@@ -329,6 +360,18 @@
             }
         };
 
+        Scene.prototype.registerAfterRender = function (func) {
+            this._onAfterRenderCallbacks.push(func);
+        };
+
+        Scene.prototype.unregisterAfterRender = function (func) {
+            var index = this._onAfterRenderCallbacks.indexOf(func);
+
+            if (index > -1) {
+                this._onAfterRenderCallbacks.splice(index, 1);
+            }
+        };
+
         Scene.prototype._addPendingData = function (data) {
             this._pendingData.push(data);
         };
@@ -432,6 +475,10 @@
         };
 
         Scene.prototype._animate = function () {
+            if (!this.animationsEnabled) {
+                return;
+            }
+
             if (!this._animationStartDate) {
                 this._animationStartDate = BABYLON.Tools.Now;
             }
@@ -662,7 +709,7 @@
         };
 
         Scene.prototype._evaluateSubMesh = function (subMesh, mesh) {
-            if (mesh.subMeshes.length == 1 || subMesh.isInFrustum(this._frustumPlanes)) {
+            if (mesh.subMeshes.length === 1 || subMesh.isInFrustum(this._frustumPlanes)) {
                 var material = subMesh.getMaterial();
 
                 if (mesh.showSubMeshesBoundingBox) {
@@ -680,7 +727,7 @@
                     }
 
                     // Dispatch
-                    this._activeVertices += subMesh.verticesCount;
+                    this._activeVertices += subMesh.indexCount;
                     this._renderingManager.dispatch(subMesh);
                 }
             }
@@ -727,18 +774,26 @@
                 }
 
                 mesh.computeWorldMatrix();
-                mesh._preActivate();
 
                 // Intersections
                 if (mesh.actionManager && mesh.actionManager.hasSpecificTriggers([BABYLON.ActionManager.OnIntersectionEnterTrigger, BABYLON.ActionManager.OnIntersectionExitTrigger])) {
                     this._meshesForIntersections.pushNoDuplicate(mesh);
                 }
 
-                if (mesh.isEnabled() && mesh.isVisible && mesh.visibility > 0 && ((mesh.layerMask & this.activeCamera.layerMask) != 0) && mesh.isInFrustum(this._frustumPlanes)) {
+                // Switch to current LOD
+                var meshLOD = mesh.getLOD(this.activeCamera);
+
+                if (!meshLOD) {
+                    continue;
+                }
+
+                mesh._preActivate();
+
+                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._activeMesh(mesh);
+                    this._activeMesh(meshLOD);
                 }
             }
 
@@ -764,35 +819,33 @@
         };
 
         Scene.prototype._activeMesh = function (mesh) {
-            if (mesh.skeleton) {
+            if (mesh.skeleton && this.skeletonsEnabled) {
                 this._activeSkeletons.pushNoDuplicate(mesh.skeleton);
             }
 
-            if (mesh.showBoundingBox) {
+            if (mesh.showBoundingBox || this.forceShowBoundingBoxes) {
                 this._boundingBoxRenderer.renderList.push(mesh.getBoundingInfo().boundingBox);
             }
 
-            var activeMesh = mesh.getLOD(this.activeCamera);
-
-            if (activeMesh && activeMesh.subMeshes) {
+            if (mesh && mesh.subMeshes) {
                 // Submeshes Octrees
                 var len;
                 var subMeshes;
 
-                if (activeMesh._submeshesOctree && activeMesh.useOctreeForRenderingSelection) {
-                    var intersections = activeMesh._submeshesOctree.select(this._frustumPlanes);
+                if (mesh._submeshesOctree && mesh.useOctreeForRenderingSelection) {
+                    var intersections = mesh._submeshesOctree.select(this._frustumPlanes);
 
                     len = intersections.length;
                     subMeshes = intersections.data;
                 } else {
-                    subMeshes = activeMesh.subMeshes;
+                    subMeshes = mesh.subMeshes;
                     len = subMeshes.length;
                 }
 
                 for (var subIndex = 0; subIndex < len; subIndex++) {
                     var subMesh = subMeshes[subIndex];
 
-                    this._evaluateSubMesh(subMesh, activeMesh);
+                    this._evaluateSubMesh(subMesh, mesh);
                 }
             }
         };
@@ -833,6 +886,8 @@
                 var skeleton = this._activeSkeletons.data[skeletonIndex];
 
                 skeleton.prepare();
+
+                this._activeBones += skeleton.bones.length;
             }
 
             // Render targets
@@ -922,7 +977,7 @@
         };
 
         Scene.prototype._processSubCameras = function (camera) {
-            if (camera.subCameras.length == 0) {
+            if (camera.subCameras.length === 0) {
                 this._renderForCamera(camera);
                 return;
             }
@@ -945,17 +1000,17 @@
                 for (var actionIndex = 0; actionIndex < sourceMesh.actionManager.actions.length; actionIndex++) {
                     var action = sourceMesh.actionManager.actions[actionIndex];
 
-                    if (action.trigger == BABYLON.ActionManager.OnIntersectionEnterTrigger || action.trigger == BABYLON.ActionManager.OnIntersectionExitTrigger) {
+                    if (action.trigger === BABYLON.ActionManager.OnIntersectionEnterTrigger || action.trigger === BABYLON.ActionManager.OnIntersectionExitTrigger) {
                         var otherMesh = action.getTriggerParameter();
 
                         var areIntersecting = otherMesh.intersectsMesh(sourceMesh, false);
                         var currentIntersectionInProgress = sourceMesh._intersectionsInProgress.indexOf(otherMesh);
 
-                        if (areIntersecting && currentIntersectionInProgress === -1 && action.trigger == BABYLON.ActionManager.OnIntersectionEnterTrigger) {
-                            sourceMesh.actionManager.processTrigger(BABYLON.ActionManager.OnIntersectionEnterTrigger, BABYLON.ActionEvent.CreateNew(sourceMesh));
+                        if (areIntersecting && currentIntersectionInProgress === -1 && action.trigger === BABYLON.ActionManager.OnIntersectionEnterTrigger) {
+                            action._executeCurrent(BABYLON.ActionEvent.CreateNew(sourceMesh));
                             sourceMesh._intersectionsInProgress.push(otherMesh);
-                        } else if (!areIntersecting && currentIntersectionInProgress > -1 && action.trigger == BABYLON.ActionManager.OnIntersectionExitTrigger) {
-                            sourceMesh.actionManager.processTrigger(BABYLON.ActionManager.OnIntersectionExitTrigger, BABYLON.ActionEvent.CreateNew(sourceMesh));
+                        } else if (!areIntersecting && currentIntersectionInProgress > -1 && action.trigger === BABYLON.ActionManager.OnIntersectionExitTrigger) {
+                            action._executeCurrent(BABYLON.ActionEvent.CreateNew(sourceMesh));
 
                             var indexOfOther = sourceMesh._intersectionsInProgress.indexOf(otherMesh);
 
@@ -974,10 +1029,14 @@
             this._spritesDuration = 0;
             this._activeParticles = 0;
             this._renderDuration = 0;
+            this._renderTargetsDuration = 0;
             this._evaluateActiveMeshesDuration = 0;
             this._totalVertices = 0;
             this._activeVertices = 0;
+            this._activeBones = 0;
+            this.getEngine().resetDrawCalls();
             this._meshesForIntersections.reset();
+            this.resetCachedMaterial();
 
             BABYLON.Tools.StartPerformanceCounter("Scene rendering");
 
@@ -1054,7 +1113,7 @@
             }
 
             // Clear
-            this._engine.clear(this.clearColor, this.autoClear || this.forceWireframe, true);
+            this._engine.clear(this.clearColor, this.autoClear || this.forceWireframe || this.forcePointsCloud, true);
 
             // Shadows
             if (this.shadowsEnabled) {
@@ -1089,11 +1148,18 @@
             // Intersection checks
             this._checkIntersections();
 
+            // Update the audio listener attached to the camera
+            this._updateAudioParameters();
+
             // After render
             if (this.afterRender) {
                 this.afterRender();
             }
 
+            for (callbackIndex = 0; callbackIndex < this._onAfterRenderCallbacks.length; callbackIndex++) {
+                this._onAfterRenderCallbacks[callbackIndex]();
+            }
+
             for (var index = 0; index < this._toBeDisposed.length; index++) {
                 this._toBeDisposed.data[index].dispose();
                 this._toBeDisposed[index] = null;
@@ -1105,6 +1171,39 @@
             this._lastFrameDuration = BABYLON.Tools.Now - startDate;
         };
 
+        Scene.prototype._updateAudioParameters = function () {
+            var listeningCamera;
+            var audioEngine = this._engine.getAudioEngine();
+
+            if (this.activeCameras.length > 0) {
+                listeningCamera = this.activeCameras[0];
+            } else {
+                listeningCamera = this.activeCamera;
+            }
+
+            if (listeningCamera && audioEngine.canUseWebAudio) {
+                audioEngine.audioContext.listener.setPosition(listeningCamera.position.x, listeningCamera.position.y, listeningCamera.position.z);
+                var mat = BABYLON.Matrix.Invert(listeningCamera.getViewMatrix());
+                var cameraDirection = BABYLON.Vector3.TransformNormal(new BABYLON.Vector3(0, 0, -1), mat);
+                cameraDirection.normalize();
+                audioEngine.audioContext.listener.setOrientation(cameraDirection.x, cameraDirection.y, cameraDirection.z, 0, 1, 0);
+                for (var i = 0; i < this.mainSoundTrack.soundCollection.length; i++) {
+                    var sound = this.mainSoundTrack.soundCollection[i];
+                    if (sound.useBabylonJSAttenuation) {
+                        sound.updateDistanceFromListener();
+                    }
+                }
+                for (var i = 0; i < this.soundTracks.length; i++) {
+                    for (var j = 0; i < this.soundTracks[i].soundCollection.length; j++) {
+                        var sound = this.soundTracks[i].soundCollection[j];
+                        if (sound.useBabylonJSAttenuation) {
+                            sound.updateDistanceFromListener();
+                        }
+                    }
+                }
+            }
+        };
+
         Scene.prototype.dispose = function () {
             this.beforeRender = null;
             this.afterRender = null;
@@ -1113,11 +1212,17 @@
 
             this._boundingBoxRenderer.dispose();
 
+            // Debug layer
+            this.debugLayer.hide();
+
             // Events
             if (this.onDispose) {
                 this.onDispose();
             }
 
+            this._onBeforeRenderCallbacks = [];
+            this._onAfterRenderCallbacks = [];
+
             this.detachControl();
 
             // Detach cameras
@@ -1214,7 +1319,7 @@
                 return;
             }
 
-            if (velocity.x != 0 || velocity.y != 0 || velocity.z != 0) {
+            if (velocity.x !== 0 || velocity.y !== 0 || velocity.z !== 0) {
                 collider._getResponse(position, velocity);
             }
 

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


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

@@ -185,13 +185,13 @@ namespace Max2Babylon
             ExportAnimation(property, animations, extractValueFunc, BabylonAnimation.DataType.Float);
         }
 
-        static void EliminateLinearAnimationKeys(List<BabylonAnimationKey> keys)
+        static void RemoveLinearAnimationKeys(List<BabylonAnimationKey> keys)
         {
             for(int ixFirst = keys.Count-3; ixFirst >=0; --ixFirst)
             {
                 while (keys.Count - ixFirst >= 3)
                 {
-                    if(!EliminateAnimationKey(keys, ixFirst))
+                    if(!RemoveAnimationKey(keys, ixFirst))
                     {
                         break;
                     }
@@ -211,9 +211,7 @@ namespace Max2Babylon
             return result;
         }
 
-
-
-        private static bool EliminateAnimationKey(List<BabylonAnimationKey> keys, int ixFirst)
+        private static bool RemoveAnimationKey(List<BabylonAnimationKey> keys, int ixFirst)
         {
             var first = keys[ixFirst];
             var middle = keys[ixFirst + 1];
@@ -258,7 +256,7 @@ namespace Max2Babylon
 
                 previous = current;
             }
-            EliminateLinearAnimationKeys(keys);
+            RemoveLinearAnimationKeys(keys);
             if (keys.Count > 0)
             {
                 var animationPresent = true;

+ 32 - 39
Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Light.cs

@@ -46,8 +46,6 @@ namespace Max2Babylon
             var lightState = Loader.Global.LightState.Create();
             maxLight.EvalLightState(0, Tools.Forever, lightState);
 
-            var directionScale = -1;
-
             switch (lightState.Type)
             {
                 case LightType.OmniLgt:
@@ -64,7 +62,6 @@ namespace Max2Babylon
                 case LightType.AmbientLgt:
                     babylonLight.type = 3;
                     babylonLight.groundColor = new float[] { 0, 0, 0 };
-                    directionScale = 1;
                     break;
             }
 
@@ -82,31 +79,30 @@ namespace Max2Babylon
                 }
             }
 
+            // Position
+            var wm = lightNode.GetObjectTM(0);
+            var position = wm.Translation;
+            babylonLight.position = new float[] { position.X, position.Y, position.Z };
+
+            // Direction
+            var target = gameLight.LightTarget;
+            if (target != null)
             {
-                // Position
-                var wm = lightNode.GetObjectTM(0);
-                var position = wm.Translation;
-                babylonLight.position = new float[] { position.X, position.Y, position.Z };
-
-                // Direction
-                var target = gameLight.LightTarget;
-                if (target != null)
-                {
-                    var targetWm = target.GetObjectTM(0);
-                    var targetPosition = targetWm.Translation;
+                var targetWm = target.GetObjectTM(0);
+                var targetPosition = targetWm.Translation;
 
-                    var direction = targetPosition.Subtract(position).Normalize;
-                    babylonLight.direction = new float[] { direction.X, direction.Y, direction.Z };
-                }
-                else
-                {
-                    var vDir = Loader.Global.Point3.Create(0, -1, 0);
-                    vDir = wm.ExtractMatrix3().VectorTransform(vDir).Normalize;
-                    babylonLight.direction = new float[] { vDir.X, vDir.Y, vDir.Z };
-                }
+                var direction = targetPosition.Subtract(position).Normalize;
+                babylonLight.direction = new float[] { direction.X, direction.Y, direction.Z };
+            }
+            else
+            {
+                var vDir = Loader.Global.Point3.Create(0, -1, 0);
+                vDir = wm.ExtractMatrix3().VectorTransform(vDir).Normalize;
+                babylonLight.direction = new float[] { vDir.X, vDir.Y, vDir.Z };
             }
 
             var maxScene = Loader.Core.RootNode;
+
             // Exclusion
             var inclusion = maxLight.ExclList.TestFlag(1); //NT_INCLUDE 
             var checkExclusionList = maxLight.ExclList.TestFlag(2); //NT_AFFECT_ILLUM
@@ -157,33 +153,30 @@ namespace Max2Babylon
             // Animations
             var animations = new List<BabylonAnimation>();
 
-            //if (!ExportVector3Controller(lightNode.TMController.PositionController, "position", animations))
-            //{
-                ExportVector3Animation("position", animations, key =>
-                {
-                    var mat = lightNode.GetObjectTM(key);
-                    var pos = mat.Translation;
-                    return new float[] { pos.X, pos.Y, pos.Z };
-                });
-            //}
+            ExportVector3Animation("position", animations, key =>
+            {
+                var mat = lightNode.GetObjectTM(key);
+                var pos = mat.Translation;
+                return new float[] { pos.X, pos.Y, pos.Z };
+            });
 
             ExportVector3Animation("direction", animations, key =>
             {
-                var wm = lightNode.GetObjectTM(key);
-                var position = wm.Translation;
-                var target = gameLight.LightTarget;
-                if (target != null)
+                var wmLight = lightNode.GetObjectTM(key);
+                var positionLight = wmLight.Translation;
+                var lightTarget = gameLight.LightTarget;
+                if (lightTarget != null)
                 {
-                    var targetWm = target.GetObjectTM(key);
+                    var targetWm = lightTarget.GetObjectTM(key);
                     var targetPosition = targetWm.Translation;
 
-                    var direction = targetPosition.Subtract(position).Normalize;
+                    var direction = targetPosition.Subtract(positionLight).Normalize;
                     return new float[] { direction.X, direction.Y, direction.Z };
                 }
                 else
                 {
                     var vDir = Loader.Global.Point3.Create(0, -1, 0);
-                    vDir = wm.ExtractMatrix3().VectorTransform(vDir).Normalize;
+                    vDir = wmLight.ExtractMatrix3().VectorTransform(vDir).Normalize;
                     return new float[] { vDir.X, vDir.Y, vDir.Z };
                 }
             });

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

@@ -48,7 +48,6 @@ namespace Max2Babylon
                 return;
             }
 
-
             var babylonMaterial = new BabylonMaterial
             {
                 name = name,

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

@@ -58,7 +58,6 @@ namespace Max2Babylon
             IGMatrix skinInitPoseMatrix = Loader.Global.GMatrix.Create(Loader.Global.Matrix3.Create(true));
             if (isSkinned)
             {
-                //unskinnedMesh = skin.InitialPose;
                 bonesCount = skin.TotalSkinBoneCount;
                 skins.Add(skin);
                 skinnedNodes.Add(meshNode);
@@ -68,39 +67,21 @@ namespace Max2Babylon
 
             // Position / rotation / scaling
             {
-                //var localTM = unskinnedMesh.IGameObjectTM;
-                //var worldTM = meshNode.GetWorldTM(0);
                 var localTM = meshNode.GetObjectTM(0);
 
                 var meshTrans = localTM.Translation;
                 var meshRotation = localTM.Rotation;
                 var meshScale = localTM.Scaling;
                 babylonMesh.position = new float[] { meshTrans.X, meshTrans.Y, meshTrans.Z };
-                //float rotx = 0, roty = 0, rotz = 0;
-                //unsafe
-                //{
-                //    meshRotation.GetEuler(new IntPtr(&rotx), new IntPtr(&roty), new IntPtr(&rotz));
-                //}
-                //babylonMesh.rotation = new float[] { rotx, roty, rotz };
                 babylonMesh.rotationQuaternion = new float[] { meshRotation.X, meshRotation.Y, meshRotation.Z, -meshRotation.W };
                 babylonMesh.scaling = new float[] { meshScale.X, meshScale.Y, meshScale.Z };
             }
-            //// Pivot // something to do with GameMesh ?
-            //meshNode.GetObjectTM
-            //var pivotMatrix = Tools.Identity;
-            //pivotMatrix.PreTranslate(meshNode.ObjOffsetPos);
-            //Loader.Global.PreRotateMatrix(pivotMatrix, meshNode.ObjOffsetRot);
-            //Loader.Global.ApplyScaling(pivotMatrix, meshNode.ObjOffsetScale);
-            //babylonMesh.pivotMatrix = pivotMatrix.ToArray();
 
             // Mesh
-
             RaiseMessage(meshNode.Name, 1);
 
             if (unskinnedMesh != null && unskinnedMesh.IGameType == Autodesk.Max.IGameObject.ObjectTypes.Mesh && unskinnedMesh.MaxMesh != null)
             {
-
-
                 if (unskinnedMesh.NumberOfFaces < 1)
                 {
                     RaiseError(string.Format("Mesh {0} has no face", babylonMesh.name), 2);
@@ -144,13 +125,13 @@ namespace Max2Babylon
                     IntPtr indexer = new IntPtr(i);
                     var channelNum = mappingChannels[indexer];
                     if (channelNum == 1)
-                {
+                    {
                         hasUV = true;
-                }
+                    }
                     else if (channelNum == 2)
-                {
+                    {
                         hasUV2 = true;
-                }
+                    }
                 }
                 var hasColor = unskinnedMesh.NumberOfColorVerts > 0;
                 var hasAlpha = unskinnedMesh.GetNumberOfMapVerts(-2) > 0;
@@ -160,7 +141,6 @@ namespace Max2Babylon
 
 
                 // Compute normals
-                // VNormal[] vnorms = Tools.ComputeNormals(mesh, optimizeVertices);
                 List<GlobalVertex>[] verticesAlreadyExported = null;
 
                 if (optimizeVertices)
@@ -171,9 +151,14 @@ namespace Max2Babylon
                 var subMeshes = new List<BabylonSubMesh>();
                 var indexStart = 0;
 
-                
+
                 for (int i = 0; i < multiMatsCount; ++i)
                 {
+                    if (meshNode.NodeMaterial == null)
+                    {
+                        continue;
+                    }
+
                     int materialId = meshNode.NodeMaterial.GetMaterialID(i);
                     ITab<IFaceEx> materialFaces = null;
                     var indexCount = 0;
@@ -185,7 +170,7 @@ namespace Max2Babylon
 
                     if (multiMatsCount == 1)
                     {
-                        for(int j = 0; j < unskinnedMesh.NumberOfFaces; ++j)
+                        for (int j = 0; j < unskinnedMesh.NumberOfFaces; ++j)
                         {
                             var face = unskinnedMesh.GetFace(j);
                             ExtractFace(skin, unskinnedMesh, vertices, indices, hasUV, hasUV2, hasColor, hasAlpha, verticesAlreadyExported, ref indexCount, ref minVertexIndex, ref maxVertexIndex, face);
@@ -203,11 +188,7 @@ namespace Max2Babylon
                             ExtractFace(skin, unskinnedMesh, vertices, indices, hasUV, hasUV2, hasColor, hasAlpha, verticesAlreadyExported, ref indexCount, ref minVertexIndex, ref maxVertexIndex, face);
                         }
                     }
-                    
-
 
-
-                   
                     if (indexCount != 0)
                     {
 
@@ -221,11 +202,9 @@ namespace Max2Babylon
                     }
                 }
 
-
-
                 if (vertices.Count >= 65536)
                 {
-                    RaiseError(string.Format("Mesh {0} has too many vertices: {1} (limit is 65535)", babylonMesh.name, vertices.Count), 2);
+                    RaiseWarning(string.Format("Mesh {0} has {1} vertices. This may prevent your scene to work on low end devices where 32 bits indice are not supported", babylonMesh.name, vertices.Count), 2);
 
                     if (!optimizeVertices)
                     {
@@ -259,19 +238,13 @@ namespace Max2Babylon
                     babylonMesh.hasVertexAlpha = hasAlpha;
                 }
 
-
-
                 babylonMesh.subMeshes = subMeshes.ToArray();
 
-
                 // Buffers - Indices
                 babylonMesh.indices = indices.ToArray();
 
             }
 
-            // handle instances and animations
-
-
             // Instances
             var tabs = Loader.Global.NodeTab.Create();
 
@@ -301,8 +274,6 @@ namespace Max2Babylon
 
                     var localTM = meshNode.GetObjectTM(0);
 
-                    //var worldTM = meshNode.GetWorldTM(0);
-                    //var objTM = meshNode.GetObjectTM(0);
                     var meshTrans = localTM.Translation;
                     var meshRotation = localTM.Rotation;
                     var meshScale = localTM.Scaling;
@@ -327,7 +298,7 @@ namespace Max2Babylon
             // Animations
             var animations = new List<BabylonAnimation>();
             GenerateCoordinatesAnimations(meshNode, animations);
-            
+
 
             if (!ExportFloatController(meshNode.MaxNode.VisController, "visibility", animations))
             {
@@ -392,45 +363,33 @@ namespace Max2Babylon
         }
 
         public static void GenerateCoordinatesAnimations(IIGameNode meshNode, List<BabylonAnimation> animations)
+        {
+            ExportVector3Animation("position", animations, key =>
             {
-            //if (!ExportVector3Controller(meshNode.TMController.PositionController, "position", animations))
-            //{
-                ExportVector3Animation("position", animations, key =>
-                {
                 var worldMatrix = meshNode.GetObjectTM(key);
                 var trans = worldMatrix.Translation;
                 return new float[] { trans.X, trans.Y, trans.Z };
-                });
-            //}
-
-
-            //if (!ExportQuaternionController(meshNode.TMController.RotationController, "rotationQuaternion", animations))
-            //{
-                ExportQuaternionAnimation("rotationQuaternion", animations, key =>
-                {
-                    var worldMatrix = meshNode.GetObjectTM(key);
+            });
 
+            ExportQuaternionAnimation("rotationQuaternion", animations, key =>
+            {
+                var worldMatrix = meshNode.GetObjectTM(key);
 
 
-                    var rot = worldMatrix.Rotation;
-                    return new float[] { rot.X, rot.Y, rot.Z, -rot.W };
-                });
-            //}
 
+                var rot = worldMatrix.Rotation;
+                return new float[] { rot.X, rot.Y, rot.Z, -rot.W };
+            });
 
-            //if (!ExportVector3Controller(meshNode.TMController.ScaleController, "scaling", animations))
-            //{
-                ExportVector3Animation("scaling", animations, key =>
-                {
-                    var worldMatrix = meshNode.GetObjectTM(key);
-                    var scale = worldMatrix.Scaling;
+            ExportVector3Animation("scaling", animations, key =>
+            {
+                var worldMatrix = meshNode.GetObjectTM(key);
+                var scale = worldMatrix.Scaling;
 
-                    return new float[] { scale.X, scale.Y, scale.Z };
-                });
-           // }
+                return new float[] { scale.X, scale.Y, scale.Z };
+            });
         }
 
-
         int CreateGlobalVertex(IIGameMesh mesh, IFaceEx face, int facePart, List<GlobalVertex> vertices, bool hasUV, bool hasUV2, bool hasColor, bool hasAlpha, List<GlobalVertex>[] verticesAlreadyExported, IIGameSkin skin)
         {
             var vertexIndex = (int)face.Vert[facePart];
@@ -439,7 +398,7 @@ namespace Max2Babylon
             {
                 BaseIndex = vertexIndex,
                 Position = mesh.GetVertex(vertexIndex, true),
-                Normal = mesh.GetNormal((int)face.Norm[facePart], true) //vnorms[vertexIndex].GetNormal(verticesAlreadyExported != null ? 1 : faceObject.SmGroup)
+                Normal = mesh.GetNormal((int)face.Norm[facePart], true)
             };
 
             if (hasUV)

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

@@ -16,94 +16,6 @@ namespace Max2Babylon
         readonly List<IIGameSkin> skins = new List<IIGameSkin>();
         readonly List<IIGameNode> skinnedNodes = new List<IIGameNode>();
 
-        //IISkin GetSkinModifier(IINode node, out IModifier skinModifier)
-        //{
-        //    skinModifier = null;
-        //    var obj = node.ObjectRef;
-
-        //    if (obj.SuperClassID != SClass_ID.GenDerivob)
-        //    {
-        //        return null;
-        //    }
-
-        //    var derivedObject = obj as IIDerivedObject;
-
-        //    if (derivedObject == null)
-        //    {
-        //        return null;
-        //    }
-
-        //    for (var index = 0; index < derivedObject.NumModifiers; index++)
-        //    {
-        //        var modifier = derivedObject.GetModifier(index);
-
-        //        if (modifier.ClassID.PartA == 9815843 && modifier.ClassID.PartB == 87654) // Skin
-        //        {
-        //            var skin = modifier.GetInterface((InterfaceID)0x00010000) as IISkin;
-
-        //            if (!skins.Contains(skin))
-        //            {
-        //                skins.Add(skin);
-        //            }
-        //            skinModifier = modifier;
-        //            return skin;
-        //        }
-        //    }
-
-
-        //    return null;
-        //}
-
-
-        //float[] GetBoneBindPoseLocalMatrix(IISkin skin, IINode bone, bool hasParent)
-        //{
-        //    var matrix = Loader.Global.Matrix3.Create();
-        //    var result = skin.GetBoneInitTM(bone, matrix, false);
-        //    if (!hasParent)
-        //    {
-        //        return matrix.ToArray();
-        //    }
-        //    else
-        //    {
-        //        var parentInverse = Loader.Global.Matrix3.Create();
-
-        //        result = skin.GetBoneInitTM(bone.ParentNode, matrix, false);
-        //        parentInverse.Invert();
-        //        return matrix.Multiply(parentInverse).ToArray();
-        //    }
-
-        //}
-        //float[] GetBoneMatrixForFrame(IINode bone, int frame, bool hasParent)
-        //{
-        //    //            var nodeTM2 = bone.GetNodeTM(frame, Tools.Forever);
-        //    //            var parent = bone.ParentNode;
-
-        //    //            if (!hasParent)
-        //    //            {
-        //    //                parent = bone;
-        //    //            }
-        //    //            else
-        //    //            {
-        //    //                parent = bone.ParentNode;
-        //    //            }
-        //    //            var inverseParentTM = parent.GetNodeTM(frame, Tools.Forever);
-        //    //            inverseParentTM.Invert();
-        //    //            var localTransform = nodeTM2.Multiply(inverseParentTM);
-        //    //            var vLocalPos = localTransform.Trans;
-        //    //            var parts = Loader.Global.AffineParts.Create();
-        //    //            Loader.Global.DecompAffine(localTransform, parts);
-        //    //            IPoint3 eulerAngs = Loader.Global.Point3.Create();
-        //    //#if MAX2015
-        //    //            var eulerAngsPtr = eulerAngs.NativePointer;
-        //    //#else
-        //    //            var eulerAngsPtr = eulerAngs.Handle;
-        //    //#endif
-        //    //            //Loader.Global.QuatToEuler(parts.Q, eulerAngsPtr);
-
-        //    //            return ( Matrix.RotationQuaternion(new Quaternion(parts.Q.X, parts.Q.Y, parts.Q.Z, parts.Q.W))*Matrix.Translation(vLocalPos.X, vLocalPos.Z, vLocalPos.Y)).ToArray();
-        //    return Matrix.Identity.ToArray();
-        //}
-
         IGMatrix WithNoScale(IGMatrix mat)
         {
             var mat3 = mat.ExtractMatrix3();
@@ -116,8 +28,7 @@ namespace Max2Babylon
             babylonSkeleton.name = "skeleton #" + babylonSkeleton.id;
 
             RaiseMessage(babylonSkeleton.name, 1);
-            //IGMatrix skinInitMatrix = Loader.Global.GMatrix.Create(Loader.Global.Matrix3.Create(true));
-            //skin.GetInitSkinTM(skinInitMatrix);
+
             var skinIndex = skins.IndexOf(skin);
             var meshNode = skinnedNodes[skinIndex];
             var skinInitMatrix = meshNode.GetObjectTM(0);
@@ -133,12 +44,11 @@ namespace Max2Babylon
                 gameBones.Add(gameBone);
                 boneIds.Add(gameBone.NodeID);
                 bones.Add(new BabylonBone { index = index, name = gameBone.Name });
-                //IGMatrix boneInitMatrix = Loader.Global.GMatrix.Create(Loader.Global.Matrix3.Create(true));
 
-                //skin.GetInitBoneTM(gameBone, boneInitMatrix);
                 var boneInitMatrix = gameBone.GetObjectTM(0);
                 bindPoseInfos.Add(new BonePoseInfo { AbsoluteTransform = boneInitMatrix });
             }
+
             // fix hierarchy an generate animation keys
             for (var index = 0; index < skin.TotalSkinBoneCount; index++)
             {
@@ -203,117 +113,11 @@ namespace Max2Babylon
 
                 babylonAnimation.keys = keys.ToArray();
                 babBone.animation = babylonAnimation;
-
             }
 
-            //FixupHierarchy(Loader.Core.RootNode, skin.GetBone(0), bones);
-
             babylonSkeleton.bones = bones.ToArray();
 
             babylonScene.SkeletonsList.Add(babylonSkeleton);
         }
-
-        //private void ExportSkin(IISkin skin, BabylonScene babylonScene)
-        //{
-
-        //    var babylonSkeleton = new BabylonSkeleton { id = skins.IndexOf(skin) };
-        //    babylonSkeleton.name = "skeleton #" + babylonSkeleton.id;
-
-        //    RaiseMessage(babylonSkeleton.name, 1);
-
-        //    var bones = new List<BabylonBone>();
-
-        //    for (var index = 0; index < skin.NumBones; index++)
-        //    {
-        //        var bone = new BabylonBone { name = skin.GetBoneName(index), index = index };
-
-        //        var maxBone = skin.GetBone(index);
-        //        var parentNode = maxBone.ParentNode;
-
-        //        if (parentNode != null)
-        //        {
-        //            for (var recurseIndex = 0; recurseIndex < index; recurseIndex++)
-        //            {
-        //                if (skin.GetBone(recurseIndex).GetGuid() == parentNode.GetGuid())
-        //                {
-        //                    bone.parentBoneIndex = recurseIndex;
-        //                    break;
-        //                }
-        //            }
-        //        }
-        //        var hasParent = bone.parentBoneIndex != -1;
-        //        var currentBoneNeutralMatrix = GetBoneBindPoseLocalMatrix(skin, maxBone, hasParent);
-        //        bone.matrix = currentBoneNeutralMatrix;
-
-        //        // Animation
-        //        var babylonAnimation = new BabylonAnimation
-        //        {
-        //            name = bone.name + "Animation",
-        //            property = "_matrix",
-        //            dataType = BabylonAnimation.DataType.Matrix,
-        //            loopBehavior = BabylonAnimation.LoopBehavior.Cycle,
-        //            framePerSecond = Loader.Global.FrameRate
-        //        };
-
-        //        var start = Loader.Core.AnimRange.Start;
-        //        var end = Loader.Core.AnimRange.End;
-
-        //        float[] previous = null;
-        //        var keys = new List<BabylonAnimationKey>();
-        //        for (var key = start; key <= end; key += Ticks)
-        //        {
-        //            var current = GetBoneMatrixForFrame(maxBone, key, hasParent);
-
-        //            if (key == start || key == end || !(previous.IsEqualTo(current)))
-        //            {
-        //                keys.Add(new BabylonAnimationKey
-        //                {
-        //                    frame = key / Ticks,
-        //                    values = current
-        //                });
-        //            }
-
-        //            previous = current;
-        //        }
-
-        //        babylonAnimation.keys = keys.ToArray();
-        //        bone.animation = babylonAnimation;
-
-        //        bones.Add(bone);
-        //    }
-        //    //FixupHierarchy(Loader.Core.RootNode, skin.GetBone(0), bones);
-
-        //    babylonSkeleton.bones = bones.ToArray();
-
-        //    babylonScene.SkeletonsList.Add(babylonSkeleton);
-        //}
-
-        //private void FixupHierarchy(IINode sceneRoot, IINode skeletonRoot, List<BabylonBone> bones)
-        //{
-        //    var skeletonTransforms = new NodeTransforms(skeletonRoot, 0);
-        //    var sceneRootTransforms = new NodeTransforms(sceneRoot, 0);
-        //    var skelAbs = skeletonTransforms.AbsoluteTransform;
-        //    var invSceneAbs = sceneRootTransforms.AbsoluteTransform;
-        //    invSceneAbs.Invert();
-        //    var skelAbsInvSceneAbs = skelAbs.Multiply(invSceneAbs);
-        //    var invSkelLocalTransform = skeletonTransforms.LocalTransform;
-        //    invSkelLocalTransform.Invert();
-        //    var skelAbsInvSceneAbsXinvSkelLocalTransform = skelAbsInvSceneAbs.Multiply(invSkelLocalTransform);
-        //    bones[0].matrix = skelAbsInvSceneAbs.ToArray();
-        //    var matskelAbsInvSceneAbsXinvSkelLocalTransform = new Matrix(skelAbsInvSceneAbsXinvSkelLocalTransform.ToArray());
-        //    foreach (var b in bones)
-        //    {
-        //        var oldTransform = new Matrix(b.matrix);
-        //        b.matrix = (oldTransform * matskelAbsInvSceneAbsXinvSkelLocalTransform).ToArray();
-        //        foreach(var frame in b.animation.keys)
-        //        {
-
-        //            var oldTransform2 = new Matrix(frame.values);
-        //            frame.values = (oldTransform2 * matskelAbsInvSceneAbsXinvSkelLocalTransform).ToArray();
-        //        }
-        //    }
-
-
-        //}
     }
 }

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

@@ -135,7 +135,7 @@ namespace Max2Babylon
 
             RaiseMessage("Exporting cameras");
             var camerasTab = gameScene.GetIGameNodeByType(Autodesk.Max.IGameObject.ObjectTypes.Camera);
-            for(int ix = 0; ix < camerasTab.Count; ++ix)
+            for (int ix = 0; ix < camerasTab.Count; ++ix)
             {
                 var indexer = new IntPtr(ix);
                 var cameraNode = camerasTab[indexer];
@@ -151,7 +151,6 @@ namespace Max2Babylon
                 }
             }
 
-
             if (mainCamera == null)
             {
                 RaiseWarning("No camera defined", 1);
@@ -170,7 +169,7 @@ namespace Max2Babylon
                 {
                     var fog = atmospheric as IStdFog;
 
-                        RaiseMessage("Exporting fog");
+                    RaiseMessage("Exporting fog");
 
                     if (fog != null)
                     {
@@ -186,8 +185,8 @@ namespace Max2Babylon
                         babylonScene.fogMode = 3;
                     }
 #endif
-                        if (mainCamera != null)
-                        {
+                    if (mainCamera != null)
+                    {
                         babylonScene.fogStart = mainCameraNode.GetEnvRange(0, 0, Tools.Forever);
                         babylonScene.fogEnd = mainCameraNode.GetEnvRange(0, 1, Tools.Forever);
                     }
@@ -201,7 +200,7 @@ namespace Max2Babylon
             var progressionStep = 80.0f / meshes.Count;
             var progression = 10.0f;
             for (int ix = 0; ix < meshes.Count; ++ix)
-                {
+            {
                 var indexer = new IntPtr(ix);
                 var meshNode = meshes[indexer];
                 Marshal.FreeHGlobal(indexer);
@@ -227,8 +226,8 @@ namespace Max2Babylon
             // Lights
             RaiseMessage("Exporting lights");
             var lightNodes = gameScene.GetIGameNodeByType(Autodesk.Max.IGameObject.ObjectTypes.Light);
-            for(var i=0;i< lightNodes.Count; ++i)
-                {
+            for (var i = 0; i < lightNodes.Count; ++i)
+            {
                 ExportLight(lightNodes[new IntPtr(i)], babylonScene);
                 CheckCancelled();
             }
@@ -283,6 +282,6 @@ namespace Max2Babylon
             RaiseMessage(string.Format("Exportation done in {0:0.00}s", watch.ElapsedMilliseconds / 1000.0), Color.Blue);
         }
 
-        
+
     }
 }

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

@@ -55,6 +55,7 @@ To export you can use the [Babylon] menu in the main menu bar.
  - Emissive color and texture
  - Opacity texture
  - Reflection texture
+ - Fresnel for diffuse, emissive, opacity and reflection
 - *Textures*
  - UV offset / scaling / angle
  - Level

+ 1 - 1
babylon.2.0-alpha.debug.js

@@ -10600,7 +10600,7 @@ var BABYLON;
             this._physicsFriction = options.friction;
             this._physicRestitution = options.restitution;
 
-            physicsEngine._registerMesh(this, impostor, options);
+            return physicsEngine._registerMesh(this, impostor, options);
         };
 
         AbstractMesh.prototype.getPhysicsImpostor = function () {

ファイルの差分が大きいため隠しています
+ 2 - 2
babylon.2.0-alpha.js