瀏覽代碼

BackGround Material

Sebastien Vandenberghe 7 年之前
父節點
當前提交
41ec0c8334

+ 34 - 0
dist/preview release/materialsLibrary/babylon.backgroundMaterial.d.ts

@@ -73,12 +73,45 @@ declare namespace BABYLON {
         protected _shadowLevel: float;
         shadowLevel: float;
         /**
+         * In case of opacity Fresnel or reflection falloff, this is use as a scene center.
+         * It is usually zero but might be interesting to modify according to your setup.
+         */
+        protected _sceneCenter: Vector3;
+        sceneCenter: Vector3;
+        /**
          * This helps specifying that the material is falling off to the sky box at grazing angle.
          * This helps ensuring a nice transition when the camera goes under the ground.
          */
         protected _opacityFresnel: boolean;
         opacityFresnel: boolean;
         /**
+         * This helps specifying that the material is falling off from diffuse to the reflection texture at grazing angle.
+         * This helps adding a mirror texture on the ground.
+         */
+        protected _reflectionFresnel: boolean;
+        reflectionFresnel: boolean;
+        /**
+         * This helps specifying the falloff radius off the reflection texture from the sceneCenter.
+         * This helps adding a nice falloff effect to the reflection if used as a mirror for instance.
+         */
+        protected _reflectionFalloffDistance: number;
+        reflectionFalloffDistance: number;
+        /**
+         * This specifies the weight of the reflection against the background in case of reflection Fresnel.
+         */
+        protected _reflectionAmount: number;
+        reflectionAmount: number;
+        /**
+         * This specifies the weight of the reflection at grazing angle.
+         */
+        protected _reflectionReflectance0: number;
+        reflectionReflectance0: number;
+        /**
+         * This specifies the weight of the reflection at a perpendicular point of view.
+         */
+        protected _reflectionReflectance90: number;
+        reflectionReflectance90: number;
+        /**
          * Helps to directly use the maps channels instead of their level.
          */
         protected _useRGBColor: boolean;
@@ -170,6 +203,7 @@ declare namespace BABYLON {
          */
         cameraColorCurves: Nullable<ColorCurves>;
         private _renderTargets;
+        private _reflectionControls;
         /**
          * constructor
          * @param name The name of the material

File diff suppressed because it is too large
+ 74 - 3
dist/preview release/materialsLibrary/babylon.backgroundMaterial.js


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/materialsLibrary/babylon.backgroundMaterial.min.js


File diff suppressed because it is too large
+ 74 - 3
dist/preview release/materialsLibrary/babylonjs.materials.js


File diff suppressed because it is too large
+ 2 - 2
dist/preview release/materialsLibrary/babylonjs.materials.min.js


+ 34 - 0
dist/preview release/materialsLibrary/babylonjs.materials.module.d.ts

@@ -933,12 +933,45 @@ declare namespace BABYLON {
         protected _shadowLevel: float;
         shadowLevel: float;
         /**
+         * In case of opacity Fresnel or reflection falloff, this is use as a scene center.
+         * It is usually zero but might be interesting to modify according to your setup.
+         */
+        protected _sceneCenter: Vector3;
+        sceneCenter: Vector3;
+        /**
          * This helps specifying that the material is falling off to the sky box at grazing angle.
          * This helps ensuring a nice transition when the camera goes under the ground.
          */
         protected _opacityFresnel: boolean;
         opacityFresnel: boolean;
         /**
+         * This helps specifying that the material is falling off from diffuse to the reflection texture at grazing angle.
+         * This helps adding a mirror texture on the ground.
+         */
+        protected _reflectionFresnel: boolean;
+        reflectionFresnel: boolean;
+        /**
+         * This helps specifying the falloff radius off the reflection texture from the sceneCenter.
+         * This helps adding a nice falloff effect to the reflection if used as a mirror for instance.
+         */
+        protected _reflectionFalloffDistance: number;
+        reflectionFalloffDistance: number;
+        /**
+         * This specifies the weight of the reflection against the background in case of reflection Fresnel.
+         */
+        protected _reflectionAmount: number;
+        reflectionAmount: number;
+        /**
+         * This specifies the weight of the reflection at grazing angle.
+         */
+        protected _reflectionReflectance0: number;
+        reflectionReflectance0: number;
+        /**
+         * This specifies the weight of the reflection at a perpendicular point of view.
+         */
+        protected _reflectionReflectance90: number;
+        reflectionReflectance90: number;
+        /**
          * Helps to directly use the maps channels instead of their level.
          */
         protected _useRGBColor: boolean;
@@ -1030,6 +1063,7 @@ declare namespace BABYLON {
          */
         cameraColorCurves: Nullable<ColorCurves>;
         private _renderTargets;
+        private _reflectionControls;
         /**
          * constructor
          * @param name The name of the material

File diff suppressed because it is too large
+ 2 - 2
materialsLibrary/src/background/babylon.backgroundMaterial.js.include.fx


+ 87 - 0
materialsLibrary/src/background/babylon.backgroundMaterial.ts

@@ -36,6 +36,16 @@ namespace BABYLON {
         public REFLECTIONBLUR = false;
 
         /**
+         * True if you want the material to fade to reflection at grazing angle.
+         */
+        public REFLECTIONFRESNEL = false;
+
+        /**
+         * True if you want the material to falloff as far as you move away from the scene center.
+         */
+        public REFLECTIONFALLOFF = false;
+
+        /**
          * False if the current Webgl implementation does not support the texture lod extension.
          */
         public TEXTURELODSUPPORT = false;
@@ -213,6 +223,15 @@ namespace BABYLON {
         public shadowLevel: float = 0;
 
         /**
+         * In case of opacity Fresnel or reflection falloff, this is use as a scene center.
+         * It is usually zero but might be interesting to modify according to your setup.
+         */
+        @serializeAsVector3()
+        protected _sceneCenter: Vector3;
+        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        public sceneCenter: Vector3 = Vector3.Zero();
+
+        /**
          * This helps specifying that the material is falling off to the sky box at grazing angle.
          * This helps ensuring a nice transition when the camera goes under the ground.
          */
@@ -222,6 +241,48 @@ namespace BABYLON {
         public opacityFresnel: boolean = true;
 
         /**
+         * This helps specifying that the material is falling off from diffuse to the reflection texture at grazing angle. 
+         * This helps adding a mirror texture on the ground.
+         */
+        @serialize()
+        protected _reflectionFresnel: boolean;
+        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        public reflectionFresnel: boolean = false;
+
+        /**
+         * This helps specifying the falloff radius off the reflection texture from the sceneCenter.
+         * This helps adding a nice falloff effect to the reflection if used as a mirror for instance.
+         */
+        @serialize()
+        protected _reflectionFalloffDistance: number;
+        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        public reflectionFalloffDistance: number = 0.0;
+
+        /**
+         * This specifies the weight of the reflection against the background in case of reflection Fresnel.
+         */
+        @serialize()
+        protected _reflectionAmount: number;
+        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        public reflectionAmount: number = 1.0;
+
+        /**
+         * This specifies the weight of the reflection at grazing angle.
+         */
+        @serialize()
+        protected _reflectionReflectance0: number;
+        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        public reflectionReflectance0: number = 0.05;
+
+        /**
+         * This specifies the weight of the reflection at a perpendicular point of view.
+         */
+        @serialize()
+        protected _reflectionReflectance90: number;
+        @expandToProperty("_markAllSubMeshesAsTexturesDirty")
+        public reflectionReflectance90: number = 0.5;
+
+        /**
          * Helps to directly use the maps channels instead of their level.
          */
         @serialize()
@@ -399,6 +460,7 @@ namespace BABYLON {
 
         // Temp values kept as cache in the material.
         private _renderTargets = new SmartArray<RenderTargetTexture>(16);
+        private _reflectionControls = BABYLON.Vector4.Zero();
 
         /**
          * constructor
@@ -545,8 +607,23 @@ namespace BABYLON {
                                 defines.REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED = true;
                                 break;
                         }
+
+                        if (this.reflectionFresnel) {
+                            defines.REFLECTIONFRESNEL = true;
+                            defines.REFLECTIONFALLOFF = this.reflectionFalloffDistance > 0;
+
+                            this._reflectionControls.x = this.reflectionAmount;
+                            this._reflectionControls.y = this.reflectionReflectance0;
+                            this._reflectionControls.z = this.reflectionReflectance90;
+                            this._reflectionControls.w = this.reflectionFalloffDistance;
+                        }
+                        else {
+                            defines.REFLECTIONFRESNEL = false;
+                            defines.REFLECTIONFALLOFF = false;
+                        }
                     } else {
                         defines.REFLECTION = false;
+                        defines.REFLECTIONFALLOFF = false;
                         defines.REFLECTIONBLUR = false;
                         defines.REFLECTIONMAP_3D = false;
                         defines.REFLECTIONMAP_SPHERICAL = false;
@@ -641,6 +718,8 @@ namespace BABYLON {
 
                         "shadowLevel", "alpha",
 
+                        "vBackgroundCenter", "vReflectionControl",
+
                         "vDiffuseInfos", "diffuseMatrix",
                 ];
 
@@ -708,6 +787,9 @@ namespace BABYLON {
             this._uniformBuffer.addUniform("pointSize", 1);
             this._uniformBuffer.addUniform("shadowLevel", 1);
             this._uniformBuffer.addUniform("alpha", 1);
+            this._uniformBuffer.addUniform("vBackgroundCenter", 3);
+            this._uniformBuffer.addUniform("vReflectionControl", 4);
+        
             this._uniformBuffer.create();
         }
 
@@ -819,6 +901,11 @@ namespace BABYLON {
                             this._uniformBuffer.setTexture("reflectionSamplerLow", reflectionTexture._lodTextureLow || reflectionTexture);
                             this._uniformBuffer.setTexture("reflectionSamplerHigh", reflectionTexture._lodTextureHigh || reflectionTexture);
                         }
+
+                        if (defines.REFLECTIONFRESNEL) {
+                            this._uniformBuffer.updateFloat3("vBackgroundCenter", this.sceneCenter.x, this.sceneCenter.y, this.sceneCenter.z);
+                            this._uniformBuffer.updateFloat4("vReflectionControl", this._reflectionControls.x, this._reflectionControls.y, this._reflectionControls.z, this._reflectionControls.w);
+                        }
                     }
                 }
 

+ 109 - 73
materialsLibrary/src/background/background.fragment.fx

@@ -37,39 +37,39 @@ varying vec3 vNormalW;
 
 // Reflection
 #ifdef REFLECTION
-	#ifdef REFLECTIONMAP_3D
-		#define sampleReflection(s, c) textureCube(s, c)
-
-		uniform samplerCube reflectionSampler;
-		
-		#ifdef TEXTURELODSUPPORT
-			#define sampleReflectionLod(s, c, l) textureCubeLodEXT(s, c, l)
-		#else
-			uniform samplerCube reflectionSamplerLow;
-			uniform samplerCube reflectionSamplerHigh;
-		#endif
-	#else
-		#define sampleReflection(s, c) texture2D(s, c)
-
-		uniform sampler2D reflectionSampler;
-
-		#ifdef TEXTURELODSUPPORT
-			#define sampleReflectionLod(s, c, l) texture2DLodEXT(s, c, l)
-		#else
-			uniform samplerCube reflectionSamplerLow;
-			uniform samplerCube reflectionSamplerHigh;
-		#endif
-	#endif
-
-	#ifdef REFLECTIONMAP_SKYBOX
-		varying vec3 vPositionUVW;
-	#else
-		#if defined(REFLECTIONMAP_EQUIRECTANGULAR_FIXED) || defined(REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED)
-			varying vec3 vDirectionW;
-		#endif
-	#endif
-
-	#include<reflectionFunction>
+    #ifdef REFLECTIONMAP_3D
+        #define sampleReflection(s, c) textureCube(s, c)
+
+        uniform samplerCube reflectionSampler;
+        
+        #ifdef TEXTURELODSUPPORT
+            #define sampleReflectionLod(s, c, l) textureCubeLodEXT(s, c, l)
+        #else
+            uniform samplerCube reflectionSamplerLow;
+            uniform samplerCube reflectionSamplerHigh;
+        #endif
+    #else
+        #define sampleReflection(s, c) texture2D(s, c)
+
+        uniform sampler2D reflectionSampler;
+
+        #ifdef TEXTURELODSUPPORT
+            #define sampleReflectionLod(s, c, l) texture2DLodEXT(s, c, l)
+        #else
+            uniform samplerCube reflectionSamplerLow;
+            uniform samplerCube reflectionSamplerHigh;
+        #endif
+    #endif
+
+    #ifdef REFLECTIONMAP_SKYBOX
+        varying vec3 vPositionUVW;
+    #else
+        #if defined(REFLECTIONMAP_EQUIRECTANGULAR_FIXED) || defined(REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED)
+            varying vec3 vDirectionW;
+        #endif
+    #endif
+
+    #include<reflectionFunction>
 #endif
 
 // Forces linear space for image processing
@@ -98,6 +98,17 @@ varying vec3 vNormalW;
 // Fog
 #include<fogFragmentDeclaration>
 
+#ifdef REFLECTIONFRESNEL
+    #define FRESNEL_MAXIMUM_ON_ROUGH 0.25
+
+    vec3 fresnelSchlickEnvironmentGGX(float VdotN, vec3 reflectance0, vec3 reflectance90, float smoothness)
+    {
+        // Schlick fresnel approximation, extended with basic smoothness term so that rough surfaces do not approach reflectance90 at grazing angle
+        float weight = mix(FRESNEL_MAXIMUM_ON_ROUGH, 1.0, smoothness);
+        return reflectance0 + weight * (reflectance90 - reflectance0) * pow(clamp(1.0 - VdotN, 0., 1.), 5.0);
+    }
+#endif
+
 void main(void) {
 #include<clipPlaneFragment>
 
@@ -124,23 +135,23 @@ void main(void) {
 #endif
 
 // _____________________________ REFLECTION ______________________________________
-vec3 environmentColor = vec3(1., 1., 1.);
+vec3 reflectionColor = vec3(1., 1., 1.);
 #ifdef REFLECTION
-	vec3 reflectionVector = computeReflectionCoords(vec4(vPositionW, 1.0), normalW);
-	#ifdef REFLECTIONMAP_OPPOSITEZ
-		reflectionVector.z *= -1.0;
-	#endif
-
-	// _____________________________ 2D vs 3D Maps ________________________________
-	#ifdef REFLECTIONMAP_3D
-		vec3 reflectionCoords = reflectionVector;
-	#else
-		vec2 reflectionCoords = reflectionVector.xy;
-		#ifdef REFLECTIONMAP_PROJECTION
-			reflectionCoords /= reflectionVector.z;
-		#endif
-		reflectionCoords.y = 1.0 - reflectionCoords.y;
-	#endif
+    vec3 reflectionVector = computeReflectionCoords(vec4(vPositionW, 1.0), normalW);
+    #ifdef REFLECTIONMAP_OPPOSITEZ
+        reflectionVector.z *= -1.0;
+    #endif
+
+    // _____________________________ 2D vs 3D Maps ________________________________
+    #ifdef REFLECTIONMAP_3D
+        vec3 reflectionCoords = reflectionVector;
+    #else
+        vec2 reflectionCoords = reflectionVector.xy;
+        #ifdef REFLECTIONMAP_PROJECTION
+            reflectionCoords /= reflectionVector.z;
+        #endif
+        reflectionCoords.y = 1.0 - reflectionCoords.y;
+    #endif
 
     #ifdef REFLECTIONBLUR
         float reflectionLOD = vReflectionInfos.y;
@@ -148,20 +159,20 @@ vec3 environmentColor = vec3(1., 1., 1.);
         #ifdef TEXTURELODSUPPORT
             // Apply environment convolution scale/offset filter tuning parameters to the mipmap LOD selection
             reflectionLOD = reflectionLOD * log2(vReflectionMicrosurfaceInfos.x) * vReflectionMicrosurfaceInfos.y + vReflectionMicrosurfaceInfos.z;
-            environmentColor = sampleReflectionLod(reflectionSampler, reflectionCoords, reflectionLOD).rgb;
+            reflectionColor = sampleReflectionLod(reflectionSampler, reflectionCoords, reflectionLOD).rgb;
         #else
             float lodReflectionNormalized = clamp(reflectionLOD, 0., 1.);
             float lodReflectionNormalizedDoubled = lodReflectionNormalized * 2.0;
 
             vec3 reflectionSpecularMid = sampleReflection(reflectionSampler, reflectionCoords).rgb;
             if(lodReflectionNormalizedDoubled < 1.0){
-                environmentColor = mix(
+                reflectionColor = mix(
                     sampleReflection(reflectionSamplerHigh, reflectionCoords).rgb,
                     reflectionSpecularMid,
                     lodReflectionNormalizedDoubled
                 );
             } else {
-                environmentColor = mix(
+                reflectionColor = mix(
                     reflectionSpecularMid,
                     sampleReflection(reflectionSamplerLow, reflectionCoords).rgb,
                     lodReflectionNormalizedDoubled - 1.0
@@ -169,19 +180,20 @@ vec3 environmentColor = vec3(1., 1., 1.);
             }
         #endif
     #else
-        environmentColor = sampleReflection(reflectionSampler, reflectionCoords).rgb;
+        vec4 reflectionSample = sampleReflection(reflectionSampler, reflectionCoords);
+        reflectionColor = reflectionSample.rgb;
     #endif
 
     #ifdef GAMMAREFLECTION
-        environmentColor = toLinearSpace(environmentColor.rgb);
+        reflectionColor = toLinearSpace(reflectionColor.rgb);
     #endif
 
     // _____________________________ Levels _____________________________________
-    environmentColor *= vReflectionInfos.x;
+    reflectionColor *= vReflectionInfos.x;
 #endif
 
-// _____________________________ Alpha Information _______________________________
-vec3 groundColor = vec3(1., 1., 1.);
+// _____________________________ Diffuse Information _______________________________
+vec3 diffuseColor = vec3(1., 1., 1.);
 float finalAlpha = alpha;
 #ifdef DIFFUSE
     vec4 diffuseMap = texture2D(diffuseSampler, vDiffuseUV);
@@ -196,14 +208,18 @@ float finalAlpha = alpha;
         finalAlpha *= diffuseMap.a;
     #endif
 
-    groundColor = diffuseMap.rgb;
+    diffuseColor = diffuseMap.rgb;
 #endif
 
-    // _____________________________ MIX ________________________________________
-    vec3 colorBase = environmentColor * groundColor;
+// _____________________________ MIX ________________________________________
+#ifdef REFLECTIONFRESNEL
+    vec3 colorBase = diffuseColor;
+#else
+    vec3 colorBase = reflectionColor * diffuseColor;
+#endif
     colorBase = max(colorBase, 0.0);
 
-    // ___________________________ COMPOSE _______________________________________
+// ___________________________ COMPOSE _______________________________________
 #ifdef USERGBCOLOR
     vec3 finalColor = colorBase;
 #else
@@ -212,13 +228,27 @@ float finalAlpha = alpha;
     finalColor += colorBase.b * vTertiaryColor.rgb * vTertiaryColor.a;
 #endif
 
-#ifdef SHADOWINUSE
-    finalColor = mix(finalColor * shadowLevel, finalColor, globalShadow);
+// ___________________________ FRESNELS _______________________________________
+#ifdef REFLECTIONFRESNEL
+    vec3 reflectionAmount = vReflectionControl.xxx;
+    vec3 reflectionReflectance0 = vReflectionControl.yyy;
+    vec3 reflectionReflectance90 = vReflectionControl.zzz;
+    float VdotN = dot(normalize(vEyePosition), normalW);
+
+    vec3 planarReflectionFresnel = fresnelSchlickEnvironmentGGX(clamp(VdotN, 0.0, 1.0), reflectionReflectance0, reflectionReflectance90, 1.0);
+    reflectionAmount *= planarReflectionFresnel;
+
+    #ifdef REFLECTIONFALLOFF
+        float reflectionDistanceFalloff = 1.0 - clamp(length(vPositionW.xyz - vBackgroundCenter) * vReflectionControl.w, 0.0, 1.0);
+        reflectionDistanceFalloff *= reflectionDistanceFalloff;
+        reflectionAmount *= reflectionDistanceFalloff;
+    #endif
+
+    finalColor = mix(finalColor, reflectionColor, clamp(reflectionAmount, 0., 1.));
 #endif
 
 #ifdef OPACITYFRESNEL
-    // TODO. Change by camera forward Direction.
-    float viewAngleToFloor = dot(normalW, normalize(vEyePosition));
+    float viewAngleToFloor = dot(normalW, normalize(vEyePosition - vBackgroundCenter));
 
     // Fade out the floor plane as the angle between the floor and the camera tends to 0 (starting from startAngle)
     const float startAngle = 0.1;
@@ -227,22 +257,28 @@ float finalAlpha = alpha;
     finalAlpha *= fadeFactor * fadeFactor;
 #endif
 
-    vec4 color = vec4(finalColor, finalAlpha);
+// ___________________________ SHADOWS _______________________________________
+#ifdef SHADOWINUSE
+    finalColor = mix(finalColor * shadowLevel, finalColor, globalShadow);
+#endif
+
+// ___________________________ FINALIZE _______________________________________
+vec4 color = vec4(finalColor, finalAlpha);
 
 #include<fogFragment>
 
 #ifdef IMAGEPROCESSINGPOSTPROCESS
-	// Sanitize output incase invalid normals or tangents have caused div by 0 or undefined behavior
-	// this also limits the brightness which helpfully reduces over-sparkling in bloom (native handles this in the bloom blur shader)
-	color.rgb = clamp(color.rgb, 0., 30.0);
+    // Sanitize output incase invalid normals or tangents have caused div by 0 or undefined behavior
+    // this also limits the brightness which helpfully reduces over-sparkling in bloom (native handles this in the bloom blur shader)
+    color.rgb = clamp(color.rgb, 0., 30.0);
 #else
-	// Alway run even to ensure going back to gamma space.
-	color = applyImageProcessing(color);
+    // Alway run even to ensure going back to gamma space.
+    color = applyImageProcessing(color);
 #endif
 
 #ifdef PREMULTIPLYALPHA
-	// Convert to associative (premultiplied) format if needed.
-	color.rgb *= color.a;
+    // Convert to associative (premultiplied) format if needed.
+    color.rgb *= color.a;
 #endif
 
     gl_FragColor = color;

+ 8 - 0
materialsLibrary/src/background/backgroundFragmentDeclaration.fx

@@ -12,4 +12,12 @@
     uniform vec2 vReflectionInfos;
     uniform mat4 reflectionMatrix;
     uniform vec3 vReflectionMicrosurfaceInfos;
+#endif
+
+#if defined(REFLECTIONFRESNEL) || defined(OPACITYFRESNEL)
+    uniform vec3 vBackgroundCenter;
+#endif
+
+#ifdef REFLECTIONFRESNEL
+    uniform vec4 vReflectionControl;
 #endif

+ 8 - 0
materialsLibrary/src/background/backgroundUboDeclaration.fx

@@ -14,6 +14,14 @@ uniform Material
 	uniform float pointSize;
 	uniform float shadowLevel;
 	uniform float alpha;
+
+	#if defined(REFLECTIONFRESNEL) || defined(OPACITYFRESNEL)
+		uniform vec3 vBackgroundCenter;
+	#endif
+
+	#ifdef REFLECTIONFRESNEL
+		uniform vec4 vReflectionControl;
+	#endif
 };
 
 uniform Scene {

+ 57 - 18
materialsLibrary/test/addbackground.js

@@ -13,8 +13,21 @@ window.prepareBackgroundMaterial = function() {
     backgroundSkybox = BABYLON.Mesh.CreateBox("hdrSkyBox", 1000.0, scene);
 	backgroundSkybox.material = backSky;
 	backgroundSkybox.setEnabled(false);
+
+	var mirrorMesh = BABYLON.Mesh.CreateTorus("torus", 4, 2, 30, scene, false);
+	mirrorMesh.setEnabled(false);
+	mirrorMesh.position = new BABYLON.Vector3(0, 3, 0);
+	mirrorMesh.material = new BABYLON.StandardMaterial("", scene);
+	mirrorMesh.material.emissiveColor = BABYLON.Color3.Red();
+
+	var mirror = new BABYLON.MirrorTexture("mirror", {ratio: 0.3}, scene, true);
+	mirror.renderList = [mirrorMesh];
+	mirror.clearColor = new BABYLON.Color4(1, 1, 1, 0.0);
+	mirror.mirrorPlane = new BABYLON.Plane(0, -1.0, 0, 0.0);
+	mirror.adaptiveBlurKernel = 64;
 	
 	registerRangeUI("background", "primaryColorR", 0, 1, function(value) {
+		mirror.clearColor.r = value;
 		back.primaryColor.r = value;
 		backSky.primaryColor.r = value;
 	}, function() {
@@ -22,6 +35,7 @@ window.prepareBackgroundMaterial = function() {
 	});
 
 	registerRangeUI("background", "primaryColorG", 0, 1, function(value) {
+		mirror.clearColor.g = value;
 		back.primaryColor.g = value;
 		backSky.primaryColor.g = value;
 	}, function() {
@@ -29,6 +43,7 @@ window.prepareBackgroundMaterial = function() {
 	});
 
 	registerRangeUI("background", "primaryColorB", 0, 1, function(value) {
+		mirror.clearColor.b = value;
 		back.primaryColor.b = value;
 		backSky.primaryColor.b = value;
 	}, function() {
@@ -70,39 +85,38 @@ window.prepareBackgroundMaterial = function() {
 		return back.secondaryLevel;
 	});
 
-	registerRangeUI("background", "thirdColorR", 0, 1, function(value) {
-		back.thirdColor.r = value;
-		backSky.thirdColor.r = value;
+	registerRangeUI("background", "tertiaryColorR", 0, 1, function(value) {
+		back.tertiaryColor.r = value;
+		backSky.tertiaryColor.r = value;
 	}, function() {
-		return back.thirdColor.r;
+		return back.tertiaryColor.r;
 	});
 
-	registerRangeUI("background", "thirdColorG", 0, 1, function(value) {
-		back.thirdColor.g = value;
-		backSky.thirdColor.g = value;
+	registerRangeUI("background", "tertiaryColorG", 0, 1, function(value) {
+		back.tertiaryColor.g = value;
+		backSky.tertiaryColor.g = value;
 	}, function() {
-		return back.thirdColor.g;
+		return back.tertiaryColor.g;
 	});
 
-	registerRangeUI("background", "thirdColorB", 0, 1, function(value) {
-		back.thirdColor.b = value;
-		backSky.thirdColor.b = value;
+	registerRangeUI("background", "tertiaryColorB", 0, 1, function(value) {
+		back.tertiaryColor.b = value;
+		backSky.tertiaryColor.b = value;
 	}, function() {
-		return back.thirdColor.b;
+		return back.tertiaryColor.b;
 	});
 
-	registerRangeUI("background", "thirdLevel", 0, 30, function(value) {
-		back.thirdLevel = value;		
-		backSky.thirdLevel = value;
+	registerRangeUI("background", "tertiaryLevel", 0, 30, function(value) {
+		back.tertiaryLevel = value;		
+		backSky.tertiaryLevel = value;
 	}, function() {
-		return back.thirdLevel;
+		return back.tertiaryLevel;
 	});
 
 	registerRangeUI("background", "reflectionBlur", 0, 1, function(value) {
-		back.reflectionBlur = value;
 		backSky.reflectionBlur = value;
 	}, function() {
-		return back.reflectionBlur;
+		return backSky.reflectionBlur;
 	});
 
 	registerRangeUI("background", "shadowLevel", 0, 1, function(value) {
@@ -118,6 +132,18 @@ window.prepareBackgroundMaterial = function() {
 		return back.alpha;
 	});
 
+	registerRangeUI("background", "mirrorAmount", 0, 10, function(value) {
+		back.reflectionAmount = value;
+	}, function() {
+		return back.reflectionAmount;
+	});
+
+	registerRangeUI("background", "mirrorFalloff", 0, 5, function(value) {
+		back.reflectionFalloffDistance = value;
+	}, function() {
+		return back.reflectionFalloffDistance;
+	});
+
 	registerButtonUI("background", "ToggleBackRGB", function() {
 		back.useRGBColor = !back.useRGBColor;
 	});
@@ -126,6 +152,19 @@ window.prepareBackgroundMaterial = function() {
 		backSky.useRGBColor = !backSky.useRGBColor;
 	});
 
+	registerButtonUI("background", "ToggleMirror", function() {
+		if (back.reflectionFresnel) {
+			back.reflectionFresnel = false;
+			back.reflectionTexture = null;
+			mirrorMesh.setEnabled(false);
+		}
+		else {
+			back.reflectionFresnel = true;
+			back.reflectionTexture = mirror;
+			mirrorMesh.setEnabled(true);
+		}
+	});
+
 
 	return back;
 }