#include "Macros.fxh" //from FNA #include "Lighting.fxh" static const int NUM_SHADOW_CASCADES = 4; DECLARE_TEXTURE(gPosition, 0); DECLARE_TEXTURE(gAlbedo, 1); DECLARE_TEXTURE(gNormal, 2); DECLARE_TEXTURE(gMetallicRoughness, 3); DECLARE_TEXTURE(shadowMapOne, 4); DECLARE_TEXTURE(shadowMapTwo, 5); DECLARE_TEXTURE(shadowMapThree, 6); DECLARE_TEXTURE(shadowMapFour, 7); BEGIN_CONSTANTS float3 EyePosition _ps(c0) _cb(c0); float3 DirectionalLightDirection _ps(c1) _cb(c1); float3 DirectionalLightColor _ps(c2) _cb(c2); float CascadeFarPlanes[NUM_SHADOW_CASCADES] _ps(c3) _cb(c3); MATRIX_CONSTANTS float4x4 LightSpaceMatrixOne _ps(c7) _cb(c7); float4x4 LightSpaceMatrixTwo _ps(c11) _cb(c11); float4x4 LightSpaceMatrixThree _ps(c15) _cb(c15); float4x4 LightSpaceMatrixFour _ps(c19) _cb(c19); // used to select shadow cascade float4x4 ViewMatrix _ps(c23) _cb(c23); END_CONSTANTS struct VertexInput { float4 Position : POSITION; float2 TexCoord : TEXCOORD; }; struct PixelInput { float4 Position : SV_POSITION; float2 TexCoord : TEXCOORD0; }; PixelInput main_vs(VertexInput input) { PixelInput output; output.Position = input.Position; output.TexCoord = input.TexCoord; return output; } // Pixel Shader float ComputeShadow(float3 positionWorldSpace, float3 N, float3 L) { float bias = 0.005 * tan(acos(dot(N, L))); bias = clamp(bias, 0, 0.01); float4 positionCameraSpace = mul(float4(positionWorldSpace, 1.0), ViewMatrix); int shadowCascadeIndex = 0; // 0 is closest for (int i = 0; i < NUM_SHADOW_CASCADES; i++) { if (abs(positionCameraSpace.z) < CascadeFarPlanes[i]) { shadowCascadeIndex = i; break; } } float4x4 lightSpaceMatrix; if (shadowCascadeIndex == 0) { lightSpaceMatrix = LightSpaceMatrixOne; } else if (shadowCascadeIndex == 1) { lightSpaceMatrix = LightSpaceMatrixTwo; } else if (shadowCascadeIndex == 2) { lightSpaceMatrix = LightSpaceMatrixThree; } else { lightSpaceMatrix = LightSpaceMatrixFour; } float4 positionLightSpace = mul(float4(positionWorldSpace, 1.0), lightSpaceMatrix); // maps to [-1, 1] float3 projectionCoords = positionLightSpace.xyz / positionLightSpace.w; // maps to [0, 1] projectionCoords.x = (projectionCoords.x * 0.5) + 0.5; projectionCoords.y = (projectionCoords.y * 0.5) + 0.5; projectionCoords.y *= -1; // in XNA clip z is 0 to 1 already float inc = 1.0 / 1024.0; float shadowFactor = 0; for (int row = -1; row <= 1; row++) { for (int col = -1; col <= 1; col++) { float closestDepth; if (shadowCascadeIndex == 0) { closestDepth = SAMPLE_TEXTURE(shadowMapOne, projectionCoords.xy + float2(row, col) * inc).r; } else if (shadowCascadeIndex == 1) { closestDepth = SAMPLE_TEXTURE(shadowMapTwo, projectionCoords.xy + float2(row, col) * inc).r; } else if (shadowCascadeIndex == 2) { closestDepth = SAMPLE_TEXTURE(shadowMapThree, projectionCoords.xy + float2(row, col) * inc).r; } else { closestDepth = SAMPLE_TEXTURE(shadowMapFour, projectionCoords.xy + float2(row, col) * inc).r; } shadowFactor += projectionCoords.z - bias > closestDepth ? 1.0 : 0.0; } } shadowFactor /= 9.0; if (projectionCoords.z > 1.0) { shadowFactor = 1.0; } return shadowFactor; } float4 ComputeColor( float3 worldPosition, float3 worldNormal, float3 albedo, float metallic, float roughness ) { float3 V = normalize(EyePosition - worldPosition); float3 N = normalize(worldNormal); float3 F0 = float3(0.04, 0.04, 0.04); F0 = lerp(F0, albedo, metallic); float3 L = normalize(DirectionalLightDirection); float3 radiance = DirectionalLightColor; float shadow = ComputeShadow(worldPosition, N, L); float3 color = ComputeLight(L, radiance, F0, V, N, albedo, metallic, roughness, (1.0 - shadow)); return float4(color, 1.0); } float4 main_ps(PixelInput input) : SV_TARGET0 { float3 worldPosition = SAMPLE_TEXTURE(gPosition, input.TexCoord).rgb; float3 normal = SAMPLE_TEXTURE(gNormal, input.TexCoord).xyz; float3 albedo = SAMPLE_TEXTURE(gAlbedo, input.TexCoord).rgb; float2 metallicRoughness = SAMPLE_TEXTURE(gMetallicRoughness, input.TexCoord).rg; return ComputeColor( worldPosition, normal, albedo, metallicRoughness.r, metallicRoughness.g ); } Technique DeferredPBR_Directional { Pass { VertexShader = compile vs_3_0 main_vs(); PixelShader = compile ps_3_0 main_ps(); } }