Browse Source

Merge pull request #1991 from sebavan/Development

Add separate chanel for glossiness/roughness, fix ambient on environment, add ambient from metallic red channel
David Catuhe 8 years ago
parent
commit
1daabb4f07
3 changed files with 362 additions and 270 deletions
  1. 155 115
      src/Materials/babylon.pbrMaterial.ts
  2. 189 154
      src/Shaders/pbr.fragment.fx
  3. 18 1
      src/Shaders/pbr.vertex.fx

+ 155 - 115
src/Materials/babylon.pbrMaterial.ts

@@ -69,9 +69,12 @@
         public SHADOWFULLFLOAT = false;
 
         public METALLICWORKFLOW = false;
-        public METALLICROUGHNESSMAP = false;
-        public METALLICROUGHNESSGSTOREINALPHA = false;
-        public METALLICROUGHNESSGSTOREINGREEN = false;
+        public METALLICMAP = false;
+        public ROUGHNESSSTOREINMETALMAPALPHA = false;
+        public ROUGHNESSSTOREINMETALMAPGREEN = false;
+        public METALLNESSSTOREINMETALMAPBLUE = false;
+        public AOSTOREINMETALMAPRED = false;
+        public MICROSURFACEMAP = false;
 
         public MORPHTARGETS = false;
         public MORPHTARGETS_NORMAL = false;
@@ -314,6 +317,13 @@
         @serialize()
         public roughness: number;
 
+        /**
+         * Used to enable roughness/glossiness fetch from a separate chanel depending on the current mode.
+         * Gray Scale represents roughness in metallic mode and glossiness in specular mode.
+         */
+        @serializeAsTexture()
+        public microSurfaceTexture: BaseTexture;
+
         @serializeAsTexture()
         public bumpTexture: BaseTexture;
 
@@ -421,6 +431,18 @@
          */
         @serialize()
         public useRoughnessFromMetallicTextureGreen = false;
