Explorar el Código

Added code for PBS model
Added code for image based specular sampling
Tiled deferred and forward rendering shaders now share code for direct lighting

BearishSun hace 8 años
padre
commit
97d803e632

+ 93 - 18
Data/Raw/Engine/Includes/LightingCommon.bslinc

@@ -7,6 +7,9 @@ Technique
 	{
 		Common = 
 		{
+			// Arbitrary limit, increase if needed
+            #define MAX_LIGHTS 512
+		
 			#define PI 3.1415926
 			#define HALF_PI 1.5707963
 			
@@ -68,7 +71,7 @@ Technique
 				return roughness4 / (PI * d * d);
 			}
 			
-			float calcDiffuseLambert(float color)
+			float3 calcDiffuseLambert(float3 color)
 			{
 				return color * (1.0f / PI);
 			}
@@ -81,11 +84,7 @@ Technique
 			
 			float3 getDirLightContibution(SurfaceData surfaceData, LightData lightData)
 			{
-				float3 N = surfaceData.worldNormal.xyz;
-				float3 L = -lightData.direction;
-				
-				float NoL = saturate(dot(N, L)); // TODO - Add bias here?
-				return lightData.color * lightData.intensity * NoL;
+				return lightData.color * lightData.intensity;
 			}
 			
 			float3 getPointLightContribution(float3 L, float3 worldPosition, SurfaceData surfaceData, LightData lightData)
@@ -95,32 +94,108 @@ Technique
 				float distanceSqrd = dot(L, L);
 				float distanceAttenuation = 1/(distanceSqrd + 1);
 				
-				L = normalize(L);
-				float NoL = saturate(dot(N, L)); // TODO - Add bias here?
-
 				float radiusAttenuation = distanceSqrd * lightData.radiusSqrdInv;
 				radiusAttenuation *= radiusAttenuation;
 				radiusAttenuation = saturate(1.0f - radiusAttenuation);
 				radiusAttenuation *= radiusAttenuation;
 
 				float attenuation = distanceAttenuation * radiusAttenuation;
-				return lightData.color * lightData.intensity * (NoL * attenuation);
+				return lightData.color * lightData.intensity * attenuation;
 			}
 			
-			float3 getPointLightContribution(float3 worldPosition, SurfaceData surfaceData, LightData lightData)
+			float3 getSpotLightContribution(float3 L, float3 worldPosition, SurfaceData surfaceData, LightData lightData)
 			{
-				float3 L = lightData.position - worldPosition;
+				float3 pointLightContribution = getPointLightContribution(L, worldPosition, surfaceData, lightData);
+				float spotFalloff = getSpotAttenuation(L, lightData.direction, lightData.spotAngles);
 				
-				return getPointLightContribution(L, worldPosition, surfaceData, lightData);
+				return pointLightContribution * spotFalloff;
 			}
 			
