Browse Source

Enhanced gbuffer & shaders with roughness/metalness, added various shader code as preparation for a physically based lighting model

BearishSun 9 years ago
parent
commit
4fe867b5ad

+ 10 - 11
Data/Examples/Example.bsl

@@ -17,19 +17,19 @@ Technique : base("Surface") =
 			SamplerState samp : register(s0);
 			Texture2D tex : register(t0);
 		
-			float4 main(
+			void main(
 				in VStoFS input, 
-				out float4 OutGBufferA : SV_Target1,
-				out float4 OutGBufferB : SV_Target2) : SV_Target0
+				out float4 OutGBufferA : SV_Target0,
+				out float4 OutGBufferB : SV_Target1,
+				out float2 OutGBufferC : SV_Target2)
 			{
 				SurfaceData surfaceData;
 				surfaceData.albedo = float4(tex.Sample(samp, input.uv0).xyz, 1.0f);
 				surfaceData.worldNormal.xyz = input.tangentToWorldZ;
+				surfaceData.roughness = 1.0f;
+				surfaceData.metalness = 0.0f;
 				
-				encodeGBuffer(surfaceData, OutGBufferA, OutGBufferB);
-				
-				// TODO - Just returning a simple ambient term, use better environment lighting later
-				return float4(surfaceData.albedo.rgb, 1.0f) * 0.2f; 
+				encodeGBuffer(surfaceData, OutGBufferA, OutGBufferB, OutGBufferC);
 			}	
 		};
 	};
@@ -57,11 +57,10 @@ Technique : base("Surface") =
 				SurfaceData surfaceData;
 				surfaceData.albedo = texture(tex, uv0);
 				surfaceData.worldNormal.xyz = tangentToWorldZ;
+				surfaceData.roughness = 1.0f;
+				surfaceData.metalness = 0.0f;
 				
-				encodeGBuffer(surfaceData, fragColor[1], fragColor[2]);
-				
-				// TODO - Just returning a simple ambient term, use better environment lighting later
-				fragColor[0] = vec4(surfaceData.albedo.rgb, 1.0f) * 0.2f; 
+				encodeGBuffer(surfaceData, fragColor[0], fragColor[1], fragColor[2]);
 			}	
 		};
 	};

BIN
Data/Examples/Example.bsl.asset


+ 6 - 2
Data/Raw/Engine/Includes/GBuffer.bslinc

@@ -10,11 +10,13 @@ Technique
 	{
 		Common = 
 		{
-			void encodeGBuffer(SurfaceData data, out float4 GBufferAData, out float4 GBufferBData)
+			void encodeGBuffer(SurfaceData data, out float4 GBufferAData, out float4 GBufferBData, out float2 GBufferCData)
 			{
 				GBufferAData = data.albedo;
 				GBufferBData.xyz = float3(data.worldNormal.xyz * 0.5f + 0.5f);
 				GBufferBData.w = 1.0f; // Marks that some deferred data was written
+				GBufferCData.x = data.roughness;
+				GBufferCData.y = data.metalness;
 			}
 		};
 	};
@@ -30,11 +32,13 @@ Technique
 	{
 		Common = 
 		{
-			void encodeGBuffer(SurfaceData data, out vec4 GBufferAData, out vec4 GBufferBData)
+			void encodeGBuffer(SurfaceData data, out vec4 GBufferAData, out vec4 GBufferBData, out vec4 GBufferCData)
 			{
 				GBufferAData = data.albedo;
 				GBufferBData.xyz = vec3(data.worldNormal.xyz * 0.5f + 0.5f);
 				GBufferBData.w = 1.0f; // Marks that some deferred data was written
+				GBufferCData.x = data.roughness;
+				GBufferCData.y = data.metalness;
 			}
 		};
 	};

+ 87 - 1
Data/Raw/Engine/Includes/LightingCommon.bslinc

@@ -20,7 +20,59 @@ Technique
 				float radiusSqrdInv;
 				float3 color;
 			};
