Browse Source

Fixing procedural textures

David Catuhe 10 năm trước cách đây
mục cha
commit
90f41e2386
46 tập tin đã thay đổi với 6201 bổ sung616 xóa
  1. 91 25
      Babylon/Audio/babylon.sound.js
  2. 89 24
      Babylon/Audio/babylon.sound.ts
  3. 4 0
      Babylon/Loading/Plugins/babylon.babylonFileLoader.js
  4. 4 0
      Babylon/Loading/Plugins/babylon.babylonFileLoader.ts
  5. 4 0
      Babylon/Materials/babylon.shaderMaterial.js
  6. 4 0
      Babylon/Materials/babylon.shaderMaterial.ts
  7. 16 7
      Babylon/Materials/babylon.standardMaterial.js
  8. 16 7
      Babylon/Materials/babylon.standardMaterial.ts
  9. 43 29
      Babylon/Materials/textures/Procedurals/babylon.customProceduralTexture.js
  10. 47 32
      Babylon/Materials/textures/Procedurals/babylon.customProceduralTexture.ts
  11. 8 1
      Babylon/Materials/textures/Procedurals/babylon.proceduralTexture.js
  12. 9 1
      Babylon/Materials/textures/Procedurals/babylon.proceduralTexture.ts
  13. 182 75
      Babylon/Materials/textures/Procedurals/babylon.standardProceduralTexture.js
  14. 151 99
      Babylon/Materials/textures/Procedurals/babylon.standardProceduralTexture.ts
  15. 27 12
      Babylon/Math/babylon.math.js
  16. 32 17
      Babylon/Math/babylon.math.ts
  17. 6 0
      Babylon/Mesh/babylon.abstractMesh.js
  18. 6 0
      Babylon/Mesh/babylon.abstractMesh.ts
  19. 15 1
      Babylon/Mesh/babylon.mesh.js
  20. 15 1
      Babylon/Mesh/babylon.mesh.ts
  21. 1 0
      Babylon/Mesh/babylon.subMesh.ts
  22. 1 0
      Babylon/Particles/babylon.particleSystem.js
  23. 1 0
      Babylon/Particles/babylon.particleSystem.ts
  24. 5 4
      Babylon/Rendering/babylon.outlineRenderer.js
  25. 4 5
      Babylon/Rendering/babylon.outlineRenderer.ts
  26. 10 0
      Babylon/Rendering/babylon.renderingGroup.js
  27. 10 0
      Babylon/Rendering/babylon.renderingGroup.ts
  28. 2 3
      Babylon/Rendering/babylon.renderingManager.js
  29. 2 3
      Babylon/Rendering/babylon.renderingManager.ts
  30. 5 16
      Babylon/Shaders/brick.fragment.fx
  31. 2 2
      Babylon/Shaders/default.fragment.fx
  32. 4 3
      Babylon/Shaders/fire.fragment.fx
  33. 10 14
      Babylon/Shaders/grass.fragment.fx
  34. 4 21
      Babylon/Shaders/marble.fragment.fx
  35. 2 2
      Babylon/Shaders/outline.fragment.fx
  36. 3 8
      Babylon/Shaders/road.fragment.fx
  37. 0 3
      Babylon/Shaders/wood.fragment.fx
  38. 44 4
      Babylon/Tools/babylon.tools.js
  39. 39 5
      Babylon/Tools/babylon.tools.ts
  40. 26 2
      Babylon/babylon.engine.js
  41. 25 5
      Babylon/babylon.engine.ts
  42. 36 2
      Babylon/babylon.scene.js
  43. 33 1
      Babylon/babylon.scene.ts
  44. 1082 162
      babylon.2.0-alpha.debug.js
  45. 19 17
      babylon.2.0-alpha.js
  46. 4062 3
      babylon.2.0.d.ts

+ 91 - 25
Babylon/Audio/babylon.sound.js