-			float3 getSpotLightContribution(float3 worldPosition, SurfaceData surfaceData, LightData lightData)
+			float3 getSurfaceShading(float3 V, float3 L, SurfaceData surfaceData)
 			{
-				float3 L = lightData.position - worldPosition;
-				float3 pointLightContribution = getPointLightContribution(L, worldPosition, surfaceData, lightData);
-				float spotFalloff = getSpotAttenuation(L, lightData.direction, lightData.spotAngles);
+				float3 N = surfaceData.worldNormal.xyz;
+
+				float3 H = normalize(V + L);
+				float LoH = saturate(dot(L, H));
+				float NoH = saturate(dot(N, H));
+				float NoV = saturate(dot(N, V));
+				float NoL = saturate(dot(N, L));
 				
-				return pointLightContribution * spotFalloff;
+				float3 diffuseColor = lerp(surfaceData.albedo.rgb, float3(0.0f, 0.0f, 0.0f), 1.0f - surfaceData.metalness);
+				
+				// Note: Using a fixed F0 value of 0.04 (plastic) for dielectrics, and using albedo as specular for conductors.
+				// For more customizability allow the user to provide separate albedo/specular colors for both types.
+				float3 specularColor = lerp(float3(0.04f, 0.04f, 0.04f), surfaceData.albedo.rgb, surfaceData.metalness);
+				
+				float3 diffuse = calcDiffuseLambert(diffuseColor);
+				float3 specular = calcMicrofacetFresnelShlick(specularColor, LoH) * 
+					calcMicrofacetDistGGX(surfaceData.roughness, NoH) *
+					calcMicrofacetShadowingSmithGGX(surfaceData.roughness, NoV, NoL);
+				
+				// Note: Need to add energy conservation between diffuse and specular terms?
+				return diffuse + specular;
+			}	
+			
+			StructuredBuffer<LightData> gLights;
+			
+			#ifdef USE_COMPUTE_INDICES
+				groupshared uint gLightIndices[MAX_LIGHTS];
+			#else
+				Buffer<uint> gLightIndices;
+			#endif
+			
+			float4 getDirectLighting(float3 worldPos, SurfaceData surfaceData, uint4 lightOffsets)
+			{
+				float3 N = surfaceData.worldNormal;
+				
+				float3 lightContribution = 0;
+				float alpha = 0.0f;
+				if(surfaceData.worldNormal.w > 0.0f)
+				{
+					for(uint i = 0; i < lightOffsets.x; ++i)
+					{
+						float3 L = -gLights[i].direction;
+						float3 lightContrib = getDirLightContibution(surfaceData, gLights[i]);
+						
+						float NoL = saturate(dot(N, L));
+						lightContribution += lightContrib * NoL;
+					}
+					
+                    for (uint i = lightOffsets.y; i < lightOffsets.z; ++i)
+                    {
+                        uint lightIdx = gLightIndices[i];
+                        
+						float3 L = gLights[lightIdx].position - worldPos;
+						L = normalize(L);
+						
+						float3 lightContrib = getPointLightContribution(L, worldPos, surfaceData, gLights[lightIdx]);
+
+						float NoL = saturate(dot(N, L));
+						lightContribution += lightContrib * NoL;
+                    }
+
+					for(uint i = lightOffsets.z; i < lightOffsets.w; ++i)
+                    {
+                        uint lightIdx = gLightIndices[i];
+						
+						float3 L = gLights[lightIdx].position - worldPos;
+						L = normalize(L);
+						
+                        float3 lightContrib = getSpotLightContribution(L, worldPos, surfaceData, gLights[lightIdx]);
+						
+						float NoL = saturate(dot(N, L));
+						lightContribution += lightContrib * NoL;
+                    }
+										
+					lightContribution += surfaceData.albedo.rgb * gAmbientFactor;
+					
+					// Note: Only possible because we are using Lambert only for lights
+					lightContribution *= surfaceData.albedo.rgb / PI;
+					
+					alpha = 1.0f;
+				}
+				
+				return float4(lightContribution, alpha);
 			}
 		};
 	};

+ 33 - 3
Data/Raw/Engine/Includes/ReflectionCubemapSampling.bslinc

@@ -6,6 +6,9 @@ Technique : base("ReflectionCubemapSampling") =
 	{
 		Common = 
 		{
+			// Arbitrary limit, increase if needed
+			#define MAX_PROBES 512
+		
 			struct ReflProbeData
 			{
 				float3 position;
@@ -23,8 +26,17 @@ Technique : base("ReflectionCubemapSampling") =
 			TextureCubeArray gReflProbeCubmaps;
 			SamplerState gReflProbeSamp;
 			
+			Texture2D gPreintegratedEnvBRDF;
+			SamplerState gPreintegratedEnvBRDFSamp;
+			
 			StructuredBuffer<ReflProbeData> gReflectionProbes;	
 
+			#ifdef USE_COMPUTE_INDICES
+				groupshared uint gReflectionProbeIndices[MAX_PROBES];
+			#else
+				Buffer<uint> gReflectionProbeIndices;
+			#endif
+			
 			cbuffer ReflProbeParams
 			{
 				uint gReflCubemapNumMips;
@@ -74,9 +86,9 @@ Technique : base("ReflectionCubemapSampling") =
 				return lookupDir;
 			}
 			
-			float3 getDistBoxToPoint(float3 point, float3 extents)
+			float3 getDistBoxToPoint(float3 pt, float3 extents)
 			{
-				float3 d = max(max(-extents - point, 0), point - extents);
+				float3 d = max(max(-extents - pt, 0), pt - extents);
 				return length(d);
 			}
 			
@@ -152,7 +164,7 @@ Technique : base("ReflectionCubemapSampling") =
 						if(probeData.type == 0) // Sphere
 						{
 							correctedDir = getLookupForSphereProxy(worldPos, dir, probeData.position, probeData.radius);
-							contibution = getSphereReflectionContribution(normalizedDist);
+							contribution = getSphereReflectionContribution(normalizedDist);
 						}
 						else if(probeData.type == 1) // Box
 						{
@@ -179,6 +191,24 @@ Technique : base("ReflectionCubemapSampling") =
 						
 				#endif
 			}
+			
+			float3 getImageBasedSpecular(float3 worldPos, float3 V, SurfaceData surfaceData)
+			{
+				// See C++ code for generation of gPreintegratedEnvBRDF to see why this code works as is
+				float3 N = surfaceData.worldNormal.xyz;
+				float NoV = saturate(dot(N, V));
+				
+				// Note: Using a fixed F0 value of 0.04 (plastic) for dielectrics, and using albedo as specular for conductors.
+				// For more customizability allow the user to provide separate albedo/specular colors for both types.
+				float3 specularColor = lerp(float3(0.04f, 0.04f, 0.04f), surfaceData.albedo.rgb, surfaceData.metalness);
+				
+				float3 R = 2 * dot(V, N) * N - V;
+				float radiance = gatherReflectionRadiance(worldPos, R, surfaceData.roughness, 0, 0);
+				
+				float2 envBRDF = gPreintegratedEnvBRDF.SampleLevel(gPreintegratedEnvBRDFSamp, float2(NoV, surfaceData.roughness), 0).rg;
+				
+				return radiance * (specularColor * envBRDF.x + envBRDF.y);
+			}		
 		};
 	};
 };

