#include "Macros.fxh" #include "Shadow.fxh" static const int NUM_SHADOW_CASCADES = 4; DECLARE_TEXTURE(gPosition, 0); DECLARE_TEXTURE(gAlbedo, 1); DECLARE_TEXTURE(gNormal, 2); 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 Softness _ps(c3) _cb(c3); float CascadeFarPlanes[NUM_SHADOW_CASCADES] _ps(c4) _cb(c4); float ShadowMapSize _ps(c8) _cb(c8); MATRIX_CONSTANTS float4x4 LightSpaceMatrixOne _ps(c9) _cb(c9); float4x4 LightSpaceMatrixTwo _ps(c13) _cb(c13); float4x4 LightSpaceMatrixThree _ps(c17) _cb(c17); float4x4 LightSpaceMatrixFour _ps(c21) _cb(c21); float4x4 ViewMatrix _ps(c25) _cb(c25); 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; } float ComputeShadow(float3 positionWorldSpace, float3 N, float3 L) { 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; } // PCF + Poisson soft shadows if (shadowCascadeIndex == 0) { return PoissonShadow( positionWorldSpace, N, L, lightSpaceMatrix, SAMPLER(shadowMapOne), ShadowMapSize ); } else if (shadowCascadeIndex == 1) { return PoissonShadow( positionWorldSpace, N, L, lightSpaceMatrix, SAMPLER(shadowMapTwo), ShadowMapSize ); } else if (shadowCascadeIndex == 2) { return PoissonShadow( positionWorldSpace, N, L, lightSpaceMatrix, SAMPLER(shadowMapThree), ShadowMapSize ); } else { return PoissonShadow( positionWorldSpace, N, L, lightSpaceMatrix, SAMPLER(shadowMapFour), ShadowMapSize ); } } // FIXME: organize this 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; float3 V = normalize(EyePosition - worldPosition); float3 L = normalize(DirectionalLightDirection); float3 N = normalize(normal); float3 H = normalize(V + L); float NdotL = dot(N, L); float NdotH = max(dot(N, H), 0.0); float lightIntensity; if (Softness > 0.0) { lightIntensity = smoothstep(0, Softness, NdotL); } else { lightIntensity = (NdotL > 0.0) ? 1.0 : 0.0; } float3 light = lightIntensity * DirectionalLightColor; float specularIntensity = pow(NdotH * lightIntensity, 32 * 32); float specularSmooth = smoothstep(0.005, 0.01, specularIntensity); float3 specular = specularSmooth * float3(1.0, 1.0, 1.0); float rimColor = float3(1.0, 1.0, 1.0); float rimThreshold = 0.1; float rimAmount = 0.76; float rimDot = 1 - dot(V, N); float rimIntensity = rimDot * pow(max(NdotL, 0.0), rimThreshold); rimIntensity = smoothstep(rimAmount - 0.01, rimAmount + 0.01, rimIntensity); float3 rim = rimIntensity * rimColor; float shadow = ComputeShadow(worldPosition, N, L); float3 color = albedo * (light + specular + rim) * shadow; return float4(color, 1.0); } Technique Deferred_Toon { Pass { VertexShader = compile vs_3_0 main_vs(); PixelShader = compile ps_3_0 main_ps(); } }