+
+        /**
+         * Specifies if the metallic texture contains the metallness information in its blue channel.
+         */
+        @serialize()
+        public useMetallnessFromMetallicTextureBlue = false;
+
+        /**
+         * Specifies if the metallic texture contains the ambient occlusion information in its red channel.
+         */
+        @serialize()
+        public useAmbientOcclusionFromMetallicTextureRed = false;
         
         /**
          * In case the reflectivity map does not contain the microsurface information in its alpha channel,
@@ -667,85 +689,85 @@
                 if (this.albedoTexture && StandardMaterial.DiffuseTextureEnabled) {
                     if (!this.albedoTexture.isReady()) {
                         return false;
-                    } else {
-                        needUVs = true;
-                        this._defines.ALBEDO = true;
                     }
+
+                    needUVs = true;
+                    this._defines.ALBEDO = true;
                 }
 
                 if (this.ambientTexture && StandardMaterial.AmbientTextureEnabled) {
                     if (!this.ambientTexture.isReady()) {
                         return false;
-                    } else {
-                        needUVs = true;
-                        this._defines.AMBIENT = true;
                     }
+                    
+                    needUVs = true;
+                    this._defines.AMBIENT = true;
                 }
 
                 if (this.opacityTexture && StandardMaterial.OpacityTextureEnabled) {
                     if (!this.opacityTexture.isReady()) {
                         return false;
-                    } else {
-                        needUVs = true;
-                        this._defines.OPACITY = true;
+                    }
+                    
+                    needUVs = true;
+                    this._defines.OPACITY = true;
 
-                        if (this.opacityTexture.getAlphaFromRGB) {
-                            this._defines.OPACITYRGB = true;
-                        }
+                    if (this.opacityTexture.getAlphaFromRGB) {
+                        this._defines.OPACITYRGB = true;
                     }
                 }
 
                 if (this.reflectionTexture && StandardMaterial.ReflectionTextureEnabled) {
                     if (!this.reflectionTexture.isReady()) {
                         return false;
-                    } else {
-                        needNormals = true;
-                        this._defines.REFLECTION = true;
+                    }
+                    
+                    needNormals = true;
+                    this._defines.REFLECTION = true;
 
-                        if (this.reflectionTexture.coordinatesMode === Texture.INVCUBIC_MODE) {
-                            this._defines.INVERTCUBICMAP = true;
-                        }
+                    if (this.reflectionTexture.coordinatesMode === Texture.INVCUBIC_MODE) {
+                        this._defines.INVERTCUBICMAP = true;
+                    }
 
-                        this._defines.REFLECTIONMAP_3D = this.reflectionTexture.isCube;
-
-                        switch (this.reflectionTexture.coordinatesMode) {
-                            case Texture.CUBIC_MODE:
-                            case Texture.INVCUBIC_MODE:
-                                this._defines.REFLECTIONMAP_CUBIC = true;
-                                break;
-                            case Texture.EXPLICIT_MODE:
-                                this._defines.REFLECTIONMAP_EXPLICIT = true;
-                                break;
-                            case Texture.PLANAR_MODE:
-                                this._defines.REFLECTIONMAP_PLANAR = true;
-                                break;
-                            case Texture.PROJECTION_MODE:
-                                this._defines.REFLECTIONMAP_PROJECTION = true;
-                                break;
-                            case Texture.SKYBOX_MODE:
-                                this._defines.REFLECTIONMAP_SKYBOX = true;
-                                break;
-                            case Texture.SPHERICAL_MODE:
-                                this._defines.REFLECTIONMAP_SPHERICAL = true;
-                                break;
-                            case Texture.EQUIRECTANGULAR_MODE:
-                                this._defines.REFLECTIONMAP_EQUIRECTANGULAR = true;
-                                break;
-                            case Texture.FIXED_EQUIRECTANGULAR_MODE:
-                                this._defines.REFLECTIONMAP_EQUIRECTANGULAR_FIXED = true;
-                                break;
-                            case Texture.FIXED_EQUIRECTANGULAR_MIRRORED_MODE:
-                                this._defines.REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED = true;
-                                break;                                
-                        }
+                    this._defines.REFLECTIONMAP_3D = this.reflectionTexture.isCube;
+
+                    switch (this.reflectionTexture.coordinatesMode) {
+                        case Texture.CUBIC_MODE:
+                        case Texture.INVCUBIC_MODE:
+                            this._defines.REFLECTIONMAP_CUBIC = true;
+                            break;
+                        case Texture.EXPLICIT_MODE:
+                            this._defines.REFLECTIONMAP_EXPLICIT = true;
+                            break;
+                        case Texture.PLANAR_MODE:
+                            this._defines.REFLECTIONMAP_PLANAR = true;
+                            break;
+                        case Texture.PROJECTION_MODE:
+                            this._defines.REFLECTIONMAP_PROJECTION = true;
+                            break;
+                        case Texture.SKYBOX_MODE:
+                            this._defines.REFLECTIONMAP_SKYBOX = true;
+                            break;
+                        case Texture.SPHERICAL_MODE:
+                            this._defines.REFLECTIONMAP_SPHERICAL = true;
+                            break;
+                        case Texture.EQUIRECTANGULAR_MODE:
+                            this._defines.REFLECTIONMAP_EQUIRECTANGULAR = true;
+                            break;
+                        case Texture.FIXED_EQUIRECTANGULAR_MODE:
+                            this._defines.REFLECTIONMAP_EQUIRECTANGULAR_FIXED = true;
+                            break;
+                        case Texture.FIXED_EQUIRECTANGULAR_MIRRORED_MODE:
+                            this._defines.REFLECTIONMAP_MIRROREDEQUIRECTANGULAR_FIXED = true;
+                            break;                                
+                    }
 
-                        if (this.reflectionTexture instanceof HDRCubeTexture && (<HDRCubeTexture>this.reflectionTexture)) {
-                            this._defines.USESPHERICALFROMREFLECTIONMAP = true;
-                            needNormals = true;
+                    if (this.reflectionTexture instanceof HDRCubeTexture && (<HDRCubeTexture>this.reflectionTexture)) {
+                        this._defines.USESPHERICALFROMREFLECTIONMAP = true;
+                        needNormals = true;
 
-                            if ((<HDRCubeTexture>this.reflectionTexture).isPMREM) {
-                                this._defines.USEPMREMREFLECTION = true;
-                            }
+                        if ((<HDRCubeTexture>this.reflectionTexture).isPMREM) {
+                            this._defines.USEPMREMREFLECTION = true;
                         }
                     }
                 }
@@ -753,92 +775,103 @@
                 if (this.lightmapTexture && StandardMaterial.LightmapTextureEnabled) {
                     if (!this.lightmapTexture.isReady()) {
                         return false;
-                    } else {
-                        needUVs = true;
-                        this._defines.LIGHTMAP = true;
-                        this._defines.USELIGHTMAPASSHADOWMAP = this.useLightmapAsShadowmap;
                     }
+
+                    needUVs = true;
+                    this._defines.LIGHTMAP = true;
+                    this._defines.USELIGHTMAPASSHADOWMAP = this.useLightmapAsShadowmap;
                 }
 
                 if (this.emissiveTexture && StandardMaterial.EmissiveTextureEnabled) {
                     if (!this.emissiveTexture.isReady()) {
                         return false;
-                    } else {
-                        needUVs = true;
-                        this._defines.EMISSIVE = true;
                     }
+
+                    needUVs = true;
+                    this._defines.EMISSIVE = true;
                 }
 
                 if (StandardMaterial.SpecularTextureEnabled) {
                     if (this.metallicTexture) {
                         if (!this.metallicTexture.isReady()) {
                             return false;
-                        } else {
-                            needUVs = true;
-                            this._defines.METALLICWORKFLOW = true;
-                            this._defines.METALLICROUGHNESSMAP = true;
-                            this._defines.METALLICROUGHNESSGSTOREINALPHA = this.useRoughnessFromMetallicTextureAlpha;
-                            this._defines.METALLICROUGHNESSGSTOREINGREEN = !this.useRoughnessFromMetallicTextureAlpha && this.useRoughnessFromMetallicTextureGreen;
                         }
+
+                        needUVs = true;
+                        this._defines.METALLICWORKFLOW = true;
+                        this._defines.METALLICMAP = true;
+                        this._defines.ROUGHNESSSTOREINMETALMAPALPHA = this.useRoughnessFromMetallicTextureAlpha;
+                        this._defines.ROUGHNESSSTOREINMETALMAPGREEN = !this.useRoughnessFromMetallicTextureAlpha && this.useRoughnessFromMetallicTextureGreen;                            
+                        this._defines.METALLNESSSTOREINMETALMAPBLUE = this.useMetallnessFromMetallicTextureBlue;                            
+                        this._defines.AOSTOREINMETALMAPRED = this.useAmbientOcclusionFromMetallicTextureRed;
                     }
                     else if (this.reflectivityTexture) {
                         if (!this.reflectivityTexture.isReady()) {
                             return false;
-                        } else {
-                            needUVs = true;
-                            this._defines.REFLECTIVITY = true;
-                            this._defines.MICROSURFACEFROMREFLECTIVITYMAP = this.useMicroSurfaceFromReflectivityMapAlpha;
-                            this._defines.MICROSURFACEAUTOMATIC = this.useAutoMicroSurfaceFromReflectivityMap;
                         }
+
+                        needUVs = true;
+                        this._defines.REFLECTIVITY = true;
+                        this._defines.MICROSURFACEFROMREFLECTIVITYMAP = this.useMicroSurfaceFromReflectivityMapAlpha;
+                        this._defines.MICROSURFACEAUTOMATIC = this.useAutoMicroSurfaceFromReflectivityMap;
+                    }
+
+                    if (this.microSurfaceTexture) {
+                        if (!this.microSurfaceTexture.isReady()) {
+                            return false;
+                        }
+
+                        needUVs = true;
+                        this._defines.MICROSURFACEMAP = true;
                     }
                 }
 
                 if (scene.getEngine().getCaps().standardDerivatives && this.bumpTexture && StandardMaterial.BumpTextureEnabled && !this.disableBumpMap) {
                     if (!this.bumpTexture.isReady()) {
                         return false;
-                    } else {
-                        needUVs = true;
-                        this._defines.BUMP = true;
-
-                        if (this.useParallax && this.albedoTexture && StandardMaterial.DiffuseTextureEnabled) {
-                            this._defines.PARALLAX = true;
-                            if (this.useParallaxOcclusion) {
-                                this._defines.PARALLAXOCCLUSION = true;
-                            }
-                        }
+                    }
+                    
+                    needUVs = true;
+                    this._defines.BUMP = true;
 
-                        if (this.invertNormalMapX) {
-                            this._defines.INVERTNORMALMAPX = true;
+                    if (this.useParallax && this.albedoTexture && StandardMaterial.DiffuseTextureEnabled) {
+                        this._defines.PARALLAX = true;
+                        if (this.useParallaxOcclusion) {
+                            this._defines.PARALLAXOCCLUSION = true;
                         }
+                    }
 
-                        if (this.invertNormalMapY) {
-                            this._defines.INVERTNORMALMAPY = true;
-                        }
+                    if (this.invertNormalMapX) {
+                        this._defines.INVERTNORMALMAPX = true;
+                    }
 
-                        if (scene._mirroredCameraPosition) {
-                            this._defines.INVERTNORMALMAPX = !this._defines.INVERTNORMALMAPX;
-                            this._defines.INVERTNORMALMAPY = !this._defines.INVERTNORMALMAPY;
-                        }
+                    if (this.invertNormalMapY) {
+                        this._defines.INVERTNORMALMAPY = true;
                     }
+
+                    if (scene._mirroredCameraPosition) {
+                        this._defines.INVERTNORMALMAPX = !this._defines.INVERTNORMALMAPX;
+                        this._defines.INVERTNORMALMAPY = !this._defines.INVERTNORMALMAPY;
+                    }                        
                 }
 
                 if (this.refractionTexture && StandardMaterial.RefractionTextureEnabled) {
                     if (!this.refractionTexture.isReady()) {
                         return false;
-                    } else {
-                        needUVs = true;
-                        this._defines.REFRACTION = true;
-                        this._defines.REFRACTIONMAP_3D = this.refractionTexture.isCube;
+                    }
+                    
+                    needUVs = true;
+                    this._defines.REFRACTION = true;
+                    this._defines.REFRACTIONMAP_3D = this.refractionTexture.isCube;
 
-                        if (this.linkRefractionWithTransparency) {
-                            this._defines.LINKREFRACTIONTOTRANSPARENCY = true;
-                        }
-                        if (this.refractionTexture instanceof HDRCubeTexture) {
-                            this._defines.REFRACTIONMAPINLINEARSPACE = true;
+                    if (this.linkRefractionWithTransparency) {
+                        this._defines.LINKREFRACTIONTOTRANSPARENCY = true;
+                    }
+                    if (this.refractionTexture instanceof HDRCubeTexture) {
+                        this._defines.REFRACTIONMAPINLINEARSPACE = true;
 
-                            if ((<HDRCubeTexture>this.refractionTexture).isPMREM) {
-                                this._defines.USEPMREMREFRACTION = true;
-                            }
+                        if ((<HDRCubeTexture>this.refractionTexture).isPMREM) {
+                            this._defines.USEPMREMREFRACTION = true;
                         }
                     }
                 }
@@ -846,9 +879,9 @@
                 if (this.cameraColorGradingTexture && StandardMaterial.ColorGradingTextureEnabled) {
                     if (!this.cameraColorGradingTexture.isReady()) {
                         return false;
-                    } else {
-                        this._defines.CAMERACOLORGRADING = true;
                     }
+                    
+                    this._defines.CAMERACOLORGRADING = true;
                 }
 
                 if (!this.backFaceCulling && this.twoSidedLighting) {
@@ -1094,9 +1127,9 @@
                 
                 var uniforms = ["world", "view", "viewProjection", "vEyePosition", "vLightsType", "vAmbientColor", "vAlbedoColor", "vReflectivityColor", "vEmissiveColor", "vReflectionColor",
                         "vFogInfos", "vFogColor", "pointSize",
-                        "vAlbedoInfos", "vAmbientInfos", "vOpacityInfos", "vReflectionInfos", "vEmissiveInfos", "vReflectivityInfos", "vBumpInfos", "vLightmapInfos", "vRefractionInfos",
+                        "vAlbedoInfos", "vAmbientInfos", "vOpacityInfos", "vReflectionInfos", "vEmissiveInfos", "vReflectivityInfos", "vMicroSurfaceSamplerInfos", "vBumpInfos", "vLightmapInfos", "vRefractionInfos",
                         "mBones",
-                        "vClipPlane", "albedoMatrix", "ambientMatrix", "opacityMatrix", "reflectionMatrix", "emissiveMatrix", "reflectivityMatrix", "bumpMatrix", "lightmapMatrix", "refractionMatrix",
+                        "vClipPlane", "albedoMatrix", "ambientMatrix", "opacityMatrix", "reflectionMatrix", "emissiveMatrix", "reflectivityMatrix", "microSurfaceSamplerMatrix", "bumpMatrix", "lightmapMatrix", "refractionMatrix",
                         "depthValues",
                         "opacityParts", "emissiveLeftColor", "emissiveRightColor",
                         "vLightingIntensity", "vOverloadedShadowIntensity", "vOverloadedIntensity", "vOverloadedAlbedo", "vOverloadedReflection", "vOverloadedReflectivity", "vOverloadedEmissive", "vOverloadedMicroSurface",
@@ -1108,7 +1141,7 @@
                         "vCameraInfos"
                 ];
 
-                var samplers = ["albedoSampler", "ambientSampler", "opacitySampler", "reflectionCubeSampler", "reflection2DSampler", "emissiveSampler", "reflectivitySampler", "bumpSampler", "lightmapSampler", "refractionCubeSampler", "refraction2DSampler"];
+                var samplers = ["albedoSampler", "ambientSampler", "opacitySampler", "reflectionCubeSampler", "reflection2DSampler", "emissiveSampler", "reflectivitySampler", "microSurfaceSampler", "bumpSampler", "lightmapSampler", "refractionCubeSampler", "refraction2DSampler"];
                 
                 ColorCurves.PrepareUniforms(uniforms); 
                 ColorGradingTexture.PrepareUniformsAndSamplers(uniforms, samplers); 
@@ -1255,15 +1288,22 @@
                         if (this.metallicTexture) {
                             this._effect.setTexture("reflectivitySampler", this.metallicTexture);
 
-                            this._effect.setFloat2("vReflectivityInfos", this.metallicTexture.coordinatesIndex, this.metallicTexture.level);
+                            this._effect.setFloat3("vReflectivityInfos", this.metallicTexture.coordinatesIndex, this.reflectivityTexture.level, this.ambientTextureStrength);
                             this._effect.setMatrix("reflectivityMatrix", this.metallicTexture.getTextureMatrix());
                         }
                         else if (this.reflectivityTexture) {
                             this._effect.setTexture("reflectivitySampler", this.reflectivityTexture);
 
-                            this._effect.setFloat2("vReflectivityInfos", this.reflectivityTexture.coordinatesIndex, this.reflectivityTexture.level);
+                            this._effect.setFloat3("vReflectivityInfos", this.reflectivityTexture.coordinatesIndex, this.reflectivityTexture.level, 1.0);
                             this._effect.setMatrix("reflectivityMatrix", this.reflectivityTexture.getTextureMatrix());
                         }
+
+                        if (this.microSurfaceTexture) {
+                            this._effect.setTexture("microSurfaceSampler", this.microSurfaceTexture);
+
+                            this._effect.setFloat2("vMicroSurfaceSamplerInfos", this.microSurfaceTexture.coordinatesIndex, this.microSurfaceTexture.level);
+                            this._effect.setMatrix("microSurfaceSamplerMatrix", this.microSurfaceTexture.getTextureMatrix());
+                        }
                     }
 
                     if (this.bumpTexture && this._myScene.getEngine().getCaps().standardDerivatives && StandardMaterial.BumpTextureEnabled && !this.disableBumpMap) {

+ 189 - 154
src/Shaders/pbr.fragment.fx

@@ -89,10 +89,16 @@ uniform sampler2D lightmapSampler;
 
 #if defined(REFLECTIVITY) || defined(METALLICWORKFLOW) 
 varying vec2 vReflectivityUV;
-uniform vec2 vReflectivityInfos;
+uniform vec3 vReflectivityInfos;
 uniform sampler2D reflectivitySampler;
 #endif
 
+#ifdef MICROSURFACEMAP
+varying vec2 vMicroSurfaceSamplerUV;
+uniform vec2 vMicroSurfaceSamplerInfos;
+uniform sampler2D microSurfaceSampler;
+#endif
+
 // Fresnel
 #include<fresnelFunction>
 
@@ -208,16 +214,16 @@ void main(void) {
 	surfaceAlbedo = texture2D(albedoSampler, vAlbedoUV + uvOffset);
 	surfaceAlbedo = vec4(toLinearSpace(surfaceAlbedo.rgb), surfaceAlbedo.a);
 
-#ifndef LINKREFRACTIONTOTRANSPARENCY
-#ifdef ALPHATEST
-	if (surfaceAlbedo.a < 0.4)
-		discard;
-#endif
-#endif
+	#ifndef LINKREFRACTIONTOTRANSPARENCY
+		#ifdef ALPHATEST
+			if (surfaceAlbedo.a < 0.4)
+				discard;
+		#endif
+	#endif
 
-#ifdef ALPHAFROMALBEDO
-	alpha *= surfaceAlbedo.a;
-#endif
+	#ifdef ALPHAFROMALBEDO
+		alpha *= surfaceAlbedo.a;
+	#endif
 
 	surfaceAlbedo.rgb *= vAlbedoInfos.y;
 #else
@@ -235,67 +241,85 @@ void main(void) {
 #endif
 
 	// Ambient color
-	vec3 ambientColor = vec3(1., 1., 1.);
+	vec3 ambientOcclusionColor = vec3(1., 1., 1.);
 
 #ifdef AMBIENT
-	ambientColor = texture2D(ambientSampler, vAmbientUV + uvOffset).rgb * vAmbientInfos.y;
-	ambientColor = vec3(1., 1., 1.) - ((vec3(1., 1., 1.) - ambientColor) * vAmbientInfos.z);
+	vec3 ambientOcclusionColorMap = texture2D(ambientSampler, vAmbientUV + uvOffset).rgb * vAmbientInfos.y;
+	ambientOcclusionColor = mix(ambientOcclusionColor, ambientOcclusionColorMap, vAmbientInfos.z);
 
-#ifdef OVERLOADEDVALUES
-	ambientColor.rgb = mix(ambientColor.rgb, vOverloadedAmbient, vOverloadedIntensity.x);
-#endif
+	#ifdef OVERLOADEDVALUES
+		ambientOcclusionColor.rgb = mix(ambientOcclusionColor.rgb, vOverloadedAmbient, vOverloadedIntensity.x);
+	#endif
 #endif
 
 	// Reflectivity map
 	float microSurface = vReflectivityColor.a;
 	vec3 surfaceReflectivityColor = vReflectivityColor.rgb;
 
-#ifdef OVERLOADEDVALUES
-	surfaceReflectivityColor.rgb = mix(surfaceReflectivityColor.rgb, vOverloadedReflectivity, vOverloadedIntensity.z);
-#endif
-
 #ifdef REFLECTIVITY
 	vec4 surfaceReflectivityColorMap = texture2D(reflectivitySampler, vReflectivityUV + uvOffset);
 	surfaceReflectivityColor = surfaceReflectivityColorMap.rgb;
 	surfaceReflectivityColor = toLinearSpace(surfaceReflectivityColor);
+	surfaceReflectivityColor *= vReflectivityInfos.y;
 
 	#ifdef OVERLOADEDVALUES
 		surfaceReflectivityColor = mix(surfaceReflectivityColor, vOverloadedReflectivity, vOverloadedIntensity.z);
 	#endif
 
 	#ifdef MICROSURFACEFROMREFLECTIVITYMAP
-		microSurface = surfaceReflectivityColorMap.a;
+		microSurface = surfaceReflectivityColorMap.a * vReflectivityInfos.z;
 	#else
 		#ifdef MICROSURFACEAUTOMATIC
 			microSurface = computeDefaultMicroSurface(microSurface, surfaceReflectivityColor);
 		#endif
 	#endif
+#else
+	#ifdef OVERLOADEDVALUES
+		surfaceReflectivityColor = mix(surfaceReflectivityColor, vOverloadedReflectivity, vOverloadedIntensity.z);
+	#endif
 #endif
 
 #ifdef METALLICWORKFLOW
 	vec2 metallicRoughness = surfaceReflectivityColor.rg;
 
-	#ifdef METALLICROUGHNESSMAP
+	#ifdef METALLICMAP
 		vec4 surfaceMetallicColorMap = texture2D(reflectivitySampler, vReflectivityUV + uvOffset);
 
-		// No gamma space from the metallic map in metallic workflow.
-		metallicRoughness.r *= surfaceMetallicColorMap.r;
-		#ifdef METALLICROUGHNESSGSTOREINALPHA
+		#ifdef AOSTOREINMETALMAPRED			
+			vec3 aoStoreInMetalMap = vec3(surfaceMetallicColorMap.r, surfaceMetallicColorMap.r, surfaceMetallicColorMap.r);
+			ambientOcclusionColor = mix(ambientOcclusionColor, aoStoreInMetalMap, vReflectivityInfos.z);
+		#endif
+
+		#ifdef METALLNESSSTOREINMETALMAPBLUE
+			metallicRoughness.r *= surfaceMetallicColorMap.b;
+		#else
+			metallicRoughness.r *= surfaceMetallicColorMap.r;
+		#endif
+
+		#ifdef ROUGHNESSSTOREINMETALMAPALPHA
 			metallicRoughness.g *= surfaceMetallicColorMap.a;
 		#else
-			#ifdef METALLICROUGHNESSGSTOREINGREEN
+			#ifdef ROUGHNESSSTOREINMETALMAPGREEN
 				metallicRoughness.g *= surfaceMetallicColorMap.g;
 			#endif
 		#endif
 	#endif
 
+	#ifdef MICROSURFACEMAP
+		vec4 microSurfaceTexel = texture2D(microSurfaceSampler, vMicroSurfaceSamplerUV + uvOffset) * vMicroSurfaceSamplerInfos.y;
+		metallicRoughness.g *= microSurfaceTexel.r;
+	#endif
+
+	// Compute microsurface form roughness.
+	microSurface = 1.0 - metallicRoughness.g;
+
 	// Diffuse is used as the base of the reflectivity.
 	vec3 baseColor = surfaceAlbedo.rgb;
 
 	// Drop the surface diffuse by the 1.0 - metalness.
 	surfaceAlbedo.rgb *= (1.0 - metallicRoughness.r);
 	
-	// Default specular reflectance at normal incidence.
+	// Default specular reflectance at normal incidence aka F0.
 	// 4% corresponds to index of refraction (IOR) of 1.50, approximately equal to glass.
 	const vec3 DefaultSpecularReflectanceDielectric = vec3(0.04, 0.04, 0.04);
 
@@ -305,8 +329,11 @@ void main(void) {
 	#ifdef OVERLOADEDVALUES
 		surfaceReflectivityColor = mix(surfaceReflectivityColor, vOverloadedReflectivity, vOverloadedIntensity.z);
 	#endif
-
-	microSurface = 1.0 - metallicRoughness.g;
+#else
+	#ifdef MICROSURFACEMAP
+		vec4 microSurfaceTexel = texture2D(microSurfaceSampler, vMicroSurfaceSamplerUV + uvOffset) * vMicroSurfaceSamplerInfos.y;
+		microSurface = microSurfaceTexel.r;
+	#endif
 #endif
 
 #ifdef OVERLOADEDVALUES
@@ -360,13 +387,12 @@ void main(void) {
 #ifdef OPACITY
 	vec4 opacityMap = texture2D(opacitySampler, vOpacityUV + uvOffset);
 
-#ifdef OPACITYRGB
-	opacityMap.rgb = opacityMap.rgb * vec3(0.3, 0.59, 0.11);
-	alpha *= (opacityMap.x + opacityMap.y + opacityMap.z)* vOpacityInfos.y;
-#else
-	alpha *= opacityMap.a * vOpacityInfos.y;
-#endif
-
+	#ifdef OPACITYRGB
+		opacityMap.rgb = opacityMap.rgb * vec3(0.3, 0.59, 0.11);
+		alpha *= (opacityMap.x + opacityMap.y + opacityMap.z)* vOpacityInfos.y;
+	#else
+		alpha *= opacityMap.a * vOpacityInfos.y;
+	#endif
 #endif
 
 #ifdef VERTEXALPHA
@@ -390,59 +416,59 @@ void main(void) {
 #ifdef REFRACTION
 	vec3 refractionVector = refract(-viewDirectionW, normalW, vRefractionInfos.y);
 
-#ifdef LODBASEDMICROSFURACE
-#ifdef USEPMREMREFRACTION
-	float lodRefraction = getMipMapIndexFromAverageSlopeWithPMREM(vMicrosurfaceTextureLods.y, alphaG);
-#else
-	float lodRefraction = getMipMapIndexFromAverageSlope(vMicrosurfaceTextureLods.y, alphaG);
-#endif
-#else
-	float biasRefraction = (vMicrosurfaceTextureLods.y + 2.) * (1.0 - microSurface);
-#endif
+	#ifdef LODBASEDMICROSFURACE
+		#ifdef USEPMREMREFRACTION
+			float lodRefraction = getMipMapIndexFromAverageSlopeWithPMREM(vMicrosurfaceTextureLods.y, alphaG);
+		#else
+			float lodRefraction = getMipMapIndexFromAverageSlope(vMicrosurfaceTextureLods.y, alphaG);
+		#endif
+	#else
+		float biasRefraction = (vMicrosurfaceTextureLods.y + 2.) * (1.0 - microSurface);
+	#endif
 
-#ifdef REFRACTIONMAP_3D
-	refractionVector.y = refractionVector.y * vRefractionInfos.w;
+	#ifdef REFRACTIONMAP_3D
+		refractionVector.y = refractionVector.y * vRefractionInfos.w;
 
-	if (dot(refractionVector, viewDirectionW) < 1.0)
-	{
-#ifdef LODBASEDMICROSFURACE
-#ifdef USEPMREMREFRACTION
-		// Empiric Threshold
-		if ((vMicrosurfaceTextureLods.y - lodRefraction) > 4.0)
+		if (dot(refractionVector, viewDirectionW) < 1.0)
 		{
-			// Bend to not reach edges.
-			float scaleRefraction = 1. - exp2(lodRefraction) / exp2(vMicrosurfaceTextureLods.y); // CubemapSize is the size of the base mipmap
-			float maxRefraction = max(max(abs(refractionVector.x), abs(refractionVector.y)), abs(refractionVector.z));
-			if (abs(refractionVector.x) != maxRefraction) refractionVector.x *= scaleRefraction;
-			if (abs(refractionVector.y) != maxRefraction) refractionVector.y *= scaleRefraction;
-			if (abs(refractionVector.z) != maxRefraction) refractionVector.z *= scaleRefraction;
-		}
-#endif
+		#ifdef LODBASEDMICROSFURACE
+			#ifdef USEPMREMREFRACTION
+					// Empiric Threshold
+					if ((vMicrosurfaceTextureLods.y - lodRefraction) > 4.0)
+					{
+						// Bend to not reach edges.
+						float scaleRefraction = 1. - exp2(lodRefraction) / exp2(vMicrosurfaceTextureLods.y); // CubemapSize is the size of the base mipmap
+						float maxRefraction = max(max(abs(refractionVector.x), abs(refractionVector.y)), abs(refractionVector.z));
+						if (abs(refractionVector.x) != maxRefraction) refractionVector.x *= scaleRefraction;
+						if (abs(refractionVector.y) != maxRefraction) refractionVector.y *= scaleRefraction;
+						if (abs(refractionVector.z) != maxRefraction) refractionVector.z *= scaleRefraction;
+					}
+			#endif
 
-		surfaceRefractionColor = textureCubeLodEXT(refractionCubeSampler, refractionVector, lodRefraction).rgb * vRefractionInfos.x;
-#else
-		surfaceRefractionColor = textureCube(refractionCubeSampler, refractionVector, biasRefraction).rgb * vRefractionInfos.x;
-#endif
-	}
+				surfaceRefractionColor = textureCubeLodEXT(refractionCubeSampler, refractionVector, lodRefraction).rgb * vRefractionInfos.x;
+		#else
+				surfaceRefractionColor = textureCube(refractionCubeSampler, refractionVector, biasRefraction).rgb * vRefractionInfos.x;
+		#endif
+		}
 
-#ifndef REFRACTIONMAPINLINEARSPACE
-	surfaceRefractionColor = toLinearSpace(surfaceRefractionColor.rgb);
-#endif
-#else
-	vec3 vRefractionUVW = vec3(refractionMatrix * (view * vec4(vPositionW + refractionVector * vRefractionInfos.z, 1.0)));
+		#ifndef REFRACTIONMAPINLINEARSPACE
+			surfaceRefractionColor = toLinearSpace(surfaceRefractionColor.rgb);
+		#endif
+	#else
+		vec3 vRefractionUVW = vec3(refractionMatrix * (view * vec4(vPositionW + refractionVector * vRefractionInfos.z, 1.0)));
 
-	vec2 refractionCoords = vRefractionUVW.xy / vRefractionUVW.z;
+		vec2 refractionCoords = vRefractionUVW.xy / vRefractionUVW.z;
 
-	refractionCoords.y = 1.0 - refractionCoords.y;
+		refractionCoords.y = 1.0 - refractionCoords.y;
 
-#ifdef LODBASEDMICROSFURACE
-	surfaceRefractionColor = texture2DLodEXT(refraction2DSampler, refractionCoords, lodRefraction).rgb * vRefractionInfos.x;
-#else
-	surfaceRefractionColor = texture2D(refraction2DSampler, refractionCoords, biasRefraction).rgb * vRefractionInfos.x;
-#endif    
+		#ifdef LODBASEDMICROSFURACE
+			surfaceRefractionColor = texture2DLodEXT(refraction2DSampler, refractionCoords, lodRefraction).rgb * vRefractionInfos.x;
+		#else
+			surfaceRefractionColor = texture2D(refraction2DSampler, refractionCoords, biasRefraction).rgb * vRefractionInfos.x;
+		#endif    
 
-	surfaceRefractionColor = toLinearSpace(surfaceRefractionColor.rgb);
-#endif
+		surfaceRefractionColor = toLinearSpace(surfaceRefractionColor.rgb);
+	#endif
 #endif
 
 	// Reflection
@@ -452,68 +478,68 @@ void main(void) {
 #ifdef REFLECTION
 	vec3 vReflectionUVW = computeReflectionCoords(vec4(vPositionW, 1.0), normalW);
 
-#ifdef LODBASEDMICROSFURACE
-#ifdef USEPMREMREFLECTION
-	float lodReflection = getMipMapIndexFromAverageSlopeWithPMREM(vMicrosurfaceTextureLods.x, alphaG);
-#else
-	float lodReflection = getMipMapIndexFromAverageSlope(vMicrosurfaceTextureLods.x, alphaG);
-#endif
-#else
-	float biasReflection = (vMicrosurfaceTextureLods.x + 2.) * (1.0 - microSurface);
-#endif
+	#ifdef LODBASEDMICROSFURACE
+		#ifdef USEPMREMREFLECTION
+			float lodReflection = getMipMapIndexFromAverageSlopeWithPMREM(vMicrosurfaceTextureLods.x, alphaG);
+		#else
+			float lodReflection = getMipMapIndexFromAverageSlope(vMicrosurfaceTextureLods.x, alphaG);
+		#endif
+	#else
+		float biasReflection = (vMicrosurfaceTextureLods.x + 2.) * (1.0 - microSurface);
+	#endif
 
-#ifdef REFLECTIONMAP_3D
+	#ifdef REFLECTIONMAP_3D
+
+		#ifdef LODBASEDMICROSFURACE
+			#ifdef USEPMREMREFLECTION
+				// Empiric Threshold
+				if ((vMicrosurfaceTextureLods.y - lodReflection) > 4.0)
+				{
+					// Bend to not reach edges.
+					float scaleReflection = 1. - exp2(lodReflection) / exp2(vMicrosurfaceTextureLods.x); // CubemapSize is the size of the base mipmap
+					float maxReflection = max(max(abs(vReflectionUVW.x), abs(vReflectionUVW.y)), abs(vReflectionUVW.z));
+					if (abs(vReflectionUVW.x) != maxReflection) vReflectionUVW.x *= scaleReflection;
+					if (abs(vReflectionUVW.y) != maxReflection) vReflectionUVW.y *= scaleReflection;
+					if (abs(vReflectionUVW.z) != maxReflection) vReflectionUVW.z *= scaleReflection;
+				}
+			#endif
 
-#ifdef LODBASEDMICROSFURACE
-#ifdef USEPMREMREFLECTION
-	// Empiric Threshold
-	if ((vMicrosurfaceTextureLods.y - lodReflection) > 4.0)
-	{
-		// Bend to not reach edges.
-		float scaleReflection = 1. - exp2(lodReflection) / exp2(vMicrosurfaceTextureLods.x); // CubemapSize is the size of the base mipmap
-		float maxReflection = max(max(abs(vReflectionUVW.x), abs(vReflectionUVW.y)), abs(vReflectionUVW.z));
-		if (abs(vReflectionUVW.x) != maxReflection) vReflectionUVW.x *= scaleReflection;
-		if (abs(vReflectionUVW.y) != maxReflection) vReflectionUVW.y *= scaleReflection;
-		if (abs(vReflectionUVW.z) != maxReflection) vReflectionUVW.z *= scaleReflection;
-	}
-#endif
-
-	environmentRadiance = textureCubeLodEXT(reflectionCubeSampler, vReflectionUVW, lodReflection).rgb * vReflectionInfos.x;
-#else
-	environmentRadiance = textureCube(reflectionCubeSampler, vReflectionUVW, biasReflection).rgb * vReflectionInfos.x;
-#endif
+			environmentRadiance = textureCubeLodEXT(reflectionCubeSampler, vReflectionUVW, lodReflection).rgb * vReflectionInfos.x;
+		#else
+			environmentRadiance = textureCube(reflectionCubeSampler, vReflectionUVW, biasReflection).rgb * vReflectionInfos.x;
+		#endif
 
-#ifdef USESPHERICALFROMREFLECTIONMAP
-#ifndef REFLECTIONMAP_SKYBOX
-	vec3 normalEnvironmentSpace = (reflectionMatrix * vec4(normalW, 1)).xyz;
-	environmentIrradiance = EnvironmentIrradiance(normalEnvironmentSpace);
-#endif
-#else
-	environmentRadiance = toLinearSpace(environmentRadiance.rgb);
+		#ifdef USESPHERICALFROMREFLECTIONMAP
+			#ifndef REFLECTIONMAP_SKYBOX
+				vec3 normalEnvironmentSpace = (reflectionMatrix * vec4(normalW, 1)).xyz;
+				environmentIrradiance = EnvironmentIrradiance(normalEnvironmentSpace);
+			#endif
+		#else
+			environmentRadiance = toLinearSpace(environmentRadiance.rgb);
 
-	environmentIrradiance = textureCube(reflectionCubeSampler, normalW, 20.).rgb * vReflectionInfos.x;
-	environmentIrradiance = toLinearSpace(environmentIrradiance.rgb);
-	environmentIrradiance *= 0.2; // Hack in case of no hdr cube map use for environment.
-#endif
-#else
-	vec2 coords = vReflectionUVW.xy;
+			environmentIrradiance = textureCube(reflectionCubeSampler, normalW, 20.).rgb * vReflectionInfos.x;
+			environmentIrradiance = toLinearSpace(environmentIrradiance.rgb);
+			environmentIrradiance *= 0.2; // Hack in case of no hdr cube map use for environment.
+		#endif
+	#else
+		vec2 coords = vReflectionUVW.xy;
 
-#ifdef REFLECTIONMAP_PROJECTION
-	coords /= vReflectionUVW.z;
-#endif
+		#ifdef REFLECTIONMAP_PROJECTION
+			coords /= vReflectionUVW.z;
+		#endif
 
-	coords.y = 1.0 - coords.y;
-#ifdef LODBASEDMICROSFURACE
-	environmentRadiance = texture2DLodEXT(reflection2DSampler, coords, lodReflection).rgb * vReflectionInfos.x;
-#else
-	environmentRadiance = texture2D(reflection2DSampler, coords, biasReflection).rgb * vReflectionInfos.x;
-#endif
+		coords.y = 1.0 - coords.y;
+		#ifdef LODBASEDMICROSFURACE
+			environmentRadiance = texture2DLodEXT(reflection2DSampler, coords, lodReflection).rgb * vReflectionInfos.x;
+		#else
+			environmentRadiance = texture2D(reflection2DSampler, coords, biasReflection).rgb * vReflectionInfos.x;
+		#endif
 
-	environmentRadiance = toLinearSpace(environmentRadiance.rgb);
+		environmentRadiance = toLinearSpace(environmentRadiance.rgb);
 
-	environmentIrradiance = texture2D(reflection2DSampler, coords, 20.).rgb * vReflectionInfos.x;
-	environmentIrradiance = toLinearSpace(environmentIrradiance.rgb);
-#endif
+		environmentIrradiance = texture2D(reflection2DSampler, coords, 20.).rgb * vReflectionInfos.x;
+		environmentIrradiance = toLinearSpace(environmentIrradiance.rgb);
+	#endif
 #endif
 
 #ifdef OVERLOADEDVALUES
@@ -591,31 +617,40 @@ void main(void) {
 
 	// Composition
 #ifdef EMISSIVEASILLUMINATION
-	vec3 finalDiffuse = max(lightDiffuseContribution * surfaceAlbedoContribution + vAmbientColor, 0.0) * surfaceAlbedo.rgb;
+	vec3 finalDiffuse = lightDiffuseContribution * surfaceAlbedoContribution;
 
-#ifdef OVERLOADEDSHADOWVALUES
-	shadowedOnlyLightDiffuseContribution = max(shadowedOnlyLightDiffuseContribution * surfaceAlbedoContribution + vAmbientColor, 0.0) * surfaceAlbedo.rgb;
-#endif
+	#ifdef OVERLOADEDSHADOWVALUES
+		shadowedOnlyLightDiffuseContribution = shadowedOnlyLightDiffuseContribution * surfaceAlbedoContribution;
+	#endif
 #else
-#ifdef LINKEMISSIVEWITHALBEDO
-	vec3 finalDiffuse = max((lightDiffuseContribution + surfaceEmissiveColor) * surfaceAlbedoContribution + vAmbientColor, 0.0) * surfaceAlbedo.rgb;
+	#ifdef LINKEMISSIVEWITHALBEDO
+		vec3 finalDiffuse = (lightDiffuseContribution + surfaceEmissiveColor) * surfaceAlbedoContribution;
 
-#ifdef OVERLOADEDSHADOWVALUES
-	shadowedOnlyLightDiffuseContribution = max((shadowedOnlyLightDiffuseContribution + surfaceEmissiveColor) * surfaceAlbedoContribution + vAmbientColor, 0.0) * surfaceAlbedo.rgb;
-#endif
-#else
-	vec3 finalDiffuse = max(lightDiffuseContribution * surfaceAlbedoContribution + surfaceEmissiveColor + vAmbientColor, 0.0) * surfaceAlbedo.rgb;
+		#ifdef OVERLOADEDSHADOWVALUES
+			shadowedOnlyLightDiffuseContribution = (shadowedOnlyLightDiffuseContribution + surfaceEmissiveColor) * surfaceAlbedoContribution;
+		#endif
+	#else
+		vec3 finalDiffuse = lightDiffuseContribution * surfaceAlbedoContribution + surfaceEmissiveColor;
 
-#ifdef OVERLOADEDSHADOWVALUES
-	shadowedOnlyLightDiffuseContribution = max(shadowedOnlyLightDiffuseContribution * surfaceAlbedoContribution + surfaceEmissiveColor + vAmbientColor, 0.0) * surfaceAlbedo.rgb;
-#endif
-#endif
+		#ifdef OVERLOADEDSHADOWVALUES
+			shadowedOnlyLightDiffuseContribution = shadowedOnlyLightDiffuseContribution * surfaceAlbedoContribution + surfaceEmissiveColor;
+		#endif
+	#endif
 #endif
 
+finalDiffuse.rgb += vAmbientColor;
+finalDiffuse *= surfaceAlbedo.rgb;
+finalDiffuse = max(finalDiffuse, 0.0);
+
 #ifdef OVERLOADEDSHADOWVALUES
+	shadowedOnlyLightDiffuseContribution += vAmbientColor;
+	shadowedOnlyLightDiffuseContribution *= surfaceAlbedo.rgb;
+	shadowedOnlyLightDiffuseContribution = max(shadowedOnlyLightDiffuseContribution, 0.0);
 	finalDiffuse = mix(finalDiffuse, shadowedOnlyLightDiffuseContribution, (1.0 - vOverloadedShadowIntensity.y));
 #endif
 
+finalDiffuse = (finalDiffuse * vLightingIntensity.x + surfaceAlbedo.rgb * environmentIrradiance) * ambientOcclusionColor;
+
 #ifdef SPECULARTERM
 	vec3 finalSpecular = lightSpecularContribution * surfaceReflectivityColor;
 	#ifdef SPECULAROVERALPHA
@@ -629,12 +664,12 @@ void main(void) {
 	alpha = clamp(alpha + getLuminance(environmentRadiance), 0., 1.);
 #endif
 
-	// Composition
-	// Reflection already includes the environment intensity.
+// Composition
+// Reflection already includes the environment intensity.
+vec4 finalColor = vec4(finalDiffuse + finalSpecular * vLightingIntensity.x + environmentRadiance + refractance, alpha);
+
 #ifdef EMISSIVEASILLUMINATION
-	vec4 finalColor = vec4(finalDiffuse * ambientColor * vLightingIntensity.x + surfaceAlbedo.rgb * environmentIrradiance + finalSpecular * vLightingIntensity.x + environmentRadiance + surfaceEmissiveColor * vLightingIntensity.y + refractance, alpha);
-#else
-	vec4 finalColor = vec4(finalDiffuse * ambientColor * vLightingIntensity.x + surfaceAlbedo.rgb * environmentIrradiance + finalSpecular * vLightingIntensity.x + environmentRadiance + refractance, alpha);
+	finalColor.rgb += (surfaceEmissiveColor * vLightingIntensity.y);
 #endif
 
 #ifdef LIGHTMAP

+ 18 - 1
src/Shaders/pbr.vertex.fx

@@ -58,10 +58,16 @@ uniform mat4 lightmapMatrix;
 
 #if defined(REFLECTIVITY) || defined(METALLICWORKFLOW) 
 varying vec2 vReflectivityUV;
-uniform vec2 vReflectivityInfos;
+uniform vec3 vReflectivityInfos;
 uniform mat4 reflectivityMatrix;
 #endif
 
+#ifdef MICROSURFACEMAP
+varying vec2 vMicroSurfaceSamplerUV;
+uniform vec2 vMicroSurfaceSamplerInfos;
+uniform mat4 microSurfaceSamplerMatrix;
+#endif
+
 #ifdef BUMP
 varying vec2 vBumpUV;
 uniform vec3 vBumpInfos;
@@ -203,6 +209,17 @@ void main(void) {
     }
 #endif
 
+#ifdef MICROSURFACEMAP
+    if (vMicroSurfaceSamplerInfos.x == 0.)
+    {
+        vMicroSurfaceSamplerUV = vec2(microSurfaceSamplerMatrix * vec4(uv, 1.0, 0.0));
+    }
+    else
+    {
+        vMicroSurfaceSamplerUV = vec2(microSurfaceSamplerMatrix * vec4(uv2, 1.0, 0.0));
+    }
+#endif
+
 #ifdef BUMP
     if (vBumpInfos.x == 0.)
     {