diff --git a/EffectInterfaces/DirectionalLightEffect.cs b/EffectInterfaces/DirectionalLightEffect.cs deleted file mode 100644 index 53ba894..0000000 --- a/EffectInterfaces/DirectionalLightEffect.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Kav -{ - public interface DirectionalLightEffect - { - int MaxDirectionalLights { get; } - DirectionalLightCollection DirectionalLights { get; } - } -} diff --git a/Effects/DeferredPBREffect.cs b/Effects/DeferredPBREffect.cs index 8b76aca..390f5f3 100644 --- a/Effects/DeferredPBREffect.cs +++ b/Effects/DeferredPBREffect.cs @@ -11,11 +11,13 @@ namespace Kav EffectParameter gMetallicRoughnessParam; EffectParameter shadowMapParam; + EffectParameter directionalLightColorParam; + EffectParameter directionalLightDirectionParam; + EffectParameter eyePositionParam; EffectParameter lightSpaceMatrixParam; PointLightCollection pointLightCollection; - DirectionalLightCollection directionalLightCollection; public Texture2D GPosition { get; set; } public Texture2D GAlbedo { get; set; } @@ -23,9 +25,12 @@ namespace Kav public Texture2D GMetallicRoughness { get; set; } public Texture2D ShadowMap { get; set; } - public Vector3 EyePosition { get; set; } + public Vector3 DirectionalLightColor { get; set; } + public Vector3 DirectionalLightDirection { get; set; } public Matrix LightSpaceMatrix { get; set; } + public Vector3 EyePosition { get; set; } + public int MaxPointLights { get; } = 64; public PointLightCollection PointLights @@ -34,14 +39,6 @@ namespace Kav private set { pointLightCollection = value; } } - public int MaxDirectionalLights { get; } = 4; - - public DirectionalLightCollection DirectionalLights - { - get { return directionalLightCollection; } - private set { directionalLightCollection = value; } - } - public DeferredPBREffect(GraphicsDevice graphicsDevice) : base(graphicsDevice, Resources.DeferredPBREffect) { CacheEffectParameters(); @@ -51,11 +48,6 @@ namespace Kav Parameters["PointLightColors"], MaxPointLights ); - - DirectionalLights = new DirectionalLightCollection( - Parameters["DirectionalLightDirections"], - Parameters["DirectionalLightColors"] - ); } protected DeferredPBREffect(DeferredPBREffect cloneSource) : base(cloneSource) @@ -77,16 +69,6 @@ namespace Kav { PointLights[i] = cloneSource.PointLights[i]; } - - DirectionalLights = new DirectionalLightCollection( - Parameters["DirectionalLightDirections"], - Parameters["DirectionalLightColors"] - ); - - for (int i = 0; i < MaxDirectionalLights; i++) - { - DirectionalLights[i] = cloneSource.DirectionalLights[i]; - } } public override Effect Clone() @@ -102,6 +84,9 @@ namespace Kav gMetallicRoughnessParam.SetValue(GMetallicRoughness); shadowMapParam.SetValue(ShadowMap); + directionalLightColorParam.SetValue(DirectionalLightColor); + directionalLightDirectionParam.SetValue(DirectionalLightDirection); + eyePositionParam.SetValue(EyePosition); lightSpaceMatrixParam.SetValue(LightSpaceMatrix); } @@ -114,9 +99,11 @@ namespace Kav gMetallicRoughnessParam = Parameters["gMetallicRoughness"]; shadowMapParam = Parameters["shadowMap"]; - eyePositionParam = Parameters["EyePosition"]; - + directionalLightDirectionParam = Parameters["DirectionalLightDirection"]; + directionalLightColorParam = Parameters["DirectionalLightColor"]; lightSpaceMatrixParam = Parameters["LightSpaceMatrix"]; + + eyePositionParam = Parameters["EyePosition"]; } } } diff --git a/Effects/DirectionalLightCollection.cs b/Effects/DirectionalLightCollection.cs deleted file mode 100644 index 10bcbda..0000000 --- a/Effects/DirectionalLightCollection.cs +++ /dev/null @@ -1,47 +0,0 @@ -using Microsoft.Xna.Framework; -using Microsoft.Xna.Framework.Graphics; - -namespace Kav -{ - public class DirectionalLightCollection - { - private readonly Vector3[] directions = new Vector3[4]; - private readonly Vector3[] colors = new Vector3[4]; - private readonly float[] intensities = new float[4]; - - readonly EffectParameter lightDirectionsParam; - readonly EffectParameter lightColorsParam; - - public DirectionalLightCollection(EffectParameter lightDirectionsParam, EffectParameter lightColorsParam) - { - this.lightDirectionsParam = lightDirectionsParam; - this.lightColorsParam = lightColorsParam; - } - - public DirectionalLight this[int i] - { - get - { - var color = colors[i] / intensities[i]; - return new DirectionalLight( - directions[i], - new Color( - color.X, - color.Y, - color.Z, - 1f - ), - intensities[i] - ); - } - set - { - directions[i] = value.Direction; - colors[i] = value.Color.ToVector3() * value.Intensity; - intensities[i] = value.Intensity; - lightDirectionsParam.SetValue(directions); - lightColorsParam.SetValue(colors); - } - } - } -} diff --git a/Effects/FXB/DeferredPBREffect.fxb b/Effects/FXB/DeferredPBREffect.fxb index 7bb8729..17baa97 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 ab998b2..64ee5cd 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 05a3df7..d6e2d9c 100644 --- a/Effects/HLSL/DeferredPBREffect.fx +++ b/Effects/HLSL/DeferredPBREffect.fx @@ -2,13 +2,12 @@ static const float PI = 3.141592653589793; static const int MAX_POINT_LIGHTS = 64; -static const int MAX_DIRECTIONAL_LIGHTS = 4; 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_TEXTURE(shadowMap, 4); BEGIN_CONSTANTS @@ -17,12 +16,12 @@ BEGIN_CONSTANTS float3 PointLightPositions[MAX_POINT_LIGHTS] _ps(c1) _cb(c1); float3 PointLightColors[MAX_POINT_LIGHTS] _ps(c65) _cb(c65); - float3 DirectionalLightDirections[MAX_DIRECTIONAL_LIGHTS] _ps(c129) _cb(c129); - float3 DirectionalLightColors[MAX_DIRECTIONAL_LIGHTS] _ps(c133) _cb(c133); + float3 DirectionalLightDirection _ps(c129) _cb(c129); + float3 DirectionalLightColor _ps(c130) _cb(c130); MATRIX_CONSTANTS - float4x4 LightSpaceMatrix _ps(c137) _cb(c137); + float4x4 LightSpaceMatrix _ps(c131) _cb(c131); END_CONSTANTS @@ -83,6 +82,7 @@ float ComputeShadow(float4 positionLightSpace) // maps to [0, 1] projectionCoords = (projectionCoords * 0.5) + 0.5; + projectionCoords.y *= -1; float closestDepth = SAMPLE_TEXTURE(shadowMap, projectionCoords.xy).r; float currentDepth = projectionCoords.z; @@ -153,13 +153,10 @@ float4 ComputeColor( } // directional light - for (int i = 0; i < MAX_DIRECTIONAL_LIGHTS; i++) - { - float3 lightDir = DirectionalLightDirections[i]; - float3 radiance = DirectionalLightColors[i]; + float3 lightDir = DirectionalLightDirection; + float3 radiance = DirectionalLightColor; - Lo += ComputeLight(lightDir, radiance, F0, V, N, albedo, metallic, roughness, (1.0 - shadow)); - } + Lo += ComputeLight(lightDir, radiance, F0, V, N, albedo, metallic, roughness, (1.0 - shadow)); float3 ambient = float3(0.03, 0.03, 0.03) * albedo; // * AO; float3 color = ambient + Lo; diff --git a/Effects/HLSL/SimpleDepthEffect.fx b/Effects/HLSL/SimpleDepthEffect.fx index 787ea2a..f813bd7 100644 --- a/Effects/HLSL/SimpleDepthEffect.fx +++ b/Effects/HLSL/SimpleDepthEffect.fx @@ -3,8 +3,6 @@ BEGIN_CONSTANTS float4x4 ModelViewProjection _vs(c0) _cb(c0); - float near _vs(c4) _cb(c4); - float far _vs(c5) _cb(c5); MATRIX_CONSTANTS @@ -26,9 +24,7 @@ VertexShaderOutput main_vs(VertexShaderInput input) VertexShaderOutput output; output.Position = mul(input.Position, ModelViewProjection); - output.Depth = output.Position.z / output.Position.w; - output.Depth = (output.Depth * 0.5) + 0.5; return output; } diff --git a/Effects/PBREffect.cs b/Effects/PBREffect.cs index db04a25..2df74cd 100644 --- a/Effects/PBREffect.cs +++ b/Effects/PBREffect.cs @@ -3,7 +3,7 @@ using Microsoft.Xna.Framework.Graphics; namespace Kav { - public class PBREffect : Effect, TransformEffect, PointLightEffect, DirectionalLightEffect + public class PBREffect : Effect, TransformEffect, PointLightEffect { EffectParameter worldParam; EffectParameter worldViewProjectionParam; @@ -31,7 +31,6 @@ namespace Kav Matrix view = Matrix.Identity; Matrix projection = Matrix.Identity; PointLightCollection pointLightCollection; - DirectionalLightCollection directionalLightCollection; Vector3 albedo; float metallic; @@ -84,14 +83,6 @@ namespace Kav private set { pointLightCollection = value; } } - public int MaxDirectionalLights { get; } = 4; - - public DirectionalLightCollection DirectionalLights - { - get { return directionalLightCollection; } - private set { directionalLightCollection = value; } - } - public Vector3 Albedo { get { return albedo; } @@ -204,11 +195,6 @@ namespace Kav Parameters["PositionLightColors"], MaxPointLights ); - - directionalLightCollection = new DirectionalLightCollection( - Parameters["LightDirections"], - Parameters["DirectionLightColors"] - ); } protected PBREffect(PBREffect cloneSource) : base(cloneSource) @@ -230,16 +216,6 @@ namespace Kav PointLights[i] = cloneSource.PointLights[i]; } - DirectionalLights = new DirectionalLightCollection( - Parameters["LightDirections"], - Parameters["DirectionLightColors"] - ); - - for (int i = 0; i < MaxDirectionalLights; i++) - { - DirectionalLights[i] = cloneSource.DirectionalLights[i]; - } - AlbedoTexture = cloneSource.AlbedoTexture; NormalTexture = cloneSource.NormalTexture; EmissionTexture = cloneSource.EmissionTexture; diff --git a/Effects/SimpleDepthEffect.cs b/Effects/SimpleDepthEffect.cs index c821a6a..9443540 100644 --- a/Effects/SimpleDepthEffect.cs +++ b/Effects/SimpleDepthEffect.cs @@ -6,8 +6,6 @@ namespace Kav public class SimpleDepthEffect : Effect { EffectParameter modelViewProjectionParam; - EffectParameter nearParam; - EffectParameter farParam; Matrix model; Matrix view; @@ -45,9 +43,6 @@ namespace Kav } } - public float Near { get; set; } - public float Far { get; set; } - public SimpleDepthEffect(GraphicsDevice graphicsDevice) : base(graphicsDevice, Resources.SimpleDepthEffect) { CacheEffectParameters(); @@ -64,16 +59,11 @@ 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/Renderer.cs b/Renderer.cs index 35f4b7d..99c26d3 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 RenderTarget2D ShadowRenderTarget { get; } private SimpleDepthEffect SimpleDepthEffect { get; } private RenderTarget2D gPosition { get; } @@ -31,10 +31,10 @@ namespace Kav RenderDimensionsX = renderDimensionsX; RenderDimensionsY = renderDimensionsY; - DepthRenderTarget = new RenderTarget2D( + ShadowRenderTarget = new RenderTarget2D( GraphicsDevice, - renderDimensionsX, - renderDimensionsY, + 1024, + 1024, false, SurfaceFormat.Single, DepthFormat.Depth24 @@ -103,14 +103,9 @@ namespace Kav Camera camera, IEnumerable<(Model, Matrix)> modelTransforms, IEnumerable pointLights, - IEnumerable directionalLights + DirectionalLight directionalLight ) { - foreach (var directionalLight in directionalLights) - { - DepthRender(modelTransforms, directionalLight); - DeferredPBREffect.LightSpaceMatrix = directionalLight.View * directionalLight.Projection; - break; // FIXME: this is a kludge - } + ShadowMapRender(camera, modelTransforms, directionalLight); GraphicsDevice.SetRenderTargets(GBuffer); GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.Black, 1f, 0); @@ -157,7 +152,7 @@ namespace Kav DeferredPBREffect.GAlbedo = gAlbedo; DeferredPBREffect.GNormal = gNormal; DeferredPBREffect.GMetallicRoughness = gMetallicRoughness; - DeferredPBREffect.ShadowMap = DepthRenderTarget; + DeferredPBREffect.ShadowMap = ShadowRenderTarget; DeferredPBREffect.EyePosition = Matrix.Invert(camera.View).Translation; int i = 0; @@ -168,13 +163,8 @@ namespace Kav i++; } - i = 0; - foreach (var directionalLight in directionalLights) - { - if (i > DeferredPBREffect.MaxDirectionalLights) { break; } - DeferredPBREffect.DirectionalLights[i] = directionalLight; - i++; - } + DeferredPBREffect.DirectionalLightColor = directionalLight.Color.ToVector3() * directionalLight.Intensity; + DeferredPBREffect.DirectionalLightDirection = directionalLight.Direction; SpriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, null, null, null, DeferredPBREffect); SpriteBatch.Draw(deferredRenderTarget, Vector2.Zero, Color.White); @@ -182,17 +172,40 @@ namespace Kav } // for shadow mapping - public void DepthRender(IEnumerable<(Model, Matrix)> modelTransforms, DirectionalLight directionalLight) + public void ShadowMapRender(Camera camera, IEnumerable<(Model, Matrix)> modelTransforms, DirectionalLight directionalLight) { - GraphicsDevice.SetRenderTarget(DepthRenderTarget); + GraphicsDevice.SetRenderTarget(ShadowRenderTarget); GraphicsDevice.Clear(Color.White); GraphicsDevice.DepthStencilState = DepthStencilState.Default; GraphicsDevice.BlendState = BlendState.Opaque; + var right = Vector3.Cross(Vector3.Up, directionalLight.Direction); + var up = Vector3.Cross(directionalLight.Direction, right); + + var lightRotation = Matrix.CreateLookAt(Vector3.Zero, -directionalLight.Direction, up); + + var cameraBoundingFrustum = new BoundingFrustum(camera.View * camera.Projection); + + Vector3[] frustumCorners = cameraBoundingFrustum.GetCorners(); + for (var i = 0; i < frustumCorners.Length; i++) + { + frustumCorners[i] = Vector3.Transform(frustumCorners[i], lightRotation); + } + + BoundingBox lightBox = BoundingBox.CreateFromPoints(frustumCorners); + Vector3 boxSize = lightBox.Max - lightBox.Min; + Vector3 halfBoxSize = boxSize * 0.5f; + + Vector3 lightPosition = lightBox.Min + halfBoxSize; + lightPosition.Z = lightBox.Min.Z; + lightPosition = Vector3.Transform(lightPosition, Matrix.Invert(lightRotation)); + + //SimpleDepthEffect.View = Matrix.CreateLookAt(lightPosition, lightPosition - directionalLight.Direction, up); + //SimpleDepthEffect.Projection = Matrix.CreateOrthographic(boxSize.X, boxSize.Y, -boxSize.Z, boxSize.Z); + SimpleDepthEffect.View = directionalLight.View; SimpleDepthEffect.Projection = directionalLight.Projection; - SimpleDepthEffect.Near = 0.1f; // FIXME: this is a kludge - SimpleDepthEffect.Far = 200f; + DeferredPBREffect.LightSpaceMatrix = SimpleDepthEffect.View * SimpleDepthEffect.Projection; foreach (var (model, transform) in modelTransforms) { @@ -266,17 +279,6 @@ namespace Kav } } - if (meshPart.Effect is DirectionalLightEffect directionalLightEffect) - { - int i = 0; - foreach (var directionalLight in directionalLights) - { - if (i > directionalLightEffect.MaxDirectionalLights) { break; } - directionalLightEffect.DirectionalLights[i] = directionalLight; - i++; - } - } - foreach (var pass in meshPart.Effect.CurrentTechnique.Passes) { pass.Apply();