-						
+			
+			float3 calcMicrofacetFresnelShlick(float3 F0, float LoH)
+			{
+				return F0 + (1.0f - F0) * pow(1.0f - LoH, 5.0f);
+			}
+
+			float calcMicrofacetShadowingSmithGGX(float roughness, float NoV, float NoL)
+			{
+				// Note: It's probably better to use the joint shadowing + masking version of this function
+				// Note: Pull these multiplies out, since they're used by the distribution function as well?
+				float roughness2 = roughness * roughness;
+				float roughness4 = roughness2 * roughness2;
+
+				// Note: Original GGX G1 multiplied by NoV & NoL (respectively), so that the microfacet function divisor gets canceled out
+				// Original formula being (ignoring the factor for masking negative directions):
+				//   G1(v) = 2 / (1 + sqrt(1 + roughness^4 * tan^2(v)))
+				//
+				// Using trig identities: tan = sin/cos & sin^2 + cos^2 = 1
+				//   G1(v) = 2 / (1 + sqrt(1 + roughness^4 * (1 - cos^2(v))/cos^2(v)))
+				//
+				// Multiply by cos(v) so that we cancel out the (NoL * NoV) factor in the microfacet formula divisor
+				//   G1(v) = 2 * cos(v) / (cos^2(v) + sqrt(cos^2 + roughness^4 - roughness^4 * cos^2(v)))
+				// 
+				// Actually do the cancellation:
+				//    G1(v) = 2 / (cos^2(v) + sqrt(cos^2 + roughness^4 - roughness^4 * cos^2(v)))
+				//
+				// Also cancel out the 2 and the 4:
+				//    G1(v) = 1 / (cos^2(v) + sqrt(cos^2 + roughness^4 - roughness^4 * cos^2(v)))
+				//
+				// Final equation being:
+				//    G(v, l) = G1(v) * G1(l)
+				//
+				// Where cos(v) is NoV or NoL
+				
+				float g1V = NoV + sqrt(NoV * (NoV - NoV * roughness4) + roughness4);
+				float g1L = NoL + sqrt(NoL * (NoL - NoL * roughness4) + roughness4);
+				return rcp(g1V * g1L);
+			}
+			
+			float calcMicrofacetDistGGX(float roughness, float NoH)
+			{
+				float roughness2 = roughness * roughness;
+				float roughness4 = roughness2 * roughness2;
+				
+				float d = (NoH * roughness4 - NoH) * NoH + 1.0f;
+				return roughness4 / (PI * d * d);
+			}
+			
+			float calcDiffuseLambert(float color)
+			{
+				return color * (1.0f / PI);
+			}
+			
 			float getSpotAttenuation(float3 worldPosToLight, float3 direction, float3 angles)
 			{
 				float output = saturate((dot(-worldPosToLight, direction) - angles.y) * angles.z);
@@ -97,6 +149,40 @@ Technique
 				vec3 color;
 			};
 									
+			vec3 calcMicrofacetFresnelShlick(vec3 F0, float LoH)
+			{
+				return F0 + (1.0f - F0) * pow(1.0f - LoH, 5.0f);
+			}
+
+			float calcMicrofacetShadowingSmithGGX(float roughness, float NoV, float NoL)
+			{
+				// Note: It's probably better to use the joint shadowing + masking version of this function
+				// Note: Pull these multiplies out, since they're used by the distribution function as well?
+				float roughness2 = roughness * roughness;
+				float roughness4 = roughness2 * roughness2;
+
+				// Note: Original GGX G1 multiplied by NoV & NoL (respectively), so that the microfacet function divisor gets canceled out
+				// See HLSL code for derivation
+				
+				float g1V = NoV + sqrt(NoV * (NoV - NoV * roughness4) + roughness4);
+				float g1L = NoL + sqrt(NoL * (NoL - NoL * roughness4) + roughness4);
+				return 1.0f / (g1V * g1L);
+			}
+			
+			float calcMicrofacetDistGGX(float roughness, float NoH)
+			{
+				float roughness2 = roughness * roughness;
+				float roughness4 = roughness2 * roughness2;
+				
+				float d = (NoH * roughness4 - NoH) * NoH + 1.0f;
+				return roughness4 / (PI * d * d);
+			}
+			
+			float calcDiffuseLambert(float color)
+			{
+				return color * (1.0f / PI);
+			}
+									
 			float getSpotAttenuation(vec3 worldPosToLight, vec3 direction, vec3 angles)
 			{
 				float atten = clamp((dot(-worldPosToLight, direction) - angles.y) * angles.z, 0.0, 1.0);

+ 4 - 0
Data/Raw/Engine/Includes/SurfaceData.bslinc

@@ -11,6 +11,8 @@ Technique : base("SurfaceData") =
 				float4 albedo;
 				float4 worldNormal;
 				float depth;
+				float roughness;
+				float metalness;
 			};
 		};
 	};
