소스 검색

Merge branch 'master' of https://github.com/BabylonJS/Babylon.js

Conflicts:
	dist/preview release/babylon.core.js
	dist/preview release/babylon.d.ts
	dist/preview release/babylon.js
	dist/preview release/babylon.max.js
	dist/preview release/babylon.noworker.js
	dist/preview release/what's new.md
David Catuhe 9 년 전
부모
커밋
b5b2789292
36개의 변경된 파일3796개의 추가작업 그리고 758개의 파일을 삭제
  1. BIN
      Exporters/3ds Max/Max2Babylon-0.20.zip
  2. 14 4
      Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Animation.cs
  3. 3 1
      Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Skeleton.cs
  4. 6 0
      Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Texture.cs
  5. BIN
      Exporters/3ds Max/Max2Babylon/Refs/BabylonFileConverter.dll
  6. 1 1
      dist/preview release/babylon.core.js
  7. 719 719
      dist/preview release/babylon.d.ts
  8. 1 1
      dist/preview release/babylon.js
  9. 1 1
      dist/preview release/babylon.max.js
  10. 1 1
      dist/preview release/babylon.noworker.js
  11. 3 2
      dist/preview release/what's new.md
  12. 41 14
      loaders/OBJ/babylon.objFileLoader.js
  13. 3 1
      loaders/OBJ/babylon.objFileLoader.ts
  14. 16 0
      materialsLibrary/config.json
  15. 286 0
      materialsLibrary/dist/babylon.fireMaterial.js
  16. 7 7
      materialsLibrary/dist/babylon.simpleMaterial.js
  17. 584 0
      materialsLibrary/dist/babylon.waterMaterial.js
  18. 0 1
      materialsLibrary/gulpfile.js
  19. 357 0
      materialsLibrary/materials/fire/babylon.fireMaterial.ts
  20. 149 0
      materialsLibrary/materials/fire/fire.fragment.fx
  21. 143 0
      materialsLibrary/materials/fire/fire.vertex.fx
  22. 1 1
      materialsLibrary/materials/simple/simple.fragment.fx
  23. 696 0
      materialsLibrary/materials/water/babylon.waterMaterial.ts
  24. 498 0
      materialsLibrary/materials/water/water.fragment.fx
  25. 207 0
      materialsLibrary/materials/water/water.vertex.fx
  26. 59 4
      materialsLibrary/test/index.html
  27. BIN
      materialsLibrary/test/textures/fire/diffuse.png
  28. BIN
      materialsLibrary/test/textures/fire/distortion.png
  29. BIN
      materialsLibrary/test/textures/fire/opacity.png
  30. BIN
      materialsLibrary/test/textures/skybox/TropicalSunnyDay_nx.jpg
  31. BIN
      materialsLibrary/test/textures/skybox/TropicalSunnyDay_ny.jpg
  32. BIN
      materialsLibrary/test/textures/skybox/TropicalSunnyDay_nz.jpg
  33. BIN
      materialsLibrary/test/textures/skybox/TropicalSunnyDay_px.jpg
  34. BIN
      materialsLibrary/test/textures/skybox/TropicalSunnyDay_py.jpg
  35. BIN
      materialsLibrary/test/textures/skybox/TropicalSunnyDay_pz.jpg
  36. BIN
      materialsLibrary/test/textures/waterbump.png

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


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