@@ -1,59 +1,119 @@
 var BABYLON;
 (function (BABYLON) {
     var Sound = (function () {
-        function Sound(url, engine, readyToPlayCallback, distanceMax, autoplay, loop) {
+        /**
+        * Create a sound and attach it to a scene
+        * @param name Name of your sound
+        * @param url Url to the sound to load async
+        * @param readyToPlayCallback Provide a callback function if you'd like to load your code once the sound is ready to be played
+        * @param options Objects to provide with the current available options: autoplay, loop, distanceMax
+        */
+        function Sound(name, url, scene, readyToPlayCallback, options) {
             var _this = this;
-            this.distanceMax = 10;
+            this.maxDistance = 10;
             this.autoplay = false;
             this.loop = false;
             this._position = BABYLON.Vector3.Zero();
-            this._orientation = BABYLON.Vector3.Zero();
+            this._direction = BABYLON.Vector3.Zero();
             this._isLoaded = false;
             this._isReadyToPlay = false;
-            this._audioEngine = engine.getAudioEngine();            
+            this._isPlaying = false;
+            this._isDirectional = false;
+            // Used if you'd like to create a directional sound.
+            // If not set, the sound will be omnidirectional
+            this._coneInnerAngle = null;
+            this._coneOuterAngle = null;
+            this._coneOuterGain = null;
+            this._name = name;
+            this._scene = scene;
+            this._audioEngine = this._scene.getEngine().getAudioEngine();
             this._readyToPlayCallback = readyToPlayCallback;
-            if (distanceMax)
-                this.distanceMax = distanceMax;
-            if (autoplay)
-                this.autoplay = autoplay;
-            if (loop)
-                this.loop = loop;
+            if (options) {
+                if (options.distanceMax) {
+                    this.maxDistance = options.distanceMax;
+                }
+                if (options.autoplay) {
+                    this.autoplay = options.autoplay;
+                }
+                if (options.loop) {
+                    this.loop = options.loop;
+                }
+            }
+
             if (this._audioEngine.canUseWebAudio) {
                 BABYLON.Tools.LoadFile(url, function (data) {
                     _this._soundLoaded(data);
                 }, null, null, true);
             }
         }
+        /**
+        * Transform this sound into a directional source
+        * @param coneInnerAngle Size of the inner cone in degree
+        * @param coneOuterAngle Size of the outer cone in degree
+        * @param coneOuterGain Volume of the sound outside the outer cone (between 0.0 and 1.0)
+        */
+        Sound.prototype.setDirectionalCone = function (coneInnerAngle, coneOuterAngle, coneOuterGain) {
+            if (coneOuterAngle < coneInnerAngle) {
+                BABYLON.Tools.Error("setDirectionalCone(): outer angle of the cone must be superior or equal to the inner angle.");
+                return;
+            }
+            this._coneInnerAngle = coneInnerAngle;
+            this._coneOuterAngle = coneOuterAngle;
+            this._coneOuterGain = coneOuterGain;
+            this._isDirectional = true;
+
+            if (this._isPlaying && this.loop) {
+                this.stop();
+                this.play();
+            }
+        };
+
         Sound.prototype.setPosition = function (newPosition) {
             this._position = newPosition;
 
-            if (this._isReadyToPlay) {
+            if (this._isPlaying) {
                 this._soundPanner.setPosition(this._position.x, this._position.y, this._position.z);
             }
         };
 
-        Sound.prototype.setOrientiation = function (newOrientation) {
-            this._orientation = newOrientation;
+        Sound.prototype.setDirection = function (newDirection) {
+            this._direction = newDirection;
 
-            if (this._isReadyToPlay) {
-                this._soundPanner.setOrientation(this._orientation.x, this._orientation.y, this._orientation.z);
+            if (this._isPlaying) {
+                console.log(this._direction.x + " " + this._direction.y + " " + this._direction.z);
+                this._soundPanner.setOrientation(this._direction.x, this._direction.y, this._direction.z);
             }
         };
 
         Sound.prototype.play = function () {
             if (this._isReadyToPlay) {
-                this._soundSource = this._audioEngine.audioContext.createBufferSource();
-                this._soundSource.buffer = this._audioBuffer;
-                this._soundPanner = this._audioEngine.audioContext.createPanner();
-                this._soundPanner.setPosition(this._position.x, this._position.y, this._position.z);
-                this._soundPanner.connect(this._audioEngine.masterGain);
-                this._soundSource.connect(this._soundPanner);
-                this._soundSource.loop = this.loop;
-                this._soundSource.start(0);
+                try  {
+                    this._soundSource = this._audioEngine.audioContext.createBufferSource();
+                    this._soundSource.buffer = this._audioBuffer;
+                    this._soundPanner = this._audioEngine.audioContext.createPanner();
+                    this._soundPanner.setPosition(this._position.x, this._position.y, this._position.z);
+
+                    //this._soundPanner.maxDistance = this.maxDistance;
+                    if (this._isDirectional) {
+                        this._soundPanner.coneInnerAngle = this._coneInnerAngle;
+                        this._soundPanner.coneOuterAngle = this._coneOuterAngle;
+                        this._soundPanner.coneOuterGain = this._coneOuterGain;
+                        this._soundPanner.setOrientation(this._direction.x, this._direction.y, this._direction.z);
+                    }
+                    this._soundPanner.connect(this._audioEngine.masterGain);
+                    this._soundSource.connect(this._soundPanner);
+                    this._soundSource.loop = this.loop;
+                    this._soundSource.start(0);
+                    this._isPlaying = true;
+                } catch (ex) {
+                    BABYLON.Tools.Error("Error while trying to play audio: " + this._name + ", " + ex.message);
+                }
             }
         };
 
         Sound.prototype.stop = function () {
+            this._soundSource.stop(0);
+            this._isPlaying = false;
         };
 
         Sound.prototype.pause = function () {
@@ -68,6 +128,12 @@
 
         Sound.prototype._onRegisterAfterWorldMatrixUpdate = function (connectedMesh) {
             this.setPosition(connectedMesh.position);
+            if (this._isDirectional) {
+                var mat = connectedMesh.getWorldMatrix();
+                var direction = BABYLON.Vector3.TransformNormal(new BABYLON.Vector3(0, 0, 1), mat);
+                direction.normalize();
+                this.setDirection(direction);
+            }
         };
 
         Sound.prototype._soundLoaded = function (audioData) {
@@ -78,10 +144,10 @@
                 _this._isReadyToPlay = true;
                 if (_this.autoplay) {
                     _this.play();
-				}
+                }
                 if (_this._readyToPlayCallback) {
                     _this._readyToPlayCallback();
-				}
+                }
             }, function (error) {
                 BABYLON.Tools.Error("Error while decoding audio data: " + error.err);
             });

+ 89 - 24
Babylon/Audio/babylon.sound.ts

@@ -1,62 +1,121 @@
 module BABYLON {
     export class Sound {
         private _audioBuffer;
-        public distanceMax: number = 10;
+        public maxDistance: number = 10;
         public autoplay: boolean = false;
         public loop: boolean = false;
         private _position: Vector3 = Vector3.Zero();
-        private _orientation: Vector3 = Vector3.Zero();
+        private _direction: Vector3 = Vector3.Zero();
         private _volume: number;
         private _currentVolume: number;
         private _isLoaded: boolean = false;
         private _isReadyToPlay: boolean = false;
+        private _isPlaying: boolean = false;
+        private _isDirectional: boolean = false;
         private _audioEngine: BABYLON.AudioEngine;
         private _readyToPlayCallback;
         private _soundSource: AudioBufferSourceNode;
         private _soundPanner: PannerNode;
+        // Used if you'd like to create a directional sound.
+        // If not set, the sound will be omnidirectional
+        private _coneInnerAngle: number = null;
+        private _coneOuterAngle: number = null;
+        private _coneOuterGain: number = null;
+        private _scene: BABYLON.Scene;
+        private _name: string;
 
-        constructor(url: string, engine: BABYLON.Engine, readyToPlayCallback, distanceMax?: number, autoplay?: boolean, loop?: boolean) {
-            this._audioEngine = engine.getAudioEngine();;
+        /**
+        * Create a sound and attach it to a scene
+        * @param name Name of your sound 
+        * @param url Url to the sound to load async
+        * @param readyToPlayCallback Provide a callback function if you'd like to load your code once the sound is ready to be played
+        * @param options Objects to provide with the current available options: autoplay, loop, distanceMax
+        */
+        constructor(name: string, url: string, scene: BABYLON.Scene, readyToPlayCallback?: () => void, options?) {
+            this._name = name;
+            this._scene = scene;
+            this._audioEngine = this._scene.getEngine().getAudioEngine();
             this._readyToPlayCallback = readyToPlayCallback;
-            if (distanceMax) this.distanceMax = distanceMax;
-            if (autoplay) this.autoplay = autoplay;
-            if (loop) this.loop = loop;
+            if (options) {
+                if (options.distanceMax) { this.maxDistance = options.distanceMax; }
+                if (options.autoplay) { this.autoplay = options.autoplay; }
+                if (options.loop) { this.loop = options.loop; }
+            }
+
             if (this._audioEngine.canUseWebAudio) {
                 BABYLON.Tools.LoadFile(url, (data) => { this._soundLoaded(data); }, null, null, true);
             }
         }
 
+        /**
+        * Transform this sound into a directional source
+        * @param coneInnerAngle Size of the inner cone in degree
+        * @param coneOuterAngle Size of the outer cone in degree
+        * @param coneOuterGain Volume of the sound outside the outer cone (between 0.0 and 1.0)
+        */
+        public setDirectionalCone(coneInnerAngle: number, coneOuterAngle: number, coneOuterGain: number) {
+            if (coneOuterAngle < coneInnerAngle) {
+                BABYLON.Tools.Error("setDirectionalCone(): outer angle of the cone must be superior or equal to the inner angle.");
+                return;
+            }
+            this._coneInnerAngle = coneInnerAngle;
+            this._coneOuterAngle = coneOuterAngle;
+            this._coneOuterGain = coneOuterGain;
+            this._isDirectional = true;
+
+            if (this._isPlaying && this.loop) {
+                this.stop();
+                this.play();
+            }
+        }
+
         public setPosition(newPosition: Vector3) {
             this._position = newPosition;
 
-            if (this._isReadyToPlay) {    
+            if (this._isPlaying) {
                 this._soundPanner.setPosition(this._position.x, this._position.y, this._position.z);
             }
         }
 
-        public setOrientiation(newOrientation: Vector3) {
-            this._orientation = newOrientation;
+        public setDirection(newDirection: Vector3) {
+            this._direction = newDirection;
 
-            if (this._isReadyToPlay) {
-                this._soundPanner.setOrientation(this._orientation.x, this._orientation.y, this._orientation.z);
+            if (this._isPlaying) {
+                console.log(this._direction.x + " " + this._direction.y + " " + this._direction.z);
+                this._soundPanner.setOrientation(this._direction.x, this._direction.y, this._direction.z);
             }
         }
 
         public play() {
             if (this._isReadyToPlay) {
-                this._soundSource = this._audioEngine.audioContext.createBufferSource();
-                this._soundSource.buffer = this._audioBuffer;
-                this._soundPanner = this._audioEngine.audioContext.createPanner();
-                this._soundPanner.setPosition(this._position.x, this._position.y, this._position.z);
-                this._soundPanner.connect(this._audioEngine.masterGain);
-                this._soundSource.connect(this._soundPanner);
-                this._soundSource.loop = this.loop;
-                this._soundSource.start(0);
+                try {
+                    this._soundSource = this._audioEngine.audioContext.createBufferSource();
+                    this._soundSource.buffer = this._audioBuffer;
+                    this._soundPanner = this._audioEngine.audioContext.createPanner();
+                    this._soundPanner.setPosition(this._position.x, this._position.y, this._position.z);
+                    //this._soundPanner.maxDistance = this.maxDistance;
+                    if (this._isDirectional) {
+                        this._soundPanner.coneInnerAngle = this._coneInnerAngle;
+                        this._soundPanner.coneOuterAngle = this._coneOuterAngle;
+                        this._soundPanner.coneOuterGain = this._coneOuterGain;
+                        this._soundPanner.setOrientation(this._direction.x, this._direction.y, this._direction.z);
+                    }
+                    this._soundPanner.connect(this._audioEngine.masterGain);
+                    this._soundSource.connect(this._soundPanner);
+                    this._soundSource.loop = this.loop;
+                    this._soundSource.start(0);
+                    this._isPlaying = true;
+                }
+                catch (ex) {
+                    BABYLON.Tools.Error("Error while trying to play audio: " + this._name + ", " + ex.message);
+                }
             }
         }
-        
+
         public stop() {
-        }   
+            this._soundSource.stop(0);
+            this._isPlaying = false;
+        }
 
         public pause() {
         }
@@ -67,6 +126,12 @@
 
         private _onRegisterAfterWorldMatrixUpdate(connectedMesh: BABYLON.AbstractMesh) {
             this.setPosition(connectedMesh.position);
+            if (this._isDirectional) {
+                var mat = connectedMesh.getWorldMatrix();
+                var direction = BABYLON.Vector3.TransformNormal(new BABYLON.Vector3(0, 0, 1), mat);
+                direction.normalize();
+                this.setDirection(direction);
+            }
         }
 
         private _soundLoaded(audioData: ArrayBuffer) {
@@ -77,8 +142,8 @@
                 if (this.autoplay) { this.play(); }
                 if (this._readyToPlayCallback) { this._readyToPlayCallback(); }
             }, function (error) {
-                BABYLON.Tools.Error("Error while decoding audio data: " + error.err);
-            });
+                    BABYLON.Tools.Error("Error while decoding audio data: " + error.err);
+                });
         }
     }
 }

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

@@ -647,6 +647,10 @@
             mesh.showBoundingBox = parsedMesh.showBoundingBox;
             mesh.showSubMeshesBoundingBox = parsedMesh.showSubMeshesBoundingBox;
 
+            if (parseMesh.applyFog !== undefined) {
+                mesh.applyFog = parseMesh.applyFog;
+            }
+
             if (parsedMesh.pickable !== undefined) {
                 mesh.isPickable = parsedMesh.pickable;
             }

+ 4 - 0
Babylon/Loading/Plugins/babylon.babylonFileLoader.ts

@@ -656,6 +656,10 @@
         mesh.showBoundingBox = parsedMesh.showBoundingBox;
         mesh.showSubMeshesBoundingBox = parsedMesh.showSubMeshesBoundingBox;
 
+        if (parseMesh.applyFog !== undefined) {
+            mesh.applyFog = parseMesh.applyFog;
+        }
+
         if (parsedMesh.pickable !== undefined) {
             mesh.isPickable = parsedMesh.pickable;
         }

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

@@ -136,6 +136,10 @@ var BABYLON;
                 this._effect.setMatrix("worldViewProjection", world.multiply(this.getScene().getTransformMatrix()));
             }
 
+            if (this._options.uniforms.indexOf("viewProjection") !== -1) {
+                this._effect.setMatrix("viewProjection", this.getScene().getTransformMatrix());
+            }
+
             for (var name in this._textures) {
                 this._effect.setTexture(name, this._textures[name]);
             }

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

@@ -136,6 +136,10 @@
                 this._effect.setMatrix("worldViewProjection", world.multiply(this.getScene().getTransformMatrix()));
             }
 
+            if (this._options.uniforms.indexOf("viewProjection") !== -1) {
+                this._effect.setMatrix("viewProjection", this.getScene().getTransformMatrix());
+            }
+
             // Texture
             for (var name in this._textures) {
                 this._effect.setTexture(name, this._textures[name]);

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

@@ -176,7 +176,7 @@ var BABYLON;
             }
 
             // Fog
-            if (scene.fogMode !== BABYLON.Scene.FOGMODE_NONE && this.fogEnabled) {
+            if (mesh && mesh.applyFog && scene.fogMode !== BABYLON.Scene.FOGMODE_NONE && this.fogEnabled) {
                 defines.push("#define FOG");
                 fallbacks.addFallback(1, "FOG");
             }
@@ -318,7 +318,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");
 
@@ -474,17 +474,26 @@ var BABYLON;
             if (this.bumpTexture && scene.getEngine().getCaps().standardDerivatives && BABYLON.StandardMaterial.BumpTextureEnabled) {
                 this._effect.setTexture("bumpSampler", this.bumpTexture);
 
-                this._effect.setFloat2("vBumpInfos", this.bumpTexture.coordinatesIndex, this.bumpTexture.level);
+                this._effect.setFloat2("vBumpInfos", this.bumpTexture.coordinatesIndex, 1.0 / this.bumpTexture.level);
                 this._effect.setMatrix("bumpMatrix", this.bumpTexture.getTextureMatrix());
             }
 
             // Colors
             scene.ambientColor.multiplyToRef(this.ambientColor, this._globalAmbientColor);
 
+            // Scaling down colors 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._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("vDiffuseColor", this.diffuseColor, this.alpha * mesh.visibility);
-            this._effect.setColor4("vSpecularColor", this.specularColor, this.specularPower);
+            this._effect.setColor4("vDiffuseColor", this._scaledDiffuse, this.alpha * mesh.visibility);
+            this._effect.setColor4("vSpecularColor", this._scaledSpecular, this.specularPower);
             this._effect.setColor3("vEmissiveColor", this.emissiveColor);
 
             if (scene.lightsEnabled) {
@@ -542,12 +551,12 @@ var BABYLON;
             }
 
             // View
-            if (scene.fogMode !== BABYLON.Scene.FOGMODE_NONE || this.reflectionTexture) {
+            if (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 (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);
             }

+ 16 - 7
Babylon/Materials/babylon.standardMaterial.ts

@@ -180,7 +180,7 @@
             }
 
             // Fog
-            if (scene.fogMode !== BABYLON.Scene.FOGMODE_NONE && this.fogEnabled) {
+            if (mesh && mesh.applyFog && scene.fogMode !== BABYLON.Scene.FOGMODE_NONE && this.fogEnabled) {
                 defines.push("#define FOG");
                 fallbacks.addFallback(1, "FOG");
             }
@@ -327,7 +327,7 @@
                     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");
 
@@ -486,17 +486,26 @@
             if (this.bumpTexture && scene.getEngine().getCaps().standardDerivatives && BABYLON.StandardMaterial.BumpTextureEnabled) {
                 this._effect.setTexture("bumpSampler", this.bumpTexture);
 
-                this._effect.setFloat2("vBumpInfos", this.bumpTexture.coordinatesIndex, this.bumpTexture.level);
+                this._effect.setFloat2("vBumpInfos", this.bumpTexture.coordinatesIndex, 1.0 / this.bumpTexture.level);
                 this._effect.setMatrix("bumpMatrix", this.bumpTexture.getTextureMatrix());
             }
 
             // Colors
             scene.ambientColor.multiplyToRef(this.ambientColor, this._globalAmbientColor);
 
+            // Scaling down colors according to emissive
+            this._scaledDiffuse.r = this.diffuseColor.r * Tools.Clamp(1.0 - this.emissiveColor.r);
+            this._scaledDiffuse.g = this.diffuseColor.g * Tools.Clamp(1.0 - this.emissiveColor.g);
+            this._scaledDiffuse.b = this.diffuseColor.b * Tools.Clamp(1.0 - this.emissiveColor.b);
+
+            this._scaledSpecular.r = this.specularColor.r * Tools.Clamp(1.0 - this.emissiveColor.r);
+            this._scaledSpecular.g = this.specularColor.g * Tools.Clamp(1.0 - this.emissiveColor.g);
+            this._scaledSpecular.b = this.specularColor.b * 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.setColor4("vDiffuseColor", this._scaledDiffuse, this.alpha * mesh.visibility);
+            this._effect.setColor4("vSpecularColor", this._scaledSpecular, this.specularPower);
             this._effect.setColor3("vEmissiveColor", this.emissiveColor);
 
             if (scene.lightsEnabled) {
@@ -554,12 +563,12 @@
             }
 
             // View
-            if (scene.fogMode !== BABYLON.Scene.FOGMODE_NONE || this.reflectionTexture) {
+            if (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 (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);
             }

+ 43 - 29
Babylon/Materials/textures/Procedurals/babylon.customProceduralTexture.js

@@ -14,21 +14,26 @@ var BABYLON;
             this._time = 0;
             this._shaderLoaded = false;
             this._updateTexture = false;
-
             this._texturePath = texturePath;
 
             //readJson
             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 = 1;
         }
         CustomProceduralTexture.prototype.loadJson = function (jsonUrl) {
+            var that = this;
+
             function noConfigFile() {
-                BABYLON.Tools.Log("No config file found in " + jsonUrl);
+                BABYLON.Tools.Log("No config file found in " + jsonUrl + " trying as a shaderstore or dom");
+                try  {
+                    that._customFragment = that._texturePath;
+                    that._updateTexture = true;
+                    that._shaderLoaded = true;
+                } catch (ex) {
+                    BABYLON.Tools.Error("No json or shaderStore or Dom element found for the Custom Procedural Texture");
+                }
             }
 
-            var that = this;
             var configFileUrl = jsonUrl + "/config.json";
             var xhr = new XMLHttpRequest();
 
@@ -37,6 +42,7 @@ var BABYLON;
                 if (xhr.status === 200 || BABYLON.Tools.ValidateXHRData(xhr, 1)) {
                     try  {
                         that._config = JSON.parse(xhr.response);
+                        that._customFragment = this._texturePath + "/custom";
                         that._updateTexture = true;
                         that._shaderLoaded = true;
                     } catch (ex) {
@@ -65,12 +71,14 @@ var BABYLON;
 
             if (this._updateTexture) {
                 this.reset();
-                this.setFragment(this._texturePath + "/custom");
+                this.setFragment(this._customFragment);
                 this.updateTextures();
                 this.updateShaderUniforms();
                 this._shaderLoaded = true;
-                this._animate = this._config.animate;
-                this.refreshRate = this._config.refreshrate;
+                if (this._config) {
+                    this._animate = this._config.animate;
+                    this.refreshRate = this._config.refreshrate;
+                }
                 this.isReady();
                 this._updateTexture = false;
                 return;
@@ -85,33 +93,39 @@ var BABYLON;
         };
 
         CustomProceduralTexture.prototype.updateTextures = 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(), false, false, BABYLON.Texture.TRILINEAR_SAMPLINGMODE, null, null, null, true));
+            if (this._config) {
+                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(), false, false, BABYLON.Texture.TRILINEAR_SAMPLINGMODE, null, null, null, true));
+                }
             }
         };
 
         CustomProceduralTexture.prototype.updateShaderUniforms = function () {
-            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;
+            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, "animate", {

+ 47 - 32
Babylon/Materials/textures/Procedurals/babylon.customProceduralTexture.ts

@@ -1,31 +1,37 @@
 module BABYLON {
     export class CustomProceduralTexture extends ProceduralTexture {
-
         private _animate: boolean = true;
         private _time: number = 0;
         private _shaderLoaded: boolean = false;
         private _config: any;
-        private _texturePath: string;
+        private _texturePath: any;
         private _updateTexture: boolean = false;
+        private _customFragment: string;
 
-        constructor(name: string, texturePath: string, size: number, scene: Scene, fallbackTexture?: Texture, generateMipMaps?: boolean) {
+        constructor(name: string, texturePath: any, size: number, scene: Scene, fallbackTexture?: Texture, generateMipMaps?: boolean) {
             super(name, size, "empty", scene, fallbackTexture, generateMipMaps);
-
             this._texturePath = texturePath;
 
             //readJson
             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 = 1;
         }
 
         private loadJson(jsonUrl: string) {
+            var that = this;
+
             function noConfigFile() {
-                BABYLON.Tools.Log("No config file found in " + jsonUrl);
+                BABYLON.Tools.Log("No config file found in " + jsonUrl + " trying as a shaderstore or dom");
+                try {
+                    that._customFragment = that._texturePath;
+                    that._updateTexture = true;
+                    that._shaderLoaded = true;
+                }
+                catch (ex) {
+                    BABYLON.Tools.Error("No json or shaderStore or Dom element found for the Custom Procedural Texture");
+                }
             }
 
-            var that = this;
             var configFileUrl = jsonUrl + "/config.json";
             var xhr: XMLHttpRequest = new XMLHttpRequest();
 
@@ -34,6 +40,7 @@
                 if (xhr.status === 200 || BABYLON.Tools.ValidateXHRData(xhr, 1)) {
                     try {
                         that._config = JSON.parse(xhr.response);
+                        that._customFragment = this._texturePath + "/custom";
                         that._updateTexture = true;
                         that._shaderLoaded = true;
                     }
@@ -65,12 +72,14 @@
 
             if (this._updateTexture) {
                 this.reset();
-                this.setFragment(this._texturePath + "/custom")
+                this.setFragment(this._customFragment);
                 this.updateTextures();
                 this.updateShaderUniforms();
                 this._shaderLoaded = true;
-                this._animate = this._config.animate;
-                this.refreshRate = this._config.refreshrate;
+                if (this._config) {
+                    this._animate = this._config.animate;
+                    this.refreshRate = this._config.refreshrate;
+                }
                 this.isReady();
                 this._updateTexture = false;
                 return;
@@ -85,33 +94,39 @@
         }
 
         public updateTextures() {
-            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(), false, false, Texture.TRILINEAR_SAMPLINGMODE, null, null, null, true));
+            if (this._config) {
+                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(), false, false, Texture.TRILINEAR_SAMPLINGMODE, null, null, null, true));
+                }
             }
         }
 
         public updateShaderUniforms() {
-            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;
+            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);
         }
 
         public get animate(): boolean {

+ 8 - 1
Babylon/Materials/textures/Procedurals/babylon.proceduralTexture.js

@@ -67,8 +67,15 @@ var BABYLON;
         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.fragmentElement == undefined) {
+                shaders = { vertex: "procedural", fragment: this._fragment };
+            } else {
+                shaders = { vertex: "procedural", fragmentElement: this._fragment.fragmentElement };
+            }
+
+            this._effect = engine.createEffect(shaders, ["position"], this._uniforms, this._samplers, "", null, null, function () {
                 _this.releaseInternalTexture();
 
                 _this._texture = _this._fallbackTexture._texture;

+ 9 - 1
Babylon/Materials/textures/Procedurals/babylon.proceduralTexture.ts

@@ -74,8 +74,16 @@
       
         public isReady(): boolean {
             var engine = this.getScene().getEngine();
+            var shaders;
 
-            this._effect = engine.createEffect({ vertex: "procedural", fragment: this._fragment },
+            if (this._fragment.fragmentElement == undefined) {
+                shaders = { vertex: "procedural", fragment: this._fragment };
+            }
+            else {
+                shaders = { vertex: "procedural", fragmentElement: this._fragment.fragmentElement };
+            }
+
+            this._effect = engine.createEffect(shaders,
                 ["position"],
                 this._uniforms,
                 this._samplers,

+ 182 - 75
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,13 +56,11 @@ var BABYLON;
             this._time = 0.0;
             this._speed = new BABYLON.Vector2(0.5, 0.3);
             this._shift = 1.6;
-            this._alpha = 1.0;
+            this._alpha = 0.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 () {
@@ -73,13 +68,13 @@ var BABYLON;
             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 +82,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 +103,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 +118,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 +133,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,
@@ -225,12 +219,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 +260,99 @@ 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._dirtColor = new BABYLON.Color3(0.6, 0.46, 0.13);
+            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("herb1", this._grassColors[0]);
+            this.setColor3("herb2", this._grassColors[1]);
+            this.setColor3("herb3", this._grassColors[2]);
+            this.setColor3("dirt", this._dirtColor);
+            this.setColor3("ground", this._groundColor);
+        };
 
-    var RockProceduralTexture = (function (_super) {
-        __extends(RockProceduralTexture, _super);
-        function RockProceduralTexture(name, size, scene, fallbackTexture, generateMipMaps) {
-            _super.call(this, name, size, "rock", scene, fallbackTexture, generateMipMaps);
+        Object.defineProperty(GrassProceduralTexture.prototype, "grassColors", {
+            get: function () {
+                return this._grassColors;
+            },
+            set: function (value) {
+                this._grassColors = value;
+                this.updateShaderUniforms();
+            },
+            enumerable: true,
+            configurable: true
+        });
 
-            // 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, "dirtColor", {
+            get: function () {
+                return this._dirtColor;
+            },
+            set: function (value) {
+                this._dirtColor = value;
+                this.updateShaderUniforms();
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+
+        Object.defineProperty(GrassProceduralTexture.prototype, "groundColor", {
+            get: function () {
+                return this._groundColor;
+            },
+            enumerable: true,
+            configurable: true
+        });
+
+        Object.defineProperty(GrassProceduralTexture.prototype, "ground", {
+            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 +363,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("brick", this._brickColor);
+            this.setColor3("joint", this._jointColor);
         };
 
         Object.defineProperty(BrickProceduralTexture.prototype, "numberOfBricksHeight", {
@@ -348,6 +404,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 +438,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("numberOfBricksHeight", this._numberOfTilesHeight);
+            this.setFloat("numberOfBricksWidth", this._numberOfTilesWidth);
+            this.setFloat("amplitude", this._amplitude);
+            this.setColor3("brick", this._marbleColor);
+            this.setColor3("joint", 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,

+ 151 - 99
Babylon/Materials/textures/Procedurals/babylon.standardProceduralTexture.ts

@@ -1,17 +1,12 @@
 module BABYLON {
     export class WoodProceduralTexture extends ProceduralTexture {
-
         private _ampScale: number = 100.0;
         private _woodColor: BABYLON.Color3 = new BABYLON.Color3(0.32, 0.17, 0.09);
 
         constructor(name: string, size: number, scene: Scene, fallbackTexture?: Texture, generateMipMaps?: boolean) {
             super(name, size, "wood", scene, fallbackTexture, generateMipMaps);
-
             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;
-
         }
 
         public updateShaderUniforms() {
@@ -28,7 +23,6 @@
             this.updateShaderUniforms();
         }
 
-
         public get woodColor(): BABYLON.Color3 {
             return this._woodColor;
         }
@@ -37,105 +31,95 @@
             this._woodColor = value;
             this.updateShaderUniforms();
         }
-
     }
 
     export class FireProceduralTexture extends ProceduralTexture {
-
         private _time: number = 0.0;
         private _speed: BABYLON.Vector2 = new BABYLON.Vector2(0.5, 0.3);
         private _shift: number = 1.6;
-        private _alpha: number = 1.0;
+        private _alpha: number = 0.0;
         private _autoGenerateTime: boolean = true;
-
-        private _fireColors: number[][];
+        private _fireColors: BABYLON.Color3[];
+        private _alphaThreshold: number = 0.5;
 
         constructor(name: string, size: number, scene: Scene, fallbackTexture?: Texture, generateMipMaps?: boolean) {
             super(name, size, "fire", scene, fallbackTexture, generateMipMaps);
-
             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;
-
         }
 
         public updateShaderUniforms() {
-
             this.setFloat("iGlobalTime", 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);
         }
 
         public render(useCameraPostProcess?: boolean) {
-
             if (this._autoGenerateTime) {
                 this._time += this.getScene().getAnimationRatio() * 0.03;
                 this.updateShaderUniforms();
             }
-
             super.render(useCameraPostProcess);
         }
 
-        public static get PurpleFireColors(): number[][] {
+        public static get PurpleFireColors(): BABYLON.Color3[] {
             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)
             ];
         }
 
-        public static get GreenFireColors(): number[][] {
+        public static get GreenFireColors(): BABYLON.Color3[] {
             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)
             ];
         }
 
-        public static get RedFireColors(): number[][] {
+        public static get RedFireColors(): BABYLON.Color3[] {
             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)
             ];
         }
 
-        public static get BlueFireColors(): number[][] {
+        public static get BlueFireColors(): BABYLON.Color3[] {
             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)
             ];
         }
 
-        public get fireColors(): number[][] {
+        public get fireColors(): BABYLON.Color3[] {
             return this._fireColors;
         }
 
-        public set fireColors(value: number[][]) {
+        public set fireColors(value: BABYLON.Color3[]) {
             this._fireColors = value;
             this.updateShaderUniforms();
         }
@@ -175,26 +159,19 @@
             this._alpha = value;
             this.updateShaderUniforms();
         }
-
     }
 
     export class CloudProceduralTexture extends ProceduralTexture {
-
         private _skyColor: BABYLON.Color3 = new BABYLON.Color3(0.15, 0.68, 1.0);
         private _cloudColor: BABYLON.Color3 = new BABYLON.Color3(1, 1, 1);
 
         constructor(name: string, size: number, scene: Scene, fallbackTexture?: Texture, generateMipMaps?: boolean) {
             super(name, size, "cloud", scene, fallbackTexture, generateMipMaps);
-
             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
         }
 
         public updateShaderUniforms() {
-
             this.setColor3("skyColor", this._skyColor);
             this.setColor3("cloudColor", this._cloudColor);
         }
@@ -219,62 +196,104 @@
     }
 
     export class GrassProceduralTexture extends ProceduralTexture {
+        private _grassColors: BABYLON.Color3[];
+        private _herb1: BABYLON.Color3 = new BABYLON.Color3(0.29, 0.38, 0.02);
+        private _herb2: BABYLON.Color3 = new BABYLON.Color3(0.36, 0.49, 0.09);
+        private _herb3: BABYLON.Color3 = new BABYLON.Color3(0.51, 0.6, 0.28);
+        private _dirtColor: BABYLON.Color3 = new BABYLON.Color3(0.6, 0.46, 0.13);
+        private _groundColor: BABYLON.Color3 = new BABYLON.Color3(1, 1, 1);
 
         constructor(name: string, size: number, scene: Scene, fallbackTexture?: Texture, generateMipMaps?: boolean) {
             super(name, size, "grass", 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._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),
+            ];
+
+            this.updateShaderUniforms();
             this.refreshRate = 0;
+        }
 
+        public updateShaderUniforms() {
+            this.setColor3("herb1", this._grassColors[0]);
+            this.setColor3("herb2", this._grassColors[1]);
+            this.setColor3("herb3", this._grassColors[2]);
+            this.setColor3("dirt", this._dirtColor);
+            this.setColor3("ground", this._groundColor);
         }
-    }
 
+        public get grassColors(): BABYLON.Color3[] {
+            return this._grassColors;
+        }
 
-    export class RockProceduralTexture extends ProceduralTexture {
+        public set grassColors(value: BABYLON.Color3[]) {
+            this._grassColors = value;
+            this.updateShaderUniforms();
+        }
 
-        constructor(name: string, size: number, scene: Scene, fallbackTexture?: Texture, generateMipMaps?: boolean) {
-            super(name, size, "rock", scene, fallbackTexture, generateMipMaps);
+        public get dirtColor(): BABYLON.Color3 {
+            return this._dirtColor;
+        }
 
-            // Use 0 to render just once, 1 to render on every frame, 2 to render every two frames and so on...
-            this.refreshRate = 0;
+        public set dirtColor(value: BABYLON.Color3) {
+            this._dirtColor = value;
+            this.updateShaderUniforms();
+        }
+
+        public get groundColor(): BABYLON.Color3 {
+            return this._groundColor;
+        }
 
+        public set ground(value: BABYLON.Color3) {
+            this.groundColor = value;
+            this.updateShaderUniforms();
         }
     }
 
     export class RoadProceduralTexture extends ProceduralTexture {
+        private _roadColor: BABYLON.Color3 = new BABYLON.Color3(0.53, 0.53, 0.53);
 
         constructor(name: string, size: number, scene: Scene, fallbackTexture?: Texture, generateMipMaps?: boolean) {
             super(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.updateShaderUniforms();
             this.refreshRate = 0;
+        }
 
+        public updateShaderUniforms() {
+            this.setColor3("roadColor", this._roadColor);
+        }
+
+        public get roadColor(): BABYLON.Color3 {
+            return this._roadColor;
         }
-    }
 
+        public set roadColor(value: BABYLON.Color3) {
+            this._roadColor = value;
+            this.updateShaderUniforms();
+        }
+    }
 
     export class BrickProceduralTexture extends ProceduralTexture {
-
         private _numberOfBricksHeight: number = 15;
         private _numberOfBricksWidth: number = 5;
+        private _jointColor: BABYLON.Color3 = new BABYLON.Color3(0.72, 0.72, 0.72);
+        private _brickColor: BABYLON.Color3 = new BABYLON.Color3(0.77, 0.47, 0.40);
 
         constructor(name: string, size: number, scene: Scene, fallbackTexture?: Texture, generateMipMaps?: boolean) {
             super(name, size, "brick", scene, fallbackTexture, generateMipMaps);
-
             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;
-
         }
 
         public updateShaderUniforms() {
-
             this.setFloat("numberOfBricksHeight", this._numberOfBricksHeight);
             this.setFloat("numberOfBricksWidth", this._numberOfBricksWidth);
+            this.setColor3("brick", this._brickColor);
+            this.setColor3("joint", this._jointColor);
         }
 
-
         public get numberOfBricksHeight(): number {
             return this._numberOfBricksHeight;
         }
@@ -292,48 +311,81 @@
             this._numberOfBricksHeight = value;
             this.updateShaderUniforms();
         }
-    }
 
+        public get jointColor(): BABYLON.Color3 {
+            return this._jointColor;
+        }
 
-    export class MarbleProceduralTexture extends ProceduralTexture {
+        public set jointColor(value: BABYLON.Color3) {
+            this._jointColor = value;
+            this.updateShaderUniforms();
+        }
+
+        public get brickColor(): BABYLON.Color3 {
+            return this._brickColor;
+        }
 
-        private _numberOfBricksHeight: number = 3;
-        private _numberOfBricksWidth: number = 3;
+        public set brickColor(value: BABYLON.Color3) {
+            this._brickColor = value;
+            this.updateShaderUniforms();
+        }
+    }
+
+    export class MarbleProceduralTexture extends ProceduralTexture {
+        private _numberOfTilesHeight: number = 3;
+        private _numberOfTilesWidth: number = 3;
+        private _amplitude: number = 9.0;
+        private _marbleColor: BABYLON.Color3 = new BABYLON.Color3(0.77, 0.47, 0.40);
+        private _jointColor: BABYLON.Color3 = new BABYLON.Color3(0.72, 0.72, 0.72);
 
         constructor(name: string, size: number, scene: Scene, fallbackTexture?: Texture, generateMipMaps?: boolean) {
             super(name, size, "marble", scene, fallbackTexture, generateMipMaps);
-
             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;
-
         }
 
         public updateShaderUniforms() {
+            this.setFloat("numberOfBricksHeight", this._numberOfTilesHeight);
+            this.setFloat("numberOfBricksWidth", this._numberOfTilesWidth);
+            this.setFloat("amplitude", this._amplitude);
+            this.setColor3("brick", this._marbleColor);
+            this.setColor3("joint", this._jointColor);
+        }
 
-            this.setFloat("numberOfBricksHeight", this._numberOfBricksHeight);
-            this.setFloat("numberOfBricksWidth", this._numberOfBricksWidth);
+        public get numberOfTilesHeight(): number {
+            return this._numberOfTilesHeight;
         }
 
-        public get numberOfBricksHeight(): number {
-            return this._numberOfBricksHeight;
+        public set numberOfTilesHeight(value: number) {
+            this._numberOfTilesHeight = value;
+            this.updateShaderUniforms();
         }
 
-        public set cloudColor(value: number) {
-            this._numberOfBricksHeight = value;
+        public get numberOfTilesWidth(): number {
+            return this._numberOfTilesWidth;
+        }
+
+        public set numberOfTilesWidth(value: number) {
+            this._numberOfTilesWidth = value;
             this.updateShaderUniforms();
         }
 
-        public get numberOfBricksWidth(): number {
-            return this._numberOfBricksWidth;
+        public get jointColor(): BABYLON.Color3 {
+            return this._jointColor;
         }
 
-        public set numberOfBricksWidth(value: number) {
-            this._numberOfBricksHeight = value;
+        public set jointColor(value: BABYLON.Color3) {
+            this._jointColor = value;
             this.updateShaderUniforms();
         }
 
-    }
+        public get marbleColor(): BABYLON.Color3 {
+            return this._marbleColor;
+        }
 
+        public set marbleColor(value: BABYLON.Color3) {
+            this._marbleColor = value;
+            this.updateShaderUniforms();
+        }
+    }
 }

+ 27 - 12
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,10 +2324,10 @@
                 var min = (minimum.x - this.origin.x) * inv;
                 var max = (maximum.x - this.origin.x) * inv;
 
-				if(max == -Infinity) {
-					max = Infinity; 
-				}
-				
+                if (max == -Infinity) {
+                    max = Infinity;
+                }
+
                 if (min > max) {
                     var temp = min;
                     min = max;
@@ -2336,10 +2351,10 @@
                 min = (minimum.y - this.origin.y) * inv;
                 max = (maximum.y - this.origin.y) * inv;
 
-				if(max == -Infinity) {
-					max = Infinity; 
-				}
-				
+                if (max == -Infinity) {
+                    max = Infinity;
+                }
+
                 if (min > max) {
                     temp = min;
                     min = max;
@@ -2363,10 +2378,10 @@
                 min = (minimum.z - this.origin.z) * inv;
                 max = (maximum.z - this.origin.z) * inv;
 
-				if(max == -Infinity) {
-					max = Infinity; 
-				}
-				
+                if (max == -Infinity) {
+                    max = Infinity;
+                }
+
                 if (min > max) {
                     temp = min;
                     min = max;

+ 32 - 17
Babylon/Math/babylon.math.ts

@@ -403,7 +403,7 @@
             return new Vector2(x, y);
         }
 
-     
+
         public static Dot(left: Vector2, right: Vector2): number {
             return left.x * right.x + left.y * right.y;
         }
@@ -825,6 +825,21 @@
             return Vector3.TransformCoordinates(vector, finalMatrix);
         }
 
+        public static UnprojectFromTransform(source: Vector3, viewportWidth: number, viewportHeight: number, world: Matrix, transform: Matrix): Vector3 {
+            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;
+        }
+
         public static Unproject(source: Vector3, viewportWidth: number, viewportHeight: number, world: Matrix, view: Matrix, projection: Matrix): Vector3 {
             var matrix = world.multiply(view).multiply(projection);
             matrix.invert();
@@ -2308,10 +2323,10 @@
                 var min = (minimum.x - this.origin.x) * inv;
                 var max = (maximum.x - this.origin.x) * inv;
 
-				if(max == -Infinity) {
-					max = Infinity; 
-				}
-				
+                if (max == -Infinity) {
+                    max = Infinity;
+                }
+
                 if (min > max) {
                     var temp = min;
                     min = max;
@@ -2336,10 +2351,10 @@
                 min = (minimum.y - this.origin.y) * inv;
                 max = (maximum.y - this.origin.y) * inv;
 
-				if(max == -Infinity) {
-					max = Infinity; 
-				}
-				
+                if (max == -Infinity) {
+                    max = Infinity;
+                }
+
                 if (min > max) {
                     temp = min;
                     min = max;
@@ -2364,10 +2379,10 @@
                 min = (minimum.z - this.origin.z) * inv;
                 max = (maximum.z - this.origin.z) * inv;
 
-				if(max == -Infinity) {
-					max = Infinity; 
-				}
-				
+                if (max == -Infinity) {
+                    max = Infinity;
+                }
+
                 if (min > max) {
                     temp = min;
                     min = max;
@@ -2501,7 +2516,7 @@
 
     export class BezierCurve {
 
-        public static interpolate(t: number, x1: number, y1: number, x2: number, y2: number) :number {
+        public static interpolate(t: number, x1: number, y1: number, x2: number, y2: number): number {
 
             // Extract X (which is equal to time here)
             var f0 = 1 - 3 * x2 + 3 * x1;
@@ -2518,12 +2533,12 @@
                 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);
+                3 * (1 - refinedT) * Math.pow(refinedT, 2) * y2 +
+                Math.pow(refinedT, 3);
 
         }
     }

+ 6 - 0
Babylon/Mesh/babylon.abstractMesh.js

@@ -16,6 +16,7 @@ var BABYLON;
             this.scaling = new BABYLON.Vector3(1, 1, 1);
             this.billboardMode = BABYLON.AbstractMesh.BILLBOARDMODE_NONE;
             this.visibility = 1.0;
+            this.alphaLayer = 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;

+ 6 - 0
Babylon/Mesh/babylon.abstractMesh.ts

@@ -34,6 +34,7 @@
         public scaling = new BABYLON.Vector3(1, 1, 1);
         public billboardMode = BABYLON.AbstractMesh.BILLBOARDMODE_NONE;
         public visibility = 1.0;
+        public alphaLayer = Number.MAX_VALUE;
         public infiniteDistance = false;
         public isVisible = true;
         public isPickable = true;
@@ -50,7 +51,12 @@
         public renderOutline = false;
         public outlineColor = BABYLON.Color3.Red();
         public outlineWidth = 0.02;
+        public renderOverlay = false;
+        public overlayColor = BABYLON.Color3.Red();
+        public overlayAlpha = 0.5;
         public hasVertexAlpha = false;
+        public useVertexColors = true;
+        public applyFog = true;
 
         public useOctreeForRenderingSelection = true;
         public useOctreeForPicking = true;

+ 15 - 1
Babylon/Mesh/babylon.mesh.js

@@ -54,6 +54,11 @@ 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);
 
@@ -522,13 +527,14 @@ 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.forceWireframe ? BABYLON.Material.WireFrameFillMode : effectiveMaterial.fillMode;
             this._bind(subMesh, effect, fillMode);
 
             var world = this.getWorldMatrix();
@@ -568,6 +574,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]();
             }

+ 15 - 1
Babylon/Mesh/babylon.mesh.ts

@@ -51,6 +51,11 @@
         }
 
         public addLODLevel(distance: number, mesh: Mesh): Mesh {
+            if (mesh && mesh._masterMesh) {
+                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);
 
@@ -521,13 +526,14 @@
             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 ? Material.WireFrameFillMode : effectiveMaterial.fillMode;
+            var fillMode = scene.forceWireframe ? Material.WireFrameFillMode : effectiveMaterial.fillMode;
             this._bind(subMesh, effect, fillMode);
 
             var world = this.getWorldMatrix();
@@ -566,6 +572,14 @@
                 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]();
             }

+ 1 - 0
Babylon/Mesh/babylon.subMesh.ts

@@ -11,6 +11,7 @@
         public _lastColliderTransformMatrix: Matrix;
 
         public _renderId = 0;
+        public _alphaLayer: number;
         public _distanceToCamera: number;
         public _id: number;
 

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

@@ -312,6 +312,7 @@
 
             // Render
             engine.enableEffect(effect);
+            engine.setState(false);
 
             var viewMatrix = this._scene.getViewMatrix();
             effect.setTexture("diffuseSampler", this.particleTexture);

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

@@ -347,6 +347,7 @@
 
             // Render
             engine.enableEffect(effect);
+            engine.setState(false);
 
             var viewMatrix = this._scene.getViewMatrix();
             effect.setTexture("diffuseSampler", this.particleTexture);

+ 5 - 4
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,8 +19,8 @@
             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

+ 4 - 5
Babylon/Rendering/babylon.outlineRenderer.ts

@@ -8,11 +8,11 @@
             this._scene = scene;
         }
 
-        public render(subMesh: SubMesh, batch: _InstancesBatch) {
+        public render(subMesh: SubMesh, batch: _InstancesBatch, useOverlay: boolean = 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;
@@ -22,8 +22,8 @@
             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
@@ -41,7 +41,6 @@
                 this._effect.setMatrix("diffuseMatrix", alphaTexture.getTextureMatrix());
             }
 
-
             if (hardwareInstancedRendering) {
                 mesh._renderWithInstances(subMesh, Material.TriangleFillMode, batch, this._effect, engine);
             } else {

+ 10 - 0
Babylon/Rendering/babylon.renderingGroup.js

@@ -48,12 +48,22 @@
             if (this._transparentSubMeshes.length) {
                 for (subIndex = 0; subIndex < this._transparentSubMeshes.length; subIndex++) {
                     submesh = this._transparentSubMeshes.data[subIndex];
+                    submesh._alphaLayer = submesh.getMesh().alphaLayer;
                     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 layer first
+                    if (a._alphaLayer > b._alphaLayer) {
+                        return 1;
+                    }
+                    if (a._alphaLayer < b._alphaLayer) {
+                        return -1;
+                    }
+
+                    // Then distance to camera
                     if (a._distanceToCamera < b._distanceToCamera) {
                         return 1;
                     }

+ 10 - 0
Babylon/Rendering/babylon.renderingGroup.ts

@@ -51,12 +51,22 @@
                 // Sorting
                 for (subIndex = 0; subIndex < this._transparentSubMeshes.length; subIndex++) {
                     submesh = this._transparentSubMeshes.data[subIndex];
+                    submesh._alphaLayer = submesh.getMesh().alphaLayer;
                     submesh._distanceToCamera = submesh.getBoundingInfo().boundingSphere.centerWorld.subtract(this._scene.activeCamera.position).length();
                 }
 
                 var sortedArray = this._transparentSubMeshes.data.slice(0, this._transparentSubMeshes.length);
 
                 sortedArray.sort((a, b) => {
+                    // Alpha layer first
+                    if (a._alphaLayer > b._alphaLayer) {
+                        return 1;
+                    }
+                    if (a._alphaLayer < b._alphaLayer) {
+                        return -1;
+                    }
+
+                    // Then distance to camera
                     if (a._distanceToCamera < b._distanceToCamera) {
                         return 1;
                     }

+ 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 - 3
Babylon/Rendering/babylon.renderingManager.ts

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

+ 5 - 16
Babylon/Shaders/brick.fragment.fx

@@ -7,6 +7,8 @@ varying vec2 vUV;
 
 uniform float numberOfBricksHeight;
 uniform float numberOfBricksWidth;
+uniform vec3 brick;
+uniform vec3 joint;
 
 float rand(vec2 n) {
 	return fract(cos(dot(n, vec2(12.9898, 4.1414))) * 43758.5453);
@@ -34,20 +36,13 @@ float round(float number){
 
 void main(void)
 {
-	vec3 brick = vec3(0.77, 0.47, 0.40);
-	vec3 joint = vec3(0.72, 0.72, 0.72);
-
 	float brickW = 1.0 / numberOfBricksWidth;
 	float brickH = 1.0 / numberOfBricksHeight;
 	float jointWPercentage = 0.01;
 	float jointHPercentage = 0.05;
-
 	vec3 color = brick;
-
-
 	float yi = vUV.y / brickH;
 	float nyi = round(yi);
-
 	float xi = vUV.x / brickW;
 
 	if (mod(floor(yi), 2.0) == 0.0){
@@ -55,10 +50,8 @@ void main(void)
 	}
 
 	float nxi = round(xi);
-
 	vec2 brickvUV = vec2((xi - floor(xi)) / brickH, (yi - floor(yi)) /  brickW);
 
-
 	if (yi < nyi + jointHPercentage && yi > nyi - jointHPercentage){
 		color = mix(joint, vec3(0.37, 0.25, 0.25), (yi - nyi) / jointHPercentage + 0.2);
 	}
@@ -66,17 +59,13 @@ void main(void)
 		color = mix(joint, vec3(0.44, 0.44, 0.44), (xi - nxi) / jointWPercentage + 0.2);
 	}
 	else {
-		float momo = mod(floor(yi) + floor(xi), 3.0);
+		float brickColorSwitch = mod(floor(yi) + floor(xi), 3.0);
 
-		if (momo == 0.0)
+		if (brickColorSwitch == 0.0)
 			color = mix(color, vec3(0.33, 0.33, 0.33), 0.3);
-		else if (momo == 2.0)
+		else if (brickColorSwitch == 2.0)
 			color = mix(color, vec3(0.11, 0.11, 0.11), 0.3);
-
-
-		//color = mix(momo, vec3(0.53, 0.2, 0.0), fbm(brickvUV * 2.0));
 	}
 
-
 	gl_FragColor = vec4(color, 1.0);
 }

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

@@ -317,9 +317,9 @@ mat3 cotangent_frame(vec3 normal, vec3 p, vec2 uv)
 
 vec3 perturbNormal(vec3 viewDir)
 {
-	vec3 map = texture2D(bumpSampler, vBumpUV).xyz * vBumpInfos.y;
+	vec3 map = texture2D(bumpSampler, vBumpUV).xyz;
 	map = map * 255. / 127. - 128. / 127.;
-	mat3 TBN = cotangent_frame(vNormalW, -viewDir, vBumpUV);
+	mat3 TBN = cotangent_frame(vNormalW * vBumpInfos.y, -viewDir, vBumpUV);
 	return normalize(TBN * map);
 }
 #endif

+ 4 - 3
Babylon/Shaders/fire.fragment.fx

@@ -11,7 +11,7 @@ uniform vec3 c5;
 uniform vec3 c6;
 uniform vec2 speed;
 uniform float shift;
-uniform float alpha;
+uniform float alphaThreshold;
 
 varying vec2 vUV;
 
@@ -36,11 +36,12 @@ float fbm(vec2 n) {
 }
 
 void main() {
-
 	vec2 p = vUV * 8.0;
 	float q = fbm(p - iGlobalTime * 0.1);
 	vec2 r = vec2(fbm(p + q + iGlobalTime * speed.x - p.x - p.y), fbm(p + q - iGlobalTime * speed.y));
 	vec3 c = mix(c1, c2, fbm(p + r)) + mix(c3, c4, r.x) - mix(c5, c6, r.y);
-	gl_FragColor = vec4(c * cos(shift * vUV.y), alpha);
+	vec3 color = c * cos(shift * vUV.y);
+	float luminance = dot(color.rgb, vec3(0.3, 0.59, 0.11));
 
+	gl_FragColor = vec4(color, luminance * alphaThreshold + (1.0 - alphaThreshold));
 }

+ 10 - 14
Babylon/Shaders/grass.fragment.fx

@@ -5,6 +5,11 @@ precision highp float;
 varying vec2 vPosition;
 varying vec2 vUV;
 
+uniform vec3 herb1;
+uniform vec3 herb2;
+uniform vec3 herb3;
+uniform vec3 dirt;
+uniform vec3 ground;
 
 float rand(vec2 n) {
 	return fract(cos(dot(n, vec2(12.9898, 4.1414))) * 43758.5453);
@@ -27,18 +32,9 @@ float fbm(vec2 n) {
 }
 
 void main(void) {
-
-	vec3 herb1 = vec3(0.29, 0.38, 0.02);
-	vec3 herb2 = vec3(0.36, 0.49, 0.09);
-	vec3 herb3 = vec3(0.51, 0.6, 0.28);
-	vec3 dirt = vec3(0.6, 0.46, 0.13);
-
-	vec3 ground = vec3(1,1,1);
-	
-	ground = mix(ground, herb1, rand(gl_FragCoord.xy * 4.0));
-	ground = mix(ground, herb2, rand(gl_FragCoord.xy * 8.0));
-	ground = mix(ground, herb3, rand(gl_FragCoord.xy));
-	ground = mix(ground, herb1, fbm(gl_FragCoord.xy * 16.0));
-
-	gl_FragColor = vec4(ground, 1.0);
+	vec3 color = mix(ground, herb1, rand(gl_FragCoord.xy * 4.0));
+	color = mix(color, herb2, rand(gl_FragCoord.xy * 8.0));
+	color = mix(color, herb3, rand(gl_FragCoord.xy));
+	color = mix(color, herb1, fbm(gl_FragCoord.xy * 16.0));
+	gl_FragColor = vec4(color, 1.0);
 }

+ 4 - 21
Babylon/Shaders/marble.fragment.fx

@@ -5,14 +5,15 @@ precision highp float;
 varying vec2 vPosition;
 varying vec2 vUV;
 
-
 uniform float numberOfBricksHeight;
 uniform float numberOfBricksWidth ;
+uniform float amplitude;
+uniform vec3 brick;
+uniform vec3 joint;
 
 const vec3 tileSize = vec3(1.1, 1.0, 1.1);
 const vec3 tilePct = vec3(0.98, 1.0, 0.98);
 
-
 float rand(vec2 n) {
 	return fract(cos(dot(n, vec2(12.9898, 4.1414))) * 43758.5453);
 }
@@ -39,7 +40,6 @@ float round(float number){
 	return sign(number)*floor(abs(number) + 0.5);
 }
 
-
 vec3 marble_color(float x)
 {
 	vec3 col;
@@ -51,23 +51,16 @@ vec3 marble_color(float x)
 	col.b *= 0.95;           
 	return col;
 }
+
 void main()
 {
-
-	vec3 brick = vec3(0.77, 0.47, 0.40);
-	vec3 joint = vec3(0.72, 0.72, 0.72);
-
 	float brickW = 1.0 / numberOfBricksWidth;
 	float brickH = 1.0 / numberOfBricksHeight;
 	float jointWPercentage = 0.01;
 	float jointHPercentage = 0.01;
-
 	vec3 color = brick;
-
-
 	float yi = vUV.y / brickH;
 	float nyi = round(yi);
-
 	float xi = vUV.x / brickW;
 
 	if (mod(floor(yi), 2.0) == 0.0){
@@ -75,10 +68,8 @@ void main()
 	}
 
 	float nxi = round(xi);
-
 	vec2 brickvUV = vec2((xi - floor(xi)) / brickH, (yi - floor(yi)) / brickW);
 
-
 	if (yi < nyi + jointHPercentage && yi > nyi - jointHPercentage){
 		color = mix(joint, vec3(0.37, 0.25, 0.25), (yi - nyi) / jointHPercentage + 0.2);
 	}
@@ -86,19 +77,11 @@ void main()
 		color = mix(joint, vec3(0.44, 0.44, 0.44), (xi - nxi) / jointWPercentage + 0.2);
 	}
 	else {
-
-		float amplitude = 9.0;
-
 		float t = 6.28 * brickvUV.x / (tileSize.x + noise(vec2(vUV)*6.0));
 		t += amplitude * turbulence(brickvUV.xy);
-
 		t = sin(t);
 		color = marble_color(t);
-
-
 	}
 
 	gl_FragColor = vec4(color, 0.0);
-
-	
 }

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

@@ -1,6 +1,6 @@
 precision highp float;
 
-uniform vec3 color;
+uniform vec4 color;
 
 #ifdef ALPHATEST
 varying vec2 vUV;
@@ -13,5 +13,5 @@ void main(void) {
 		discard;
 #endif
 
-	gl_FragColor = vec4(color, 1.);
+	gl_FragColor = color;
 }

+ 3 - 8
Babylon/Shaders/road.fragment.fx

@@ -3,6 +3,7 @@ precision highp float;
 #endif
 
 varying vec2 vUV;                    
+uniform vec3 roadColor;
 
 float rand(vec2 n) {
 	return fract(cos(dot(n, vec2(12.9898, 4.1414))) * 43758.5453);
@@ -25,13 +26,7 @@ float fbm(vec2 n) {
 }
 
 void main(void) {
-
-
-	vec3 gray = vec3(0.53, 0.53, 0.53);
-
 	float ratioy = mod(gl_FragCoord.y * 100.0 , fbm(vUV * 2.0));
-		
-	gray = gray * ratioy;
-
-	gl_FragColor = vec4(gray, 1.0);
+	vec3 color = roadColor * ratioy;
+	gl_FragColor = vec4(color, 1.0);
 }

+ 0 - 3
Babylon/Shaders/wood.fragment.fx

@@ -8,7 +8,6 @@ varying vec2 vUV;
 uniform float ampScale;
 uniform vec3 woodColor;
 
-
 float rand(vec2 n) {
 	return fract(cos(dot(n, vec2(12.9898, 4.1414))) * 43758.5453);
 }
@@ -30,9 +29,7 @@ float fbm(vec2 n) {
 }
 
 void main(void) {
-
 	float ratioy = mod(vUV.x * ampScale, 2.0 + fbm(vUV * 0.8));
 	vec3 wood = woodColor * ratioy;
-
 	gl_FragColor = vec4(wood, 1.0);
 }

+ 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 - 5
Babylon/Tools/babylon.tools.ts

@@ -312,7 +312,14 @@
             }
         }
 
-        // Misc.        
+        // Misc.   
+        public static Clamp(value:number, min = 0, max = 1): number {
+            return Math.min(max, Math.max(min, value));
+        }     
+
+        public static Format(value: number, decimals: number = 2): string {
+            return value.toFixed(decimals);
+        }
 
         public static CheckExtends(v: Vector3, min: Vector3, max: Vector3): void {
             if (v.x < min.x)
@@ -612,6 +619,9 @@
         private static _MessageLogLevel = 1;
         private static _WarningLogLevel = 2;
         private static _ErrorLogLevel = 4;
+        private static _LogCache = "";
+
+        public static OnNewCacheEntry: (entry: string) => void;
 
         static get NoneLogLevel(): number {
             return Tools._NoneLogLevel;
@@ -633,11 +643,19 @@
             return Tools._MessageLogLevel | Tools._WarningLogLevel | Tools._ErrorLogLevel;
         }
 
+        private static _AddLogEntry(entry: string) {
+            Tools._LogCache = entry + Tools._LogCache;
+
+            if (Tools.OnNewCacheEntry) {
+                Tools.OnNewCacheEntry(entry);
+            }
+        }
+
         private static _FormatMessage(message: string): string {
             var padStr = i => (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;
         }
 
         public static Log: (message: string) => void = Tools._LogEnabled;
@@ -646,7 +664,11 @@
             // nothing to do
         }
         private static _LogEnabled(message: string): void {
-            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);
         }
 
         public static Warn: (message: string) => void = Tools._WarnEnabled;
@@ -655,7 +677,11 @@
             // nothing to do
         }
         private static _WarnEnabled(message: string): void {
-            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);
         }
 
         public static Error: (message: string) => void = Tools._ErrorEnabled;
@@ -664,7 +690,15 @@
             // nothing to do
         }
         private static _ErrorEnabled(message: string): void {
-            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);
+        }
+
+        public static get LogCache(): string {
+            return Tools._LogCache;
         }
 
         public static set LogLevels(level: number) {

+ 26 - 2
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();
@@ -473,6 +474,8 @@
             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 () {
@@ -588,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;
         };
@@ -734,7 +749,7 @@
         };
 
         Engine.prototype.flushFramebuffer = function () {
-            this._gl.flush();
+            //   this._gl.flush();
         };
 
         Engine.prototype.restoreDefaultFramebuffer = function () {
@@ -936,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) {
@@ -948,6 +965,7 @@
             }
 
             this._gl.drawArrays(this._gl.POINTS, verticesStart, verticesCount);
+            this._drawCalls++;
         };
 
         // Shaders
@@ -1189,6 +1207,12 @@
                     this._alphaState.alphaBlend = true;
                     break;
             }
+
+            this._alphaMode = mode;
+        };
+
+        Engine.prototype.getAlphaMode = function () {
+            return this._alphaMode;
         };
 
         Engine.prototype.setAlphaTesting = function (enable) {

+ 25 - 5
Babylon/babylon.engine.ts

@@ -354,8 +354,6 @@
         private static _DELAYLOADSTATE_LOADING = 2;
         private static _DELAYLOADSTATE_NOTLOADED = 4;
 
-        private _audioEngine: BABYLON.AudioEngine;
-
         public static get ALPHA_DISABLE(): number {
             return Engine._ALPHA_DISABLE;
         }
@@ -397,7 +395,6 @@
         // Public members
         public isFullscreen = false;
         public isPointerLock = false;
-        public forceWireframe = false;
         public cullBackFaces = true;
         public renderEvenInBackground = true;
         public scenes = new Array<Scene>();
@@ -407,6 +404,8 @@
         private _renderingCanvas: HTMLCanvasElement;
         private _windowIsBackground = false;
 
+        private _audioEngine: BABYLON.AudioEngine;
+
         private _onBlur: () => void;
         private _onFocus: () => void;
         private _onFullscreenChange: () => void;
@@ -425,9 +424,12 @@
         private _loadingTextDiv: HTMLDivElement;
         private _loadingDivBackgroundColor = "black";
 
+        private _drawCalls = 0;
+
         // States
         private _depthCullingState = new _DepthCullingState();
         private _alphaState = new _AlphaState();
+        private _alphaMode = Engine.ALPHA_DISABLE;
 
         // Cache
         private _loadedTexturesCache = new Array<WebGLTexture>();
@@ -550,6 +552,8 @@
             document.addEventListener("webkitpointerlockchange", this._onPointerLockChange, false);
 
             this._audioEngine = new BABYLON.AudioEngine();
+
+            Tools.Log("Babylon.js engine (v" + Engine.Version + ") launched");
         }
 
         public getAudioEngine(): AudioEngine {
@@ -602,7 +606,15 @@
             return this._caps;
         }
 
+        public get drawCalls(): number {
+            return this._drawCalls;
+        }
+
         // Methods
+        public resetDrawCalls(): void {
+            this._drawCalls = 0;
+        }
+
         public setDepthFunctionToGreater(): void {
             this._depthCullingState.depthFunc = this._gl.GREATER;
         }
@@ -746,7 +758,7 @@
         }
 
         public flushFramebuffer(): void {
-            this._gl.flush();
+         //   this._gl.flush();
         }
 
         public restoreDefaultFramebuffer(): void {
@@ -949,6 +961,8 @@
             }
 
             this._gl.drawElements(useTriangles ? this._gl.TRIANGLES : this._gl.LINES, indexCount, indexFormat, indexStart * 2);
+
+            this._drawCalls++;
         }
 
         public drawPointClouds(verticesStart: number, verticesCount: number, instancesCount?: number): void {
@@ -961,6 +975,7 @@
             }
 
             this._gl.drawArrays(this._gl.POINTS, verticesStart, verticesCount);
+            this._drawCalls++;
         }
 
         // Shaders
@@ -1191,7 +1206,6 @@
         }
 
         public setAlphaMode(mode: number): void {
-
             switch (mode) {
                 case BABYLON.Engine.ALPHA_DISABLE:
                     this.setDepthWrite(true);
@@ -1208,6 +1222,12 @@
                     this._alphaState.alphaBlend = true;
                     break;
             }
+
+            this._alphaMode = mode;
+        }
+
+        public getAlphaMode(): number {
+            return this._alphaMode;
         }
 
         public setAlphaTesting(enable: boolean): void {

+ 36 - 2
Babylon/babylon.scene.js

@@ -8,6 +8,7 @@
             this.clearColor = new BABYLON.Color3(0.2, 0.2, 0.3);
             this.ambientColor = new BABYLON.Color3(0, 0, 0);
             this.forceWireframe = false;
+            this.forceShowBoundingBoxes = false;
             this.cameraToUseForPointers = null;
             // Fog
             this.fogMode = BABYLON.Scene.FOGMODE_NONE;
@@ -75,6 +76,7 @@
             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);
@@ -98,10 +100,20 @@
             this._outlineRenderer = new BABYLON.OutlineRenderer(this);
 
             this.attachControl();
+
+            this._debugLayer = new BABYLON.DebugLayer(this);
         }
-        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,
@@ -329,6 +341,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);
         };
@@ -776,7 +800,7 @@
                 this._activeSkeletons.pushNoDuplicate(mesh.skeleton);
             }
 
-            if (mesh.showBoundingBox) {
+            if (mesh.showBoundingBox || this.forceShowBoundingBoxes) {
                 this._boundingBoxRenderer.renderList.push(mesh.getBoundingInfo().boundingBox);
             }
 
@@ -980,9 +1004,11 @@
             this._spritesDuration = 0;
             this._activeParticles = 0;
             this._renderDuration = 0;
+            this._renderTargetsDuration = 0;
             this._evaluateActiveMeshesDuration = 0;
             this._totalVertices = 0;
             this._activeVertices = 0;
+            this.getEngine().resetDrawCalls();
             this._meshesForIntersections.reset();
 
             BABYLON.Tools.StartPerformanceCounter("Scene rendering");
@@ -1103,6 +1129,10 @@
                 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;
@@ -1141,12 +1171,16 @@
 
             this._boundingBoxRenderer.dispose();
 
+            // Debug layer
+            this.debugLayer.enabled = false;
+
             // Events
             if (this.onDispose) {
                 this.onDispose();
             }
 
             this._onBeforeRenderCallbacks = [];
+            this._onAfterRenderCallbacks = [];
 
             this.detachControl();
 

+ 33 - 1
Babylon/babylon.scene.ts

@@ -23,6 +23,7 @@
         public beforeCameraRender: (camera: Camera) => void;
         public afterCameraRender: (camera: Camera) => void;
         public forceWireframe = false;
+        public forceShowBoundingBoxes = false;
         public clipPlane: Plane;
 
         // Pointers
@@ -140,6 +141,7 @@
         private _pendingData = [];//ANY
 
         private _onBeforeRenderCallbacks = new Array<() => void>();
+        private _onAfterRenderCallbacks = new Array<() => void>();
 
         private _activeMeshes = new SmartArray<Mesh>(256);
         private _processedMaterials = new SmartArray<Material>(256);
@@ -169,6 +171,8 @@
 
         private _pointerOverMesh: AbstractMesh;
 
+        private _debugLayer: DebugLayer;
+
         // Constructor
         constructor(engine: Engine) {
             this._engine = engine;
@@ -185,9 +189,15 @@
             this._outlineRenderer = new OutlineRenderer(this);
 
             this.attachControl();
+
+            this._debugLayer = new DebugLayer(this);
         }
 
         // Properties 
+        public get debugLayer(): DebugLayer {
+            return this._debugLayer;
+        }
+
         public get meshUnderPointer(): AbstractMesh {
             return this._meshUnderPointer;
         }
@@ -408,6 +418,18 @@
             }
         }
 
+        public registerAfterRender(func: () => void): void {
+            this._onAfterRenderCallbacks.push(func);
+        }
+
+        public unregisterAfterRender(func: () => void): void {
+            var index = this._onAfterRenderCallbacks.indexOf(func);
+
+            if (index > -1) {
+                this._onAfterRenderCallbacks.splice(index, 1);
+            }
+        }
+
         public _addPendingData(data): void {
             this._pendingData.push(data);
         }
@@ -852,7 +874,7 @@
                 this._activeSkeletons.pushNoDuplicate(mesh.skeleton);
             }
 
-            if (mesh.showBoundingBox) {
+            if (mesh.showBoundingBox || this.forceShowBoundingBoxes) {
                 this._boundingBoxRenderer.renderList.push(mesh.getBoundingInfo().boundingBox);
             }            
 
@@ -1058,9 +1080,11 @@
             this._spritesDuration = 0;
             this._activeParticles = 0;
             this._renderDuration = 0;
+            this._renderTargetsDuration = 0;
             this._evaluateActiveMeshesDuration = 0;
             this._totalVertices = 0;
             this._activeVertices = 0;
+            this.getEngine().resetDrawCalls();
             this._meshesForIntersections.reset();
 
             Tools.StartPerformanceCounter("Scene rendering");
@@ -1181,6 +1205,10 @@
                 this.afterRender();
             }
 
+            for (callbackIndex = 0; callbackIndex < this._onAfterRenderCallbacks.length; callbackIndex++) {
+                this._onAfterRenderCallbacks[callbackIndex]();
+            }
+
             // Cleaning
             for (var index = 0; index < this._toBeDisposed.length; index++) {
                 this._toBeDisposed.data[index].dispose();
@@ -1222,12 +1250,16 @@
 
             this._boundingBoxRenderer.dispose();
 
+            // Debug layer
+            this.debugLayer.enabled = false;
+
             // Events
             if (this.onDispose) {
                 this.onDispose();
             }
 
             this._onBeforeRenderCallbacks = [];
+            this._onAfterRenderCallbacks = [];
 
             this.detachControl();
 

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 1082 - 162
babylon.2.0-alpha.debug.js


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 19 - 17
babylon.2.0-alpha.js


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 4062 - 3
babylon.2.0.d.ts