@@ -29,6 +31,8 @@ Technique : base("SurfaceData") =
 				vec4 albedo;
 				vec4 worldNormal;
 				float depth;
+				float roughness;
+				float metalness;
 			};
 		};
 	};

+ 10 - 11
Data/Raw/Engine/Shaders/Default.bsl

@@ -8,19 +8,19 @@ Technique : base("Surface") =
 	{
 		Fragment =
 		{
-			float4 main(
+			void main(
 				in VStoFS input, 
-				out float4 OutGBufferA : SV_Target1,
-				out float4 OutGBufferB : SV_Target2) : SV_Target0
+				out float4 OutGBufferA : SV_Target0,
+				out float4 OutGBufferB : SV_Target1,
+				out float2 OutGBufferC : SV_Target2)
 			{
 				SurfaceData surfaceData;
 				surfaceData.albedo = float4(0.05f, 0.05f, 0.05f, 1.0f);
 				surfaceData.worldNormal.xyz = input.tangentToWorldZ;
+				surfaceData.roughness = 1.0f;
+				surfaceData.metalness = 0.0f;
 				
-				encodeGBuffer(surfaceData, OutGBufferA, OutGBufferB);
-				
-				// TODO - Just returning a simple ambient term, use better environment lighting later
-				return float4(surfaceData.albedo.rgb, 1.0f); 
+				encodeGBuffer(surfaceData, OutGBufferA, OutGBufferB, OutGBufferC);
 			}	
 		};
 	};
@@ -45,11 +45,10 @@ Technique : base("Surface") =
 				SurfaceData surfaceData;
 				surfaceData.albedo = vec4(0.05f, 0.05f, 0.05f, 1.0f);
 				surfaceData.worldNormal.xyz = tangentToWorldZ;
+				surfaceData.roughness = 1.0f;
+				surfaceData.metalness = 0.0f;
 				
-				encodeGBuffer(surfaceData, fragColor[1], fragColor[2]);
-				
-				// TODO - Just returning a simple ambient term, use better environment lighting later
-				fragColor[0] = vec4(surfaceData.albedo.rgb, 1.0f); 
+				encodeGBuffer(surfaceData, fragColor[0], fragColor[1], fragColor[2]);
 			}	
 		};
 	};

+ 22 - 13
Data/Raw/Engine/Shaders/Diffuse.bsl

@@ -4,9 +4,13 @@ Parameters =
 {
 	Sampler2D 	gAlbedoSamp : alias("gAlbedoTex");
 	Sampler2D 	gNormalSamp : alias("gNormalTex");
+	Sampler2D	gRoughnessSamp : alias("gRoughnessTex");
+	Sampler2D	gMetalnessSamp : alias("gMetalnessTex");
 	
 	Texture2D 	gAlbedoTex;
 	Texture2D	gNormalTex = "normal";
+	Texture2D	gRoughnessTex = "white";
+	Texture2D	gMetalnessTex = "black";
 };
 
 Technique : base("Surface") =
@@ -19,14 +23,19 @@ Technique : base("Surface") =
 		{
 			SamplerState gAlbedoSamp : register(s0);
 			SamplerState gNormalSamp : register(s1);
+			SamplerState gRoughnessSamp : register(s2);
+			SamplerState gMetalnessSamp : register(s3);
 			
 			Texture2D gAlbedoTex : register(t0);
 			Texture2D gNormalTex : register(t1);
+			Texture2D gRoughnessTex : register(t2);
+			Texture2D gMetalnessTex : register(t3);
 			
-			float4 main(
+			void main(
 				in VStoFS input, 
-				out float4 OutGBufferA : SV_Target1,
-				out float4 OutGBufferB : SV_Target2) : SV_Target0
+				out float4 OutGBufferA : SV_Target0,
+				out float4 OutGBufferB : SV_Target1,
+				out float2 OutGBufferC : SV_Target2)
 			{
 				float3 normal = normalize(gNormalTex.Sample(gNormalSamp, input.uv0) * 2.0f - float3(1, 1, 1));
 				float3 worldNormal = calcWorldNormal(input, normal);
@@ -34,11 +43,10 @@ Technique : base("Surface") =
 				SurfaceData surfaceData;
 				surfaceData.albedo = gAlbedoTex.Sample(gAlbedoSamp, input.uv0);
 				surfaceData.worldNormal.xyz = worldNormal;
+				surfaceData.roughness = gRoughnessTex.Sample(gRoughnessSamp, input.uv0).x;
+				surfaceData.metalness = gMetalnessTex.Sample(gMetalnessSamp, input.uv0).x;
 				
-				encodeGBuffer(surfaceData, OutGBufferA, OutGBufferB);
-				
-				// TODO - Just returning a simple ambient term, use better environment lighting later
-				return float4(surfaceData.albedo.rgb, 1.0f) * 0.01f; 
+				encodeGBuffer(surfaceData, OutGBufferA, OutGBufferB, OutGBufferC);
 			}	
 		};
 	};