+ 0 - 1
Data/Raw/Engine/Shaders/LightGridLLCreation.bsl

@@ -21,7 +21,6 @@ Technique
 	{
 		Compute = 
 		{
-			StructuredBuffer<LightData> gLights : register(t0);
 			RWBuffer<uint> gLinkedListCounter : register(u0);
 			RWBuffer<uint> gLinkedListHeads : register(u1);
 			RWBuffer<uint4> gLinkedList : register(u2);

+ 2 - 2
Data/Raw/Engine/Shaders/Skybox.bsl

@@ -48,7 +48,7 @@ Technique : inherits("PerCameraData") =
 				#ifdef SOLID_COLOR
 					return gClearColor;
 				#else
-					return gSkyTex.Sample(gSkySamp, dir);
+					return gSkyTex.SampleLevel(gSkySamp, dir, 0);
 				#endif
 				}
 		};	
@@ -102,7 +102,7 @@ Technique : inherits("PerCameraData") =
 			#ifdef SOLID_COLOR
 				fragColor = gClearColor;
 			#else
-				fragColor = texture(gSkyTex, dir);
+				fragColor = textureLod(gSkyTex, dir, 0);
 			#endif
 			}	
 		};

+ 18 - 31
Data/Raw/Engine/Shaders/TiledDeferredLighting.bsl

@@ -1,6 +1,9 @@
 #include "$ENGINE$\GBuffer.bslinc"
 #include "$ENGINE$\PerCameraData.bslinc"
+#define USE_COMPUTE_INDICES
 #include "$ENGINE$\LightingCommon.bslinc"
