diff --git a/Effects/DeferredPBREffect.cs b/Effects/DeferredPBREffect.cs index 97c8615..8b76aca 100644 --- a/Effects/DeferredPBREffect.cs +++ b/Effects/DeferredPBREffect.cs @@ -9,8 +9,11 @@ namespace Kav EffectParameter gAlbedoParam; EffectParameter gNormalParam; EffectParameter gMetallicRoughnessParam; + EffectParameter shadowMapParam; EffectParameter eyePositionParam; + EffectParameter lightSpaceMatrixParam; + PointLightCollection pointLightCollection; DirectionalLightCollection directionalLightCollection; @@ -18,8 +21,10 @@ namespace Kav public Texture2D GAlbedo { get; set; } public Texture2D GNormal { get; set; } public Texture2D GMetallicRoughness { get; set; } + public Texture2D ShadowMap { get; set; } public Vector3 EyePosition { get; set; } + public Matrix LightSpaceMatrix { get; set; } public int MaxPointLights { get; } = 64; @@ -95,8 +100,10 @@ namespace Kav gAlbedoParam.SetValue(GAlbedo); gNormalParam.SetValue(GNormal); gMetallicRoughnessParam.SetValue(GMetallicRoughness); + shadowMapParam.SetValue(ShadowMap); eyePositionParam.SetValue(EyePosition); + lightSpaceMatrixParam.SetValue(LightSpaceMatrix); } void CacheEffectParameters() @@ -105,8 +112,11 @@ namespace Kav gAlbedoParam = Parameters["gAlbedo"]; gNormalParam = Parameters["gNormal"]; gMetallicRoughnessParam = Parameters["gMetallicRoughness"]; + shadowMapParam = Parameters["shadowMap"]; eyePositionParam = Parameters["EyePosition"]; + + lightSpaceMatrixParam = Parameters["LightSpaceMatrix"]; } } } diff --git a/Effects/FXB/DeferredPBREffect.fxb b/Effects/FXB/DeferredPBREffect.fxb index 10298d5..7bb8729 100644 Binary files a/Effects/FXB/DeferredPBREffect.fxb and b/Effects/FXB/DeferredPBREffect.fxb differ diff --git a/Effects/FXB/SimpleDepthEffect.fxb b/Effects/FXB/SimpleDepthEffect.fxb index e2baafe..ab998b2 100644 Binary files a/Effects/FXB/SimpleDepthEffect.fxb and b/Effects/FXB/SimpleDepthEffect.fxb differ diff --git a/Effects/HLSL/DeferredPBREffect.fx b/Effects/HLSL/DeferredPBREffect.fx index a49f27a..05a3df7 100644 --- a/Effects/HLSL/DeferredPBREffect.fx +++ b/Effects/HLSL/DeferredPBREffect.fx @@ -8,6 +8,7 @@ DECLARE_TEXTURE(gPosition, 0); DECLARE_TEXTURE(gAlbedo, 1); DECLARE_TEXTURE(gNormal, 2); DECLARE_TEXTURE(gMetallicRoughness, 3); +DECLARE_TEXTURE(shadowMap, 4); // TODO: one map per directional light BEGIN_CONSTANTS @@ -21,6 +22,8 @@ BEGIN_CONSTANTS MATRIX_CONSTANTS + float4x4 LightSpaceMatrix _ps(c137) _cb(c137); + END_CONSTANTS struct PixelInput @@ -71,6 +74,24 @@ float GeometrySmith(float3 N, float3 V, float3 L, float roughness) return ggx1 * ggx2; } +float ComputeShadow(float4 positionLightSpace) +{ + float bias = 0.01; + + // maps to [-1, 1] + float3 projectionCoords = positionLightSpace.xyz / positionLightSpace.w; + + // maps to [0, 1] + projectionCoords = (projectionCoords * 0.5) + 0.5; + + float closestDepth = SAMPLE_TEXTURE(shadowMap, projectionCoords.xy).r; + float currentDepth = projectionCoords.z; + + float shadow = currentDepth - bias > closestDepth ? 1.0 : 0.0; + + return shadow; +} + float3 ComputeLight( float3 lightDir, float3 radiance, @@ -79,7 +100,8 @@ float3 ComputeLight( float3 N, float3 albedo, float metallic, - float roughness + float roughness, + float shadow ) { float3 L = normalize(lightDir); float3 H = normalize(V + L); @@ -98,7 +120,7 @@ float3 ComputeLight( kD *= 1.0 - metallic; float NdotL = max(dot(N, L), 0.0); - return (kD * albedo / PI + specular) * radiance * NdotL; + return (kD * albedo / PI + specular) * radiance * NdotL * shadow; } float4 ComputeColor( @@ -108,6 +130,9 @@ float4 ComputeColor( float metallic, float roughness ) { + float4 positionLightSpace = mul(float4(worldPosition, 1.0), LightSpaceMatrix); + float shadow = ComputeShadow(positionLightSpace); + float3 V = normalize(EyePosition - worldPosition); float3 N = normalize(worldNormal); @@ -124,7 +149,7 @@ float4 ComputeColor( float attenuation = 1.0 / (distance * distance); float3 radiance = PointLightColors[i] * attenuation; - Lo += ComputeLight(lightDir, radiance, F0, V, N, albedo, metallic, roughness); + Lo += ComputeLight(lightDir, radiance, F0, V, N, albedo, metallic, roughness, 1.0); } // directional light @@ -133,7 +158,7 @@ float4 ComputeColor( float3 lightDir = DirectionalLightDirections[i]; float3 radiance = DirectionalLightColors[i]; - Lo += ComputeLight(lightDir, radiance, F0, V, N, albedo, metallic, roughness); + Lo += ComputeLight(lightDir, radiance, F0, V, N, albedo, metallic, roughness, (1.0 - shadow)); } float3 ambient = float3(0.03, 0.03, 0.03) * albedo; // * AO; @@ -148,13 +173,13 @@ float4 ComputeColor( float4 main_ps(PixelInput input) : SV_TARGET0 { - float3 fragPosition = SAMPLE_TEXTURE(gPosition, input.TexCoord).rgb; + 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( - fragPosition, + worldPosition, normal, albedo, metallicRoughness.r, diff --git a/Effects/HLSL/SimpleDepthEffect.fx b/Effects/HLSL/SimpleDepthEffect.fx index 8b19a4e..787ea2a 100644 --- a/Effects/HLSL/SimpleDepthEffect.fx +++ b/Effects/HLSL/SimpleDepthEffect.fx @@ -3,6 +3,8 @@ BEGIN_CONSTANTS float4x4 ModelViewProjection _vs(c0) _cb(c0); + float near _vs(c4) _cb(c4); + float far _vs(c5) _cb(c5); MATRIX_CONSTANTS @@ -16,21 +18,31 @@ struct VertexShaderInput struct VertexShaderOutput { float4 Position : SV_Position; + float Depth : TEXCOORD0; }; VertexShaderOutput main_vs(VertexShaderInput input) { VertexShaderOutput output; - output.Position = mul(float4(input.Position.xyz, 1.0), ModelViewProjection); + output.Position = mul(input.Position, ModelViewProjection); + + output.Depth = output.Position.z / output.Position.w; + output.Depth = (output.Depth * 0.5) + 0.5; return output; } +float4 main_ps(VertexShaderOutput input) : SV_TARGET0 +{ + return float4(input.Depth, 0.0, 0.0, 0.0); +} + Technique SimpleDepth { Pass { VertexShader = compile vs_3_0 main_vs(); + PixelShader = compile ps_3_0 main_ps(); } } diff --git a/Effects/SimpleDepthEffect.cs b/Effects/SimpleDepthEffect.cs index f68f513..c821a6a 100644 --- a/Effects/SimpleDepthEffect.cs +++ b/Effects/SimpleDepthEffect.cs @@ -6,6 +6,8 @@ namespace Kav public class SimpleDepthEffect : Effect { EffectParameter modelViewProjectionParam; + EffectParameter nearParam; + EffectParameter farParam; Matrix model; Matrix view; @@ -42,6 +44,10 @@ namespace Kav dirtyFlags |= EffectDirtyFlags.WorldViewProj; } } + + public float Near { get; set; } + public float Far { get; set; } + public SimpleDepthEffect(GraphicsDevice graphicsDevice) : base(graphicsDevice, Resources.SimpleDepthEffect) { CacheEffectParameters(); @@ -58,11 +64,16 @@ namespace Kav dirtyFlags &= ~EffectDirtyFlags.WorldViewProj; } + + nearParam.SetValue(Near); + farParam.SetValue(Far); } private void CacheEffectParameters() { modelViewProjectionParam = Parameters["ModelViewProjection"]; + nearParam = Parameters["near"]; + farParam = Parameters["far"]; } } } diff --git a/Lights/DirectionalLight.cs b/Lights/DirectionalLight.cs index 31ca4fd..a22ab33 100644 --- a/Lights/DirectionalLight.cs +++ b/Lights/DirectionalLight.cs @@ -12,7 +12,7 @@ namespace Kav { get { - return Matrix.CreateLookAt(-Direction * 100f, Vector3.Zero, Vector3.Up); + return Matrix.CreateLookAt(Direction * 100f, Vector3.Zero, Vector3.Up); } } diff --git a/Renderer.cs b/Renderer.cs index c53f855..35f4b7d 100644 --- a/Renderer.cs +++ b/Renderer.cs @@ -36,7 +36,7 @@ namespace Kav renderDimensionsX, renderDimensionsY, false, - SurfaceFormat.HalfSingle, // unused + SurfaceFormat.Single, DepthFormat.Depth24 ); @@ -105,6 +105,13 @@ namespace Kav IEnumerable pointLights, IEnumerable directionalLights ) { + foreach (var directionalLight in directionalLights) + { + DepthRender(modelTransforms, directionalLight); + DeferredPBREffect.LightSpaceMatrix = directionalLight.View * directionalLight.Projection; + break; // FIXME: this is a kludge + } + GraphicsDevice.SetRenderTargets(GBuffer); GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.Black, 1f, 0); GraphicsDevice.DepthStencilState = DepthStencilState.Default; @@ -150,6 +157,7 @@ namespace Kav DeferredPBREffect.GAlbedo = gAlbedo; DeferredPBREffect.GNormal = gNormal; DeferredPBREffect.GMetallicRoughness = gMetallicRoughness; + DeferredPBREffect.ShadowMap = DepthRenderTarget; DeferredPBREffect.EyePosition = Matrix.Invert(camera.View).Translation; int i = 0; @@ -173,23 +181,18 @@ namespace Kav SpriteBatch.End(); } - public void Render( - Camera camera, - IEnumerable<(Model, Matrix)> modelTransforms, - IEnumerable pointLights, - IEnumerable directionalLights - ) { - Render(camera.View, camera.Projection, modelTransforms, pointLights, directionalLights); - } - // for shadow mapping public void DepthRender(IEnumerable<(Model, Matrix)> modelTransforms, DirectionalLight directionalLight) { GraphicsDevice.SetRenderTarget(DepthRenderTarget); - GraphicsDevice.Clear(ClearOptions.DepthBuffer, Color.Black, 1, 0); - + GraphicsDevice.Clear(Color.White); + GraphicsDevice.DepthStencilState = DepthStencilState.Default; + GraphicsDevice.BlendState = BlendState.Opaque; + SimpleDepthEffect.View = directionalLight.View; SimpleDepthEffect.Projection = directionalLight.Projection; + SimpleDepthEffect.Near = 0.1f; // FIXME: this is a kludge + SimpleDepthEffect.Far = 200f; foreach (var (model, transform) in modelTransforms) { @@ -220,6 +223,15 @@ namespace Kav } } + public void Render( + Camera camera, + IEnumerable<(Model, Matrix)> modelTransforms, + IEnumerable pointLights, + IEnumerable directionalLights + ) { + Render(camera.View, camera.Projection, modelTransforms, pointLights, directionalLights); + } + private void Render( Matrix view, Matrix projection,