@@ -54,11 +62,13 @@ Technique : base("Surface") =
 		{
 			layout(location = 0) in vec2 uv0;
 			layout(location = 2) in vec3 tangentToWorldZ;
-			layout(location = 3) in vec4 tangentToWorldX;			
+			layout(location = 3) in vec4 tangentToWorldX;
 		
 			layout(binding = 4) uniform sampler2D gAlbedoTex;
 			layout(binding = 5) uniform sampler2D gNormalTex;
-
+			layout(binding = 6) uniform sampler2D gRoughnessTex;
+			layout(binding = 7) uniform sampler2D gMetalnessTex;
+			
 			layout(location = 0) out vec4 fragColor[3];
 			
 			void main()
@@ -69,11 +79,10 @@ Technique : base("Surface") =
 				SurfaceData surfaceData;
 				surfaceData.albedo = texture(gAlbedoTex, uv0);
 				surfaceData.worldNormal.xyz = worldNormal;
+				surfaceData.roughness = texture(gRoughnessTex, uv0).x;
+				surfaceData.metalness = texture(gMetalnessTex, uv0).x;
 				
-				encodeGBuffer(surfaceData, fragColor[1], fragColor[2]);
-				
-				// TODO - Just returning a simple ambient term, use better environment lighting later
-				fragColor[0] = vec4(surfaceData.albedo.rgb, 1.0f) * 0.01f; 
+				encodeGBuffer(surfaceData, fragColor[0], fragColor[1], fragColor[2]);
 			}	
 		};
 	};

+ 35 - 19
Data/Raw/Engine/Shaders/TiledDeferredLighting.bsl

@@ -6,10 +6,12 @@ Parameters =
 {
 	Sampler2D 	gGBufferASamp : alias("gGBufferATex");
 	Sampler2D 	gGBufferBSamp : alias("gGBufferBTex");
+	Sampler2D 	gGBufferCSamp : alias("gGBufferCTex");
 	Sampler2D 	gDepthBufferSamp : alias("gDepthBufferTex");
 	
 	Texture2D 	gGBufferATex : auto("GBufferA");
 	Texture2D	gGBufferBTex : auto("GBufferB");
+	Texture2D	gGBufferCTex : auto("GBufferC");
 	Texture2D 	gDepthBufferTex : auto("GBufferDepth");
 };
 
@@ -34,19 +36,22 @@ Technique
 
 			SamplerState gGBufferASamp : register(s0);
 			SamplerState gGBufferBSamp : register(s1);
-			SamplerState gDepthBufferSamp : register(s2);
+			SamplerState gGBufferCSamp : register(s2);
+			SamplerState gDepthBufferSamp : register(s3);
 	
 			#if MSAA_COUNT > 1
 			Texture2DMS<float4, MSAA_COUNT> gGBufferATex : register(t0);
 			Texture2DMS<float4, MSAA_COUNT>	gGBufferBTex : register(t1);
-			Texture2DMS<float4, MSAA_COUNT> gDepthBufferTex : register(t2);
+			Texture2DMS<float2, MSAA_COUNT>	gGBufferCTex : register(t2);
+			Texture2DMS<float4, MSAA_COUNT> gDepthBufferTex : register(t3);
 			#else
 			Texture2D gGBufferATex : register(t0);
 			Texture2D gGBufferBTex : register(t1);
-			Texture2D gDepthBufferTex : register(t2);
+			Texture2D gGBufferCTex : register(t2);
+			Texture2D gDepthBufferTex : register(t3);
 			#endif
 			
