Pārlūkot izejas kodu

Fixing procedural textures

David Catuhe 10 gadi atpakaļ
vecāks
revīzija
90f41e2386
46 mainītis faili ar 6201 papildinājumiem un 616 dzēšanām
  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();
 

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 1082 - 162
babylon.2.0-alpha.debug.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 19 - 17
babylon.2.0-alpha.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 4062 - 3
babylon.2.0.d.ts