+#include "$ENGINE$\ReflectionCubemapCommon.bslinc"
+#include "$ENGINE$\ReflectionCubemapSampling.bslinc"
 
 Parameters =
 {
@@ -23,7 +26,9 @@ Blocks =
 Technique 
   : inherits("GBuffer")
   : inherits("PerCameraData")
-  : inherits("LightingCommon") =
+  : inherits("LightingCommon")
+  : inherits("ReflectionCubemapCommon")
+  : inherits("ReflectionCubemapSampling") =
 {
 	Language = "HLSL11";
 	
@@ -31,9 +36,6 @@ Technique
 	{
 		Compute = 
 		{
-			// Arbitrary limit, increase if needed
-            #define MAX_LIGHTS 512
-
 			SamplerState gGBufferASamp : register(s0);
 			SamplerState gGBufferBSamp : register(s1);
 			SamplerState gGBufferCSamp : register(s2);
@@ -66,8 +68,6 @@ Technique
 				return output;
 			}			
 						
-			StructuredBuffer<LightData> gLights : register(t4);		
-		
 			cbuffer Params : register(b0)
 			{
 				// Offsets at which specific light types begin in gLights buffer
@@ -143,7 +143,6 @@ Technique
 
             groupshared uint sNumLightsPerType[2];
 			groupshared uint sTotalNumLights;
-            groupshared uint sLightIndices[MAX_LIGHTS];
 
 			float4 getLighting(float2 clipSpacePos, SurfaceData surfaceData)
 			{
@@ -155,31 +154,19 @@ Technique
 				float4 worldPosition4D = mul(gMatScreenToWorld, mixedSpacePos);
 				float3 worldPosition = worldPosition4D.xyz / worldPosition4D.w;
 				
-				float3 lightAccumulator = 0;
-				float alpha = 0.0f;
-				if(surfaceData.worldNormal.w > 0.0f)
-				{
-					for(uint i = 0; i < gLightOffsets[0]; ++i)
-						lightAccumulator += getDirLightContibution(surfaceData, gLights[i]);
-					
-                    for (uint i = 0; i < sNumLightsPerType[0]; ++i)
-                    {
-                        uint lightIdx = sLightIndices[i];
-                        lightAccumulator += getPointLightContribution(worldPosition, surfaceData, gLights[lightIdx]);
-                    }
+				uint4 lightOffsets;
+				lightOffsets.x = gLightOffsets[0];
+				lightOffsets.y = 0;
+				lightOffsets.z = sNumLightsPerType[0];
+				lightOffsets.w = sTotalNumLights;
+				
+				float4 directLighting = getDirectLighting(worldPosition, surfaceData, lightOffsets);
+				float3 imageBasedSpecular = getImageBasedSpecular(worldPosition, gViewDir, surfaceData);
 
-					for(uint i = sNumLightsPerType[0]; i < sTotalNumLights; ++i)
-                    {
-                        uint lightIdx = sLightIndices[i];
-                        lightAccumulator += getSpotLightContribution(worldPosition, surfaceData, gLights[lightIdx]);
-                    }
-					
-					lightAccumulator += surfaceData.albedo * gAmbientFactor;
-					alpha = 1.0f;
-				}
+				float4 totalLighting = directLighting;
+				totalLighting.rgb += imageBasedSpecular;
 				
-				float3 diffuse = surfaceData.albedo.xyz / PI; // TODO - Add better lighting model later
-				return float4(lightAccumulator * diffuse, alpha);
+				return totalLighting;				
 			}
 			
 			[numthreads(TILE_SIZE, TILE_SIZE, 1)]
@@ -331,7 +318,7 @@ Technique
 								
 								uint idx;
 								InterlockedAdd(sTotalNumLights, 1U, idx);
-								sLightIndices[idx] = i;
+								gLightIndices[idx] = i;
 							}
 						}
 					}

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

@@ -54,8 +54,6 @@ Technique
 			Texture2D gMetalnessTex : register(t3);
 			
 			Buffer<uint3> gGridOffsetsAndSize : register(t4);
-			Buffer<uint> gGridLightIndices : register(t5);
-			StructuredBuffer<LightData> gLights : register(t6);
 
 			cbuffer MaterialParams : register(b5)
 			{
@@ -70,44 +68,22 @@ Technique
 				SurfaceData surfaceData;
 				surfaceData.albedo = gAlbedoTex.Sample(gAlbedoSamp, input.uv0);
 				surfaceData.worldNormal.xyz = worldNormal;
+				surfaceData.worldNormal.w = 0.0f;
 				surfaceData.roughness = gRoughnessTex.Sample(gRoughnessSamp, input.uv0).x;
 				surfaceData.metalness = gMetalnessTex.Sample(gMetalnessSamp, input.uv0).x;
 				
-				float3 lightAccumulator = 0;
-				
-				// Directional lights
-				for(uint lightIdx = 0; lightIdx < gLightOffsets[0]; ++lightIdx)
-					lightAccumulator += getDirLightContibution(surfaceData, gLights[lightIdx]);
-				
 				uint2 pixelPos = (uint2)input.position.xy;
 				uint cellIdx = calcCellIdx(pixelPos, input.position.z);
 				uint3 offsetAndSize = gGridOffsetsAndSize[cellIdx];
 				
-				// Radial lights
-				uint i = offsetAndSize.x;
-				uint end = offsetAndSize.x + offsetAndSize.y;
-				for(; i < end; i++)
-				{
-					uint lightIndex = gGridLightIndices[i];
-					LightData lightData = gLights[lightIndex];
-					
-					lightAccumulator += getPointLightContribution(input.worldPosition, surfaceData, lightData);
-				}
-				
-				// Spot lights
-				end += offsetAndSize.z;
-				for(; i < end; i++)
-				{
-					uint lightIndex = gGridLightIndices[i];
-					LightData lightData = gLights[lightIndex];
-					
-					lightAccumulator += getSpotLightContribution(input.worldPosition, surfaceData, lightData);
-				}
-				
-				lightAccumulator += surfaceData.albedo.xyz * gAmbientFactor;
+				uint4 lightOffsets;
+				lightOffsets.x = gLightOffsets[0];
+				lightOffsets.y = offsetAndSize.x;
+				lightOffsets.z = lightOffsets.y + offsetAndSize.y;
+				lightOffsets.w = lightOffsets.z + offsetAndSize.z;
 				
-				float3 diffuse = surfaceData.albedo.xyz / PI;
-				return float4(diffuse * lightAccumulator, gOpacity); // TODO - Add better lighting model later
+				float3 color = getDirectLighting(input.worldPosition, surfaceData, lightOffsets);
+				return float4(color, gOpacity);
 			}	
 		};
 	};