-			SurfaceData decodeGBuffer(float4 GBufferAData, float4 GBufferBData, float deviceZ)
+			SurfaceData decodeGBuffer(float4 GBufferAData, float4 GBufferBData, float2 GBufferCData, float deviceZ)
 			{
 				SurfaceData output;
 				
@@ -55,11 +60,13 @@ Technique
 				output.worldNormal = GBufferBData * float4(2, 2, 2, 1) - float4(1, 1, 1, 0);
 				output.worldNormal.xyz = normalize(output.worldNormal.xyz);
 				output.depth = convertFromDeviceZ(deviceZ);
+				output.roughness = GBufferCData.x;
+				output.metalness = GBufferCData.y;
 				
 				return output;
 			}			
 						
-			StructuredBuffer<LightData> gLights : register(t3);		
+			StructuredBuffer<LightData> gLights : register(t4);		
 		
 			cbuffer Params : register(b0)
 			{
@@ -111,9 +118,10 @@ Technique
 			{
 				float4 GBufferAData = gGBufferATex.Load(pixelPos, sampleIndex);
 				float4 GBufferBData = gGBufferBTex.Load(pixelPos, sampleIndex);
+				float2 GBufferCData = gGBufferCTex.Load(pixelPos, sampleIndex).rg;
 				float deviceZ = gDepthBufferTex.Load(pixelPos, sampleIndex).r;
 				
-				return decodeGBuffer(GBufferAData, GBufferBData, deviceZ);
+				return decodeGBuffer(GBufferAData, GBufferBData, GBufferCData, deviceZ);
 			}
 			
 			#else
@@ -123,9 +131,10 @@ Technique
 			{
 				float4 GBufferAData = gGBufferATex.Load(int3(pixelPos, 0));
 				float4 GBufferBData = gGBufferBTex.Load(int3(pixelPos, 0));
+				float2 GBufferCData = gGBufferCTex.Load(int3(pixelPos, 0)).rg;
 				float deviceZ = gDepthBufferTex.Load(int3(pixelPos, 0)).r;
 				
-				return decodeGBuffer(GBufferAData, GBufferBData, deviceZ);
+				return decodeGBuffer(GBufferAData, GBufferBData, GBufferCData, deviceZ);
 			}			
 			#endif
 						
@@ -208,7 +217,7 @@ Technique
 					sTileMinZ = 0x7F7FFFFF;
 					sTileMaxZ = 0;
 					sNumLightsPerType[0] = 0;
-					sNumLightsPerType[0] = 0;
+					sNumLightsPerType[1] = 0;
 					sTotalNumLights = 0;
 				}
 				
@@ -389,14 +398,16 @@ Technique
 			#if MSAA_COUNT > 1
 			layout(binding = 1) uniform sampler2DMS gGBufferATex;
 			layout(binding = 2) uniform sampler2DMS gGBufferBTex;
-			layout(binding = 3) uniform sampler2DMS gDepthBufferTex;
+			layout(binding = 3) uniform sampler2DMS gGBufferCTex;
+			layout(binding = 4) uniform sampler2DMS gDepthBufferTex;
 			#else
 			layout(binding = 1) uniform sampler2D gGBufferATex;
 			layout(binding = 2) uniform sampler2D gGBufferBTex;
-			layout(binding = 3) uniform sampler2D gDepthBufferTex;
+			layout(binding = 3) uniform sampler2D gGBufferCTex;
+			layout(binding = 4) uniform sampler2D gDepthBufferTex;
 			#endif
 			
-			SurfaceData decodeGBuffer(vec4 GBufferAData, vec4 GBufferBData, float deviceZ)
+			SurfaceData decodeGBuffer(vec4 GBufferAData, vec4 GBufferBData, vec2 GBufferCData, float deviceZ)
 			{
 				SurfaceData surfaceData;
 				
@@ -405,6 +416,8 @@ Technique
 				surfaceData.worldNormal = GBufferBData * vec4(2, 2, 2, 1) - vec4(1, 1, 1, 0);
 				surfaceData.worldNormal.xyz = normalize(surfaceData.worldNormal.xyz);
 				surfaceData.depth = convertFromDeviceZ(deviceZ);
+				surfaceData.roughness = GBufferCData.x;
+				surfaceData.metalness = GBufferCData.y;
 				
 				return surfaceData;
 			}
