Browse Source

Merge branch 'master' of https://github.com/julien-moreau/Babylon.js

Conflicts:
	materialsLibrary/test/index.html
luaacro 9 năm trước cách đây
mục cha
commit
ec830e0f4c

+ 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": {

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 450 - 0
materialsLibrary/dist/babylon.fireMaterial.js


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 7 - 7
materialsLibrary/dist/babylon.simpleMaterial.js


Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 573 - 0
materialsLibrary/dist/babylon.waterMaterial.js


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

@@ -0,0 +1,542 @@
+/// <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 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 FireMaterial extends Material {
+        public diffuseTexture: BaseTexture;
+        public distortionTexture: BaseTexture;
+        public opacityTexture: BaseTexture;
+
+        public diffuseColor = new Color3(1, 1, 1);
+        public disableLighting = false;
+        
+        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;
+            }
+
+            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 = "fire";
+                
+                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",
+                        "vDiffuseInfos", 
+                        "mBones",
+                        "vClipPlane", "diffuseMatrix",
+                        "shadowsInfo0", "shadowsInfo1", "shadowsInfo2", "shadowsInfo3",
+                        // Fire
+                        "time"
+                    ],
+                    ["diffuseSampler",
+                        "shadowSampler0", "shadowSampler1", "shadowSampler2", "shadowSampler3",
+                        // 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());
+                }
+                if (this.opacityTexture && StandardMaterial.OpacityTextureEnabled) {
+                    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);
+
+            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);
+            }
+            
+            // Time
+            this._lastTime += scene.getEngine().getDeltaTime();
+            this._effect.setFloat("time", this._lastTime);
+
+            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;
+        }
+    }
+} 
+

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

@@ -0,0 +1,485 @@
+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 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;
+
+// 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 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 = (noise0 * 2.0 - 1.0) * distortionAmount0 + (noise1 * 2.0 - 1.0) * distortionAmount1 + (noise2 * 2.0 - 1.0) * distortionAmount2;
+	
+	vec4 perturbedBaseCoords = noiseSum + vec4(vDiffuseUV, 0.0, 1.0) * (vDiffuseUV.y * heightAttenuation.x + heightAttenuation.y);
+	
+	baseColor = texture2D(diffuseSampler, perturbedBaseCoords.xy) * 2.0;
+	baseColor *= texture2D(opacitySampler, perturbedBaseCoords.xy);
+
+#ifdef ALPHATEST
+	if (baseColor.a < 0.4)
+		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(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;
+}

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

@@ -0,0 +1,192 @@
+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;
+uniform mat4 diffuseMatrix;
+uniform vec2 vDiffuseInfos;
+#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
+
+// Fire
+uniform float time;
+
+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
+#ifndef UV1
+	vec2 uv = vec2(0., 0.);
+#endif
+#ifndef UV2
+	vec2 uv2 = vec2(0., 0.);
+#endif
+
+#ifdef DIFFUSE
+	if (vDiffuseInfos.x == 0.)
+	{
+		vDiffuseUV = vec2(diffuseMatrix * vec4(uv, 1.0, 0.0));
+	}
+	else
+	{
+		vDiffuseUV = vec2(diffuseMatrix * vec4(uv2, 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
+
+	// Fire
+	vec3 layerSpeed = vec3(0.2, 0.52, 0.1);
+	
+	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();

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

@@ -0,0 +1,684 @@
+/// <reference path="../../../dist/preview release/babylon.d.ts"/>
+/// <reference path="../simple/babylon.simpleMaterial.ts"/>
+
+module BABYLON {
+	var maxSimultaneousLights = 4;
+
+    class WaterMaterialDefines extends MaterialDefines {
+        public DIFFUSE = 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 bump height related to the bump map
+        */
+		public waveHeight: number = 0.3;
+        /**
+        * @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 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.DiffuseTextureEnabled) {
+                    if (!this.bumpTexture.isReady()) {
+                        return false;
+                    } else {
+                        needUVs = true;
+                        this._defines.DIFFUSE = 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", "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.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);
+			
+			this._refractionRTT.renderList = scene.meshes;
+			this._reflectionRTT.renderList = scene.meshes;
+			
+			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;
+		}
+	}
+}

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

@@ -0,0 +1,496 @@
+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 DIFFUSE
+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 DIFFUSE
+	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
+
+	// 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;
+
+	// 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;
+}

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

@@ -0,0 +1,202 @@
+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 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 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 DIFFUSE
+	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
+
+	worldPos = viewProjection * finalWorld * vec4(position, 1.0);
+	gl_Position = worldPos;
+
+	// Water
+	vWaveHeight = waveHeight;
+	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;
+}

+ 45 - 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,24 @@
 
 			// 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);
+			
+			var plane = BABYLON.MeshBuilder.CreateBox("plane", { width: 30, height: 0.1, depth:30 }, scene);
 			plane.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 +139,16 @@
 				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.enableRenderTargets(false);
+				water.bumpTexture = new BABYLON.Texture("textures/waterbump.png", scene);
+				
+				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 +164,24 @@
 					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);
+							break;
+						case "fire":
+							currentMaterial = fire;
+							break;
 						default:
 							currentMaterial = std;
 							break;
@@ -174,6 +209,8 @@
 					currentMesh.setEnabled(true);
 					currentMesh.receiveShadows = true;
 					currentMesh.material = currentMaterial;
+					
+					water.mesh = currentMesh;
 				});
 
 				var f1 = gui.addFolder('lights');
@@ -203,6 +240,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