@@ -201,7 +201,7 @@ namespace Max2Babylon
 
         static float[] weightedLerp(int frame0, int frame1, int frame2, float[] value0, float[] value2)
         {
-            double weight2 = (double)(frame1 - frame0) / (double)(frame2 - frame0);
+            double weight2 = (frame1 - frame0) / (double)(frame2 - frame0);
             double weight0 = 1 - weight2;
             float[] result = new float[value0.Length];
             for (int i = 0; i < result.Length; ++i)
@@ -237,6 +237,8 @@ namespace Max2Babylon
 
         private static void ExportAnimation(string property, List<BabylonAnimation> animations, Func<int, float[]> extractValueFunc, BabylonAnimation.DataType dataType)
         {
+            var exportNonOptimizedAnimations = Loader.Core.RootNode.GetBoolProperty("babylonjs_exportnonoptimizedanimations");
+
             var start = Loader.Core.AnimRange.Start;
             var end = Loader.Core.AnimRange.End;
 
@@ -246,6 +248,10 @@ namespace Max2Babylon
             {
                 var current = extractValueFunc(key);
 
+                if (exportNonOptimizedAnimations && previous != null && previous.IsEqualTo(current))
+                {
+                    continue; // Do not add key
+                }
 
                 keys.Add(new BabylonAnimationKey()
                 {
@@ -253,11 +259,15 @@ namespace Max2Babylon
                     values = current
                 });
 
-
                 previous = current;
             }
-            RemoveLinearAnimationKeys(keys);
-            if (keys.Count > 0)
+
+            if (!exportNonOptimizedAnimations)
+            {
+                RemoveLinearAnimationKeys(keys);
+            }
+
+            if (keys.Count > 1)
             {
                 var animationPresent = true;
 

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

@@ -59,6 +59,8 @@ namespace Max2Babylon
             }
 
             // fix hierarchy an generate animation keys
+            var exportNonOptimizedAnimations = Loader.Core.RootNode.GetBoolProperty("babylonjs_exportnonoptimizedanimations");
+
             for (var index = 0; index < skin.TotalSkinBoneCount; index++)
             {
                 var gameBone = gameBones[index];
@@ -108,7 +110,7 @@ namespace Max2Babylon
                     }
 
                     var current = mat.ToArray();
-                    if (key == start || key == end || !(previous.IsEqualTo(current)))
+                    if (key == start || key == end || exportNonOptimizedAnimations || !(previous.IsEqualTo(current)))
                     {
                         keys.Add(new BabylonAnimationKey
                         {

+ 6 - 0
Exporters/3ds Max/Max2Babylon/Exporter/BabylonExporter.Texture.cs

@@ -65,6 +65,12 @@ namespace Max2Babylon
 
             var texMap = stdMat.GetSubTexmap(index);
 
+            if (texMap == null)
+            {
+                RaiseWarning("Texture channel " + index + " activated but no texture found.");
+                return null;
+            }
+
             // Fallout
             if (texMap.ClassName == "Falloff") // This is the only way I found to detect it. This is crappy but it works
             {

BIN
Exporters/3ds Max/Max2Babylon/Refs/BabylonFileConverter.dll


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 1 - 1
dist/preview release/babylon.core.js


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 719 - 719
dist/preview release/babylon.d.ts


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 1 - 1
dist/preview release/babylon.js


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 1 - 1
dist/preview release/babylon.max.js


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 1 - 1
dist/preview release/babylon.noworker.js


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

@@ -10,7 +10,8 @@
     - Sprites now can be [picked](http://www.babylonjs-playground.com/#1XMVZW#3) and can use [actions](http://www.babylonjs-playground.com/#9RUHH#3) ([deltakosh](https://github.com/deltakosh))
     - New `Mesh.CreatePolygon()` method ([jerome](https://github.com/jbousquie))
     - Introducing [babylon.core.js](http://doc.babylonjs.com/generals/Framework_versions) ([deltakosh](https://github.com/deltakosh))
-  - **Updates**    
+  - **Updates**
+    - Adding `StandardMaterial.linkEmissiveWithDiffuse` to, well, link emissive with diffuse value. (With)[http://www.babylonjs-playground.com/#2FPUCS#2] and (without)[http://www.babylonjs-playground.com/#2FPUCS#1] ([deltakosh](https://github.com/deltakosh))
     - Adding support for equi-rectangular mapping. See [demo here](http://www.babylonjs-playground.com/#27FN5R#8) ([deltakosh](https://github.com/deltakosh))
     - Sprites and particles scheduler updated to be resolved before transparent objects ([deltakosh](https://github.com/deltakosh))
     - Added `DirectionalLight.autoUpdateExtends` to prevent directional lights to adapt to scene extends ([deltakosh](https://github.com/deltakosh))
@@ -30,7 +31,7 @@
     - New `Material.getBindedMeshes()` function ([deltakosh](https://github.com/deltakosh))
     - OimoJS Plugin now uses Quaternions exclusively and calculates body rotations correctly. [PR](https://github.com/BabylonJS/Babylon.js/pull/761) ([RaananW](https://github.com/RaananW))
     - It is now possible to get the physics engine's body and wolrd objects using the physics engine. [PR](https://github.com/BabylonJS/Babylon.js/pull/761) ([RaananW](https://github.com/RaananW))
-    - new Heightmap Impostor for Cannon.js physics engine. [PR](https://github.com/BabylonJS/Babylon.js/pull/78), [Demo] (http://www.babylonjs-playground.com/#EXL6K#1) ([RaananW](https://github.com/RaananW))
+    - new Heightmap Impostor for Cannon.js physics engine. [PR](https://github.com/BabylonJS/Babylon.js/pull/78), [Demo] (http://www.babylonjs-playground.com/#D3LQD#3) ([RaananW](https://github.com/RaananW))
     - A plane mesh can be created with a source plane (math). [PR](https://github.com/BabylonJS/Babylon.js/pull/779) ([RaananW](https://github.com/RaananW))
   - **Bug fixes**
     - Fixed a bug with spherical mapping ([deltakosh](https://github.com/deltakosh)) 

+ 41 - 14
loaders/OBJ/babylon.objFileLoader.js

@@ -1,4 +1,3 @@
-/// <reference path="../../dist/babylon.2.2.d.ts" />
 var BABYLON;
 (function (BABYLON) {
     /**
@@ -27,6 +26,7 @@ var BABYLON;
                 var color;
                 //New material
                 var material;
+                //Look at each line
                 for (var i = 0; i < lines.length; i++) {
                     var line = lines[i].trim();
                     // Blank line or comment
@@ -202,7 +202,9 @@ var BABYLON;
             var loadedMeshes = this._parseSolid(meshesNames, scene, data, rootUrl);
             //Push meshes from OBJ file into the variable mesh of this function
             if (meshes) {
-                loadedMeshes = loadedMeshes.concat(meshes);
+                loadedMeshes.forEach(function (mesh) {
+                    meshes.push(mesh);
+                });
             }
             return true;
         };
@@ -330,6 +332,7 @@ var BABYLON;
              * Transform BABYLON.Vector() object onto 3 digits in an array
              */
             var unwrapData = function () {
+                //Every array has the same length
                 for (var l = 0; l < wrappedPositionForBabylon.length; l++) {
                     //Push the x, y, z values of each element in the unwrapped array
                     unwrappedPositionsForBabylon.push(wrappedPositionForBabylon[l].x, wrappedPositionForBabylon[l].y, wrappedPositionForBabylon[l].z);
@@ -375,10 +378,15 @@ var BABYLON;
             var setDataForCurrentFaceWithPattern1 = function (face, v) {
                 //Get the indices of triangles for each polygon
                 getTriangles(face, v);
+                //For each element in the triangles array.
+                //This var could contains 1 to an infinity of triangles
                 for (var k = 0; k < triangles.length; k++) {
                     // Set position indice
                     var indicePositionFromObj = parseInt(triangles[k]) - 1;
-                    setData(indicePositionFromObj, 0, 0, positions[indicePositionFromObj], BABYLON.Vector2.Zero(), BABYLON.Vector3.Up());
+                    setData(indicePositionFromObj, 0, 0, //In the pattern 1, normals and uvs are not defined
+                    positions[indicePositionFromObj], //Get the vectors data
+                    BABYLON.Vector2.Zero(), BABYLON.Vector3.Up() //Create default vectors
+                    );
                 }
                 //Reset variable for the next line
                 triangles = [];
@@ -400,7 +408,10 @@ var BABYLON;
                     var indicePositionFromObj = parseInt(point[0]) - 1;
                     //Set uv indice
                     var indiceUvsFromObj = parseInt(point[1]) - 1;
-                    setData(indicePositionFromObj, indiceUvsFromObj, 0, positions[indicePositionFromObj], uvs[indiceUvsFromObj], BABYLON.Vector3.Up());
+                    setData(indicePositionFromObj, indiceUvsFromObj, 0, //Default value for normals
+                    positions[indicePositionFromObj], //Get the values for each element
+                    uvs[indiceUvsFromObj], BABYLON.Vector3.Up() //Default value for normals
+                    );
                 }
                 //Reset variable for the next line
                 triangles = [];
@@ -424,7 +435,8 @@ var BABYLON;
                     var indiceUvsFromObj = parseInt(point[1]) - 1;
                     // Set normal indice
                     var indiceNormalFromObj = parseInt(point[2]) - 1;
-                    setData(indicePositionFromObj, indiceUvsFromObj, indiceNormalFromObj, positions[indicePositionFromObj], uvs[indiceUvsFromObj], normals[indiceNormalFromObj]);
+                    setData(indicePositionFromObj, indiceUvsFromObj, indiceNormalFromObj, positions[indicePositionFromObj], uvs[indiceUvsFromObj], normals[indiceNormalFromObj] //Set the vector for each component
+                    );
                 }
                 //Reset variable for the next line
                 triangles = [];
@@ -444,7 +456,9 @@ var BABYLON;
                     // We check indices, and normals
                     var indicePositionFromObj = parseInt(point[0]) - 1;
                     var indiceNormalFromObj = parseInt(point[1]) - 1;
-                    setData(indicePositionFromObj, 1, indiceNormalFromObj, positions[indicePositionFromObj], BABYLON.Vector2.Zero(), normals[indiceNormalFromObj]);
+                    setData(indicePositionFromObj, 1, //Default value for uv
+                    indiceNormalFromObj, positions[indicePositionFromObj], //Get each vector of data
+                    BABYLON.Vector2.Zero(), normals[indiceNormalFromObj]);
                 }
                 //Reset variable for the next line
                 triangles = [];
@@ -475,6 +489,7 @@ var BABYLON;
             //Main function
             //Split the file into lines
             var lines = data.split('\n');
+            //Look at each line
             for (var i = 0; i < lines.length; i++) {
                 var line = lines[i].trim();
                 var result;
@@ -507,30 +522,36 @@ var BABYLON;
                     //Value of result:
                     //["f 1/1/1 2/2/2 3/3/3", "1/1/1 2/2/2 3/3/3"...]
                     //Set the data for this face
-                    setDataForCurrentFaceWithPattern3(result[1].trim().split(" "), 1);
+                    setDataForCurrentFaceWithPattern3(result[1].trim().split(" "), // ["1/1/1", "2/2/2", "3/3/3"]
+                    1);
                 }
                 else if ((result = this.facePattern4.exec(line)) !== null) {
                     //Value of result:
                     //["f 1//1 2//2 3//3", "1//1 2//2 3//3"...]
                     //Set the data for this face
-                    setDataForCurrentFaceWithPattern4(result[1].trim().split(" "), 1);
+                    setDataForCurrentFaceWithPattern4(result[1].trim().split(" "), // ["1//1", "2//2", "3//3"]
+                    1);
                 }
                 else if ((result = this.facePattern2.exec(line)) !== null) {
                     //Value of result:
                     //["f 1/1 2/2 3/3", "1/1 2/2 3/3"...]
                     //Set the data for this face
-                    setDataForCurrentFaceWithPattern2(result[1].trim().split(" "), 1);
+                    setDataForCurrentFaceWithPattern2(result[1].trim().split(" "), // ["1/1", "2/2", "3/3"]
+                    1);
                 }
                 else if ((result = this.facePattern1.exec(line)) !== null) {
                     //Value of result
                     //["f 1 2 3", "1 2 3"...]
                     //Set the data for this face
-                    setDataForCurrentFaceWithPattern1(result[1].trim().split(" "), 1);
+                    setDataForCurrentFaceWithPattern1(result[1].trim().split(" "), // ["1", "2", "3"]
+                    1);
                 }
                 else if (this.group.test(line) || this.obj.test(line)) {
                     //Create a new mesh corresponding to the name of the group.
                     //Definition of the mesh
-                    var objMesh = {
+                    var objMesh = 
+                    //Set the name of the current obj mesh
+                    {
                         name: line.substring(2).trim(),
                         indices: undefined,
                         positions: undefined,
@@ -554,7 +575,9 @@ var BABYLON;
                         //Set the data for the previous mesh
                         addPreviousObjMesh();
                         //Create a new mesh
-                        var objMesh = {
+                        var objMesh = 
+                        //Set the name of the current obj mesh
+                        {
                             name: objMeshName + "_mm" + increment.toString(),
                             indices: undefined,
                             positions: undefined,
@@ -618,6 +641,7 @@ var BABYLON;
             var vertexData = new BABYLON.VertexData(); //The container for the values
             var babylonMeshesArray = []; //The mesh for babylon
             var materialToUse = [];
+            //Set data for each mesh
             for (var j = 0; j < meshesFromObj.length; j++) {
                 //check meshesNames (stlFileLoader)
                 if (meshesNames && meshesFromObj[j].name) {
@@ -657,11 +681,15 @@ var BABYLON;
                 this._loadMTL(fileToLoad, rootUrl, function (dataLoaded) {
                     //Create materials thanks MTLLoader function
                     materialsFromMTLFile.parseMTL(scene, dataLoaded, rootUrl);
+                    //Look at each material loaded in the mtl file
                     for (var n = 0; n < materialsFromMTLFile.materials.length; n++) {
                         //Three variables to get all meshes with the same material
                         var startIndex = 0;
                         var _indices = [];
                         var _index;
+                        //The material from MTL file is used in the meshes loaded
+                        //Push the indice in an array
+                        //Check if the material is not used for another mesh
                         while ((_index = materialToUse.indexOf(materialsFromMTLFile.materials[n].name, startIndex)) > -1) {
                             _indices.push(_index);
                             startIndex = _index + 1;
@@ -689,5 +717,4 @@ var BABYLON;
     BABYLON.OBJFileLoader = OBJFileLoader;
     //Add this loader into the register plugin
     BABYLON.SceneLoader.RegisterPlugin(new OBJFileLoader());
-})(BABYLON || (BABYLON = {}));
-//# sourceMappingURL=babylon.objFileLoader.js.map
+})(BABYLON || (BABYLON = {}));

+ 3 - 1
loaders/OBJ/babylon.objFileLoader.ts

@@ -218,7 +218,9 @@ module BABYLON {
             var loadedMeshes = this._parseSolid(meshesNames, scene, data, rootUrl);
             //Push meshes from OBJ file into the variable mesh of this function
             if (meshes) {
-                loadedMeshes = loadedMeshes.concat(meshes);
+                loadedMeshes.forEach(function (mesh) {
+                    meshes.push(mesh);
+                });
             }
             return true;
         }

+ 16 - 0
materialsLibrary/config.json

@@ -7,6 +7,22 @@
         "materials/simple/simple.fragment.fx"
       ],
       "output": "babylon.simpleMaterial.js"
+    },
+    {
+      "file": "materials/water/babylon.waterMaterial.ts",
+      "shaderFiles": [
+        "materials/water/water.vertex.fx",
+        "materials/water/water.fragment.fx"
+      ],
+      "output": "babylon.waterMaterial.js"
+    },
+    {
+      "file": "materials/fire/babylon.fireMaterial.ts",
+      "shaderFiles": [
+        "materials/fire/fire.vertex.fx",
+        "materials/fire/fire.fragment.fx"
+      ],
+      "output": "babylon.fireMaterial.js"
     }
   ],
   "build": {

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 286 - 0
materialsLibrary/dist/babylon.fireMaterial.js


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 7 - 7
materialsLibrary/dist/babylon.simpleMaterial.js


파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 584 - 0
materialsLibrary/dist/babylon.waterMaterial.js


+ 0 - 1
materialsLibrary/gulpfile.js

@@ -1,5 +1,4 @@
 var gulp = require("gulp");
-var uglify = require("gulp-uglify");
 var typescript = require("gulp-typescript");
 var srcToVariable = require("./gulp-srcToVariable");
 var merge2 = require("merge2");

+ 357 - 0
materialsLibrary/materials/fire/babylon.fireMaterial.ts

@@ -0,0 +1,357 @@
+/// <reference path="../../../dist/preview release/babylon.d.ts"/>
+
+module BABYLON {
+    var maxSimultaneousLights = 4;
+
+    class FireMaterialDefines extends MaterialDefines {
+        public DIFFUSE = false;
+        public CLIPPLANE = false;
+        public ALPHATEST = false;
+        public POINTSIZE = false;
+        public FOG = false;
+        public UV1 = false;
+        public NORMAL = false;
+        public VERTEXCOLOR = false;
+        public VERTEXALPHA = false;
+        public BONES = false;
+        public BONES4 = false;
+        public BonesPerMesh = 0;
+        public INSTANCES = false;
+
+        constructor() {
+            super();
+            this._keys = Object.keys(this);
+        }
+    }
+
+    export class FireMaterial extends Material {
+        public diffuseTexture: BaseTexture;
+        public distortionTexture: BaseTexture;
+        public opacityTexture: BaseTexture;
+
+        public diffuseColor = new Color3(1, 1, 1);
+        public disableLighting = false;
+        
+        public speed = 1.0;
+        
+        private _scaledDiffuse = new Color3();
+        private _renderId: number;
+
+        private _defines = new FireMaterialDefines();
+        private _cachedDefines = new FireMaterialDefines();
+        
+        private _lastTime: number = 0;
+
+        constructor(name: string, scene: Scene) {
+            super(name, scene);
+
+            this._cachedDefines.BonesPerMesh = -1;
+        }
+
+        public needAlphaBlending(): boolean {
+            return (this.alpha < 1.0);
+        }
+
+        public needAlphaTesting(): boolean {
+            return false;
+        }
+
+        public getAlphaTestTexture(): BaseTexture {
+            return null;
+        }
+
+        // Methods   
+        private _checkCache(scene: Scene, mesh?: AbstractMesh, useInstances?: boolean): boolean {
+            if (!mesh) {
+                return true;
+            }
+
+            if (this._defines.INSTANCES !== useInstances) {
+                return false;
+            }
+
+            if (mesh._materialDefines && mesh._materialDefines.isEqual(this._defines)) {
+                return true;
+            }
+
+            return false;
+        }
+
+        public isReady(mesh?: AbstractMesh, useInstances?: boolean): boolean {
+            if (this.checkReadyOnlyOnce) {
+                if (this._wasPreviouslyReady) {
+                    return true;
+                }
+            }
+
+            var scene = this.getScene();
+
+            if (!this.checkReadyOnEveryCall) {
+                if (this._renderId === scene.getRenderId()) {
+                    if (this._checkCache(scene, mesh, useInstances)) {
+                        return true;
+                    }
+                }
+            }
+
+            var engine = scene.getEngine();
+            var needNormals = false;
+            var needUVs = false;
+
+            this._defines.reset();
+
+            // Textures
+            if (scene.texturesEnabled) {
+                if (this.diffuseTexture && StandardMaterial.DiffuseTextureEnabled) {
+                    if (!this.diffuseTexture.isReady()) {
+                        return false;
+                    } else {
+                        needUVs = true;
+                        this._defines.DIFFUSE = true;
+                    }
+                }                
+            }
+
+            // Effect
+            if (scene.clipPlane) {
+                this._defines.CLIPPLANE = true;
+            }
+            
+            this._defines.ALPHATEST = true;
+
+            // Point size
+            if (this.pointsCloud || scene.forcePointsCloud) {
+                this._defines.POINTSIZE = true;
+            }
+
+            // Fog
+            if (scene.fogEnabled && mesh && mesh.applyFog && scene.fogMode !== Scene.FOGMODE_NONE && this.fogEnabled) {
+                this._defines.FOG = true;
+            }
+            
+            // Attribs
+            if (mesh) {
+                if (needNormals && mesh.isVerticesDataPresent(VertexBuffer.NormalKind)) {
+                    this._defines.NORMAL = true;
+                }
+                if (needUVs) {
+                    if (mesh.isVerticesDataPresent(VertexBuffer.UVKind)) {
+                        this._defines.UV1 = true;
+                    }
+                }
+                if (mesh.useVertexColors && mesh.isVerticesDataPresent(VertexBuffer.ColorKind)) {
+                    this._defines.VERTEXCOLOR = true;
+
+                    if (mesh.hasVertexAlpha) {
+                        this._defines.VERTEXALPHA = true;
+                    }
+                }
+                if (mesh.useBones && mesh.computeBonesUsingShaders) {
+                    this._defines.BONES = true;
+                    this._defines.BonesPerMesh = (mesh.skeleton.bones.length + 1);
+                    this._defines.BONES4 = true;
+                }
+
+                // Instances
+                if (useInstances) {
+                    this._defines.INSTANCES = true;
+                }
+            }
+
+            // Get correct effect      
+            if (!this._defines.isEqual(this._cachedDefines)) {
+                this._defines.cloneTo(this._cachedDefines);
+
+                scene.resetCachedMaterial();
+
+                // Fallbacks
+                var fallbacks = new EffectFallbacks();             
+                if (this._defines.FOG) {
+                    fallbacks.addFallback(1, "FOG");
+                }
+             
+                if (this._defines.BONES4) {
+                    fallbacks.addFallback(0, "BONES4");
+                }
+
+                //Attributes
+                var attribs = [VertexBuffer.PositionKind];
+
+                if (this._defines.NORMAL) {
+                    attribs.push(VertexBuffer.NormalKind);
+                }
+
+                if (this._defines.UV1) {
+                    attribs.push(VertexBuffer.UVKind);
+                }
+
+                if (this._defines.VERTEXCOLOR) {
+                    attribs.push(VertexBuffer.ColorKind);
+                }
+
+                if (this._defines.BONES) {
+                    attribs.push(VertexBuffer.MatricesIndicesKind);
+                    attribs.push(VertexBuffer.MatricesWeightsKind);
+                }
+
+                if (this._defines.INSTANCES) {
+                    attribs.push("world0");
+                    attribs.push("world1");
+                    attribs.push("world2");
+                    attribs.push("world3");
+                }
+
+                // Legacy browser patch
+                var shaderName = "fire";
+                
+                var join = this._defines.toString();
+                this._effect = scene.getEngine().createEffect(shaderName,
+                    attribs,
+                    ["world", "view", "viewProjection", "vEyePosition",
+                        "vFogInfos", "vFogColor", "pointSize",
+                        "vDiffuseInfos", 
+                        "mBones",
+                        "vClipPlane", "diffuseMatrix",
+                        // Fire
+                        "time", "speed"
+                    ],
+                    ["diffuseSampler",
+                        // Fire
+                        "distortionSampler", "opacitySampler"
+                    ],
+                    join, fallbacks, this.onCompiled, this.onError);
+            }
+            
+            if (!this._effect.isReady()) {
+                return false;
+            }
+
+            this._renderId = scene.getRenderId();
+            this._wasPreviouslyReady = true;
+
+            if (mesh) {
+                if (!mesh._materialDefines) {
+                    mesh._materialDefines = new FireMaterialDefines();
+                }
+
+                this._defines.cloneTo(mesh._materialDefines);
+            }
+
+            return true;
+        }
+
+        public bindOnlyWorldMatrix(world: Matrix): void {
+            this._effect.setMatrix("world", world);
+        }
+
+        public bind(world: Matrix, mesh?: Mesh): void {
+            var scene = this.getScene();
+
+            // Matrices        
+            this.bindOnlyWorldMatrix(world);
+            this._effect.setMatrix("viewProjection", scene.getTransformMatrix());
+
+            // Bones
+            if (mesh && mesh.useBones && mesh.computeBonesUsingShaders) {
+                this._effect.setMatrices("mBones", mesh.skeleton.getTransformMatrices());
+            }
+
+            if (scene.getCachedMaterial() !== this) {
+                // Textures        
+                if (this.diffuseTexture && StandardMaterial.DiffuseTextureEnabled) {
+                    this._effect.setTexture("diffuseSampler", this.diffuseTexture);
+
+                    this._effect.setFloat2("vDiffuseInfos", this.diffuseTexture.coordinatesIndex, this.diffuseTexture.level);
+                    this._effect.setMatrix("diffuseMatrix", this.diffuseTexture.getTextureMatrix());
+                    
+                    this._effect.setTexture("distortionSampler", this.distortionTexture);
+                    this._effect.setTexture("opacitySampler", this.opacityTexture);
+                }
+                
+                // Clip plane
+                if (scene.clipPlane) {
+                    var clipPlane = scene.clipPlane;
+                    this._effect.setFloat4("vClipPlane", clipPlane.normal.x, clipPlane.normal.y, clipPlane.normal.z, clipPlane.d);
+                }
+
+                // Point size
+                if (this.pointsCloud) {
+                    this._effect.setFloat("pointSize", this.pointSize);
+                }
+
+                this._effect.setVector3("vEyePosition", scene._mirroredCameraPosition ? scene._mirroredCameraPosition : scene.activeCamera.position);                
+            }
+
+            this._effect.setColor4("vDiffuseColor", this._scaledDiffuse, this.alpha * mesh.visibility);
+
+            // View
+            if (scene.fogEnabled && mesh.applyFog && scene.fogMode !== Scene.FOGMODE_NONE) {
+                this._effect.setMatrix("view", scene.getViewMatrix());
+            }
+            
+            // Fog
+            if (scene.fogEnabled && mesh.applyFog && scene.fogMode !== Scene.FOGMODE_NONE) {
+                this._effect.setFloat4("vFogInfos", scene.fogMode, scene.fogStart, scene.fogEnd, scene.fogDensity);
+                this._effect.setColor3("vFogColor", scene.fogColor);
+            }
+            
+            // Time
+            this._lastTime += scene.getEngine().getDeltaTime();
+            this._effect.setFloat("time", this._lastTime);
+            
+            // Speed
+            this._effect.setFloat("speed", this.speed);
+
+            super.bind(world, mesh);
+        }
+
+        public getAnimatables(): IAnimatable[] {
+            var results = [];
+
+            if (this.diffuseTexture && this.diffuseTexture.animations && this.diffuseTexture.animations.length > 0) {
+                results.push(this.diffuseTexture);
+            }
+            if (this.distortionTexture && this.distortionTexture.animations && this.distortionTexture.animations.length > 0) {
+                results.push(this.distortionTexture);
+            }
+            if (this.opacityTexture && this.opacityTexture.animations && this.opacityTexture.animations.length > 0) {
+                results.push(this.opacityTexture);
+            }
+
+            return results;
+        }
+
+        public dispose(forceDisposeEffect?: boolean): void {
+            if (this.diffuseTexture) {
+                this.diffuseTexture.dispose();
+            }
+            if (this.distortionTexture) {
+                this.distortionTexture.dispose();
+            }
+
+            super.dispose(forceDisposeEffect);
+        }
+
+        public clone(name: string): FireMaterial {
+            var newMaterial = new FireMaterial(name, this.getScene());
+
+            // Base material
+            this.copyTo(newMaterial);
+
+            // Fire material
+            if (this.diffuseTexture && this.diffuseTexture.clone) {
+                newMaterial.diffuseTexture = this.diffuseTexture.clone();
+            }
+            if (this.distortionTexture && this.distortionTexture.clone) {
+                newMaterial.distortionTexture = this.distortionTexture.clone();
+            }
+            if (this.opacityTexture && this.opacityTexture.clone) {
+                newMaterial.opacityTexture = this.opacityTexture.clone();
+            }
+
+            newMaterial.diffuseColor = this.diffuseColor.clone();
+            return newMaterial;
+        }
+    }
+} 
+

+ 149 - 0
materialsLibrary/materials/fire/fire.fragment.fx

@@ -0,0 +1,149 @@
+precision highp float;
+
+// Constants
+uniform vec3 vEyePosition;
+
+// Input
+varying vec3 vPositionW;
+
+#ifdef NORMAL
+varying vec3 vNormalW;
+#endif
+
+#ifdef VERTEXCOLOR
+varying vec4 vColor;
+#endif
+
+// Samplers
+#ifdef DIFFUSE
+varying vec2 vDiffuseUV;
+uniform sampler2D diffuseSampler;
+uniform vec2 vDiffuseInfos;
+#endif
+
+// Fire
+uniform sampler2D distortionSampler;
+uniform sampler2D opacitySampler;
+
+varying vec2 vDistortionCoords1;
+varying vec2 vDistortionCoords2;
+varying vec2 vDistortionCoords3;
+
+#ifdef CLIPPLANE
+varying float fClipDistance;
+#endif
+
+// Fog
+#ifdef FOG
+
+#define FOGMODE_NONE    0.
+#define FOGMODE_EXP     1.
+#define FOGMODE_EXP2    2.
+#define FOGMODE_LINEAR  3.
+#define E 2.71828
+
+uniform vec4 vFogInfos;
+uniform vec3 vFogColor;
+varying float fFogDistance;
+
+float CalcFogFactor()
+{
+	float fogCoeff = 1.0;
+	float fogStart = vFogInfos.y;
+	float fogEnd = vFogInfos.z;
+	float fogDensity = vFogInfos.w;
+
+	if (FOGMODE_LINEAR == vFogInfos.x)
+	{
+		fogCoeff = (fogEnd - fFogDistance) / (fogEnd - fogStart);
+	}
+	else if (FOGMODE_EXP == vFogInfos.x)
+	{
+		fogCoeff = 1.0 / pow(E, fFogDistance * fogDensity);
+	}
+	else if (FOGMODE_EXP2 == vFogInfos.x)
+	{
+		fogCoeff = 1.0 / pow(E, fFogDistance * fFogDistance * fogDensity * fogDensity);
+	}
+
+	return clamp(fogCoeff, 0.0, 1.0);
+}
+#endif
+
+vec4 bx2(vec4 x)
+{
+   return vec4(2.0) * x - vec4(1.0);
+}
+
+void main(void) {
+	// Clip plane
+#ifdef CLIPPLANE
+	if (fClipDistance > 0.0)
+		discard;
+#endif
+
+	vec3 viewDirectionW = normalize(vEyePosition - vPositionW);
+
+	// Base color
+	vec4 baseColor = vec4(1., 1., 1., 1.);
+
+	// Alpha
+	float alpha = 1.0;
+
+#ifdef DIFFUSE
+	// Fire
+	const float distortionAmount0  = 0.092;
+	const float distortionAmount1  = 0.092;
+	const float distortionAmount2  = 0.092;
+	
+	vec2 heightAttenuation = vec2(0.3, 0.39);
+	
+	vec4 noise0 = texture2D(distortionSampler, vDistortionCoords1);
+	vec4 noise1 = texture2D(distortionSampler, vDistortionCoords2);
+	vec4 noise2 = texture2D(distortionSampler, vDistortionCoords3);
+	
+	vec4 noiseSum = bx2(noise0) * distortionAmount0 + bx2(noise1) * distortionAmount1 + bx2(noise2) * distortionAmount2;
+	
+	vec4 perturbedBaseCoords = vec4(vDiffuseUV, 0.0, 1.0) + noiseSum * (vDiffuseUV.y * heightAttenuation.x + heightAttenuation.y);
+	
+	vec4 opacityColor = texture2D(opacitySampler, perturbedBaseCoords.xy);
+	
+	baseColor = texture2D(diffuseSampler, perturbedBaseCoords.xy) * 2.0;
+	baseColor *= opacityColor;
+
+#ifdef ALPHATEST
+	if (opacityColor.r < 0.1)
+		discard;
+#endif
+
+	baseColor.rgb *= vDiffuseInfos.y;
+#endif
+
+#ifdef VERTEXCOLOR
+	baseColor.rgb *= vColor.rgb;
+#endif
+
+	// Bump
+#ifdef NORMAL
+	vec3 normalW = normalize(vNormalW);
+#else
+	vec3 normalW = vec3(1.0, 1.0, 1.0);
+#endif
+
+	// Lighting
+	vec3 diffuseBase = vec3(1.0, 1.0, 1.0);
+
+#ifdef VERTEXALPHA
+	alpha *= vColor.a;
+#endif
+
+	// Composition
+	vec4 color = vec4(baseColor.rgb, alpha);
+
+#ifdef FOG
+	float fog = CalcFogFactor();
+	color.rgb = fog * color.rgb + (1.0 - fog) * vFogColor;
+#endif
+
+	gl_FragColor = color;
+}

+ 143 - 0
materialsLibrary/materials/fire/fire.vertex.fx

@@ -0,0 +1,143 @@
+precision highp float;
+
+// Attributes
+attribute vec3 position;
+#ifdef NORMAL
+attribute vec3 normal;
+#endif
+#ifdef UV1
+attribute vec2 uv;
+#endif
+#ifdef UV2
+attribute vec2 uv2;
+#endif
+#ifdef VERTEXCOLOR
+attribute vec4 color;
+#endif
+#ifdef BONES
+attribute vec4 matricesIndices;
+attribute vec4 matricesWeights;
+#endif
+
+// Uniforms
+
+#ifdef INSTANCES
+attribute vec4 world0;
+attribute vec4 world1;
+attribute vec4 world2;
+attribute vec4 world3;
+#else
+uniform mat4 world;
+#endif
+
+uniform mat4 view;
+uniform mat4 viewProjection;
+
+#ifdef DIFFUSE
+varying vec2 vDiffuseUV;
+#endif
+
+#ifdef BONES
+uniform mat4 mBones[BonesPerMesh];
+#endif
+
+#ifdef POINTSIZE
+uniform float pointSize;
+#endif
+
+// Output
+varying vec3 vPositionW;
+#ifdef NORMAL
+varying vec3 vNormalW;
+#endif
+
+#ifdef VERTEXCOLOR
+varying vec4 vColor;
+#endif
+
+#ifdef CLIPPLANE
+uniform vec4 vClipPlane;
+varying float fClipDistance;
+#endif
+
+#ifdef FOG
+varying float fFogDistance;
+#endif
+
+// Fire
+uniform float time;
+uniform float speed;
+
+varying vec2 vDistortionCoords1;
+varying vec2 vDistortionCoords2;
+varying vec2 vDistortionCoords3;
+
+void main(void) {
+	mat4 finalWorld;
+
+#ifdef INSTANCES
+	finalWorld = mat4(world0, world1, world2, world3);
+#else
+	finalWorld = world;
+#endif
+
+#ifdef BONES
+	mat4 m0 = mBones[int(matricesIndices.x)] * matricesWeights.x;
+	mat4 m1 = mBones[int(matricesIndices.y)] * matricesWeights.y;
+	mat4 m2 = mBones[int(matricesIndices.z)] * matricesWeights.z;
+
+#ifdef BONES4
+	mat4 m3 = mBones[int(matricesIndices.w)] * matricesWeights.w;
+	finalWorld = finalWorld * (m0 + m1 + m2 + m3);
+#else
+	finalWorld = finalWorld * (m0 + m1 + m2);
+#endif 
+
+#endif
+	gl_Position = viewProjection * finalWorld * vec4(position, 1.0);
+
+	vec4 worldPos = finalWorld * vec4(position, 1.0);
+	vPositionW = vec3(worldPos);
+
+#ifdef NORMAL
+	vNormalW = normalize(vec3(finalWorld * vec4(normal, 0.0)));
+#endif
+
+	// Texture coordinates
+#ifdef DIFFUSE
+	vDiffuseUV = uv;
+	vDiffuseUV.y -= 0.2;
+#endif
+
+	// Clip plane
+#ifdef CLIPPLANE
+	fClipDistance = dot(worldPos, vClipPlane);
+#endif
+
+	// Fog
+#ifdef FOG
+	fFogDistance = (view * worldPos).z;
+#endif
+
+	// Vertex color
+#ifdef VERTEXCOLOR
+	vColor = color;
+#endif
+
+	// Point size
+#ifdef POINTSIZE
+	gl_PointSize = pointSize;
+#endif
+
+	// Fire
+	vec3 layerSpeed = vec3(-0.2, -0.52, -0.1) * speed;
+	
+	vDistortionCoords1.x = uv.x;
+	vDistortionCoords1.y = uv.y + layerSpeed.x * time / 1000.0;
+	
+	vDistortionCoords2.x = uv.x;
+	vDistortionCoords2.y = uv.y + layerSpeed.y * time / 1000.0;
+	
+	vDistortionCoords3.x = uv.x;
+	vDistortionCoords3.y = uv.y + layerSpeed.z * time / 1000.0;
+}

+ 1 - 1
materialsLibrary/materials/simple/simple.fragment.fx

@@ -450,7 +450,7 @@ void main(void) {
 	vec3 finalDiffuse = clamp(diffuseBase * diffuseColor, 0.0, 1.0) * baseColor.rgb;
 
 	// Composition
-	vec4 color = vec4(finalDiffuse * baseAmbientColor + finalSpecular + reflectionColor, alpha);
+	vec4 color = vec4(finalDiffuse, alpha);
 
 #ifdef FOG
 	float fog = CalcFogFactor();

+ 696 - 0
materialsLibrary/materials/water/babylon.waterMaterial.ts

@@ -0,0 +1,696 @@
+/// <reference path="../../../dist/preview release/babylon.d.ts"/>
+/// <reference path="../simple/babylon.simpleMaterial.ts"/>
+
+module BABYLON {
+	var maxSimultaneousLights = 4;
+
+    class WaterMaterialDefines extends MaterialDefines {
+        public BUMP = false;
+        public REFLECTION = false;
+        public CLIPPLANE = false;
+        public ALPHATEST = false;
+        public POINTSIZE = false;
+        public FOG = false;
+        public LIGHT0 = false;
+        public LIGHT1 = false;
+        public LIGHT2 = false;
+        public LIGHT3 = false;
+        public SPOTLIGHT0 = false;
+        public SPOTLIGHT1 = false;
+        public SPOTLIGHT2 = false;
+        public SPOTLIGHT3 = false;
+        public HEMILIGHT0 = false;
+        public HEMILIGHT1 = false;
+        public HEMILIGHT2 = false;
+        public HEMILIGHT3 = false;
+        public POINTDIRLIGHT0 = false;
+        public POINTDIRLIGHT1 = false;
+        public POINTDIRLIGHT2 = false;
+        public POINTDIRLIGHT3 = false;
+        public SHADOW0 = false;
+        public SHADOW1 = false;
+        public SHADOW2 = false;
+        public SHADOW3 = false;
+        public SHADOWS = false;
+        public SHADOWVSM0 = false;
+        public SHADOWVSM1 = false;
+        public SHADOWVSM2 = false;
+        public SHADOWVSM3 = false;
+        public SHADOWPCF0 = false;
+        public SHADOWPCF1 = false;
+        public SHADOWPCF2 = false;
+        public SHADOWPCF3 = false;
+        public NORMAL = false;
+        public UV1 = false;
+        public UV2 = false;
+        public VERTEXCOLOR = false;
+        public VERTEXALPHA = false;
+        public BONES = false;
+        public BONES4 = false;
+        public BonesPerMesh = 0;
+        public INSTANCES = false;
+
+        constructor() {
+            super();
+            this._keys = Object.keys(this);
+        }
+    }
+	
+	export class WaterMaterial extends Material {
+		/*
+		* Public members
+		*/
+        public bumpTexture: BaseTexture;
+        public diffuseColor = new Color3(1, 1, 1);
+        public disableLighting = false;
+        
+        /**
+        * @param {number}: Represents the wind force
+        */
+		public windForce: number = 6;
+        /**
+        * @param {Vector2}: The direction of the wind in the plane (X, Z)
+        */
+		public windDirection: Vector2 = new Vector2(0, 1);
+        /**
+        * @param {number}: Wave height, represents the height of the waves
+        */
+		public waveHeight: number = 0.4;
+        /**
+        * @param {number}: Bump height, represents the bump height related to the bump map
+        */
+		public bumpHeight: number = 0.4;
+        /**
+        * @param {number}: The water color blended with the reflection and refraction samplers
+        */
+		public waterColor: Color3 = new Color3(0.1, 0.1, 0.6);
+        /**
+        * @param {number}: The blend factor related to the water color
+        */
+		public colorBlendFactor: number = 0.2;
+        /**
+        * @param {number}: Represents the maximum length of a wave
+        */
+		public waveLength: number = 0.1;
+		
+		/*
+		* Private members
+		*/
+		private _mesh: Mesh;
+		
+		private _refractionRTT: RenderTargetTexture;
+		private _reflectionRTT: RenderTargetTexture;
+		
+		private _material: ShaderMaterial;
+		
+		private _reflectionTransform: Matrix = Matrix.Zero();
+		private _lastTime: number = 0;
+        
+        private _scaledDiffuse = new Color3();
+        private _renderId: number;
+
+        private _defines = new WaterMaterialDefines();
+        private _cachedDefines = new WaterMaterialDefines();
+		
+		/**
+		* Constructor
+		*/
+		constructor(name: string, scene: Scene, sourceMesh: Mesh = null, renderTargetSize: Vector2 = new Vector2(512, 512)) {
+            super(name, scene);
+			
+			// Set this
+			this._mesh = sourceMesh;
+			
+			// Create render targets
+			this._createRenderTargets(scene, renderTargetSize);
+        }
+		
+        // Get / Set
+		public get mesh(): Mesh {
+			return this._mesh;
+		}
+		
+		public set mesh(mesh: Mesh) {
+			this._mesh = mesh;
+		}
+        
+        public get refractionTexture(): RenderTargetTexture {
+            return this._refractionRTT;
+        }
+        
+        public get reflectioNTexture(): RenderTargetTexture {
+            return this._reflectionRTT;
+        }
+		
+        // Methods
+        public addToRenderList(node: any): void {
+            this._refractionRTT.renderList.push(node);
+            this._reflectionRTT.renderList.push(node);
+        }
+        
+        public enableRenderTargets(enable: boolean): void {
+            var refreshRate = enable ? 1 : 0;
+            
+            this._refractionRTT.refreshRate = refreshRate;
+            this._reflectionRTT.refreshRate = refreshRate;
+        }
+        
+		public needAlphaBlending(): boolean {
+            return (this.alpha < 1.0);
+        }
+
+        public needAlphaTesting(): boolean {
+            return false;
+        }
+
+        public getAlphaTestTexture(): BaseTexture {
+            return null;
+        }
+         
+        private _checkCache(scene: Scene, mesh?: AbstractMesh, useInstances?: boolean): boolean {
+            if (!mesh) {
+                return true;
+            }
+
+            if (this._defines.INSTANCES !== useInstances) {
+                return false;
+            }
+
+            if (mesh._materialDefines && mesh._materialDefines.isEqual(this._defines)) {
+                return true;
+            }
+
+            return false;
+        }
+		
+		public isReady(mesh?: AbstractMesh, useInstances?: boolean): boolean {
+			if (this.checkReadyOnlyOnce) {
+                if (this._wasPreviouslyReady) {
+                    return true;
+                }
+            }
+
+            var scene = this.getScene();
+
+            if (!this.checkReadyOnEveryCall) {
+                if (this._renderId === scene.getRenderId()) {
+                    if (this._checkCache(scene, mesh, useInstances)) {
+                        return true;
+                    }
+                }
+            }
+
+            var engine = scene.getEngine();
+            var needNormals = false;
+            var needUVs = false;
+
+            this._defines.reset();
+
+            // Textures
+            if (scene.texturesEnabled) {
+                if (this.bumpTexture && StandardMaterial.BumpTextureEnabled) {
+                    if (!this.bumpTexture.isReady()) {
+                        return false;
+                    } else {
+                        needUVs = true;
+                        this._defines.BUMP = true;
+                    }
+                }
+                
+                if (StandardMaterial.ReflectionTextureEnabled) {
+                    this._defines.REFLECTION = true;
+                }
+            }
+
+            // Effect
+            if (scene.clipPlane) {
+                this._defines.CLIPPLANE = true;
+            }
+
+            if (engine.getAlphaTesting()) {
+                this._defines.ALPHATEST = true;
+            }
+
+            // Point size
+            if (this.pointsCloud || scene.forcePointsCloud) {
+                this._defines.POINTSIZE = true;
+            }
+
+            // Fog
+            if (scene.fogEnabled && mesh && mesh.applyFog && scene.fogMode !== Scene.FOGMODE_NONE && this.fogEnabled) {
+                this._defines.FOG = true;
+            }
+
+            var lightIndex = 0;
+            if (scene.lightsEnabled && !this.disableLighting) {
+                for (var index = 0; index < scene.lights.length; index++) {
+                    var light = scene.lights[index];
+
+                    if (!light.isEnabled()) {
+                        continue;
+                    }
+
+                    // Excluded check
+                    if (light._excludedMeshesIds.length > 0) {
+                        for (var excludedIndex = 0; excludedIndex < light._excludedMeshesIds.length; excludedIndex++) {
+                            var excludedMesh = scene.getMeshByID(light._excludedMeshesIds[excludedIndex]);
+
+                            if (excludedMesh) {
+                                light.excludedMeshes.push(excludedMesh);
+                            }
+                        }
+
+                        light._excludedMeshesIds = [];
+                    }
+
+                    // Included check
+                    if (light._includedOnlyMeshesIds.length > 0) {
+                        for (var includedOnlyIndex = 0; includedOnlyIndex < light._includedOnlyMeshesIds.length; includedOnlyIndex++) {
+                            var includedOnlyMesh = scene.getMeshByID(light._includedOnlyMeshesIds[includedOnlyIndex]);
+
+                            if (includedOnlyMesh) {
+                                light.includedOnlyMeshes.push(includedOnlyMesh);
+                            }
+                        }
+
+                        light._includedOnlyMeshesIds = [];
+                    }
+
+                    if (!light.canAffectMesh(mesh)) {
+                        continue;
+                    }
+                    needNormals = true;
+                    this._defines["LIGHT" + lightIndex] = true;
+
+                    var type;
+                    if (light instanceof SpotLight) {
+                        type = "SPOTLIGHT" + lightIndex;
+                    } else if (light instanceof HemisphericLight) {
+                        type = "HEMILIGHT" + lightIndex;
+                    } else {
+                        type = "POINTDIRLIGHT" + lightIndex;
+                    }
+
+                    this._defines[type] = true;
+
+                    // Shadows
+                    if (scene.shadowsEnabled) {
+                        var shadowGenerator = light.getShadowGenerator();
+                        if (mesh && mesh.receiveShadows && shadowGenerator) {
+                            this._defines["SHADOW" + lightIndex] = true;
+
+                            this._defines.SHADOWS = true;
+
+                            if (shadowGenerator.useVarianceShadowMap || shadowGenerator.useBlurVarianceShadowMap) {
+                                this._defines["SHADOWVSM" + lightIndex] = true;
+                            }
+
+                            if (shadowGenerator.usePoissonSampling) {
+                                this._defines["SHADOWPCF" + lightIndex] = true;
+                            }
+                        }
+                    }
+
+                    lightIndex++;
+                    if (lightIndex === maxSimultaneousLights)
+                        break;
+                }
+            }
+
+            // Attribs
+            if (mesh) {
+                if (needNormals && mesh.isVerticesDataPresent(VertexBuffer.NormalKind)) {
+                    this._defines.NORMAL = true;
+                }
+                if (needUVs) {
+                    if (mesh.isVerticesDataPresent(VertexBuffer.UVKind)) {
+                        this._defines.UV1 = true;
+                    }
+                    if (mesh.isVerticesDataPresent(VertexBuffer.UV2Kind)) {
+                        this._defines.UV2 = true;
+                    }
+                }
+                if (mesh.useVertexColors && mesh.isVerticesDataPresent(VertexBuffer.ColorKind)) {
+                    this._defines.VERTEXCOLOR = true;
+
+                    if (mesh.hasVertexAlpha) {
+                        this._defines.VERTEXALPHA = true;
+                    }
+                }
+                if (mesh.useBones && mesh.computeBonesUsingShaders) {
+                    this._defines.BONES = true;
+                    this._defines.BonesPerMesh = (mesh.skeleton.bones.length + 1);
+                    this._defines.BONES4 = true;
+                }
+
+                // Instances
+                if (useInstances) {
+                    this._defines.INSTANCES = true;
+                }
+            }
+
+            // Get correct effect      
+            if (!this._defines.isEqual(this._cachedDefines)) {
+                this._defines.cloneTo(this._cachedDefines);
+
+                scene.resetCachedMaterial();
+
+                // Fallbacks
+                var fallbacks = new EffectFallbacks();             
+                if (this._defines.FOG) {
+                    fallbacks.addFallback(1, "FOG");
+                }
+
+                for (lightIndex = 0; lightIndex < maxSimultaneousLights; lightIndex++) {
+                    if (!this._defines["LIGHT" + lightIndex]) {
+                        continue;
+                    }
+
+                    if (lightIndex > 0) {
+                        fallbacks.addFallback(lightIndex, "LIGHT" + lightIndex);
+                    }
+
+                    if (this._defines["SHADOW" + lightIndex]) {
+                        fallbacks.addFallback(0, "SHADOW" + lightIndex);
+                    }
+
+                    if (this._defines["SHADOWPCF" + lightIndex]) {
+                        fallbacks.addFallback(0, "SHADOWPCF" + lightIndex);
+                    }
+
+                    if (this._defines["SHADOWVSM" + lightIndex]) {
+                        fallbacks.addFallback(0, "SHADOWVSM" + lightIndex);
+                    }
+                }
+             
+                if (this._defines.BONES4) {
+                    fallbacks.addFallback(0, "BONES4");
+                }
+
+                //Attributes
+                var attribs = [VertexBuffer.PositionKind];
+
+                if (this._defines.NORMAL) {
+                    attribs.push(VertexBuffer.NormalKind);
+                }
+
+                if (this._defines.UV1) {
+                    attribs.push(VertexBuffer.UVKind);
+                }
+
+                if (this._defines.UV2) {
+                    attribs.push(VertexBuffer.UV2Kind);
+                }
+
+                if (this._defines.VERTEXCOLOR) {
+                    attribs.push(VertexBuffer.ColorKind);
+                }
+
+                if (this._defines.BONES) {
+                    attribs.push(VertexBuffer.MatricesIndicesKind);
+                    attribs.push(VertexBuffer.MatricesWeightsKind);
+                }
+
+                if (this._defines.INSTANCES) {
+                    attribs.push("world0");
+                    attribs.push("world1");
+                    attribs.push("world2");
+                    attribs.push("world3");
+                }
+
+                // Legacy browser patch
+                var shaderName = "water";
+                var join = this._defines.toString();
+				
+                this._effect = scene.getEngine().createEffect(shaderName,
+                    attribs,
+                    ["world", "view", "viewProjection", "vEyePosition", "vLightsType", "vDiffuseColor",
+                        "vLightData0", "vLightDiffuse0", "vLightSpecular0", "vLightDirection0", "vLightGround0", "lightMatrix0",
+                        "vLightData1", "vLightDiffuse1", "vLightSpecular1", "vLightDirection1", "vLightGround1", "lightMatrix1",
+                        "vLightData2", "vLightDiffuse2", "vLightSpecular2", "vLightDirection2", "vLightGround2", "lightMatrix2",
+                        "vLightData3", "vLightDiffuse3", "vLightSpecular3", "vLightDirection3", "vLightGround3", "lightMatrix3",
+                        "vFogInfos", "vFogColor", "pointSize",
+                        "vNormalInfos", 
+                        "mBones",
+                        "vClipPlane", "normalMatrix",
+                        "shadowsInfo0", "shadowsInfo1", "shadowsInfo2", "shadowsInfo3",
+						// Water
+						"worldReflectionViewProjection", "windDirection", "waveLength", "time", "windForce",
+						"cameraPosition", "bumpHeight", "waveHeight", "waterColor", "colorBlendFactor"
+                    ],
+                    ["normalSampler",
+                        "shadowSampler0", "shadowSampler1", "shadowSampler2", "shadowSampler3",
+						// Water
+						"refractionSampler", "reflectionSampler"
+                    ],
+                    join, fallbacks, this.onCompiled, this.onError);
+            }
+            if (!this._effect.isReady()) {
+                return false;
+            }
+
+            this._renderId = scene.getRenderId();
+            this._wasPreviouslyReady = true;
+
+            if (mesh) {
+                if (!mesh._materialDefines) {
+                    mesh._materialDefines = new WaterMaterialDefines();
+                }
+
+                this._defines.cloneTo(mesh._materialDefines);
+            }
+
+            return true;
+		}
+        
+        public bindOnlyWorldMatrix(world: Matrix): void {
+            this._effect.setMatrix("world", world);
+        }
+		
+		public bind(world: Matrix, mesh?: Mesh): void {
+            var scene = this.getScene();
+
+            // Matrices        
+            this.bindOnlyWorldMatrix(world);
+            this._effect.setMatrix("viewProjection", scene.getTransformMatrix());
+
+            // Bones
+            if (mesh && mesh.useBones && mesh.computeBonesUsingShaders) {
+                this._effect.setMatrices("mBones", mesh.skeleton.getTransformMatrices());
+            }
+
+            if (scene.getCachedMaterial() !== this) {
+                // Textures        
+                if (this.bumpTexture && StandardMaterial.BumpTextureEnabled) {
+                    this._effect.setTexture("normalSampler", this.bumpTexture);
+
+                    this._effect.setFloat2("vNormalInfos", this.bumpTexture.coordinatesIndex, this.bumpTexture.level);
+                    this._effect.setMatrix("normalMatrix", this.bumpTexture.getTextureMatrix());
+                }
+                // Clip plane
+                if (scene.clipPlane) {
+                    var clipPlane = scene.clipPlane;
+                    this._effect.setFloat4("vClipPlane", clipPlane.normal.x, clipPlane.normal.y, clipPlane.normal.z, clipPlane.d);
+                }
+
+                // Point size
+                if (this.pointsCloud) {
+                    this._effect.setFloat("pointSize", this.pointSize);
+                }
+
+                this._effect.setVector3("vEyePosition", scene._mirroredCameraPosition ? scene._mirroredCameraPosition : scene.activeCamera.position);                
+            }
+
+            this._effect.setColor4("vDiffuseColor", this._scaledDiffuse, this.alpha * mesh.visibility);
+
+            if (scene.lightsEnabled && !this.disableLighting) {
+                var lightIndex = 0;
+                for (var index = 0; index < scene.lights.length; index++) {
+                    var light = scene.lights[index];
+
+                    if (!light.isEnabled()) {
+                        continue;
+                    }
+
+                    if (!light.canAffectMesh(mesh)) {
+                        continue;
+                    }
+
+                    if (light instanceof PointLight) {
+                        // Point Light
+                        light.transferToEffect(this._effect, "vLightData" + lightIndex);
+                    } else if (light instanceof DirectionalLight) {
+                        // Directional Light
+                        light.transferToEffect(this._effect, "vLightData" + lightIndex);
+                    } else if (light instanceof SpotLight) {
+                        // Spot Light
+                        light.transferToEffect(this._effect, "vLightData" + lightIndex, "vLightDirection" + lightIndex);
+                    } else if (light instanceof HemisphericLight) {
+                        // Hemispheric Light
+                        light.transferToEffect(this._effect, "vLightData" + lightIndex, "vLightGround" + lightIndex);
+                    }
+
+                    light.diffuse.scaleToRef(light.intensity, this._scaledDiffuse);
+                    this._effect.setColor4("vLightDiffuse" + lightIndex, this._scaledDiffuse, light.range);
+
+                    // Shadows
+                    if (scene.shadowsEnabled) {
+                        var shadowGenerator = light.getShadowGenerator();
+                        if (mesh.receiveShadows && shadowGenerator) {
+                            this._effect.setMatrix("lightMatrix" + lightIndex, shadowGenerator.getTransformMatrix());
+                            this._effect.setTexture("shadowSampler" + lightIndex, shadowGenerator.getShadowMapForRendering());
+                            this._effect.setFloat3("shadowsInfo" + lightIndex, shadowGenerator.getDarkness(), shadowGenerator.getShadowMap().getSize().width, shadowGenerator.bias);
+                        }
+                    }
+
+                    lightIndex++;
+
+                    if (lightIndex === maxSimultaneousLights)
+                        break;
+                }
+            }
+
+            // View
+            if (scene.fogEnabled && mesh.applyFog && scene.fogMode !== Scene.FOGMODE_NONE) {
+                this._effect.setMatrix("view", scene.getViewMatrix());
+            }
+
+            // Fog
+            if (scene.fogEnabled && mesh.applyFog && scene.fogMode !== Scene.FOGMODE_NONE) {
+                this._effect.setFloat4("vFogInfos", scene.fogMode, scene.fogStart, scene.fogEnd, scene.fogDensity);
+                this._effect.setColor3("vFogColor", scene.fogColor);
+            }
+            
+            // Water
+            if (StandardMaterial.ReflectionTextureEnabled) {
+                this._effect.setTexture("refractionSampler", this._refractionRTT);
+                this._effect.setTexture("reflectionSampler", this._reflectionRTT);
+            }
+            
+			var wrvp = this._mesh.getWorldMatrix().multiply(this._reflectionTransform).multiply(scene.getProjectionMatrix());
+			this._lastTime += scene.getEngine().getDeltaTime();
+			
+			this._effect.setMatrix("worldReflectionViewProjection", wrvp);
+			this._effect.setVector2("windDirection", this.windDirection);
+			this._effect.setFloat("waveLength", this.waveLength);
+			this._effect.setFloat("time", this._lastTime / 100000);
+			this._effect.setFloat("windForce", this.windForce);
+			this._effect.setFloat("waveHeight", this.waveHeight);
+            this._effect.setFloat("bumpHeight", this.bumpHeight);
+			this._effect.setColor4("waterColor", this.waterColor, 1.0);
+			this._effect.setFloat("colorBlendFactor", this.colorBlendFactor);
+
+            super.bind(world, mesh);
+		}
+		
+		private _createRenderTargets(scene: Scene, renderTargetSize: Vector2): void {
+			// Render targets
+			this._refractionRTT = new RenderTargetTexture(name + "_refraction", {width: renderTargetSize.x, height: renderTargetSize.y}, scene, false, true);
+			this._reflectionRTT = new RenderTargetTexture(name + "_reflection", {width: renderTargetSize.x, height: renderTargetSize.y}, scene, false, true);
+			
+			scene.customRenderTargets.push(this._refractionRTT);
+			scene.customRenderTargets.push(this._reflectionRTT);
+			
+			var isVisible: boolean;
+			var clipPlane = null;
+			var savedViewMatrix;
+			var mirrorMatrix = Matrix.Zero();
+			
+			this._refractionRTT.onBeforeRender = () => {
+				isVisible = this._mesh.isVisible;
+				this._mesh.isVisible = false;
+				
+				// Clip plane
+				clipPlane = scene.clipPlane;
+				//scene.clipPlane = Plane.FromPositionAndNormal(new Vector3(0, this._mesh.position.y, 0), new Vector3(0, 1, 0));
+			};
+			
+			this._refractionRTT.onAfterRender = () => {
+				this._mesh.isVisible = isVisible;
+				
+				// Clip plane
+				scene.clipPlane = clipPlane;
+			};
+			
+			this._reflectionRTT.onBeforeRender = () => {
+				isVisible = this._mesh.isVisible;
+				this._mesh.isVisible = false;
+				
+				// Clip plane
+				clipPlane = scene.clipPlane;
+				scene.clipPlane = Plane.FromPositionAndNormal(new Vector3(0, this._mesh.position.y, 0), new Vector3(0, -1, 0));
+				
+				// Transform
+				Matrix.ReflectionToRef(scene.clipPlane, mirrorMatrix);
+				savedViewMatrix = scene.getViewMatrix();
+				
+				mirrorMatrix.multiplyToRef(savedViewMatrix, this._reflectionTransform);
+				scene.setTransformMatrix(this._reflectionTransform, scene.getProjectionMatrix());
+				scene.getEngine().cullBackFaces = false;
+                scene._mirroredCameraPosition = Vector3.TransformCoordinates(scene.activeCamera.position, mirrorMatrix);
+			};
+			
+			this._reflectionRTT.onAfterRender = () => {
+				this._mesh.isVisible = isVisible;
+				
+				// Clip plane
+				scene.clipPlane = clipPlane;
+				
+				// Transform
+				scene.setTransformMatrix(savedViewMatrix, scene.getProjectionMatrix());
+                scene.getEngine().cullBackFaces = true;
+                scene._mirroredCameraPosition = null;
+			};
+		}
+        
+        public getAnimatables(): IAnimatable[] {
+            var results = [];
+
+            if (this.bumpTexture && this.bumpTexture.animations && this.bumpTexture.animations.length > 0) {
+                results.push(this.bumpTexture);
+            }
+            if (this._reflectionRTT && this._reflectionRTT.animations && this._reflectionRTT.animations.length > 0) {
+                results.push(this._reflectionRTT);
+            }
+            if (this._refractionRTT && this._refractionRTT.animations && this._refractionRTT.animations.length > 0) {
+                results.push(this._refractionRTT);
+            }
+
+            return results;
+        }
+
+        public dispose(forceDisposeEffect?: boolean): void {
+            if (this.bumpTexture) {
+                this.bumpTexture.dispose();
+            }
+            if (this._reflectionRTT) {
+                this._reflectionRTT.dispose();
+            }
+            if (this._refractionRTT) {
+                this._refractionRTT.dispose();
+            }
+
+            super.dispose(forceDisposeEffect);
+        }
+
+        public clone(name: string): WaterMaterial {
+            var newMaterial = new WaterMaterial(name, this.getScene());
+
+            // Base material
+            this.copyTo(newMaterial);
+
+            // water material
+            if (this.bumpTexture && this.bumpTexture.clone) {
+                newMaterial.bumpTexture = this.bumpTexture.clone();
+            }
+
+            newMaterial.diffuseColor = this.diffuseColor.clone();
+            return newMaterial;
+        }
+        
+		public static CreateDefaultMesh(name: string, scene: Scene): Mesh {
+			var mesh = Mesh.CreateGround(name, 512, 512, 32, scene, false);
+			return mesh;
+		}
+	}
+}

+ 498 - 0
materialsLibrary/materials/water/water.fragment.fx

@@ -0,0 +1,498 @@
+precision highp float;
+
+// Constants
+uniform vec3 vEyePosition;
+uniform vec4 vDiffuseColor;
+
+// Input
+varying vec3 vPositionW;
+
+#ifdef NORMAL
+varying vec3 vNormalW;
+#endif
+
+#ifdef VERTEXCOLOR
+varying vec4 vColor;
+#endif
+
+// Lights
+#ifdef LIGHT0
+uniform vec4 vLightData0;
+uniform vec4 vLightDiffuse0;
+#ifdef SHADOW0
+varying vec4 vPositionFromLight0;
+uniform sampler2D shadowSampler0;
+uniform vec3 shadowsInfo0;
+#endif
+#ifdef SPOTLIGHT0
+uniform vec4 vLightDirection0;
+#endif
+#ifdef HEMILIGHT0
+uniform vec3 vLightGround0;
+#endif
+#endif
+
+#ifdef LIGHT1
+uniform vec4 vLightData1;
+uniform vec4 vLightDiffuse1;
+#ifdef SHADOW1
+varying vec4 vPositionFromLight1;
+uniform sampler2D shadowSampler1;
+uniform vec3 shadowsInfo1;
+#endif
+#ifdef SPOTLIGHT1
+uniform vec4 vLightDirection1;
+#endif
+#ifdef HEMILIGHT1
+uniform vec3 vLightGround1;
+#endif
+#endif
+
+#ifdef LIGHT2
+uniform vec4 vLightData2;
+uniform vec4 vLightDiffuse2;
+#ifdef SHADOW2
+varying vec4 vPositionFromLight2;
+uniform sampler2D shadowSampler2;
+uniform vec3 shadowsInfo2;
+#endif
+#ifdef SPOTLIGHT2
+uniform vec4 vLightDirection2;
+#endif
+#ifdef HEMILIGHT2
+uniform vec3 vLightGround2;
+#endif
+#endif
+
+#ifdef LIGHT3
+uniform vec4 vLightData3;
+uniform vec4 vLightDiffuse3;
+#ifdef SHADOW3
+varying vec4 vPositionFromLight3;
+uniform sampler2D shadowSampler3;
+uniform vec3 shadowsInfo3;
+#endif
+#ifdef SPOTLIGHT3
+uniform vec4 vLightDirection3;
+#endif
+#ifdef HEMILIGHT3
+uniform vec3 vLightGround3;
+#endif
+#endif
+
+// Samplers
+#ifdef BUMP
+varying vec2 vNormalUV;
+uniform sampler2D normalSampler;
+uniform vec2 vNormalInfos;
+#endif
+
+uniform sampler2D refractionSampler;
+uniform sampler2D reflectionSampler;
+
+// Water uniforms
+const float LOG2 = 1.442695;
+
+uniform vec3 cameraPosition;
+
+uniform vec4 waterColor;
+uniform float colorBlendFactor;
+
+// Water varyings
+varying vec3 vRefractionMapTexCoord;
+varying vec3 vReflectionMapTexCoord;
+varying vec3 vPosition;
+varying float vWaveHeight;
+
+// Shadows
+#ifdef SHADOWS
+
+float unpack(vec4 color)
+{
+	const vec4 bit_shift = vec4(1.0 / (255.0 * 255.0 * 255.0), 1.0 / (255.0 * 255.0), 1.0 / 255.0, 1.0);
+	return dot(color, bit_shift);
+}
+
+float unpackHalf(vec2 color)
+{
+	return color.x + (color.y / 255.0);
+}
+
+float computeShadow(vec4 vPositionFromLight, sampler2D shadowSampler, float darkness, float bias)
+{
+	vec3 depth = vPositionFromLight.xyz / vPositionFromLight.w;
+	depth = 0.5 * depth + vec3(0.5);
+	vec2 uv = depth.xy;
+
+	if (uv.x < 0. || uv.x > 1.0 || uv.y < 0. || uv.y > 1.0)
+	{
+		return 1.0;
+	}
+
+	float shadow = unpack(texture2D(shadowSampler, uv)) + bias;
+
+	if (depth.z > shadow)
+	{
+		return darkness;
+	}
+	return 1.;
+}
+
+float computeShadowWithPCF(vec4 vPositionFromLight, sampler2D shadowSampler, float mapSize, float bias, float darkness)
+{
+	vec3 depth = vPositionFromLight.xyz / vPositionFromLight.w;
+	depth = 0.5 * depth + vec3(0.5);
+	vec2 uv = depth.xy;
+
+	if (uv.x < 0. || uv.x > 1.0 || uv.y < 0. || uv.y > 1.0)
+	{
+		return 1.0;
+	}
+
+	float visibility = 1.;
+
+	vec2 poissonDisk[4];
+	poissonDisk[0] = vec2(-0.94201624, -0.39906216);
+	poissonDisk[1] = vec2(0.94558609, -0.76890725);
+	poissonDisk[2] = vec2(-0.094184101, -0.92938870);
+	poissonDisk[3] = vec2(0.34495938, 0.29387760);
+
+	// Poisson Sampling
+	float biasedDepth = depth.z - bias;
+
+	if (unpack(texture2D(shadowSampler, uv + poissonDisk[0] / mapSize)) < biasedDepth) visibility -= 0.25;
+	if (unpack(texture2D(shadowSampler, uv + poissonDisk[1] / mapSize)) < biasedDepth) visibility -= 0.25;
+	if (unpack(texture2D(shadowSampler, uv + poissonDisk[2] / mapSize)) < biasedDepth) visibility -= 0.25;
+	if (unpack(texture2D(shadowSampler, uv + poissonDisk[3] / mapSize)) < biasedDepth) visibility -= 0.25;
+
+	return  min(1.0, visibility + darkness);
+}
+
+// Thanks to http://devmaster.net/
+float linstep(float low, float high, float v) {
+	return clamp((v - low) / (high - low), 0.0, 1.0);
+}
+
+float ChebychevInequality(vec2 moments, float compare, float bias)
+{
+	float p = smoothstep(compare - bias, compare, moments.x);
+	float variance = max(moments.y - moments.x * moments.x, 0.02);
+	float d = compare - moments.x;
+	float p_max = linstep(0.2, 1.0, variance / (variance + d * d));
+
+	return clamp(max(p, p_max), 0.0, 1.0);
+}
+
+float computeShadowWithVSM(vec4 vPositionFromLight, sampler2D shadowSampler, float bias, float darkness)
+{
+	vec3 depth = vPositionFromLight.xyz / vPositionFromLight.w;
+	depth = 0.5 * depth + vec3(0.5);
+	vec2 uv = depth.xy;
+
+	if (uv.x < 0. || uv.x > 1.0 || uv.y < 0. || uv.y > 1.0 || depth.z >= 1.0)
+	{
+		return 1.0;
+	}
+
+	vec4 texel = texture2D(shadowSampler, uv);
+
+	vec2 moments = vec2(unpackHalf(texel.xy), unpackHalf(texel.zw));
+	return min(1.0, 1.0 - ChebychevInequality(moments, depth.z, bias) + darkness);
+}
+#endif
+
+#ifdef CLIPPLANE
+varying float fClipDistance;
+#endif
+
+// Fog
+#ifdef FOG
+
+#define FOGMODE_NONE    0.
+#define FOGMODE_EXP     1.
+#define FOGMODE_EXP2    2.
+#define FOGMODE_LINEAR  3.
+#define E 2.71828
+
+uniform vec4 vFogInfos;
+uniform vec3 vFogColor;
+varying float fFogDistance;
+
+float CalcFogFactor()
+{
+	float fogCoeff = 1.0;
+	float fogStart = vFogInfos.y;
+	float fogEnd = vFogInfos.z;
+	float fogDensity = vFogInfos.w;
+
+	if (FOGMODE_LINEAR == vFogInfos.x)
+	{
+		fogCoeff = (fogEnd - fFogDistance) / (fogEnd - fogStart);
+	}
+	else if (FOGMODE_EXP == vFogInfos.x)
+	{
+		fogCoeff = 1.0 / pow(E, fFogDistance * fogDensity);
+	}
+	else if (FOGMODE_EXP2 == vFogInfos.x)
+	{
+		fogCoeff = 1.0 / pow(E, fFogDistance * fFogDistance * fogDensity * fogDensity);
+	}
+
+	return clamp(fogCoeff, 0.0, 1.0);
+}
+#endif
+
+// Light Computing
+struct lightingInfo
+{
+	vec3 diffuse;
+};
+
+lightingInfo computeLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec3 diffuseColor, float range) {
+	lightingInfo result;
+
+	vec3 lightVectorW;
+	float attenuation = 1.0;
+	if (lightData.w == 0.)
+	{
+		vec3 direction = lightData.xyz - vPositionW;
+
+		attenuation = max(0., 1.0 - length(direction) / range);
+		lightVectorW = normalize(direction);
+	}
+	else
+	{
+		lightVectorW = normalize(-lightData.xyz);
+	}
+
+	// diffuse
+	float ndl = max(0., dot(vNormal, lightVectorW));
+	result.diffuse = ndl * diffuseColor * attenuation;
+
+	return result;
+}
+
+lightingInfo computeSpotLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec4 lightDirection, vec3 diffuseColor, float range) {
+	lightingInfo result;
+
+	vec3 direction = lightData.xyz - vPositionW;
+	vec3 lightVectorW = normalize(direction);
+	float attenuation = max(0., 1.0 - length(direction) / range);
+
+	// diffuse
+	float cosAngle = max(0., dot(-lightDirection.xyz, lightVectorW));
+	float spotAtten = 0.0;
+
+	if (cosAngle >= lightDirection.w)
+	{
+		cosAngle = max(0., pow(cosAngle, lightData.w));
+		spotAtten = clamp((cosAngle - lightDirection.w) / (1. - cosAngle), 0.0, 1.0);
+
+		// Diffuse
+		float ndl = max(0., dot(vNormal, -lightDirection.xyz));
+		result.diffuse = ndl * spotAtten * diffuseColor * attenuation;
+
+		return result;
+	}
+
+	result.diffuse = vec3(0.);
+
+	return result;
+}
+
+lightingInfo computeHemisphericLighting(vec3 viewDirectionW, vec3 vNormal, vec4 lightData, vec3 diffuseColor, vec3 groundColor) {
+	lightingInfo result;
+
+	// Diffuse
+	float ndl = dot(vNormal, lightData.xyz) * 0.5 + 0.5;
+	result.diffuse = mix(groundColor, diffuseColor, ndl);
+
+	return result;
+}
+
+void main(void) {
+	// Clip plane
+#ifdef CLIPPLANE
+	if (fClipDistance > 0.0)
+		discard;
+#endif
+
+	vec3 viewDirectionW = normalize(vEyePosition - vPositionW);
+
+	// Base color
+	vec4 baseColor = vec4(1., 1., 1., 1.);
+	vec3 diffuseColor = vDiffuseColor.rgb;
+
+	// Alpha
+	float alpha = vDiffuseColor.a;
+
+#ifdef BUMP
+	baseColor = texture2D(normalSampler, vNormalUV);
+
+#ifdef ALPHATEST
+	if (baseColor.a < 0.4)
+		discard;
+#endif
+
+	baseColor.rgb *= vNormalInfos.y;
+#endif
+
+#ifdef VERTEXCOLOR
+	baseColor.rgb *= vColor.rgb;
+#endif
+
+#ifdef REFLECTION
+	// Water
+	vec2 perturbation = vWaveHeight * (baseColor.rg - 0.5);
+	
+	vec2 projectedRefractionTexCoords = clamp(vRefractionMapTexCoord.xy / vRefractionMapTexCoord.z + perturbation, 0.0, 1.0);
+	vec4 refractiveColor = texture2D(refractionSampler, projectedRefractionTexCoords);
+	
+	vec2 projectedReflectionTexCoords = clamp(vReflectionMapTexCoord.xy / vReflectionMapTexCoord.z + perturbation, 0.0, 1.0);
+	vec4 reflectiveColor = texture2D(reflectionSampler, projectedReflectionTexCoords);
+	
+	vec3 eyeVector = normalize(vEyePosition - vPosition);
+	vec3 upVector = vec3(0.0, 1.0, 0.0);
+	
+	float fresnelTerm = max(dot(eyeVector, upVector), 0.0);
+	
+	vec4 combinedColor = refractiveColor * fresnelTerm + reflectiveColor * (1.0 - fresnelTerm);
+	
+	baseColor = colorBlendFactor * waterColor + (1.0 - colorBlendFactor) * combinedColor;
+#endif
+
+	// Bump
+#ifdef NORMAL
+	vec3 normalW = normalize(vNormalW);
+#else
+	vec3 normalW = vec3(1.0, 1.0, 1.0);
+#endif
+
+	// Lighting
+	vec3 diffuseBase = vec3(0., 0., 0.);
+	float shadow = 1.;
+
+#ifdef LIGHT0
+#ifdef SPOTLIGHT0
+	lightingInfo info = computeSpotLighting(viewDirectionW, normalW, vLightData0, vLightDirection0, vLightDiffuse0.rgb, vLightDiffuse0.a);
+#endif
+#ifdef HEMILIGHT0
+	lightingInfo info = computeHemisphericLighting(viewDirectionW, normalW, vLightData0, vLightDiffuse0.rgb, vLightGround0);
+#endif
+#ifdef POINTDIRLIGHT0
+	lightingInfo info = computeLighting(viewDirectionW, normalW, vLightData0, vLightDiffuse0.rgb, vLightDiffuse0.a);
+#endif
+#ifdef SHADOW0
+#ifdef SHADOWVSM0
+	shadow = computeShadowWithVSM(vPositionFromLight0, shadowSampler0, shadowsInfo0.z, shadowsInfo0.x);
+#else
+#ifdef SHADOWPCF0
+	shadow = computeShadowWithPCF(vPositionFromLight0, shadowSampler0, shadowsInfo0.y, shadowsInfo0.z, shadowsInfo0.x);
+#else
+	shadow = computeShadow(vPositionFromLight0, shadowSampler0, shadowsInfo0.x, shadowsInfo0.z);
+#endif
+#endif
+#else
+	shadow = 1.;
+#endif
+	diffuseBase += info.diffuse * shadow;
+#endif
+
+#ifdef LIGHT1
+
+#ifdef SPOTLIGHT1
+	info = computeSpotLighting(viewDirectionW, normalW, vLightData1, vLightDirection1, vLightDiffuse1.rgb, vLightDiffuse1.a);
+#endif
+#ifdef HEMILIGHT1
+	info = computeHemisphericLighting(viewDirectionW, normalW, vLightData1, vLightDiffuse1.rgb, vLightGround1);
+#endif
+#ifdef POINTDIRLIGHT1
+	info = computeLighting(viewDirectionW, normalW, vLightData1, vLightDiffuse1.rgb, vLightDiffuse1.a);
+#endif
+#ifdef SHADOW1
+#ifdef SHADOWVSM1
+	shadow = computeShadowWithVSM(vPositionFromLight1, shadowSampler1, shadowsInfo1.z, shadowsInfo1.x);
+#else
+#ifdef SHADOWPCF1
+	shadow = computeShadowWithPCF(vPositionFromLight1, shadowSampler1, shadowsInfo1.y, shadowsInfo1.z, shadowsInfo1.x);
+#else
+	shadow = computeShadow(vPositionFromLight1, shadowSampler1, shadowsInfo1.x, shadowsInfo1.z);
+#endif
+#endif
+#else
+	shadow = 1.;
+#endif
+	diffuseBase += info.diffuse * shadow;
+
+#endif
+
+#ifdef LIGHT2
+#ifdef SPOTLIGHT2
+	info = computeSpotLighting(viewDirectionW, normalW, vLightData2, vLightDirection2, vLightDiffuse2.rgb, vLightDiffuse2.a);
+#endif
+#ifdef HEMILIGHT2
+	info = computeHemisphericLighting(viewDirectionW, normalW, vLightData2, vLightDiffuse2.rgb, vLightGround2);
+#endif
+#ifdef POINTDIRLIGHT2
+	info = computeLighting(viewDirectionW, normalW, vLightData2, vLightDiffuse2.rgb, vLightDiffuse2.a);
+#endif
+#ifdef SHADOW2
+#ifdef SHADOWVSM2
+	shadow = computeShadowWithVSM(vPositionFromLight2, shadowSampler2, shadowsInfo2.z, shadowsInfo2.x);
+#else
+#ifdef SHADOWPCF2
+	shadow = computeShadowWithPCF(vPositionFromLight2, shadowSampler2, shadowsInfo2.y, shadowsInfo2.z, shadowsInfo2.x);
+#else
+	shadow = computeShadow(vPositionFromLight2, shadowSampler2, shadowsInfo2.x, shadowsInfo2.z);
+#endif	
+#endif	
+#else
+	shadow = 1.;
+#endif
+	diffuseBase += info.diffuse * shadow;
+
+#endif
+
+#ifdef LIGHT3
+
+#ifdef SPOTLIGHT3
+	info = computeSpotLighting(viewDirectionW, normalW, vLightData3, vLightDirection3, vLightDiffuse3.rgb, vLightDiffuse3.a);
+#endif
+#ifdef HEMILIGHT3
+	info = computeHemisphericLighting(viewDirectionW, normalW, vLightData3, vLightDiffuse3.rgb, vLightGround3);
+#endif
+#ifdef POINTDIRLIGHT3
+	info = computeLighting(viewDirectionW, normalW, vLightData3, vLightDiffuse3.rgb, vLightDiffuse3.a);
+#endif
+#ifdef SHADOW3
+#ifdef SHADOWVSM3
+	shadow = computeShadowWithVSM(vPositionFromLight3, shadowSampler3, shadowsInfo3.z, shadowsInfo3.x);
+#else
+#ifdef SHADOWPCF3
+	shadow = computeShadowWithPCF(vPositionFromLight3, shadowSampler3, shadowsInfo3.y, shadowsInfo3.z, shadowsInfo3.x);
+#else
+	shadow = computeShadow(vPositionFromLight3, shadowSampler3, shadowsInfo3.x, shadowsInfo3.z);
+#endif	
+#endif	
+#else
+	shadow = 1.;
+#endif
+	diffuseBase += info.diffuse * shadow;
+#endif
+
+#ifdef VERTEXALPHA
+	alpha *= vColor.a;
+#endif
+
+	vec3 finalDiffuse = clamp(diffuseBase * diffuseColor, 0.0, 1.0) * baseColor.rgb;
+
+	// Composition
+	vec4 color = vec4(finalDiffuse, alpha);
+
+#ifdef FOG
+	float fog = CalcFogFactor();
+	color.rgb = fog * color.rgb + (1.0 - fog) * vFogColor;
+#endif
+	
+	gl_FragColor = color;
+}

+ 207 - 0
materialsLibrary/materials/water/water.vertex.fx

@@ -0,0 +1,207 @@
+precision highp float;
+
+// Attributes
+attribute vec3 position;
+#ifdef NORMAL
+attribute vec3 normal;
+#endif
+#ifdef UV1
+attribute vec2 uv;
+#endif
+#ifdef UV2
+attribute vec2 uv2;
+#endif
+#ifdef VERTEXCOLOR
+attribute vec4 color;
+#endif
+#ifdef BONES
+attribute vec4 matricesIndices;
+attribute vec4 matricesWeights;
+#endif
+
+// Uniforms
+
+#ifdef INSTANCES
+attribute vec4 world0;
+attribute vec4 world1;
+attribute vec4 world2;
+attribute vec4 world3;
+#else
+uniform mat4 world;
+#endif
+
+uniform mat4 view;
+uniform mat4 viewProjection;
+
+#ifdef BUMP
+varying vec2 vNormalUV;
+uniform mat4 normalMatrix;
+uniform vec2 vNormalInfos;
+#endif
+
+#ifdef BONES
+uniform mat4 mBones[BonesPerMesh];
+#endif
+
+#ifdef POINTSIZE
+uniform float pointSize;
+#endif
+
+// Output
+varying vec3 vPositionW;
+#ifdef NORMAL
+varying vec3 vNormalW;
+#endif
+
+#ifdef VERTEXCOLOR
+varying vec4 vColor;
+#endif
+
+#ifdef CLIPPLANE
+uniform vec4 vClipPlane;
+varying float fClipDistance;
+#endif
+
+#ifdef FOG
+varying float fFogDistance;
+#endif
+
+#ifdef SHADOWS
+#ifdef LIGHT0
+uniform mat4 lightMatrix0;
+varying vec4 vPositionFromLight0;
+#endif
+#ifdef LIGHT1
+uniform mat4 lightMatrix1;
+varying vec4 vPositionFromLight1;
+#endif
+#ifdef LIGHT2
+uniform mat4 lightMatrix2;
+varying vec4 vPositionFromLight2;
+#endif
+#ifdef LIGHT3
+uniform mat4 lightMatrix3;
+varying vec4 vPositionFromLight3;
+#endif
+#endif
+
+// Water uniforms
+uniform mat4 worldReflectionViewProjection;
+uniform vec2 windDirection;
+uniform float waveLength;
+uniform float time;
+uniform float windForce;
+uniform float bumpHeight;
+uniform float waveHeight;
+
+// Water varyings
+varying vec3 vPosition;
+varying vec3 vRefractionMapTexCoord;
+varying vec3 vReflectionMapTexCoord;
+varying float vWaveHeight;
+
+void main(void) {
+	mat4 finalWorld;
+
+#ifdef INSTANCES
+	finalWorld = mat4(world0, world1, world2, world3);
+#else
+	finalWorld = world;
+#endif
+
+#ifdef BONES
+	mat4 m0 = mBones[int(matricesIndices.x)] * matricesWeights.x;
+	mat4 m1 = mBones[int(matricesIndices.y)] * matricesWeights.y;
+	mat4 m2 = mBones[int(matricesIndices.z)] * matricesWeights.z;
+
+#ifdef BONES4
+	mat4 m3 = mBones[int(matricesIndices.w)] * matricesWeights.w;
+	finalWorld = finalWorld * (m0 + m1 + m2 + m3);
+#else
+	finalWorld = finalWorld * (m0 + m1 + m2);
+#endif 
+
+#endif
+
+	vec4 worldPos = finalWorld * vec4(position, 1.0);
+	vPositionW = vec3(worldPos);
+
+#ifdef NORMAL
+	vNormalW = normalize(vec3(finalWorld * vec4(normal, 0.0)));
+#endif
+
+	// Texture coordinates
+#ifndef UV1
+	vec2 uv = vec2(0., 0.);
+#endif
+#ifndef UV2
+	vec2 uv2 = vec2(0., 0.);
+#endif
+
+#ifdef BUMP
+	if (vNormalInfos.x == 0.)
+	{
+		vNormalUV = vec2(normalMatrix * vec4((uv * 1.0) / waveLength + time * windForce * windDirection, 1.0, 0.0));
+	}
+	else
+	{
+		vNormalUV = vec2(normalMatrix * vec4((uv2 * 1.0) / waveLength + time * windForce * windDirection, 1.0, 0.0));
+	}
+#endif
+
+	// Clip plane
+#ifdef CLIPPLANE
+	fClipDistance = dot(worldPos, vClipPlane);
+#endif
+
+	// Fog
+#ifdef FOG
+	fFogDistance = (view * worldPos).z;
+#endif
+
+	// Shadows
+#ifdef SHADOWS
+#ifdef LIGHT0
+	vPositionFromLight0 = lightMatrix0 * worldPos;
+#endif
+#ifdef LIGHT1
+	vPositionFromLight1 = lightMatrix1 * worldPos;
+#endif
+#ifdef LIGHT2
+	vPositionFromLight2 = lightMatrix2 * worldPos;
+#endif
+#ifdef LIGHT3
+	vPositionFromLight3 = lightMatrix3 * worldPos;
+#endif
+#endif
+
+	// Vertex color
+#ifdef VERTEXCOLOR
+	vColor = color;
+#endif
+
+	// Point size
+#ifdef POINTSIZE
+	gl_PointSize = pointSize;
+#endif
+
+	vec3 p = position;
+	p.y += (sin(((p.x / 0.05) + time * 100.0)) * waveHeight * 5.0) + (cos(((p.z / 0.05) + time * 100.0)) * waveHeight * 5.0);
+	
+	gl_Position = viewProjection * finalWorld * vec4(p, 1.0);;
+
+	worldPos = viewProjection * finalWorld * vec4(position, 1.0);
+
+	// Water
+	vWaveHeight = bumpHeight;
+	vPosition = position;
+	
+	vRefractionMapTexCoord.x = 0.5 * (worldPos.w + worldPos.x);
+	vRefractionMapTexCoord.y = 0.5 * (worldPos.w + worldPos.y);
+	vRefractionMapTexCoord.z = worldPos.w;
+	
+	worldPos = worldReflectionViewProjection * vec4(position, 1.0);
+	vReflectionMapTexCoord.x = 0.5 * (worldPos.w + worldPos.x);
+	vReflectionMapTexCoord.y = 0.5 * (worldPos.w + worldPos.y);
+	vReflectionMapTexCoord.z = worldPos.w;
+}

+ 59 - 4
materialsLibrary/test/index.html

@@ -5,6 +5,8 @@
 	<script src="dat.gui.min.js"></script>
 	<script src="babylon.max.js"></script>
 	<script src="../dist/babylon.simpleMaterial.js"></script>
+	<script src="../dist/babylon.waterMaterial.js"></script>
+	<script src="../dist/babylon.fireMaterial.js"></script>
 
 	<style>
 		html, body {
@@ -60,10 +62,28 @@
 
 			// Create meshes
 			var sphere = BABYLON.Mesh.CreateSphere("sphere", 32, 30.0, scene);
+			
 			var plane = BABYLON.MeshBuilder.CreateBox("plane", { width: 30, height: 1, depth:30 }, scene);
 			plane.setEnabled(false);
+			
+			var ground = BABYLON.Mesh.CreateGround("ground", 512, 512, 32, scene, false);
+			ground.scaling = new BABYLON.Vector3(0.1, 0.1, 0.1);
+			ground.setEnabled(false);
+			
 			var knot = BABYLON.Mesh.CreateTorusKnot("knot", 10, 3, 128, 64, 2, 3, scene);
 			knot.setEnabled(false);
+			
+			// Skybox
+			var skybox = BABYLON.Mesh.CreateBox("skyBox", 1000.0, scene);
+			var skyboxMaterial = new BABYLON.StandardMaterial("skyBox", scene);
+			skyboxMaterial.backFaceCulling = false;
+			skyboxMaterial.reflectionTexture = new BABYLON.CubeTexture("textures/skybox/TropicalSunnyDay", scene);
+			skyboxMaterial.reflectionTexture.coordinatesMode = BABYLON.Texture.SKYBOX_MODE;
+			skyboxMaterial.diffuseColor = new BABYLON.Color3(0, 0, 0);
+			skyboxMaterial.specularColor = new BABYLON.Color3(0, 0, 0);
+			skyboxMaterial.disableLighting = true;
+			skybox.material = skyboxMaterial;
+			skybox.setEnabled(false);
 
 			var currentMesh = sphere;
 
@@ -123,7 +143,22 @@
 				simple.diffuseTexture = new BABYLON.Texture("textures/amiga.jpg", scene);
 				simple.diffuseTexture.uScale = 5;
 				simple.diffuseTexture.vScale = 5;
-
+				
+				var water = new BABYLON.WaterMaterial("water", scene, currentMesh);
+				water.backFaceCulling = false;
+				water.enableRenderTargets(false);
+				water.bumpTexture = new BABYLON.Texture("textures/waterbump.png", scene);
+				water.windForce = -45;
+				water.waveHeight = 1.3;
+				water.addToRenderList(skybox);
+				water.addToRenderList(shadowCaster);
+				water.addToRenderList(shadowCaster2);
+				
+				var fire = new BABYLON.FireMaterial("fire", scene);
+				fire.diffuseTexture = new BABYLON.Texture("textures/fire/diffuse.png", scene);
+				fire.distortionTexture = new BABYLON.Texture("textures/fire/distortion.png", scene);
+				fire.opacityTexture = new BABYLON.Texture("textures/fire/opacity.png", scene);
+				
 				// Default to std
 				var currentMaterial = std;
 				sphere.material = std;				
@@ -139,14 +174,25 @@
 					directionalLight: false,
 					castShadows: false,
 					spotLight: false,
-					fog: false
+					fog: false,
+					skybox: false
 				}
 
-				gui.add(options, 'material', ['standard', 'simple']).onFinishChange(function () {
+				gui.add(options, 'material', ['standard', 'simple', 'water', 'fire']).onFinishChange(function () {
+					water.enableRenderTargets(false);
+					
 					switch (options.material) {
 						case "simple":
 							currentMaterial = simple;
 							break;
+						case "water":
+							currentMaterial = water;
+							water.enableRenderTargets(true);
+							skybox.setEnabled(true);
+							break;
+						case "fire":
+							currentMaterial = fire;
+							break;
 						default:
 							currentMaterial = std;
 							break;
@@ -155,7 +201,7 @@
 					currentMesh.material = currentMaterial;
 				});
 
-				gui.add(options, 'mesh', ['sphere', 'knot', 'plane', 'rabbit']).onFinishChange(function () {
+				gui.add(options, 'mesh', ['sphere', 'knot', 'plane', 'ground', 'rabbit']).onFinishChange(function () {
 					currentMesh.setEnabled(false);
 					switch (options.mesh) {
 						case "sphere":
@@ -167,6 +213,9 @@
 						case "plane":
 							currentMesh = plane;
 							break;
+						case "ground":
+							currentMesh = ground;
+							break;
 						case "rabbit":
 							currentMesh = rabbit;
 							break;
@@ -174,6 +223,8 @@
 					currentMesh.setEnabled(true);
 					currentMesh.receiveShadows = true;
 					currentMesh.material = currentMaterial;
+					
+					water.mesh = currentMesh;
 				});
 
 				var f1 = gui.addFolder('lights');
@@ -203,6 +254,10 @@
 				gui.add(options, 'fog').onChange(function () {
 					scene.fogMode = options.fog ? BABYLON.Scene.FOGMODE_EXP : BABYLON.Scene.FOGMODE_NONE;
 				});
+				
+				gui.add(options, 'skybox').onChange(function() {
+					skybox.setEnabled(options.skybox);
+				});
 			});
 		}
 

BIN
materialsLibrary/test/textures/fire/diffuse.png


BIN
materialsLibrary/test/textures/fire/distortion.png


BIN
materialsLibrary/test/textures/fire/opacity.png


BIN
materialsLibrary/test/textures/skybox/TropicalSunnyDay_nx.jpg


BIN
materialsLibrary/test/textures/skybox/TropicalSunnyDay_ny.jpg


BIN
materialsLibrary/test/textures/skybox/TropicalSunnyDay_nz.jpg


BIN
materialsLibrary/test/textures/skybox/TropicalSunnyDay_px.jpg


BIN
materialsLibrary/test/textures/skybox/TropicalSunnyDay_py.jpg


BIN
materialsLibrary/test/textures/skybox/TropicalSunnyDay_pz.jpg


BIN
materialsLibrary/test/textures/waterbump.png