@@ -437,9 +450,10 @@ Technique
 			{
 				vec4 GBufferAData = texelFetch(gGBufferATex, pixelPos, sampleIndex);
 				vec4 GBufferBData = texelFetch(gGBufferBTex, pixelPos, sampleIndex);
+				vec2 GBufferCData = texelFetch(gGBufferCTex, pixelPos, sampleIndex).rg;
 				float deviceZ = texelFetch(gDepthBufferTex, pixelPos, sampleIndex).r;
 				
-				return decodeGBuffer(GBufferAData, GBufferBData, deviceZ);
+				return decodeGBuffer(GBufferAData, GBufferBData, GBufferCData, deviceZ);
 			}
 			
 			#else
@@ -450,19 +464,20 @@ Technique
 			{
 				vec4 GBufferAData = texelFetch(gGBufferATex, pixelPos, 0);
 				vec4 GBufferBData = texelFetch(gGBufferBTex, pixelPos, 0);
+				vec2 GBufferCData = texelFetch(gGBufferCTex, pixelPos, 0).rg;
 				float deviceZ = texelFetch(gDepthBufferTex, pixelPos, 0).r;
 				
-				return decodeGBuffer(GBufferAData, GBufferBData, deviceZ);
+				return decodeGBuffer(GBufferAData, GBufferBData, GBufferCData, deviceZ);
 			}	
 			
 			#endif
 			
-			layout(std430, binding = 4) readonly buffer gLights
+			layout(std430, binding = 6) readonly buffer gLights
 			{
-				LightData[] gLightsData;
+				LightData gLightsData[];
 			};
 
-			layout(binding = 6, std140) uniform Params
+			layout(binding = 7, std140) uniform Params
 			{
 				// Offsets at which specific light types begin in gLights buffer
 				// Assumed directional lights start at 0
@@ -550,7 +565,7 @@ Technique
 					sTileMinZ = 0x7F7FFFFF;
 					sTileMaxZ = 0;
 					sNumLightsPerType[0] = 0;
-					sNumLightsPerType[0] = 0;
+					sNumLightsPerType[1] = 0;
 					sTotalNumLights = 0;
 				}
 				
