diff --git a/Effects/DeferredPBREffect.cs b/Effects/DeferredPBREffect.cs index 8b76aca..9569420 100644 --- a/Effects/DeferredPBREffect.cs +++ b/Effects/DeferredPBREffect.cs @@ -12,7 +12,6 @@ namespace Kav EffectParameter shadowMapParam; EffectParameter eyePositionParam; - EffectParameter lightSpaceMatrixParam; PointLightCollection pointLightCollection; DirectionalLightCollection directionalLightCollection; @@ -21,10 +20,9 @@ namespace Kav public Texture2D GAlbedo { get; set; } public Texture2D GNormal { get; set; } public Texture2D GMetallicRoughness { get; set; } - public Texture2D ShadowMap { get; set; } + public TextureCube DirectionalShadowMap { get; set; } public Vector3 EyePosition { get; set; } - public Matrix LightSpaceMatrix { get; set; } public int MaxPointLights { get; } = 64; @@ -54,7 +52,8 @@ namespace Kav DirectionalLights = new DirectionalLightCollection( Parameters["DirectionalLightDirections"], - Parameters["DirectionalLightColors"] + Parameters["DirectionalLightColors"], + Parameters["DirectionalLightMatrices"] ); } @@ -80,7 +79,8 @@ namespace Kav DirectionalLights = new DirectionalLightCollection( Parameters["DirectionalLightDirections"], - Parameters["DirectionalLightColors"] + Parameters["DirectionalLightColors"], + Parameters["DirectionalLightMatrices"] ); for (int i = 0; i < MaxDirectionalLights; i++) @@ -100,10 +100,9 @@ namespace Kav gAlbedoParam.SetValue(GAlbedo); gNormalParam.SetValue(GNormal); gMetallicRoughnessParam.SetValue(GMetallicRoughness); - shadowMapParam.SetValue(ShadowMap); + shadowMapParam.SetValue(DirectionalShadowMap); eyePositionParam.SetValue(EyePosition); - lightSpaceMatrixParam.SetValue(LightSpaceMatrix); } void CacheEffectParameters() @@ -115,8 +114,6 @@ namespace Kav shadowMapParam = Parameters["shadowMap"]; eyePositionParam = Parameters["EyePosition"]; - - lightSpaceMatrixParam = Parameters["LightSpaceMatrix"]; } } } diff --git a/Effects/DirectionalLightCollection.cs b/Effects/DirectionalLightCollection.cs index 10bcbda..93ab4a4 100644 --- a/Effects/DirectionalLightCollection.cs +++ b/Effects/DirectionalLightCollection.cs @@ -8,14 +8,20 @@ namespace Kav private readonly Vector3[] directions = new Vector3[4]; private readonly Vector3[] colors = new Vector3[4]; private readonly float[] intensities = new float[4]; + private readonly Matrix[] lightSpaceMatrices = new Matrix[4]; readonly EffectParameter lightDirectionsParam; readonly EffectParameter lightColorsParam; + readonly EffectParameter lightSpaceMatricesParam; - public DirectionalLightCollection(EffectParameter lightDirectionsParam, EffectParameter lightColorsParam) - { + public DirectionalLightCollection( + EffectParameter lightDirectionsParam, + EffectParameter lightColorsParam, + EffectParameter lightSpaceMatricesParam + ) { this.lightDirectionsParam = lightDirectionsParam; this.lightColorsParam = lightColorsParam; + this.lightSpaceMatricesParam = lightSpaceMatricesParam; } public DirectionalLight this[int i] @@ -39,8 +45,10 @@ namespace Kav directions[i] = value.Direction; colors[i] = value.Color.ToVector3() * value.Intensity; intensities[i] = value.Intensity; + lightSpaceMatrices[i] = value.View * value.Projection; lightDirectionsParam.SetValue(directions); lightColorsParam.SetValue(colors); + lightSpaceMatricesParam.SetValue(lightSpaceMatrices); } } } diff --git a/Effects/FXB/DeferredPBREffect.fxb b/Effects/FXB/DeferredPBREffect.fxb index 7bb8729..b3e2383 100644 Binary files a/Effects/FXB/DeferredPBREffect.fxb and b/Effects/FXB/DeferredPBREffect.fxb differ diff --git a/Effects/HLSL/DeferredPBREffect.fx b/Effects/HLSL/DeferredPBREffect.fx index 05a3df7..5795238 100644 --- a/Effects/HLSL/DeferredPBREffect.fx +++ b/Effects/HLSL/DeferredPBREffect.fx @@ -8,7 +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 +DECLARE_CUBEMAP(shadowMap, 4); BEGIN_CONSTANTS @@ -22,7 +22,7 @@ BEGIN_CONSTANTS MATRIX_CONSTANTS - float4x4 LightSpaceMatrix _ps(c137) _cb(c137); + float4x4 DirectionalLightMatrices[MAX_DIRECTIONAL_LIGHTS] _ps(c137) _cb(c137); END_CONSTANTS @@ -74,17 +74,56 @@ float GeometrySmith(float3 N, float3 V, float3 L, float roughness) return ggx1 * ggx2; } -float ComputeShadow(float4 positionLightSpace) +float3 ConvertCubeUVToXYZ(int index, float u, float v) { - float bias = 0.01; + float uc = 2.0 * u - 1.0; + float vc = 2.0 * v - 1.0; + + if (index == 0) { return float3(1.0, vc, -uc); } + if (index == 1) { return float3(-1.0, vc, uc); } + if (index == 2) { return float3(uc, 1.0, -vc); } + if (index == 3) { return float3(uc, -1.0, vc); } + if (index == 4) { return float3(uc, vc, -1.0); } + if (index == 5) { return float3(-uc, vc, 1.0); } + + return float3(1.0, 0.0, 0.5); +} + +float ComputeShadow(float4 positionLightSpace, int directionalLightIndex) +{ + float bias = 0.001; // maps to [-1, 1] float3 projectionCoords = positionLightSpace.xyz / positionLightSpace.w; - // maps to [0, 1] - projectionCoords = (projectionCoords * 0.5) + 0.5; + float3 cubeMapSampleVector; - float closestDepth = SAMPLE_TEXTURE(shadowMap, projectionCoords.xy).r; + if (directionalLightIndex == 0) + { + cubeMapSampleVector = float3(1.0f, projectionCoords.y, -projectionCoords.x); + } + else if (directionalLightIndex == 1) + { + cubeMapSampleVector = float3(-1.0f, projectionCoords.y, projectionCoords.x); + } + else if (directionalLightIndex == 2) + { + cubeMapSampleVector = float3(projectionCoords.x, 1.0f, projectionCoords.y); + } + else if (directionalLightIndex == 3) + { + cubeMapSampleVector = float3(projectionCoords.x, -1.0f, -projectionCoords.y); + } + else if (directionalLightIndex == 4) + { + cubeMapSampleVector = float3(projectionCoords.x, projectionCoords.y, 1.0); + } + else + { + cubeMapSampleVector = float3(-projectionCoords.x, projectionCoords.y, -1.0); + } + + float closestDepth = SAMPLE_CUBEMAP(shadowMap, cubeMapSampleVector).r; float currentDepth = projectionCoords.z; float shadow = currentDepth - bias > closestDepth ? 1.0 : 0.0; @@ -130,9 +169,6 @@ 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); @@ -153,8 +189,11 @@ float4 ComputeColor( } // directional light - for (int i = 0; i < MAX_DIRECTIONAL_LIGHTS; i++) + for (int i = 0; i < 1; i++) { + float4 positionLightSpace = mul(float4(worldPosition, 1.0), DirectionalLightMatrices[i]); + float shadow = ComputeShadow(positionLightSpace, i); + float3 lightDir = DirectionalLightDirections[i]; float3 radiance = DirectionalLightColors[i]; diff --git a/Effects/PBREffect.cs b/Effects/PBREffect.cs index db04a25..5405d7e 100644 --- a/Effects/PBREffect.cs +++ b/Effects/PBREffect.cs @@ -207,7 +207,8 @@ namespace Kav directionalLightCollection = new DirectionalLightCollection( Parameters["LightDirections"], - Parameters["DirectionLightColors"] + Parameters["DirectionLightColors"], + Parameters["DirectionalLightMatrices"] ); } @@ -232,7 +233,8 @@ namespace Kav DirectionalLights = new DirectionalLightCollection( Parameters["LightDirections"], - Parameters["DirectionLightColors"] + Parameters["DirectionLightColors"], + Parameters["DirectionalLightMatrices"] ); for (int i = 0; i < MaxDirectionalLights; i++) diff --git a/Lights/DirectionalLight.cs b/Lights/DirectionalLight.cs index a22ab33..9780535 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 * 4.5f, Vector3.Zero, Vector3.Up); } } @@ -20,7 +20,7 @@ namespace Kav { get { - return Matrix.CreateOrthographic(20f, 20f, 1f, 101f); + return Matrix.CreateOrthographic(20f, 20f, 1f, 7.5f); } } diff --git a/Renderer.cs b/Renderer.cs index 35f4b7d..9b52411 100644 --- a/Renderer.cs +++ b/Renderer.cs @@ -10,7 +10,7 @@ namespace Kav private int RenderDimensionsX { get; } private int RenderDimensionsY { get; } - private RenderTarget2D DepthRenderTarget { get; } + private RenderTargetCube DirectionalLightDepthTarget { get; } private SimpleDepthEffect SimpleDepthEffect { get; } private RenderTarget2D gPosition { get; } @@ -31,10 +31,9 @@ namespace Kav RenderDimensionsX = renderDimensionsX; RenderDimensionsY = renderDimensionsY; - DepthRenderTarget = new RenderTarget2D( + DirectionalLightDepthTarget = new RenderTargetCube( GraphicsDevice, - renderDimensionsX, - renderDimensionsY, + 1024, false, SurfaceFormat.Single, DepthFormat.Depth24 @@ -96,6 +95,13 @@ namespace Kav GraphicsDevice.SetRenderTarget(deferredRenderTarget); graphicsDevice.Clear(Color.White); + + for (int i = 0; i < 6; i++) + { + GraphicsDevice.SetRenderTarget(DirectionalLightDepthTarget, (CubeMapFace) i); + GraphicsDevice.Clear(Color.White); + } + GraphicsDevice.SetRenderTarget(null); } @@ -105,11 +111,13 @@ namespace Kav IEnumerable pointLights, IEnumerable directionalLights ) { + var directionalLightIndex = 0; + foreach (var directionalLight in directionalLights) { - DepthRender(modelTransforms, directionalLight); - DeferredPBREffect.LightSpaceMatrix = directionalLight.View * directionalLight.Projection; - break; // FIXME: this is a kludge + if (directionalLightIndex > 5) { break; } + ShadowMapRender(modelTransforms, directionalLight, (CubeMapFace) directionalLightIndex); + directionalLightIndex += 1; } GraphicsDevice.SetRenderTargets(GBuffer); @@ -157,7 +165,7 @@ namespace Kav DeferredPBREffect.GAlbedo = gAlbedo; DeferredPBREffect.GNormal = gNormal; DeferredPBREffect.GMetallicRoughness = gMetallicRoughness; - DeferredPBREffect.ShadowMap = DepthRenderTarget; + DeferredPBREffect.DirectionalShadowMap = DirectionalLightDepthTarget; DeferredPBREffect.EyePosition = Matrix.Invert(camera.View).Translation; int i = 0; @@ -182,9 +190,9 @@ namespace Kav } // for shadow mapping - public void DepthRender(IEnumerable<(Model, Matrix)> modelTransforms, DirectionalLight directionalLight) + public void ShadowMapRender(IEnumerable<(Model, Matrix)> modelTransforms, DirectionalLight directionalLight, CubeMapFace face) { - GraphicsDevice.SetRenderTarget(DepthRenderTarget); + GraphicsDevice.SetRenderTarget(DirectionalLightDepthTarget, face); GraphicsDevice.Clear(Color.White); GraphicsDevice.DepthStencilState = DepthStencilState.Default; GraphicsDevice.BlendState = BlendState.Opaque;