@@ -599,8 +614,9 @@ Technique
 					uint lightsEnd = gLightOffsets[type + 1];
 					for (uint i = lightOffset; i < lightsEnd && i < MAX_LIGHTS; i += TILE_SIZE)
 					{
-						vec4 lightPosition = gMatView * vec4(gLightsData[i].position, 1.0f);
-						float lightRadius = gLightsData[i].radius;
+						LightData lightData = gLightsData[i];
+						vec4 lightPosition = gMatView * vec4(lightData.position, 1.0f);
+						float lightRadius = lightData.radius;
 						
 						bool lightInTile = true;
 					

+ 22 - 8
Data/Raw/Engine/Shaders/Transparent.bsl

@@ -6,9 +6,13 @@ Parameters =
 {
 	Sampler2D 	gAlbedoSamp : alias("gAlbedoTex");
 	Sampler2D 	gNormalSamp : alias("gNormalTex");
+	Sampler2D	gRoughnessSamp : alias("gRoughnessTex");
+	Sampler2D	gMetalnessSamp : alias("gMetalnessTex");
 	
 	Texture2D 	gAlbedoTex;
 	Texture2D	gNormalTex = "normal";
+	Texture2D	gRoughnessTex = "white";
+	Texture2D	gMetalnessTex = "black";
 	
 	float		gOpacity   = 1.0f;
 };
@@ -41,13 +45,17 @@ Technique
 		{
 			SamplerState gAlbedoSamp : register(s0);
 			SamplerState gNormalSamp : register(s1);
+			SamplerState gRoughnessSamp : register(s2);
+			SamplerState gMetalnessSamp : register(s3);
 			
 			Texture2D gAlbedoTex : register(t0);
 			Texture2D gNormalTex : register(t1);
+			Texture2D gRoughnessTex : register(t2);
+			Texture2D gMetalnessTex : register(t3);
 			
-			Buffer<uint3> gGridOffsetsAndSize : register(t2);
-			Buffer<uint> gGridLightIndices : register(t3);
-			StructuredBuffer<LightData> gLights : register(t4);
+			Buffer<uint3> gGridOffsetsAndSize : register(t4);
+			Buffer<uint> gGridLightIndices : register(t5);
+			StructuredBuffer<LightData> gLights : register(t6);
 
 			cbuffer MaterialParams : register(b5)
 			{
@@ -62,6 +70,8 @@ Technique
 				SurfaceData surfaceData;
 				surfaceData.albedo = gAlbedoTex.Sample(gAlbedoSamp, input.uv0);
 				surfaceData.worldNormal.xyz = worldNormal;
+				surfaceData.roughness = gRoughnessTex.Sample(gRoughnessSamp, input.uv0).x;
+				surfaceData.metalness = gMetalnessTex.Sample(gMetalnessSamp, input.uv0).x;
 				
 				float3 lightAccumulator = 0;
 				
@@ -129,15 +139,17 @@ Technique
 		
 			layout(binding = 5) uniform sampler2D gAlbedoTex;
 			layout(binding = 6) uniform sampler2D gNormalTex;
-
-			layout(binding = 7) uniform usamplerBuffer gGridOffsetsAndSize;
-			layout(binding = 8) uniform usamplerBuffer gGridLightIndices;
-			layout(std430, binding = 9) readonly buffer gLights
+			layout(binding = 7) uniform sampler2D gRoughnessTex;
+			layout(binding = 8) uniform sampler2D gMetalnessTex;
+			
+			layout(binding = 9) uniform usamplerBuffer gGridOffsetsAndSize;
+			layout(binding = 10) uniform usamplerBuffer gGridLightIndices;
+			layout(std430, binding = 11) readonly buffer gLights
 			{
 				LightData[] gLightsData;
 			};
 						
-			layout(binding = 10, std140) uniform MaterialParams
+			layout(binding = 12, std140) uniform MaterialParams
 			{
 				float gOpacity;
 			};
@@ -152,6 +164,8 @@ Technique
 				SurfaceData surfaceData;
 				surfaceData.albedo = texture(gAlbedoTex, uv0);
 				surfaceData.worldNormal.xyz = worldNormal;
+				surfaceData.roughness = texture(gRoughnessTex, uv0).x;
+				surfaceData.metalness = texture(gMetalnessTex, uv0).x;
 				
 				// Directional lights
 				vec3 lightAccumulator = vec3(0, 0, 0);

+ 1 - 0
Source/RenderBeast/Include/BsLightRendering.h

@@ -95,6 +95,7 @@ namespace bs { namespace ct
 
 		GpuParamTexture mGBufferA;
 		GpuParamTexture mGBufferB;
+		GpuParamTexture mGBufferC;
 		GpuParamTexture mGBufferDepth;
 
 		Vector3I mLightOffsets;

+ 1 - 0
Source/RenderBeast/Include/BsRenderBeast.h

@@ -28,6 +28,7 @@ namespace bs
 	/** Semantics that may be used for signaling the renderer for what is a certain shader parameter used for. */
 	static StringID RPS_GBufferA = "GBufferA";
 	static StringID RPS_GBufferB = "GBufferB";
+	static StringID RPS_GBufferC = "GBufferC";
 	static StringID RPS_GBufferDepth = "GBufferDepth";
 	static StringID RPS_BoneMatrices = "BoneMatrices";
 

+ 4 - 0
Source/RenderBeast/Include/BsRenderTargets.h

@@ -61,6 +61,9 @@ namespace bs { namespace ct
 		/**	Returns the second color texture of the gbuffer as a bindable texture. */
 		SPtr<Texture> getTextureB() const;
 
+		/**	Returns the third color texture of the gbuffer as a bindable texture. */
+		SPtr<Texture> getTextureC() const;
+
 		/**	Returns the depth texture of the gbuffer as a bindable texture. */
 		SPtr<Texture> getTextureDepth() const;
 
@@ -99,6 +102,7 @@ namespace bs { namespace ct
 		SPtr<PooledRenderTexture> mSceneColorTex;
 		SPtr<PooledRenderTexture> mAlbedoTex;
 		SPtr<PooledRenderTexture> mNormalTex;
+		SPtr<PooledRenderTexture> mRoughMetalTex;
 		SPtr<PooledRenderTexture> mDepthTex;
 
 		SPtr<PooledRenderTexture> mSceneColorNonMSAATex;

+ 3 - 0
Source/RenderBeast/Source/BsLightRendering.cpp

@@ -97,6 +97,8 @@ namespace bs { namespace ct
 				params->getTextureParam(GPT_COMPUTE_PROGRAM, entry.second.name, mGBufferA);
 			else if (entry.second.rendererSemantic == RPS_GBufferB)
 				params->getTextureParam(GPT_COMPUTE_PROGRAM, entry.second.name, mGBufferB);
+			else if (entry.second.rendererSemantic == RPS_GBufferC)
+				params->getTextureParam(GPT_COMPUTE_PROGRAM, entry.second.name, mGBufferC);
 			else if (entry.second.rendererSemantic == RPS_GBufferDepth)
 				params->getTextureParam(GPT_COMPUTE_PROGRAM, entry.second.name, mGBufferDepth);
 		}
@@ -138,6 +140,7 @@ namespace bs { namespace ct
 
 		mGBufferA.set(gbuffer->getTextureA());
 		mGBufferB.set(gbuffer->getTextureB());
+		mGBufferC.set(gbuffer->getTextureC());
 		mGBufferDepth.set(gbuffer->getTextureDepth());
 
 		mParamsSet->setParamBlockBuffer("PerCamera", perCamera, true);

+ 13 - 4
Source/RenderBeast/Source/BsRenderTargets.cpp

@@ -44,6 +44,8 @@ namespace bs { namespace ct
 			height, TU_RENDERTARGET, mViewTarget.numSamples, true));
 		SPtr<PooledRenderTexture> newNormalRT = texPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(mNormalFormat, width, 
 			height, TU_RENDERTARGET, mViewTarget.numSamples, false));
+		SPtr<PooledRenderTexture> newRoughMetalRT = texPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(PF_FLOAT16_RG, width,
+			height, TU_RENDERTARGET, mViewTarget.numSamples, false));
 		SPtr<PooledRenderTexture> newDepthRT = texPool.get(POOLED_RENDER_TEXTURE_DESC::create2D(PF_D32_S8X24, width, height, 
 			TU_DEPTHSTENCIL, mViewTarget.numSamples, false));
 
@@ -64,27 +66,29 @@ namespace bs { namespace ct
 																					 height, TU_RENDERTARGET, 1, false));
 		}
 
-		bool rebuildTargets = newColorRT != mSceneColorTex || newAlbedoRT != mAlbedoTex || newNormalRT != mNormalTex || newDepthRT != mDepthTex;
+		bool rebuildTargets = newColorRT != mSceneColorTex || newAlbedoRT != mAlbedoTex || newNormalRT != mNormalTex 
+			|| newRoughMetalRT != mRoughMetalTex || newDepthRT != mDepthTex;
 
 		mSceneColorTex = newColorRT;
 		mAlbedoTex = newAlbedoRT;
 		mNormalTex = newNormalRT;
+		mRoughMetalTex = newRoughMetalRT;
 		mDepthTex = newDepthRT;
 
 		if (mGBufferRT == nullptr || mSceneColorRT == nullptr || rebuildTargets)
 		{
 			RENDER_TEXTURE_DESC gbufferDesc;
-			gbufferDesc.colorSurfaces[0].texture = mSceneColorTex->texture;
+			gbufferDesc.colorSurfaces[0].texture = mAlbedoTex->texture;
 			gbufferDesc.colorSurfaces[0].face = 0;
 			gbufferDesc.colorSurfaces[0].numFaces = 1;
 			gbufferDesc.colorSurfaces[0].mipLevel = 0;
 
-			gbufferDesc.colorSurfaces[1].texture = mAlbedoTex->texture;
+			gbufferDesc.colorSurfaces[1].texture = mNormalTex->texture;
 			gbufferDesc.colorSurfaces[1].face = 0;
 			gbufferDesc.colorSurfaces[1].numFaces = 1;
 			gbufferDesc.colorSurfaces[1].mipLevel = 0;
 
-			gbufferDesc.colorSurfaces[2].texture = mNormalTex->texture;
+			gbufferDesc.colorSurfaces[2].texture = mRoughMetalTex->texture;
 			gbufferDesc.colorSurfaces[2].face = 0;
 			gbufferDesc.colorSurfaces[2].numFaces = 1;
 			gbufferDesc.colorSurfaces[2].mipLevel = 0;
@@ -173,6 +177,11 @@ namespace bs { namespace ct
 		return mNormalTex->texture;
 	}
 
+	SPtr<Texture> RenderTargets::getTextureC() const
+	{
+		return mRoughMetalTex->texture;
+	}
+
 	SPtr<Texture> RenderTargets::getTextureDepth() const
 	{
 		return mDepthTex->texture;