From ee8b0c5ee840bf180f1498a0cd9e81b94e4598cd Mon Sep 17 00:00:00 2001 From: cosmonaut Date: Mon, 7 Dec 2020 01:30:09 -0800 Subject: [PATCH 01/12] started adding support for instanced draws + started decoupling API --- Effects/DeferredPBR_GBufferEffect.cs | 39 +++- Effects/DiffuseLitSpriteEffect.cs | 4 +- Effects/EffectHelpers.cs | 3 +- Effects/FXB/DeferredPBR_GBufferEffect.fxb | 4 +- Effects/HLSL/DeferredPBR_GBufferEffect.fx | 38 +++- Effects/PBREffect.cs | 10 +- Geometry/Interfaces/IGBufferDrawable.cs | 16 ++ Geometry/Interfaces/IIndexDrawable.cs | 10 + Geometry/MeshPart.cs | 20 +- Geometry/MeshSprite.cs | 2 +- Renderer.cs | 244 ++++++++++++++++------ VertexDeclarations.cs | 23 ++ Vertices/GBufferInstanceVertex.cs | 32 +++ 13 files changed, 353 insertions(+), 92 deletions(-) create mode 100644 Geometry/Interfaces/IGBufferDrawable.cs create mode 100644 Geometry/Interfaces/IIndexDrawable.cs create mode 100644 VertexDeclarations.cs create mode 100644 Vertices/GBufferInstanceVertex.cs diff --git a/Effects/DeferredPBR_GBufferEffect.cs b/Effects/DeferredPBR_GBufferEffect.cs index 26a9c8f..b7eeb65 100644 --- a/Effects/DeferredPBR_GBufferEffect.cs +++ b/Effects/DeferredPBR_GBufferEffect.cs @@ -17,6 +17,7 @@ namespace Kav EffectParameter metallicParam; EffectParameter roughnessParam; + EffectParameter vertexShaderIndexParam; EffectParameter shaderIndexParam; Matrix world = Matrix.Identity; @@ -30,6 +31,7 @@ namespace Kav bool albedoTextureEnabled = false; bool metallicRoughnessMapEnabled = false; bool normalMapEnabled = false; + bool hardwareInstancingEnabled = false; EffectDirtyFlags dirtyFlags = EffectDirtyFlags.All; @@ -100,7 +102,7 @@ namespace Kav { albedoTextureParam.SetValue(value); albedoTextureEnabled = value != null; - dirtyFlags |= EffectDirtyFlags.ShaderIndex; + dirtyFlags |= EffectDirtyFlags.PixelShaderIndex; } } @@ -111,7 +113,7 @@ namespace Kav { normalTextureParam.SetValue(value); normalMapEnabled = value != null; - dirtyFlags |= EffectDirtyFlags.ShaderIndex; + dirtyFlags |= EffectDirtyFlags.PixelShaderIndex; } } @@ -122,7 +124,20 @@ namespace Kav { metallicRoughnessTextureParam.SetValue(value); metallicRoughnessMapEnabled = value != null; - dirtyFlags |= EffectDirtyFlags.ShaderIndex; + dirtyFlags |= EffectDirtyFlags.PixelShaderIndex; + } + } + + public bool HardwareInstancingEnabled + { + get { return hardwareInstancingEnabled; } + set + { + if (value != hardwareInstancingEnabled) + { + hardwareInstancingEnabled = value; + dirtyFlags |= EffectDirtyFlags.VertexShaderIndex; + } } } @@ -175,14 +190,19 @@ namespace Kav dirtyFlags &= ~EffectDirtyFlags.WorldViewProj; } - if ((dirtyFlags & EffectDirtyFlags.EyePosition) != 0) + if ((dirtyFlags & EffectDirtyFlags.VertexShaderIndex) != 0) { - Matrix.Invert(ref view, out Matrix inverseView); + int vertexShaderIndex = 0; - dirtyFlags &= ~EffectDirtyFlags.EyePosition; + if (hardwareInstancingEnabled) + { + vertexShaderIndex = 1; + } + + vertexShaderIndexParam.SetValue(vertexShaderIndex); } - if ((dirtyFlags & EffectDirtyFlags.ShaderIndex) != 0) + if ((dirtyFlags & EffectDirtyFlags.PixelShaderIndex) != 0) { int shaderIndex = 0; @@ -217,7 +237,7 @@ namespace Kav shaderIndexParam.SetValue(shaderIndex); - dirtyFlags &= ~EffectDirtyFlags.ShaderIndex; + dirtyFlags &= ~EffectDirtyFlags.PixelShaderIndex; } } @@ -235,7 +255,8 @@ namespace Kav metallicParam = Parameters["MetallicValue"]; roughnessParam = Parameters["RoughnessValue"]; - shaderIndexParam = Parameters["ShaderIndex"]; + shaderIndexParam = Parameters["PixelShaderIndex"]; + vertexShaderIndexParam = Parameters["VertexShaderIndex"]; } } } diff --git a/Effects/DiffuseLitSpriteEffect.cs b/Effects/DiffuseLitSpriteEffect.cs index faf05b3..ae8618c 100644 --- a/Effects/DiffuseLitSpriteEffect.cs +++ b/Effects/DiffuseLitSpriteEffect.cs @@ -40,7 +40,7 @@ namespace Kav if (normalMapEnabled != value) { normalMapEnabled = value; - dirtyFlags |= EffectDirtyFlags.ShaderIndex; + dirtyFlags |= EffectDirtyFlags.PixelShaderIndex; } } } @@ -142,7 +142,7 @@ namespace Kav dirtyFlags &= ~EffectDirtyFlags.WorldViewProj; } - if ((dirtyFlags & EffectDirtyFlags.ShaderIndex) != 0) + if ((dirtyFlags & EffectDirtyFlags.PixelShaderIndex) != 0) { int shaderIndex = 0; diff --git a/Effects/EffectHelpers.cs b/Effects/EffectHelpers.cs index 5a23251..c20bfcd 100644 --- a/Effects/EffectHelpers.cs +++ b/Effects/EffectHelpers.cs @@ -8,7 +8,8 @@ namespace Kav WorldViewProj = 1, World = 2, EyePosition = 4, - ShaderIndex = 8, + VertexShaderIndex = 8, + PixelShaderIndex = 16, All = -1 } } diff --git a/Effects/FXB/DeferredPBR_GBufferEffect.fxb b/Effects/FXB/DeferredPBR_GBufferEffect.fxb index 3aff2ad..6199ff0 100644 --- a/Effects/FXB/DeferredPBR_GBufferEffect.fxb +++ b/Effects/FXB/DeferredPBR_GBufferEffect.fxb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1208a4d715117867d4bd2b877526b526eadd5b47bf99c6e8dfbf2d8d3487478c -size 7476 +oid sha256:14ff7607c5d2f267e84e5e68bb2d1d10f0191f63325f0bb3f9c320f566807f35 +size 8492 diff --git a/Effects/HLSL/DeferredPBR_GBufferEffect.fx b/Effects/HLSL/DeferredPBR_GBufferEffect.fx index f24da19..f5322d2 100644 --- a/Effects/HLSL/DeferredPBR_GBufferEffect.fx +++ b/Effects/HLSL/DeferredPBR_GBufferEffect.fx @@ -25,6 +25,13 @@ struct VertexInput float2 TexCoord : TEXCOORD0; }; +struct InstanceInput +{ + float4x4 World : TEXCOORD0; + float4x4 WorldInverseTranspose : TEXCOORD1; + float4x4 WorldViewProjection : TEXCOORD2; +}; + struct PixelInput { float4 Position : SV_POSITION; @@ -55,6 +62,18 @@ PixelInput main_vs(VertexInput input) return output; } +PixelInput instanced_vs(VertexInput input, InstanceInput instanceInput) +{ + PixelInput output; + + output.PositionWorld = mul(input.Position, instanceInput.World).xyz; + output.NormalWorld = mul(input.Normal, (float3x3)instanceInput.WorldInverseTranspose).xyz; + output.TexCoord = input.TexCoord; + output.Position = mul(input.Position, instanceInput.WorldViewProjection); + + return output; +} + // Pixel Shaders // Easy trick to get tangent-normals to world-space to keep PBR code simplified. @@ -171,6 +190,19 @@ PixelOutput AlbedoMetallicRoughnessNormalMapPS(PixelInput input) return output; } +VertexShader VSArray[2] = +{ + compile vs_3_0 main_vs(), + compile vs_3_0 instanced_vs() +}; + +int VSIndices[2] = +{ + 0, 1 +}; + +int VertexShaderIndex = 0; + PixelShader PSArray[8] = { compile ps_3_0 NonePS(), @@ -191,13 +223,13 @@ int PSIndices[8] = 0, 1, 2, 3, 4, 5, 6, 7 }; -int ShaderIndex = 0; +int PixelShaderIndex = 0; Technique GBuffer { Pass { - VertexShader = compile vs_3_0 main_vs(); - PixelShader = (PSArray[PSIndices[ShaderIndex]]); + VertexShader = (VSArray[VSIndices[VertexShaderIndex]]); + PixelShader = (PSArray[PSIndices[PixelShaderIndex]]); } } diff --git a/Effects/PBREffect.cs b/Effects/PBREffect.cs index 2df74cd..4b80ecb 100644 --- a/Effects/PBREffect.cs +++ b/Effects/PBREffect.cs @@ -130,7 +130,7 @@ namespace Kav { albedoTextureParam.SetValue(value); albedoTextureEnabled = value != null; - dirtyFlags |= EffectDirtyFlags.ShaderIndex; + dirtyFlags |= EffectDirtyFlags.PixelShaderIndex; } } @@ -141,7 +141,7 @@ namespace Kav { normalTextureParam.SetValue(value); normalMapEnabled = value != null; - dirtyFlags |= EffectDirtyFlags.ShaderIndex; + dirtyFlags |= EffectDirtyFlags.PixelShaderIndex; } } @@ -164,7 +164,7 @@ namespace Kav { metallicRoughnessTextureParam.SetValue(value); metallicRoughnessMapEnabled = value != null; - dirtyFlags |= EffectDirtyFlags.ShaderIndex; + dirtyFlags |= EffectDirtyFlags.PixelShaderIndex; } } @@ -266,7 +266,7 @@ namespace Kav dirtyFlags &= ~EffectDirtyFlags.EyePosition; } - if ((dirtyFlags & EffectDirtyFlags.ShaderIndex) != 0) + if ((dirtyFlags & EffectDirtyFlags.PixelShaderIndex) != 0) { int shaderIndex = 0; @@ -301,7 +301,7 @@ namespace Kav shaderIndexParam.SetValue(shaderIndex); - dirtyFlags &= ~EffectDirtyFlags.ShaderIndex; + dirtyFlags &= ~EffectDirtyFlags.PixelShaderIndex; } } diff --git a/Geometry/Interfaces/IGBufferDrawable.cs b/Geometry/Interfaces/IGBufferDrawable.cs new file mode 100644 index 0000000..bf84905 --- /dev/null +++ b/Geometry/Interfaces/IGBufferDrawable.cs @@ -0,0 +1,16 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; + +namespace Kav +{ + public interface IGBufferDrawable + { + Vector3 Albedo { get; } + float Metallic { get; } + float Roughness { get; } + + Texture2D AlbedoTexture { get; } + Texture2D NormalTexture { get; } + Texture2D MetallicRoughnessTexture { get; } + } +} diff --git a/Geometry/Interfaces/IIndexDrawable.cs b/Geometry/Interfaces/IIndexDrawable.cs new file mode 100644 index 0000000..f59f8d4 --- /dev/null +++ b/Geometry/Interfaces/IIndexDrawable.cs @@ -0,0 +1,10 @@ +using Microsoft.Xna.Framework.Graphics; + +namespace Kav +{ + public interface IIndexDrawable + { + VertexBuffer VertexBuffer { get; } + IndexBuffer IndexBuffer { get; } + } +} diff --git a/Geometry/MeshPart.cs b/Geometry/MeshPart.cs index 25cb93c..2a669eb 100644 --- a/Geometry/MeshPart.cs +++ b/Geometry/MeshPart.cs @@ -3,7 +3,7 @@ using Microsoft.Xna.Framework.Graphics; namespace Kav { - public class MeshPart + public class MeshPart : IIndexDrawable { public IndexBuffer IndexBuffer { get; } public VertexBuffer VertexBuffer { get; } @@ -11,27 +11,27 @@ namespace Kav public Vector3[] Positions { get; } public BoundingBox BoundingBox { get; } - + private Texture2D albedoTexture = null; private Texture2D normalTexture = null; private Texture2D metallicRoughnessTexture = null; - public Texture2D AlbedoTexture - { + public Texture2D AlbedoTexture + { get { return DisableAlbedoMap ? null : albedoTexture; } set { albedoTexture = value; } } - public Texture2D NormalTexture - { - get { return DisableNormalMap ? null : normalTexture; } + public Texture2D NormalTexture + { + get { return DisableNormalMap ? null : normalTexture; } set { normalTexture = value; } } - public Texture2D MetallicRoughnessTexture - { + public Texture2D MetallicRoughnessTexture + { get { return DisableMetallicRoughnessMap ? null : metallicRoughnessTexture; } - set { metallicRoughnessTexture = value; } + set { metallicRoughnessTexture = value; } } public Vector3 Albedo { get; set; } = Vector3.One; diff --git a/Geometry/MeshSprite.cs b/Geometry/MeshSprite.cs index ac50ab7..dce9752 100644 --- a/Geometry/MeshSprite.cs +++ b/Geometry/MeshSprite.cs @@ -4,7 +4,7 @@ using Microsoft.Xna.Framework.Graphics; namespace Kav { - public class MeshSprite : ICullable + public class MeshSprite : ICullable, IIndexDrawable { private static readonly int PixelScale = 40; private static readonly short[] Indices = new short[] diff --git a/Renderer.cs b/Renderer.cs index 08c673e..efa2e38 100644 --- a/Renderer.cs +++ b/Renderer.cs @@ -8,18 +8,16 @@ namespace Kav { public class Renderer { + private const int MAX_INSTANCE_VERTEX_COUNT = 1000000; private const int MAX_SHADOW_CASCADES = 4; private int ShadowMapSize { get; } private GraphicsDevice GraphicsDevice { get; } - private int RenderDimensionsX { get; } - private int RenderDimensionsY { get; } private VertexBuffer FullscreenTriangle { get; } private int NumShadowCascades { get; } private RenderTarget2D ColorRenderTarget { get; } - private RenderTarget2D DirectionalRenderTarget { get; } private RenderTarget2D[] ShadowRenderTargets { get; } private DeferredPBREffect DeferredPBREffect { get; } @@ -35,10 +33,10 @@ namespace Kav private SkyboxEffect SkyboxEffect { get; } private DiffuseLitSpriteEffect DiffuseLitSpriteEffect { get; } - private RenderTarget2D gPosition { get; } - private RenderTarget2D gNormal { get; } - private RenderTarget2D gAlbedo { get; } - private RenderTarget2D gMetallicRoughness { get; } + private RenderTarget2D GPosition { get; } + private RenderTarget2D GNormal { get; } + private RenderTarget2D GAlbedo { get; } + private RenderTarget2D GMetallicRoughness { get; } private RenderTargetCube PointShadowCubeMap { get; } private RenderTargetBinding[] GBuffer { get; } @@ -47,6 +45,9 @@ namespace Kav private SpriteBatch SpriteBatch { get; } + private DynamicVertexBuffer GBufferInstanceVertexBuffer { get; } + private readonly GBufferInstanceVertex[] GBufferInstanceVertices = new GBufferInstanceVertex[MAX_INSTANCE_VERTEX_COUNT]; + public Renderer( GraphicsDevice graphicsDevice, int renderDimensionsX, @@ -55,8 +56,6 @@ namespace Kav int shadowMapSize ) { GraphicsDevice = graphicsDevice; - RenderDimensionsX = renderDimensionsX; - RenderDimensionsY = renderDimensionsY; ShadowMapSize = shadowMapSize; @@ -86,18 +85,7 @@ namespace Kav RenderTargetUsage.PreserveContents ); - DirectionalRenderTarget = new RenderTarget2D( - graphicsDevice, - renderDimensionsX, - renderDimensionsY, - false, - SurfaceFormat.Color, - DepthFormat.None, - 0, - RenderTargetUsage.PreserveContents - ); - - gPosition = new RenderTarget2D( + GPosition = new RenderTarget2D( GraphicsDevice, renderDimensionsX, renderDimensionsY, @@ -106,7 +94,7 @@ namespace Kav DepthFormat.Depth24 ); - gNormal = new RenderTarget2D( + GNormal = new RenderTarget2D( GraphicsDevice, renderDimensionsX, renderDimensionsY, @@ -115,7 +103,7 @@ namespace Kav DepthFormat.None ); - gAlbedo = new RenderTarget2D( + GAlbedo = new RenderTarget2D( GraphicsDevice, renderDimensionsX, renderDimensionsY, @@ -124,7 +112,7 @@ namespace Kav DepthFormat.None ); - gMetallicRoughness = new RenderTarget2D( + GMetallicRoughness = new RenderTarget2D( GraphicsDevice, renderDimensionsX, renderDimensionsY, @@ -134,10 +122,10 @@ namespace Kav ); GBuffer = new RenderTargetBinding[4] { - new RenderTargetBinding(gPosition), - new RenderTargetBinding(gNormal), - new RenderTargetBinding(gAlbedo), - new RenderTargetBinding(gMetallicRoughness) + new RenderTargetBinding(GPosition), + new RenderTargetBinding(GNormal), + new RenderTargetBinding(GAlbedo), + new RenderTargetBinding(GMetallicRoughness) }; PointShadowCubeMap = new RenderTargetCube( @@ -175,6 +163,13 @@ namespace Kav ); SpriteBatch = new SpriteBatch(graphicsDevice); + + GBufferInstanceVertexBuffer = new DynamicVertexBuffer( + GraphicsDevice, + VertexDeclarations.GBufferInstanceDeclaration, + MAX_INSTANCE_VERTEX_COUNT, + BufferUsage.WriteOnly + ); } public void DeferredRender( @@ -185,23 +180,47 @@ namespace Kav IEnumerable pointLights, DirectionalLight? directionalLight ) { - GBufferRender(camera, modelTransforms); + GBufferRender(GBuffer, camera, modelTransforms); GraphicsDevice.SetRenderTarget(ColorRenderTarget); GraphicsDevice.Clear(Color.Black); - AmbientLightRender(ambientLight); + AmbientLightRender( + ColorRenderTarget, + GPosition, + GAlbedo, + ambientLight + ); DeferredPointLightEffect.EyePosition = camera.Position; foreach (var pointLight in pointLights) { - PointLightRender(camera, modelTransforms, pointLight); + PointLightRender( + ColorRenderTarget, + GPosition, + GAlbedo, + GNormal, + GMetallicRoughness, + camera, + modelTransforms, + pointLight + ); } if (directionalLight.HasValue) { - DirectionalLightRender(camera, modelTransforms, directionalLight.Value); + DirectionalLightRender( + ColorRenderTarget, + GPosition, + GAlbedo, + GNormal, + GMetallicRoughness, + camera, + modelTransforms, + directionalLight.Value, + NumShadowCascades + ); } GraphicsDevice.SetRenderTarget(renderTarget); @@ -219,7 +238,7 @@ namespace Kav DirectionalLight? directionalLight, TextureCube skybox ) { - GBufferRender(camera, modelTransforms); + GBufferRender(GBuffer, camera, modelTransforms); GraphicsDevice.SetRenderTarget(ColorRenderTarget); GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.Black, 1f, 0); @@ -228,18 +247,44 @@ namespace Kav DepthRender(camera, modelTransforms); GraphicsDevice.DepthStencilState = DepthStencilState.DepthRead; - AmbientLightRender(ambientLight); + AmbientLightRender( + ColorRenderTarget, + GPosition, + GAlbedo, + ambientLight + ); + foreach (var pointLight in pointLights) { - PointLightRender(camera, modelTransforms, pointLight); + PointLightRender( + ColorRenderTarget, + GPosition, + GAlbedo, + GNormal, + GMetallicRoughness, + camera, + modelTransforms, + pointLight + ); } if (directionalLight.HasValue) { - DirectionalLightToonRender(camera, modelTransforms, directionalLight.Value); + DirectionalLightToonRender( + ColorRenderTarget, + GPosition, + GAlbedo, + GNormal, + GMetallicRoughness, + camera, + modelTransforms, + directionalLight.Value, + NumShadowCascades, + false + ); } - SkyboxRender(camera, skybox); + SkyboxRender(ColorRenderTarget, camera, skybox); GraphicsDevice.SetRenderTarget(renderTarget); SpriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Opaque, null, null, null, null); @@ -394,9 +439,11 @@ namespace Kav } private void SkyboxRender( + RenderTarget2D renderTarget, PerspectiveCamera camera, TextureCube skybox ) { + GraphicsDevice.SetRenderTarget(renderTarget); GraphicsDevice.RasterizerState.CullMode = CullMode.CullClockwiseFace; SkyboxEffect.Skybox = skybox; @@ -425,12 +472,68 @@ namespace Kav GraphicsDevice.RasterizerState.CullMode = CullMode.CullCounterClockwiseFace; } - private void GBufferRender( + /// + /// GBuffer binding must have 4 render targets. + /// + public void InstancedGBufferRender( + RenderTargetBinding[] gBuffer, + PerspectiveCamera camera, + T drawable, + int numInstances, + IEnumerable transforms + ) where T : IIndexDrawable, IGBufferDrawable { + GraphicsDevice.SetRenderTargets(gBuffer); + GraphicsDevice.DepthStencilState = DepthStencilState.Default; + GraphicsDevice.BlendState = BlendState.Opaque; + + Deferred_GBufferEffect.Albedo = drawable.Albedo; + Deferred_GBufferEffect.Metallic = drawable.Metallic; + Deferred_GBufferEffect.Roughness = drawable.Roughness; + + Deferred_GBufferEffect.AlbedoTexture = drawable.AlbedoTexture; + Deferred_GBufferEffect.NormalTexture = drawable.NormalTexture; + Deferred_GBufferEffect.MetallicRoughnessTexture = drawable.MetallicRoughnessTexture; + + int i = 0; + foreach (var transform in transforms) + { + if (i >= numInstances) { break; } + GBufferInstanceVertices[i].World = transform; + GBufferInstanceVertices[i].WorldInverseTranspose = Matrix.Transpose(Matrix.Invert(transform)); + GBufferInstanceVertices[i].WorldViewProjection = transform * camera.View * camera.Projection; + i += 1; + } + + GBufferInstanceVertexBuffer.SetData( + GBufferInstanceVertices, + 0, + numInstances, + SetDataOptions.Discard + ); + + GraphicsDevice.SetVertexBuffers( + drawable.VertexBuffer, + new VertexBufferBinding(GBufferInstanceVertexBuffer, 0, 1) + ); + GraphicsDevice.Indices = drawable.IndexBuffer; + + GraphicsDevice.DrawInstancedPrimitives( + PrimitiveType.TriangleList, + 0, + 0, + drawable.VertexBuffer.VertexCount, + 0, + drawable.IndexBuffer.IndexCount / 3, + numInstances + ); + } + + public void GBufferRender( + RenderTargetBinding[] gBuffer, PerspectiveCamera camera, IEnumerable<(Model, Matrix)> modelTransforms ) { - GraphicsDevice.SetRenderTargets(GBuffer); - GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.Black, 1f, 0); + GraphicsDevice.SetRenderTargets(gBuffer); GraphicsDevice.DepthStencilState = DepthStencilState.Default; GraphicsDevice.BlendState = BlendState.Opaque; @@ -475,9 +578,13 @@ namespace Kav } } - private void AmbientLightRender(AmbientLight ambientLight) - { - GraphicsDevice.SetRenderTarget(ColorRenderTarget); + public void AmbientLightRender( + RenderTarget2D renderTarget, + Texture2D gPosition, + Texture2D gAlbedo, + AmbientLight ambientLight + ) { + GraphicsDevice.SetRenderTarget(renderTarget); GraphicsDevice.BlendState = BlendState.Opaque; DeferredAmbientLightEffect.GPosition = gPosition; @@ -492,14 +599,19 @@ namespace Kav } } - private void PointLightRender( + public void PointLightRender( + RenderTarget2D renderTarget, + Texture2D gPosition, + Texture2D gAlbedo, + Texture2D gNormal, + Texture2D gMetallicRoughness, PerspectiveCamera camera, IEnumerable<(Model, Matrix)> modelTransforms, PointLight pointLight ) { RenderPointShadows(camera, modelTransforms, pointLight); - GraphicsDevice.SetRenderTarget(ColorRenderTarget); + GraphicsDevice.SetRenderTarget(renderTarget); GraphicsDevice.DepthStencilState = DepthStencilState.DepthRead; GraphicsDevice.BlendState = BlendState.Additive; @@ -523,28 +635,38 @@ namespace Kav } } - private void DirectionalLightRender( + public void DirectionalLightRender( + RenderTarget2D renderTarget, + Texture2D gPosition, + Texture2D gAlbedo, + Texture2D gNormal, + Texture2D gMetallicRoughness, PerspectiveCamera camera, IEnumerable<(Model, Matrix)> modelTransforms, - DirectionalLight directionalLight + DirectionalLight directionalLight, + int numShadowCascades ) { RenderDirectionalShadows(camera, modelTransforms, directionalLight, DeferredDirectionalLightEffect); + GraphicsDevice.SetRenderTarget(renderTarget); + GraphicsDevice.DepthStencilState = DepthStencilState.DepthRead; + GraphicsDevice.BlendState = BlendState.Additive; + DeferredDirectionalLightEffect.GPosition = gPosition; DeferredDirectionalLightEffect.GAlbedo = gAlbedo; DeferredDirectionalLightEffect.GNormal = gNormal; DeferredDirectionalLightEffect.GMetallicRoughness = gMetallicRoughness; DeferredDirectionalLightEffect.ShadowMapOne = ShadowRenderTargets[0]; - if (NumShadowCascades > 1) + if (numShadowCascades > 1) { DeferredDirectionalLightEffect.ShadowMapTwo = ShadowRenderTargets[1]; } - if (NumShadowCascades > 2) + if (numShadowCascades > 2) { DeferredDirectionalLightEffect.ShadowMapThree = ShadowRenderTargets[2]; } - if (NumShadowCascades > 3) + if (numShadowCascades > 3) { DeferredDirectionalLightEffect.ShadowMapFour = ShadowRenderTargets[3]; } @@ -556,9 +678,6 @@ namespace Kav DeferredDirectionalLightEffect.ViewMatrix = camera.View; DeferredDirectionalLightEffect.EyePosition = camera.Position; - GraphicsDevice.SetRenderTarget(ColorRenderTarget); - GraphicsDevice.BlendState = BlendState.Additive; - foreach (EffectPass pass in DeferredDirectionalLightEffect.CurrentTechnique.Passes) { pass.Apply(); @@ -568,13 +687,20 @@ namespace Kav } private void DirectionalLightToonRender( + RenderTarget2D renderTarget, + Texture2D gPosition, + Texture2D gAlbedo, + Texture2D gNormal, + Texture2D gMetallicRoughness, PerspectiveCamera camera, IEnumerable<(Model, Matrix)> modelTransforms, - DirectionalLight directionalLight + DirectionalLight directionalLight, + int numShadowCascades, + bool ditheredShadows ) { RenderDirectionalShadows(camera, modelTransforms, directionalLight, Deferred_ToonEffect); - GraphicsDevice.SetRenderTarget(ColorRenderTarget); + GraphicsDevice.SetRenderTarget(renderTarget); GraphicsDevice.DepthStencilState = DepthStencilState.DepthRead; GraphicsDevice.BlendState = BlendState.Additive; @@ -583,7 +709,7 @@ namespace Kav Deferred_ToonEffect.GNormal = gNormal; Deferred_ToonEffect.GMetallicRoughness = gMetallicRoughness; - Deferred_ToonEffect.DitheredShadows = false; + Deferred_ToonEffect.DitheredShadows = ditheredShadows; Deferred_ToonEffect.EyePosition = camera.Position; @@ -592,15 +718,15 @@ namespace Kav directionalLight.Color.ToVector3() * directionalLight.Intensity; Deferred_ToonEffect.ShadowMapOne = ShadowRenderTargets[0]; - if (NumShadowCascades > 1) + if (numShadowCascades > 1) { Deferred_ToonEffect.ShadowMapTwo = ShadowRenderTargets[1]; } - if (NumShadowCascades > 2) + if (numShadowCascades > 2) { Deferred_ToonEffect.ShadowMapThree = ShadowRenderTargets[2]; } - if (NumShadowCascades > 3) + if (numShadowCascades > 3) { Deferred_ToonEffect.ShadowMapFour = ShadowRenderTargets[3]; } diff --git a/VertexDeclarations.cs b/VertexDeclarations.cs new file mode 100644 index 0000000..a12b2f8 --- /dev/null +++ b/VertexDeclarations.cs @@ -0,0 +1,23 @@ +using Microsoft.Xna.Framework.Graphics; + +namespace Kav +{ + public static class VertexDeclarations + { + public static VertexDeclaration GBufferInstanceDeclaration = new VertexDeclaration + ( + new VertexElement(0, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 0), + new VertexElement(16, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 1), + new VertexElement(32, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 2), + new VertexElement(48, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 3), + new VertexElement(64, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 4), + new VertexElement(80, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 5), + new VertexElement(96, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 6), + new VertexElement(112, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 7), + new VertexElement(128, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 8), + new VertexElement(144, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 9), + new VertexElement(160, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 10), + new VertexElement(176, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 11) + ); + } +} diff --git a/Vertices/GBufferInstanceVertex.cs b/Vertices/GBufferInstanceVertex.cs new file mode 100644 index 0000000..63e8d1e --- /dev/null +++ b/Vertices/GBufferInstanceVertex.cs @@ -0,0 +1,32 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; + +namespace Kav +{ + public struct GBufferInstanceVertex : IVertexType + { + VertexDeclaration IVertexType.VertexDeclaration + { + get + { + return VertexDeclarations.GBufferInstanceDeclaration; + } + } + + public Matrix World { get; set; } + public Matrix WorldInverseTranspose { get; set; } + public Matrix WorldViewProjection { get; set; } + + public static readonly VertexDeclaration VertexDeclaration; + + public GBufferInstanceVertex( + Matrix world, + Matrix worldInverseTranspose, + Matrix worldViewProjection + ) { + World = world; + WorldInverseTranspose = worldInverseTranspose; + WorldViewProjection = worldViewProjection; + } + } +} -- 2.25.1 From 8b43e8f45ee6fa35f5c4d4924a62a3fcafe61301 Mon Sep 17 00:00:00 2001 From: cosmonaut Date: Mon, 7 Dec 2020 01:57:57 -0800 Subject: [PATCH 02/12] start removing global render procedures --- Renderer.cs | 184 ++++------------------------------------------------ 1 file changed, 11 insertions(+), 173 deletions(-) diff --git a/Renderer.cs b/Renderer.cs index efa2e38..fa36434 100644 --- a/Renderer.cs +++ b/Renderer.cs @@ -33,14 +33,8 @@ namespace Kav private SkyboxEffect SkyboxEffect { get; } private DiffuseLitSpriteEffect DiffuseLitSpriteEffect { get; } - private RenderTarget2D GPosition { get; } - private RenderTarget2D GNormal { get; } - private RenderTarget2D GAlbedo { get; } - private RenderTarget2D GMetallicRoughness { get; } private RenderTargetCube PointShadowCubeMap { get; } - private RenderTargetBinding[] GBuffer { get; } - private Kav.Model UnitCube { get; } private SpriteBatch SpriteBatch { get; } @@ -85,49 +79,6 @@ namespace Kav RenderTargetUsage.PreserveContents ); - GPosition = new RenderTarget2D( - GraphicsDevice, - renderDimensionsX, - renderDimensionsY, - false, - SurfaceFormat.Vector4, - DepthFormat.Depth24 - ); - - GNormal = new RenderTarget2D( - GraphicsDevice, - renderDimensionsX, - renderDimensionsY, - false, - SurfaceFormat.Vector4, - DepthFormat.None - ); - - GAlbedo = new RenderTarget2D( - GraphicsDevice, - renderDimensionsX, - renderDimensionsY, - false, - SurfaceFormat.Color, - DepthFormat.None - ); - - GMetallicRoughness = new RenderTarget2D( - GraphicsDevice, - renderDimensionsX, - renderDimensionsY, - false, - SurfaceFormat.HalfVector2, - DepthFormat.None - ); - - GBuffer = new RenderTargetBinding[4] { - new RenderTargetBinding(GPosition), - new RenderTargetBinding(GNormal), - new RenderTargetBinding(GAlbedo), - new RenderTargetBinding(GMetallicRoughness) - }; - PointShadowCubeMap = new RenderTargetCube( GraphicsDevice, shadowMapSize, @@ -172,126 +123,6 @@ namespace Kav ); } - public void DeferredRender( - RenderTarget2D renderTarget, - PerspectiveCamera camera, - IEnumerable<(Model, Matrix)> modelTransforms, - AmbientLight ambientLight, - IEnumerable pointLights, - DirectionalLight? directionalLight - ) { - GBufferRender(GBuffer, camera, modelTransforms); - - GraphicsDevice.SetRenderTarget(ColorRenderTarget); - GraphicsDevice.Clear(Color.Black); - - AmbientLightRender( - ColorRenderTarget, - GPosition, - GAlbedo, - ambientLight - ); - - DeferredPointLightEffect.EyePosition = camera.Position; - - foreach (var pointLight in pointLights) - { - PointLightRender( - ColorRenderTarget, - GPosition, - GAlbedo, - GNormal, - GMetallicRoughness, - camera, - modelTransforms, - pointLight - ); - } - - if (directionalLight.HasValue) - { - DirectionalLightRender( - ColorRenderTarget, - GPosition, - GAlbedo, - GNormal, - GMetallicRoughness, - camera, - modelTransforms, - directionalLight.Value, - NumShadowCascades - ); - } - - GraphicsDevice.SetRenderTarget(renderTarget); - SpriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Opaque, null, null, null, ToneMapEffect); - SpriteBatch.Draw(ColorRenderTarget, Vector2.Zero, Color.White); - SpriteBatch.End(); - } - - public void DeferredToonRender( - RenderTarget2D renderTarget, - PerspectiveCamera camera, - IEnumerable<(Model, Matrix)> modelTransforms, - AmbientLight ambientLight, - IEnumerable pointLights, - DirectionalLight? directionalLight, - TextureCube skybox - ) { - GBufferRender(GBuffer, camera, modelTransforms); - - GraphicsDevice.SetRenderTarget(ColorRenderTarget); - GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.Black, 1f, 0); - GraphicsDevice.DepthStencilState = DepthStencilState.Default; - - DepthRender(camera, modelTransforms); - GraphicsDevice.DepthStencilState = DepthStencilState.DepthRead; - - AmbientLightRender( - ColorRenderTarget, - GPosition, - GAlbedo, - ambientLight - ); - - foreach (var pointLight in pointLights) - { - PointLightRender( - ColorRenderTarget, - GPosition, - GAlbedo, - GNormal, - GMetallicRoughness, - camera, - modelTransforms, - pointLight - ); - } - - if (directionalLight.HasValue) - { - DirectionalLightToonRender( - ColorRenderTarget, - GPosition, - GAlbedo, - GNormal, - GMetallicRoughness, - camera, - modelTransforms, - directionalLight.Value, - NumShadowCascades, - false - ); - } - - SkyboxRender(ColorRenderTarget, camera, skybox); - - GraphicsDevice.SetRenderTarget(renderTarget); - SpriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Opaque, null, null, null, null); - SpriteBatch.Draw(ColorRenderTarget, Vector2.Zero, Color.White); - SpriteBatch.End(); - } - // TODO: we could make this a lot more efficient probably // draws mesh sprites with a forward rendered diffuse lighting technique public void MeshSpriteRender( @@ -307,7 +138,7 @@ namespace Kav GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.Black, 1f, 0); GraphicsDevice.DepthStencilState = DepthStencilState.Default; - DepthRender(camera, modelTransforms); + DepthRender(ColorRenderTarget, camera, modelTransforms); GraphicsDevice.Clear(ClearOptions.Target, new Color(0, 0, 0, 0), 1f, 0); GraphicsDevice.DepthStencilState = DepthStencilState.DepthRead; @@ -401,10 +232,14 @@ namespace Kav SpriteBatch.End(); } - private void DepthRender( + public void DepthRender( + RenderTarget2D renderTarget, PerspectiveCamera camera, IEnumerable<(Model, Matrix)> modelTransforms ) { + GraphicsDevice.SetRenderTarget(renderTarget); + GraphicsDevice.DepthStencilState = DepthStencilState.Default; + var boundingFrustum = new BoundingFrustum(camera.View * camera.Projection); foreach (var (model, transform) in FrustumCull(boundingFrustum, modelTransforms)) @@ -438,7 +273,7 @@ namespace Kav } } - private void SkyboxRender( + public void SkyboxRender( RenderTarget2D renderTarget, PerspectiveCamera camera, TextureCube skybox @@ -586,6 +421,7 @@ namespace Kav ) { GraphicsDevice.SetRenderTarget(renderTarget); GraphicsDevice.BlendState = BlendState.Opaque; + GraphicsDevice.DepthStencilState = DepthStencilState.DepthRead; DeferredAmbientLightEffect.GPosition = gPosition; DeferredAmbientLightEffect.GAlbedo = gAlbedo; @@ -621,6 +457,8 @@ namespace Kav DeferredPointLightEffect.GMetallicRoughness = gMetallicRoughness; DeferredPointLightEffect.ShadowMap = PointShadowCubeMap; + DeferredPointLightEffect.EyePosition = camera.Position; + DeferredPointLightEffect.PointLightPosition = pointLight.Position; DeferredPointLightEffect.PointLightColor = pointLight.Color.ToVector3() * pointLight.Intensity; @@ -686,7 +524,7 @@ namespace Kav } } - private void DirectionalLightToonRender( + public void DirectionalLightToonRender( RenderTarget2D renderTarget, Texture2D gPosition, Texture2D gAlbedo, -- 2.25.1 From b784f9df4b7a3a65a1183680e9af5ce8f8cc6959 Mon Sep 17 00:00:00 2001 From: cosmonaut Date: Mon, 7 Dec 2020 13:50:32 -0800 Subject: [PATCH 03/12] trying different shader semantics --- Effects/DeferredPBR_GBufferEffect.cs | 25 +++++++----------- Effects/EffectHelpers.cs | 1 + Effects/FXB/DeferredPBR_GBufferEffect.fxb | 4 +-- Effects/HLSL/DeferredPBR_GBufferEffect.fx | 21 +++++++-------- Geometry/MeshPart.cs | 2 +- Renderer.cs | 31 +++++++++++++++-------- VertexDeclarations.cs | 16 +++--------- Vertices/GBufferInstanceVertex.cs | 10 +++----- 8 files changed, 51 insertions(+), 59 deletions(-) diff --git a/Effects/DeferredPBR_GBufferEffect.cs b/Effects/DeferredPBR_GBufferEffect.cs index b7eeb65..335a592 100644 --- a/Effects/DeferredPBR_GBufferEffect.cs +++ b/Effects/DeferredPBR_GBufferEffect.cs @@ -6,8 +6,7 @@ namespace Kav public class DeferredPBR_GBufferEffect : Effect, TransformEffect { EffectParameter worldParam; - EffectParameter worldViewProjectionParam; - EffectParameter worldInverseTransposeParam; + EffectParameter viewProjectionParam; EffectParameter albedoTextureParam; EffectParameter normalTextureParam; @@ -41,7 +40,7 @@ namespace Kav set { world = value; - dirtyFlags |= EffectDirtyFlags.World | EffectDirtyFlags.WorldViewProj; + dirtyFlags |= EffectDirtyFlags.World; } } @@ -51,7 +50,7 @@ namespace Kav set { view = value; - dirtyFlags |= EffectDirtyFlags.WorldViewProj | EffectDirtyFlags.EyePosition; + dirtyFlags |= EffectDirtyFlags.ViewProj | EffectDirtyFlags.EyePosition; } } @@ -61,7 +60,7 @@ namespace Kav set { projection = value; - dirtyFlags |= EffectDirtyFlags.WorldViewProj; + dirtyFlags |= EffectDirtyFlags.ViewProj; } } @@ -174,20 +173,15 @@ namespace Kav { worldParam.SetValue(world); - Matrix.Invert(ref world, out Matrix worldInverse); - Matrix.Transpose(ref worldInverse, out Matrix worldInverseTranspose); - worldInverseTransposeParam.SetValue(worldInverseTranspose); - dirtyFlags &= ~EffectDirtyFlags.World; } - if ((dirtyFlags & EffectDirtyFlags.WorldViewProj) != 0) + if ((dirtyFlags & EffectDirtyFlags.ViewProj) != 0) { - Matrix.Multiply(ref world, ref view, out Matrix worldView); - Matrix.Multiply(ref worldView, ref projection, out Matrix worldViewProj); - worldViewProjectionParam.SetValue(worldViewProj); + Matrix.Multiply(ref view, ref projection, out Matrix viewProj); + viewProjectionParam.SetValue(viewProj); - dirtyFlags &= ~EffectDirtyFlags.WorldViewProj; + dirtyFlags &= ~EffectDirtyFlags.ViewProj; } if ((dirtyFlags & EffectDirtyFlags.VertexShaderIndex) != 0) @@ -244,8 +238,7 @@ namespace Kav void CacheEffectParameters() { worldParam = Parameters["World"]; - worldViewProjectionParam = Parameters["WorldViewProjection"]; - worldInverseTransposeParam = Parameters["WorldInverseTranspose"]; + viewProjectionParam = Parameters["ViewProjection"]; albedoTextureParam = Parameters["AlbedoTexture"]; normalTextureParam = Parameters["NormalTexture"]; diff --git a/Effects/EffectHelpers.cs b/Effects/EffectHelpers.cs index c20bfcd..56a0cec 100644 --- a/Effects/EffectHelpers.cs +++ b/Effects/EffectHelpers.cs @@ -10,6 +10,7 @@ namespace Kav EyePosition = 4, VertexShaderIndex = 8, PixelShaderIndex = 16, + ViewProj = 32, All = -1 } } diff --git a/Effects/FXB/DeferredPBR_GBufferEffect.fxb b/Effects/FXB/DeferredPBR_GBufferEffect.fxb index 6199ff0..5c38c1e 100644 --- a/Effects/FXB/DeferredPBR_GBufferEffect.fxb +++ b/Effects/FXB/DeferredPBR_GBufferEffect.fxb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:14ff7607c5d2f267e84e5e68bb2d1d10f0191f63325f0bb3f9c320f566807f35 -size 8492 +oid sha256:a0fde33abf96c838d507d637922e614e8490f41b700846c87f5d344e14699959 +size 9228 diff --git a/Effects/HLSL/DeferredPBR_GBufferEffect.fx b/Effects/HLSL/DeferredPBR_GBufferEffect.fx index f5322d2..328ad7c 100644 --- a/Effects/HLSL/DeferredPBR_GBufferEffect.fx +++ b/Effects/HLSL/DeferredPBR_GBufferEffect.fx @@ -13,8 +13,7 @@ BEGIN_CONSTANTS MATRIX_CONSTANTS float4x4 World _vs(c0) _cb(c7); - float4x4 WorldInverseTranspose _vs(c4) _cb(c11); - float4x4 WorldViewProjection _vs(c8) _cb(c15); + float4x4 ViewProjection _vs(c4) _cb(c11); END_CONSTANTS @@ -22,14 +21,12 @@ struct VertexInput { float4 Position : POSITION; float3 Normal : NORMAL; - float2 TexCoord : TEXCOORD0; + float2 TexCoord : TEXCOORD; }; struct InstanceInput { - float4x4 World : TEXCOORD0; - float4x4 WorldInverseTranspose : TEXCOORD1; - float4x4 WorldViewProjection : TEXCOORD2; + float4x4 World : COLOR0; }; struct PixelInput @@ -55,9 +52,11 @@ PixelInput main_vs(VertexInput input) PixelInput output; output.PositionWorld = mul(input.Position, World).xyz; - output.NormalWorld = mul(input.Normal, (float3x3)WorldInverseTranspose).xyz; + output.NormalWorld = normalize(mul(input.Normal, World)); output.TexCoord = input.TexCoord; - output.Position = mul(input.Position, WorldViewProjection); + + float4x4 worldViewProjection = mul(World, ViewProjection); + output.Position = mul(input.Position, worldViewProjection); return output; } @@ -67,9 +66,11 @@ PixelInput instanced_vs(VertexInput input, InstanceInput instanceInput) PixelInput output; output.PositionWorld = mul(input.Position, instanceInput.World).xyz; - output.NormalWorld = mul(input.Normal, (float3x3)instanceInput.WorldInverseTranspose).xyz; + output.NormalWorld = normalize(mul(input.Normal, instanceInput.World)); output.TexCoord = input.TexCoord; - output.Position = mul(input.Position, instanceInput.WorldViewProjection); + + float4x4 worldViewProjection = mul(World, ViewProjection); + output.Position = mul(input.Position, worldViewProjection); return output; } diff --git a/Geometry/MeshPart.cs b/Geometry/MeshPart.cs index 2a669eb..f2eac05 100644 --- a/Geometry/MeshPart.cs +++ b/Geometry/MeshPart.cs @@ -3,7 +3,7 @@ using Microsoft.Xna.Framework.Graphics; namespace Kav { - public class MeshPart : IIndexDrawable + public class MeshPart : IIndexDrawable, IGBufferDrawable { public IndexBuffer IndexBuffer { get; } public VertexBuffer VertexBuffer { get; } diff --git a/Renderer.cs b/Renderer.cs index fa36434..ccdef63 100644 --- a/Renderer.cs +++ b/Renderer.cs @@ -321,6 +321,8 @@ namespace Kav GraphicsDevice.DepthStencilState = DepthStencilState.Default; GraphicsDevice.BlendState = BlendState.Opaque; + Deferred_GBufferEffect.HardwareInstancingEnabled = true; + Deferred_GBufferEffect.Albedo = drawable.Albedo; Deferred_GBufferEffect.Metallic = drawable.Metallic; Deferred_GBufferEffect.Roughness = drawable.Roughness; @@ -329,13 +331,14 @@ namespace Kav Deferred_GBufferEffect.NormalTexture = drawable.NormalTexture; Deferred_GBufferEffect.MetallicRoughnessTexture = drawable.MetallicRoughnessTexture; + Deferred_GBufferEffect.View = camera.View; + Deferred_GBufferEffect.Projection = camera.Projection; + int i = 0; foreach (var transform in transforms) { if (i >= numInstances) { break; } GBufferInstanceVertices[i].World = transform; - GBufferInstanceVertices[i].WorldInverseTranspose = Matrix.Transpose(Matrix.Invert(transform)); - GBufferInstanceVertices[i].WorldViewProjection = transform * camera.View * camera.Projection; i += 1; } @@ -352,15 +355,19 @@ namespace Kav ); GraphicsDevice.Indices = drawable.IndexBuffer; - GraphicsDevice.DrawInstancedPrimitives( - PrimitiveType.TriangleList, - 0, - 0, - drawable.VertexBuffer.VertexCount, - 0, - drawable.IndexBuffer.IndexCount / 3, - numInstances - ); + foreach (var pass in Deferred_GBufferEffect.CurrentTechnique.Passes) + { + pass.Apply(); + GraphicsDevice.DrawInstancedPrimitives( + PrimitiveType.TriangleList, + 0, + 0, + drawable.VertexBuffer.VertexCount, + 0, + drawable.IndexBuffer.IndexCount / 3, + numInstances + ); + } } public void GBufferRender( @@ -384,6 +391,8 @@ namespace Kav Deferred_GBufferEffect.View = camera.View; Deferred_GBufferEffect.Projection = camera.Projection; + Deferred_GBufferEffect.HardwareInstancingEnabled = false; + Deferred_GBufferEffect.Albedo = meshPart.Albedo; Deferred_GBufferEffect.Metallic = meshPart.Metallic; Deferred_GBufferEffect.Roughness = meshPart.Roughness; diff --git a/VertexDeclarations.cs b/VertexDeclarations.cs index a12b2f8..1e8b869 100644 --- a/VertexDeclarations.cs +++ b/VertexDeclarations.cs @@ -6,18 +6,10 @@ namespace Kav { public static VertexDeclaration GBufferInstanceDeclaration = new VertexDeclaration ( - new VertexElement(0, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 0), - new VertexElement(16, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 1), - new VertexElement(32, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 2), - new VertexElement(48, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 3), - new VertexElement(64, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 4), - new VertexElement(80, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 5), - new VertexElement(96, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 6), - new VertexElement(112, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 7), - new VertexElement(128, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 8), - new VertexElement(144, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 9), - new VertexElement(160, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 10), - new VertexElement(176, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 11) + new VertexElement(0, VertexElementFormat.HalfVector4, VertexElementUsage.Color, 0), + new VertexElement(16, VertexElementFormat.HalfVector4, VertexElementUsage.Color, 1), + new VertexElement(32, VertexElementFormat.HalfVector4, VertexElementUsage.Color, 2), + new VertexElement(48, VertexElementFormat.HalfVector4, VertexElementUsage.Color, 3) ); } } diff --git a/Vertices/GBufferInstanceVertex.cs b/Vertices/GBufferInstanceVertex.cs index 63e8d1e..329c8e9 100644 --- a/Vertices/GBufferInstanceVertex.cs +++ b/Vertices/GBufferInstanceVertex.cs @@ -1,8 +1,10 @@ +using System.Runtime.InteropServices; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; namespace Kav { + [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct GBufferInstanceVertex : IVertexType { VertexDeclaration IVertexType.VertexDeclaration @@ -14,19 +16,13 @@ namespace Kav } public Matrix World { get; set; } - public Matrix WorldInverseTranspose { get; set; } - public Matrix WorldViewProjection { get; set; } public static readonly VertexDeclaration VertexDeclaration; public GBufferInstanceVertex( - Matrix world, - Matrix worldInverseTranspose, - Matrix worldViewProjection + Matrix world ) { World = world; - WorldInverseTranspose = worldInverseTranspose; - WorldViewProjection = worldViewProjection; } } } -- 2.25.1 From 283b0786417e5ff2f17bdb010402011e2a0a4ed0 Mon Sep 17 00:00:00 2001 From: cosmonaut Date: Mon, 7 Dec 2020 14:42:02 -0800 Subject: [PATCH 04/12] instanced g buffer draws work now --- Effects/FXB/DeferredPBR_GBufferEffect.fxb | 4 ++-- Effects/HLSL/DeferredPBR_GBufferEffect.fx | 4 ++-- Renderer.cs | 2 +- VertexDeclarations.cs | 8 ++++---- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Effects/FXB/DeferredPBR_GBufferEffect.fxb b/Effects/FXB/DeferredPBR_GBufferEffect.fxb index 5c38c1e..4ad7c73 100644 --- a/Effects/FXB/DeferredPBR_GBufferEffect.fxb +++ b/Effects/FXB/DeferredPBR_GBufferEffect.fxb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a0fde33abf96c838d507d637922e614e8490f41b700846c87f5d344e14699959 -size 9228 +oid sha256:7c70594ec60f6f791f6d836d0ca1736284e8158f11ce439a18ad120fc440ad10 +size 9148 diff --git a/Effects/HLSL/DeferredPBR_GBufferEffect.fx b/Effects/HLSL/DeferredPBR_GBufferEffect.fx index 328ad7c..13c48c2 100644 --- a/Effects/HLSL/DeferredPBR_GBufferEffect.fx +++ b/Effects/HLSL/DeferredPBR_GBufferEffect.fx @@ -26,7 +26,7 @@ struct VertexInput struct InstanceInput { - float4x4 World : COLOR0; + float4x4 World : TEXCOORD2; }; struct PixelInput @@ -69,7 +69,7 @@ PixelInput instanced_vs(VertexInput input, InstanceInput instanceInput) output.NormalWorld = normalize(mul(input.Normal, instanceInput.World)); output.TexCoord = input.TexCoord; - float4x4 worldViewProjection = mul(World, ViewProjection); + float4x4 worldViewProjection = mul(instanceInput.World, ViewProjection); output.Position = mul(input.Position, worldViewProjection); return output; diff --git a/Renderer.cs b/Renderer.cs index ccdef63..45afee8 100644 --- a/Renderer.cs +++ b/Renderer.cs @@ -8,7 +8,7 @@ namespace Kav { public class Renderer { - private const int MAX_INSTANCE_VERTEX_COUNT = 1000000; + private const int MAX_INSTANCE_VERTEX_COUNT = 1000; private const int MAX_SHADOW_CASCADES = 4; private int ShadowMapSize { get; } diff --git a/VertexDeclarations.cs b/VertexDeclarations.cs index 1e8b869..d77327b 100644 --- a/VertexDeclarations.cs +++ b/VertexDeclarations.cs @@ -6,10 +6,10 @@ namespace Kav { public static VertexDeclaration GBufferInstanceDeclaration = new VertexDeclaration ( - new VertexElement(0, VertexElementFormat.HalfVector4, VertexElementUsage.Color, 0), - new VertexElement(16, VertexElementFormat.HalfVector4, VertexElementUsage.Color, 1), - new VertexElement(32, VertexElementFormat.HalfVector4, VertexElementUsage.Color, 2), - new VertexElement(48, VertexElementFormat.HalfVector4, VertexElementUsage.Color, 3) + new VertexElement(0, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 2), + new VertexElement(16, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 3), + new VertexElement(32, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 4), + new VertexElement(48, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 5) ); } } -- 2.25.1 From e2fdbff7d10f3052d1213d839902ad43902a0025 Mon Sep 17 00:00:00 2001 From: cosmonaut Date: Mon, 7 Dec 2020 14:58:03 -0800 Subject: [PATCH 05/12] cullable instance calls --- Geometry/MeshPart.cs | 2 +- Renderer.cs | 35 +++++++++++++++++++++++++++-------- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/Geometry/MeshPart.cs b/Geometry/MeshPart.cs index f2eac05..c8d033b 100644 --- a/Geometry/MeshPart.cs +++ b/Geometry/MeshPart.cs @@ -3,7 +3,7 @@ using Microsoft.Xna.Framework.Graphics; namespace Kav { - public class MeshPart : IIndexDrawable, IGBufferDrawable + public class MeshPart : IIndexDrawable, IGBufferDrawable, ICullable { public IndexBuffer IndexBuffer { get; } public VertexBuffer VertexBuffer { get; } diff --git a/Renderer.cs b/Renderer.cs index 45afee8..1fe0b9c 100644 --- a/Renderer.cs +++ b/Renderer.cs @@ -8,7 +8,7 @@ namespace Kav { public class Renderer { - private const int MAX_INSTANCE_VERTEX_COUNT = 1000; + private const int MAX_INSTANCE_VERTEX_COUNT = 1000000; private const int MAX_SHADOW_CASCADES = 4; private int ShadowMapSize { get; } @@ -314,9 +314,10 @@ namespace Kav RenderTargetBinding[] gBuffer, PerspectiveCamera camera, T drawable, - int numInstances, IEnumerable transforms - ) where T : IIndexDrawable, IGBufferDrawable { + ) where T : ICullable, IIndexDrawable, IGBufferDrawable { + int numInstances = 0; + GraphicsDevice.SetRenderTargets(gBuffer); GraphicsDevice.DepthStencilState = DepthStencilState.Default; GraphicsDevice.BlendState = BlendState.Opaque; @@ -334,12 +335,13 @@ namespace Kav Deferred_GBufferEffect.View = camera.View; Deferred_GBufferEffect.Projection = camera.Projection; - int i = 0; - foreach (var transform in transforms) + var boundingFrustum = new BoundingFrustum(camera.View * camera.Projection); + + foreach (var transform in FrustumCull(boundingFrustum, drawable, transforms)) { - if (i >= numInstances) { break; } - GBufferInstanceVertices[i].World = transform; - i += 1; + + GBufferInstanceVertices[numInstances].World = transform; + numInstances += 1; } GBufferInstanceVertexBuffer.SetData( @@ -824,6 +826,23 @@ namespace Kav } } + private static IEnumerable FrustumCull( + BoundingFrustum boundingFrustum, + T cullable, + IEnumerable transforms + ) where T : ICullable + { + foreach (var transform in transforms) + { + var boundingBox = TransformedBoundingBox(cullable.BoundingBox, transform); + var containment = boundingFrustum.Contains(boundingBox); + if (containment != ContainmentType.Disjoint) + { + yield return transform; + } + } + } + private static BoundingBox TransformedBoundingBox(BoundingBox boundingBox, Matrix matrix) { var center = (boundingBox.Min + boundingBox.Max) / 2f; -- 2.25.1 From bb694d3dbe47dcfcee6bfe3fb315587419ba8c0f Mon Sep 17 00:00:00 2001 From: cosmonaut Date: Mon, 7 Dec 2020 15:51:24 -0800 Subject: [PATCH 06/12] handle case where there are no instances --- Renderer.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Renderer.cs b/Renderer.cs index 1fe0b9c..05b2ab1 100644 --- a/Renderer.cs +++ b/Renderer.cs @@ -344,6 +344,8 @@ namespace Kav numInstances += 1; } + if (numInstances == 0) { return; } + GBufferInstanceVertexBuffer.SetData( GBufferInstanceVertices, 0, -- 2.25.1 From fe222e266ffc296ffacbed82dccecedb45204537 Mon Sep 17 00:00:00 2001 From: cosmonaut Date: Mon, 7 Dec 2020 18:46:53 -0800 Subject: [PATCH 07/12] started instance based depth render --- Renderer.cs | 57 ++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 41 insertions(+), 16 deletions(-) diff --git a/Renderer.cs b/Renderer.cs index 05b2ab1..e3d2820 100644 --- a/Renderer.cs +++ b/Renderer.cs @@ -128,18 +128,12 @@ namespace Kav public void MeshSpriteRender( RenderTarget2D renderTarget, PerspectiveCamera camera, - IEnumerable<(Model, Matrix)> modelTransforms, IEnumerable<(MeshSprite, Matrix)> meshSpriteTransforms, AmbientLight ambientLight, IEnumerable pointLights, DirectionalLight? directionalLight ) { - GraphicsDevice.SetRenderTarget(ColorRenderTarget); - GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.Black, 1f, 0); - GraphicsDevice.DepthStencilState = DepthStencilState.Default; - - DepthRender(ColorRenderTarget, camera, modelTransforms); - GraphicsDevice.Clear(ClearOptions.Target, new Color(0, 0, 0, 0), 1f, 0); + GraphicsDevice.SetRenderTarget(renderTarget); GraphicsDevice.DepthStencilState = DepthStencilState.DepthRead; GraphicsDevice.RasterizerState = RasterizerState.CullNone; @@ -224,12 +218,6 @@ namespace Kav ); } } - - GraphicsDevice.SetRenderTarget(renderTarget); - GraphicsDevice.Clear(new Color(0, 0, 0, 0)); - SpriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, null, null, null, null); - SpriteBatch.Draw(ColorRenderTarget, Vector2.Zero, Color.White); - SpriteBatch.End(); } public void DepthRender( @@ -248,7 +236,7 @@ namespace Kav { foreach (var meshPart in modelMesh.MeshParts) { - SimpleDepthEffect.Model = transform; + SimpleDepthEffect.World = transform; SimpleDepthEffect.View = camera.View; SimpleDepthEffect.Projection = camera.Projection; @@ -280,6 +268,8 @@ namespace Kav ) { GraphicsDevice.SetRenderTarget(renderTarget); GraphicsDevice.RasterizerState.CullMode = CullMode.CullClockwiseFace; + GraphicsDevice.DepthStencilState = DepthStencilState.DepthRead; + SkyboxEffect.Skybox = skybox; var view = camera.View; @@ -312,6 +302,7 @@ namespace Kav /// public void InstancedGBufferRender( RenderTargetBinding[] gBuffer, + RenderTarget2D depthBuffer, PerspectiveCamera camera, T drawable, IEnumerable transforms @@ -339,7 +330,6 @@ namespace Kav foreach (var transform in FrustumCull(boundingFrustum, drawable, transforms)) { - GBufferInstanceVertices[numInstances].World = transform; numInstances += 1; } @@ -372,6 +362,41 @@ namespace Kav numInstances ); } + + GraphicsDevice.SetRenderTarget(depthBuffer); + + foreach (var pass in Deferred_GBufferEffect.CurrentTechnique.Passes) + { + pass.Apply(); + GraphicsDevice.DrawInstancedPrimitives( + PrimitiveType.TriangleList, + 0, + 0, + drawable.VertexBuffer.VertexCount, + 0, + drawable.IndexBuffer.IndexCount / 3, + numInstances + ); + } + + //SimpleDepthEffect.HardwareInstancingEnabled = true; + //SimpleDepthEffect.View = camera.View; + //SimpleDepthEffect.Projection = camera.Projection; + + //foreach (var pass in SimpleDepthEffect.CurrentTechnique.Passes) + //{ + // pass.Apply(); + + // GraphicsDevice.DrawInstancedPrimitives( + // PrimitiveType.TriangleList, + // 0, + // 0, + // drawable.VertexBuffer.VertexCount, + // 0, + // drawable.IndexBuffer.IndexCount / 3, + // numInstances + // ); + //} } public void GBufferRender( @@ -694,7 +719,7 @@ namespace Kav GraphicsDevice.SetVertexBuffer(meshPart.VertexBuffer); GraphicsDevice.Indices = meshPart.IndexBuffer; - SimpleDepthEffect.Model = transform; + SimpleDepthEffect.World = transform; foreach (var pass in SimpleDepthEffect.CurrentTechnique.Passes) { -- 2.25.1 From 84601379b56c5a665e45c34737e02196eee84a36 Mon Sep 17 00:00:00 2001 From: cosmonaut Date: Mon, 7 Dec 2020 20:10:27 -0800 Subject: [PATCH 08/12] major API refactor --- EffectInterfaces/IHasWorldMatrix.cs | 9 + Effects/LinearDepthEffect.cs | 24 +- Effects/SimpleDepthEffect.cs | 63 +++- Renderer.cs | 444 +++++++++++++--------------- Vertices/GBufferInstanceVertex.cs | 2 +- 5 files changed, 282 insertions(+), 260 deletions(-) create mode 100644 EffectInterfaces/IHasWorldMatrix.cs diff --git a/EffectInterfaces/IHasWorldMatrix.cs b/EffectInterfaces/IHasWorldMatrix.cs new file mode 100644 index 0000000..7f87b42 --- /dev/null +++ b/EffectInterfaces/IHasWorldMatrix.cs @@ -0,0 +1,9 @@ +using Microsoft.Xna.Framework; + +namespace Kav +{ + public interface IHasWorldMatrix + { + Matrix World { get; set; } + } +} diff --git a/Effects/LinearDepthEffect.cs b/Effects/LinearDepthEffect.cs index 2a6a76a..5b62977 100644 --- a/Effects/LinearDepthEffect.cs +++ b/Effects/LinearDepthEffect.cs @@ -3,28 +3,28 @@ using Microsoft.Xna.Framework.Graphics; namespace Kav { - public class LinearDepthEffect : Effect + public class LinearDepthEffect : Effect, IHasWorldMatrix { - EffectParameter modelParam; - EffectParameter modelViewProjectionParam; + EffectParameter worldParam; + EffectParameter worldViewProjectionParam; EffectParameter lightPositionParam; EffectParameter farPlaneParam; EffectDirtyFlags dirtyFlags = EffectDirtyFlags.All; - Matrix model; + Matrix world; Matrix view; Matrix projection; public Vector3 LightPosition { get; set; } public float FarPlane { get; set; } - public Matrix Model + public Matrix World { - get { return model; } + get { return world; } set { - model = value; + world = value; dirtyFlags |= EffectDirtyFlags.World; dirtyFlags |= EffectDirtyFlags.WorldViewProj; } @@ -60,16 +60,16 @@ namespace Kav if ((dirtyFlags & EffectDirtyFlags.WorldViewProj) != 0) { Matrix.Multiply(ref view, ref projection, out Matrix viewProjection); - Matrix.Multiply(ref model, ref viewProjection, out Matrix worldViewProj); + Matrix.Multiply(ref world, ref viewProjection, out Matrix worldViewProj); - modelViewProjectionParam.SetValue(worldViewProj); + worldViewProjectionParam.SetValue(worldViewProj); dirtyFlags &= ~EffectDirtyFlags.WorldViewProj; } if ((dirtyFlags & EffectDirtyFlags.World) != 0) { - modelParam.SetValue(model); + worldParam.SetValue(world); dirtyFlags &= ~EffectDirtyFlags.World; } @@ -80,8 +80,8 @@ namespace Kav private void CacheEffectParameters() { - modelParam = Parameters["Model"]; - modelViewProjectionParam = Parameters["ModelViewProjection"]; + worldParam = Parameters["Model"]; + worldViewProjectionParam = Parameters["ModelViewProjection"]; lightPositionParam = Parameters["LightPosition"]; farPlaneParam = Parameters["FarPlane"]; diff --git a/Effects/SimpleDepthEffect.cs b/Effects/SimpleDepthEffect.cs index 1854e3c..200d743 100644 --- a/Effects/SimpleDepthEffect.cs +++ b/Effects/SimpleDepthEffect.cs @@ -3,23 +3,26 @@ using Microsoft.Xna.Framework.Graphics; namespace Kav { - public class SimpleDepthEffect : Effect + public class SimpleDepthEffect : Effect, IHasWorldMatrix { - EffectParameter modelViewProjectionParam; + EffectParameter worldParam; + EffectParameter viewProjectionParam; + EffectParameter vertexShaderIndexParam; - Matrix model; + Matrix world; Matrix view; Matrix projection; + bool hardwareInstancingEnabled = false; EffectDirtyFlags dirtyFlags = EffectDirtyFlags.All; - public Matrix Model + public Matrix World { - get { return model; } + get { return world; } set { - model = value; - dirtyFlags |= EffectDirtyFlags.WorldViewProj; + world = value; + dirtyFlags |= EffectDirtyFlags.World; } } @@ -29,7 +32,7 @@ namespace Kav set { view = value; - dirtyFlags |= EffectDirtyFlags.WorldViewProj; + dirtyFlags |= EffectDirtyFlags.ViewProj; } } @@ -39,7 +42,20 @@ namespace Kav set { projection = value; - dirtyFlags |= EffectDirtyFlags.WorldViewProj; + dirtyFlags |= EffectDirtyFlags.ViewProj; + } + } + + public bool HardwareInstancingEnabled + { + get { return hardwareInstancingEnabled; } + set + { + if (value != hardwareInstancingEnabled) + { + hardwareInstancingEnabled = value; + dirtyFlags |= EffectDirtyFlags.VertexShaderIndex; + } } } @@ -50,20 +66,39 @@ namespace Kav protected override void OnApply() { - if ((dirtyFlags & EffectDirtyFlags.WorldViewProj) != 0) + if ((dirtyFlags & EffectDirtyFlags.World) != 0) + { + worldParam.SetValue(world); + + dirtyFlags &= ~EffectDirtyFlags.World; + } + + if ((dirtyFlags & EffectDirtyFlags.ViewProj) != 0) { Matrix.Multiply(ref view, ref projection, out Matrix viewProjection); - Matrix.Multiply(ref model, ref viewProjection, out Matrix worldViewProj); + viewProjectionParam.SetValue(viewProjection); - modelViewProjectionParam.SetValue(worldViewProj); + dirtyFlags &= ~EffectDirtyFlags.ViewProj; + } - dirtyFlags &= ~EffectDirtyFlags.WorldViewProj; + if ((dirtyFlags & EffectDirtyFlags.VertexShaderIndex) != 0) + { + int vertexShaderIndex = 0; + + if (hardwareInstancingEnabled) + { + vertexShaderIndex = 1; + } + + vertexShaderIndexParam.SetValue(vertexShaderIndex); } } private void CacheEffectParameters() { - modelViewProjectionParam = Parameters["ModelViewProjection"]; + worldParam = Parameters["World"]; + viewProjectionParam = Parameters["ViewProjection"]; + vertexShaderIndexParam = Parameters["VertexShaderIndex"]; } } } diff --git a/Renderer.cs b/Renderer.cs index e3d2820..b5e97b7 100644 --- a/Renderer.cs +++ b/Renderer.cs @@ -220,48 +220,145 @@ namespace Kav } } - public void DepthRender( - RenderTarget2D renderTarget, + // Renders a series of drawable-transform pairs using an effect that has a World matrix. + // Effect must be pre-configured!! + public static void CullAndRenderIndexed( + GraphicsDevice graphicsDevice, PerspectiveCamera camera, - IEnumerable<(Model, Matrix)> modelTransforms - ) { - GraphicsDevice.SetRenderTarget(renderTarget); - GraphicsDevice.DepthStencilState = DepthStencilState.Default; - + IEnumerable<(T, Matrix)> drawableTransformPairs, + U effect + ) where T : IIndexDrawable, ICullable where U : Effect, IHasWorldMatrix + { var boundingFrustum = new BoundingFrustum(camera.View * camera.Projection); - foreach (var (model, transform) in FrustumCull(boundingFrustum, modelTransforms)) + foreach (var (drawable, transform) in FrustumCull(boundingFrustum, drawableTransformPairs)) { - foreach (var modelMesh in model.Meshes) - { - foreach (var meshPart in modelMesh.MeshParts) - { - SimpleDepthEffect.World = transform; - SimpleDepthEffect.View = camera.View; - SimpleDepthEffect.Projection = camera.Projection; + effect.World = transform; - GraphicsDevice.SetVertexBuffer(meshPart.VertexBuffer); - GraphicsDevice.Indices = meshPart.IndexBuffer; - - foreach (var pass in SimpleDepthEffect.CurrentTechnique.Passes) - { - pass.Apply(); - - GraphicsDevice.DrawIndexedPrimitives( - PrimitiveType.TriangleList, - 0, - 0, - meshPart.VertexBuffer.VertexCount, - 0, - meshPart.Triangles.Length - ); - } - } - } + RenderIndexed( + graphicsDevice, + drawable, + effect + ); } } - public void SkyboxRender( + public static void RenderIndexed( + GraphicsDevice graphicsDevice, + T drawable, + U effect + ) where T : IIndexDrawable where U : Effect + { + graphicsDevice.SetVertexBuffer(drawable.VertexBuffer); + graphicsDevice.Indices = drawable.IndexBuffer; + + foreach (var pass in effect.CurrentTechnique.Passes) + { + pass.Apply(); + + graphicsDevice.DrawIndexedPrimitives( + PrimitiveType.TriangleList, + 0, + 0, + drawable.VertexBuffer.VertexCount, + 0, + drawable.IndexBuffer.IndexCount / 3 + ); + } + } + + public static int FillAndSetBuffersForInstancing( + GraphicsDevice graphicsDevice, + PerspectiveCamera camera, + T drawable, + IEnumerable transforms, + V[] vertexData, + DynamicVertexBuffer dynamicVertexBuffer + ) where T : ICullable, IIndexDrawable where V : struct, IVertexType, IHasWorldMatrix + { + var boundingFrustum = new BoundingFrustum(camera.View * camera.Projection); + + int numInstances = 0; + foreach (var transform in FrustumCull(boundingFrustum, drawable, transforms)) + { + vertexData[numInstances].World = transform; + numInstances += 1; + } + + if (numInstances == 0) { return 0; } + + dynamicVertexBuffer.SetData( + vertexData, + 0, + numInstances, + SetDataOptions.Discard + ); + + graphicsDevice.SetVertexBuffers( + drawable.VertexBuffer, + new VertexBufferBinding(dynamicVertexBuffer, 0, 1) + ); + graphicsDevice.Indices = drawable.IndexBuffer; + + return numInstances; + } + + public static void RenderInstanced( + GraphicsDevice graphicsDevice, + T drawable, + U effect, + int numInstances + ) where T : ICullable, IIndexDrawable where U : Effect + { + foreach (var pass in effect.CurrentTechnique.Passes) + { + pass.Apply(); + + graphicsDevice.DrawInstancedPrimitives( + PrimitiveType.TriangleList, + 0, + 0, + drawable.VertexBuffer.VertexCount, + 0, + drawable.IndexBuffer.IndexCount / 3, + numInstances + ); + } + } + + // TODO: can probably make this static somehow + public void RenderFullscreenEffect( + Effect effect + ) { + foreach (var pass in effect.CurrentTechnique.Passes) + { + pass.Apply(); + GraphicsDevice.SetVertexBuffer(FullscreenTriangle); + GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, 1); + } + } + + public void RenderDepth( + RenderTarget2D renderTarget, + PerspectiveCamera camera, + IEnumerable<(T, Matrix)> drawableTransforms + ) where T : ICullable, IIndexDrawable + { + GraphicsDevice.SetRenderTarget(renderTarget); + GraphicsDevice.DepthStencilState = DepthStencilState.Default; + + SimpleDepthEffect.View = camera.View; + SimpleDepthEffect.Projection = camera.Projection; + + CullAndRenderIndexed( + GraphicsDevice, + camera, + drawableTransforms, + SimpleDepthEffect + ); + } + + public void RenderSkybox( RenderTarget2D renderTarget, PerspectiveCamera camera, TextureCube skybox @@ -274,41 +371,29 @@ namespace Kav var view = camera.View; view.Translation = Vector3.Zero; - SkyboxEffect.View = view; + SkyboxEffect.View = view; SkyboxEffect.Projection = camera.Projection; - GraphicsDevice.SetVertexBuffer(UnitCube.Meshes[0].MeshParts[0].VertexBuffer); - GraphicsDevice.Indices = UnitCube.Meshes[0].MeshParts[0].IndexBuffer; + RenderIndexed( + GraphicsDevice, + UnitCube.Meshes[0].MeshParts[0], + SkyboxEffect + ); - foreach (var pass in SkyboxEffect.CurrentTechnique.Passes) - { - pass.Apply(); - - GraphicsDevice.DrawIndexedPrimitives( - PrimitiveType.TriangleList, - 0, - 0, - UnitCube.Meshes[0].MeshParts[0].VertexBuffer.VertexCount, - 0, - UnitCube.Meshes[0].MeshParts[0].Triangles.Length - ); - } GraphicsDevice.RasterizerState.CullMode = CullMode.CullCounterClockwiseFace; } /// /// GBuffer binding must have 4 render targets. /// - public void InstancedGBufferRender( + public void RenderGBufferInstanced( RenderTargetBinding[] gBuffer, RenderTarget2D depthBuffer, PerspectiveCamera camera, T drawable, IEnumerable transforms ) where T : ICullable, IIndexDrawable, IGBufferDrawable { - int numInstances = 0; - GraphicsDevice.SetRenderTargets(gBuffer); GraphicsDevice.DepthStencilState = DepthStencilState.Default; GraphicsDevice.BlendState = BlendState.Opaque; @@ -326,132 +411,67 @@ namespace Kav Deferred_GBufferEffect.View = camera.View; Deferred_GBufferEffect.Projection = camera.Projection; - var boundingFrustum = new BoundingFrustum(camera.View * camera.Projection); - - foreach (var transform in FrustumCull(boundingFrustum, drawable, transforms)) - { - GBufferInstanceVertices[numInstances].World = transform; - numInstances += 1; - } - - if (numInstances == 0) { return; } - - GBufferInstanceVertexBuffer.SetData( + var numInstances = FillAndSetBuffersForInstancing( + GraphicsDevice, + camera, + drawable, + transforms, GBufferInstanceVertices, - 0, - numInstances, - SetDataOptions.Discard + GBufferInstanceVertexBuffer ); - GraphicsDevice.SetVertexBuffers( - drawable.VertexBuffer, - new VertexBufferBinding(GBufferInstanceVertexBuffer, 0, 1) + RenderInstanced( + GraphicsDevice, + drawable, + Deferred_GBufferEffect, + numInstances ); - GraphicsDevice.Indices = drawable.IndexBuffer; - - foreach (var pass in Deferred_GBufferEffect.CurrentTechnique.Passes) - { - pass.Apply(); - GraphicsDevice.DrawInstancedPrimitives( - PrimitiveType.TriangleList, - 0, - 0, - drawable.VertexBuffer.VertexCount, - 0, - drawable.IndexBuffer.IndexCount / 3, - numInstances - ); - } + // re-render to get depth GraphicsDevice.SetRenderTarget(depthBuffer); - foreach (var pass in Deferred_GBufferEffect.CurrentTechnique.Passes) - { - pass.Apply(); - GraphicsDevice.DrawInstancedPrimitives( - PrimitiveType.TriangleList, - 0, - 0, - drawable.VertexBuffer.VertexCount, - 0, - drawable.IndexBuffer.IndexCount / 3, - numInstances - ); - } - - //SimpleDepthEffect.HardwareInstancingEnabled = true; - //SimpleDepthEffect.View = camera.View; - //SimpleDepthEffect.Projection = camera.Projection; - - //foreach (var pass in SimpleDepthEffect.CurrentTechnique.Passes) - //{ - // pass.Apply(); - - // GraphicsDevice.DrawInstancedPrimitives( - // PrimitiveType.TriangleList, - // 0, - // 0, - // drawable.VertexBuffer.VertexCount, - // 0, - // drawable.IndexBuffer.IndexCount / 3, - // numInstances - // ); - //} + RenderInstanced( + GraphicsDevice, + drawable, + Deferred_GBufferEffect, + numInstances + ); } - public void GBufferRender( + public void RenderGBufferIndexed( RenderTargetBinding[] gBuffer, PerspectiveCamera camera, - IEnumerable<(Model, Matrix)> modelTransforms - ) { + IEnumerable<(T, Matrix)> drawableTransforms + ) where T : ICullable, IIndexDrawable, IGBufferDrawable { GraphicsDevice.SetRenderTargets(gBuffer); GraphicsDevice.DepthStencilState = DepthStencilState.Default; GraphicsDevice.BlendState = BlendState.Opaque; + Deferred_GBufferEffect.HardwareInstancingEnabled = false; + Deferred_GBufferEffect.View = camera.View; + Deferred_GBufferEffect.Projection = camera.Projection; + var boundingFrustum = new BoundingFrustum(camera.View * camera.Projection); - foreach (var (model, transform) in FrustumCull(boundingFrustum, modelTransforms)) + foreach (var (drawable, transform) in FrustumCull(boundingFrustum, drawableTransforms)) { - foreach (var modelMesh in model.Meshes) - { - foreach (var meshPart in modelMesh.MeshParts) - { - Deferred_GBufferEffect.World = transform; - Deferred_GBufferEffect.View = camera.View; - Deferred_GBufferEffect.Projection = camera.Projection; + Deferred_GBufferEffect.World = transform; - Deferred_GBufferEffect.HardwareInstancingEnabled = false; + Deferred_GBufferEffect.HardwareInstancingEnabled = false; - Deferred_GBufferEffect.Albedo = meshPart.Albedo; - Deferred_GBufferEffect.Metallic = meshPart.Metallic; - Deferred_GBufferEffect.Roughness = meshPart.Roughness; + Deferred_GBufferEffect.Albedo = drawable.Albedo; + Deferred_GBufferEffect.Metallic = drawable.Metallic; + Deferred_GBufferEffect.Roughness = drawable.Roughness; - Deferred_GBufferEffect.AlbedoTexture = meshPart.AlbedoTexture; - Deferred_GBufferEffect.NormalTexture = meshPart.NormalTexture; - Deferred_GBufferEffect.MetallicRoughnessTexture = meshPart.MetallicRoughnessTexture; + Deferred_GBufferEffect.AlbedoTexture = drawable.AlbedoTexture; + Deferred_GBufferEffect.NormalTexture = drawable.NormalTexture; + Deferred_GBufferEffect.MetallicRoughnessTexture = drawable.MetallicRoughnessTexture; - GraphicsDevice.SetVertexBuffer(meshPart.VertexBuffer); - GraphicsDevice.Indices = meshPart.IndexBuffer; - - foreach (var pass in Deferred_GBufferEffect.CurrentTechnique.Passes) - { - pass.Apply(); - - GraphicsDevice.DrawIndexedPrimitives( - PrimitiveType.TriangleList, - 0, - 0, - meshPart.VertexBuffer.VertexCount, - 0, - meshPart.Triangles.Length - ); - } - } - } + RenderIndexed(GraphicsDevice, drawable, Deferred_GBufferEffect); } } - public void AmbientLightRender( + public void RenderAmbientLight( RenderTarget2D renderTarget, Texture2D gPosition, Texture2D gAlbedo, @@ -465,25 +485,20 @@ namespace Kav DeferredAmbientLightEffect.GAlbedo = gAlbedo; DeferredAmbientLightEffect.AmbientColor = ambientLight.Color.ToVector3(); - foreach (var pass in DeferredAmbientLightEffect.CurrentTechnique.Passes) - { - pass.Apply(); - GraphicsDevice.SetVertexBuffer(FullscreenTriangle); - GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, 1); - } + RenderFullscreenEffect(DeferredAmbientLightEffect); } - public void PointLightRender( + public void RenderPointLight( RenderTarget2D renderTarget, Texture2D gPosition, Texture2D gAlbedo, Texture2D gNormal, Texture2D gMetallicRoughness, PerspectiveCamera camera, - IEnumerable<(Model, Matrix)> modelTransforms, + IEnumerable<(T, Matrix)> modelTransforms, PointLight pointLight - ) { - RenderPointShadows(camera, modelTransforms, pointLight); + ) where T : ICullable, IIndexDrawable { + RenderPointShadows(PointShadowCubeMap, camera, modelTransforms, pointLight); GraphicsDevice.SetRenderTarget(renderTarget); GraphicsDevice.DepthStencilState = DepthStencilState.DepthRead; @@ -503,26 +518,21 @@ namespace Kav DeferredPointLightEffect.FarPlane = 25f; // FIXME: magic value - foreach (var pass in DeferredPointLightEffect.CurrentTechnique.Passes) - { - pass.Apply(); - GraphicsDevice.SetVertexBuffer(FullscreenTriangle); - GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, 1); - } + RenderFullscreenEffect(DeferredPointLightEffect); } - public void DirectionalLightRender( + public void RenderDirectionalLight( RenderTarget2D renderTarget, Texture2D gPosition, Texture2D gAlbedo, Texture2D gNormal, Texture2D gMetallicRoughness, PerspectiveCamera camera, - IEnumerable<(Model, Matrix)> modelTransforms, + IEnumerable<(T, Matrix)> modelTransforms, DirectionalLight directionalLight, int numShadowCascades - ) { - RenderDirectionalShadows(camera, modelTransforms, directionalLight, DeferredDirectionalLightEffect); + ) where T : ICullable, IIndexDrawable { + //RenderDirectionalShadows(camera, modelTransforms, directionalLight, DeferredDirectionalLightEffect); GraphicsDevice.SetRenderTarget(renderTarget); GraphicsDevice.DepthStencilState = DepthStencilState.DepthRead; @@ -554,27 +564,22 @@ namespace Kav DeferredDirectionalLightEffect.ViewMatrix = camera.View; DeferredDirectionalLightEffect.EyePosition = camera.Position; - foreach (EffectPass pass in DeferredDirectionalLightEffect.CurrentTechnique.Passes) - { - pass.Apply(); - GraphicsDevice.SetVertexBuffer(FullscreenTriangle); - GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, 1); - } + RenderFullscreenEffect(DeferredDirectionalLightEffect); } - public void DirectionalLightToonRender( + public void RenderDirectionalLightToon( RenderTarget2D renderTarget, Texture2D gPosition, Texture2D gAlbedo, Texture2D gNormal, Texture2D gMetallicRoughness, PerspectiveCamera camera, - IEnumerable<(Model, Matrix)> modelTransforms, + IEnumerable<(T, Matrix)> modelTransforms, DirectionalLight directionalLight, int numShadowCascades, bool ditheredShadows - ) { - RenderDirectionalShadows(camera, modelTransforms, directionalLight, Deferred_ToonEffect); + ) where T : ICullable, IIndexDrawable { + //RenderDirectionalShadows(camera, modelTransforms, directionalLight, Deferred_ToonEffect); GraphicsDevice.SetRenderTarget(renderTarget); GraphicsDevice.DepthStencilState = DepthStencilState.DepthRead; @@ -609,20 +614,15 @@ namespace Kav Deferred_ToonEffect.ViewMatrix = camera.View; - foreach (EffectPass pass in Deferred_ToonEffect.CurrentTechnique.Passes) - { - pass.Apply(); - GraphicsDevice.SetVertexBuffer(FullscreenTriangle); - GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, 1); - } + RenderFullscreenEffect(Deferred_ToonEffect); } - private void RenderDirectionalShadows( + private void RenderDirectionalShadows( PerspectiveCamera camera, IEnumerable<(Model, Matrix)> modelTransforms, DirectionalLight directionalLight, ShadowCascadeEffect effect - ) { + ) where T : ICullable, IIndexDrawable { // render the individual shadow cascades var previousFarPlane = camera.NearPlane; for (var i = 0; i < NumShadowCascades; i++) @@ -739,26 +739,18 @@ namespace Kav } } - private void RenderPointShadows( + private void RenderPointShadows( + RenderTargetCube pointShadowCubeMap, PerspectiveCamera camera, - IEnumerable<(Model, Matrix)> modelTransforms, + IEnumerable<(T, Matrix)> modelTransforms, PointLight pointLight - ) { + ) where T : ICullable, IIndexDrawable { GraphicsDevice.DepthStencilState = DepthStencilState.Default; GraphicsDevice.BlendState = BlendState.Opaque; - LinearDepthEffect.Projection = Matrix.CreatePerspectiveFieldOfView( - MathHelper.PiOver2, - 1, - 0.1f, - 25f // FIXME: magic value - ); - LinearDepthEffect.FarPlane = 25f; - LinearDepthEffect.LightPosition = pointLight.Position; - foreach (CubeMapFace face in Enum.GetValues(typeof(CubeMapFace))) { - GraphicsDevice.SetRenderTarget(PointShadowCubeMap, face); + GraphicsDevice.SetRenderTarget(pointShadowCubeMap, face); Vector3 targetDirection; Vector3 targetUpDirection; @@ -805,36 +797,22 @@ namespace Kav pointLight.Position + targetDirection, targetUpDirection ); + LinearDepthEffect.Projection = Matrix.CreatePerspectiveFieldOfView( + MathHelper.PiOver2, + 1, + 0.1f, + 25f // FIXME: magic value + ); + LinearDepthEffect.FarPlane = 25f; - var boundingFrustum = new BoundingFrustum(LinearDepthEffect.View * LinearDepthEffect.Projection); + LinearDepthEffect.LightPosition = pointLight.Position; - foreach (var (model, transform) in FrustumCull(boundingFrustum, modelTransforms)) - { - foreach (var modelMesh in model.Meshes) - { - foreach (var meshPart in modelMesh.MeshParts) - { - GraphicsDevice.SetVertexBuffer(meshPart.VertexBuffer); - GraphicsDevice.Indices = meshPart.IndexBuffer; - - LinearDepthEffect.Model = transform; - - foreach (var pass in LinearDepthEffect.CurrentTechnique.Passes) - { - pass.Apply(); - - GraphicsDevice.DrawIndexedPrimitives( - PrimitiveType.TriangleList, - 0, - 0, - meshPart.VertexBuffer.VertexCount, - 0, - meshPart.Triangles.Length - ); - } - } - } - } + CullAndRenderIndexed( + GraphicsDevice, + camera, + modelTransforms, + LinearDepthEffect + ); } } diff --git a/Vertices/GBufferInstanceVertex.cs b/Vertices/GBufferInstanceVertex.cs index 329c8e9..32ae321 100644 --- a/Vertices/GBufferInstanceVertex.cs +++ b/Vertices/GBufferInstanceVertex.cs @@ -5,7 +5,7 @@ using Microsoft.Xna.Framework.Graphics; namespace Kav { [StructLayout(LayoutKind.Sequential, Pack = 1)] - public struct GBufferInstanceVertex : IVertexType + public struct GBufferInstanceVertex : IVertexType, IHasWorldMatrix { VertexDeclaration IVertexType.VertexDeclaration { -- 2.25.1 From 96f6d228966e900a511164a176d1f2ae1f1caaa4 Mon Sep 17 00:00:00 2001 From: cosmonaut Date: Mon, 7 Dec 2020 21:36:16 -0800 Subject: [PATCH 09/12] shadow refactor --- DirectionalShadowMapData.cs | 58 ++++++++++ Renderer.cs | 215 +++++++++++++++--------------------- 2 files changed, 146 insertions(+), 127 deletions(-) create mode 100644 DirectionalShadowMapData.cs diff --git a/DirectionalShadowMapData.cs b/DirectionalShadowMapData.cs new file mode 100644 index 0000000..4eca964 --- /dev/null +++ b/DirectionalShadowMapData.cs @@ -0,0 +1,58 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; + +namespace Kav +{ + public class DirectionalShadowMapData + { + public static readonly int MAX_SHADOW_CASCADES = 4; + + public RenderTarget2D[] ShadowMaps { get; } + + public Matrix LightSpaceMatrixOne { get; set; } + public Matrix LightSpaceMatrixTwo { get; set; } + public Matrix LightSpaceMatrixThree { get; set; } + public Matrix LightSpaceMatrixFour { get; set; } + + public float[] CascadeFarPlanes { get; } + + public int ShadowMapSize { get; } + public int NumShadowCascades { get; } + + internal DirectionalShadowMapData( + GraphicsDevice graphicsDevice, + int shadowMapSize, + int numCascades + ) { + ShadowMapSize = shadowMapSize; + NumShadowCascades = (int)MathHelper.Clamp(numCascades, 1, MAX_SHADOW_CASCADES); + + ShadowMaps = new RenderTarget2D[NumShadowCascades]; + + for (var i = 0; i < NumShadowCascades; i++) + { + ShadowMaps[i] = new RenderTarget2D( + graphicsDevice, + shadowMapSize, + shadowMapSize, + false, + SurfaceFormat.Single, + DepthFormat.Depth24, + 0, + RenderTargetUsage.PreserveContents + ); + } + + CascadeFarPlanes = new float[MAX_SHADOW_CASCADES]; + } + + public void Clear(GraphicsDevice graphicsDevice) + { + foreach (var shadowMap in ShadowMaps) + { + graphicsDevice.SetRenderTarget(shadowMap); + graphicsDevice.Clear(Color.White); + } + } + } +} diff --git a/Renderer.cs b/Renderer.cs index b5e97b7..fb153dc 100644 --- a/Renderer.cs +++ b/Renderer.cs @@ -10,15 +10,10 @@ namespace Kav { private const int MAX_INSTANCE_VERTEX_COUNT = 1000000; private const int MAX_SHADOW_CASCADES = 4; - private int ShadowMapSize { get; } private GraphicsDevice GraphicsDevice { get; } private VertexBuffer FullscreenTriangle { get; } - private int NumShadowCascades { get; } - - private RenderTarget2D ColorRenderTarget { get; } - private RenderTarget2D[] ShadowRenderTargets { get; } private DeferredPBREffect DeferredPBREffect { get; } /* FIXME: these next two dont actually have anything to do with PBR */ @@ -33,8 +28,6 @@ namespace Kav private SkyboxEffect SkyboxEffect { get; } private DiffuseLitSpriteEffect DiffuseLitSpriteEffect { get; } - private RenderTargetCube PointShadowCubeMap { get; } - private Kav.Model UnitCube { get; } private SpriteBatch SpriteBatch { get; } @@ -43,50 +36,10 @@ namespace Kav private readonly GBufferInstanceVertex[] GBufferInstanceVertices = new GBufferInstanceVertex[MAX_INSTANCE_VERTEX_COUNT]; public Renderer( - GraphicsDevice graphicsDevice, - int renderDimensionsX, - int renderDimensionsY, - int numShadowCascades, - int shadowMapSize + GraphicsDevice graphicsDevice ) { GraphicsDevice = graphicsDevice; - ShadowMapSize = shadowMapSize; - - NumShadowCascades = (int)MathHelper.Clamp(numShadowCascades, 1, MAX_SHADOW_CASCADES); - ShadowRenderTargets = new RenderTarget2D[numShadowCascades]; - - for (var i = 0; i < numShadowCascades; i++) - { - ShadowRenderTargets[i] = new RenderTarget2D( - GraphicsDevice, - ShadowMapSize, - ShadowMapSize, - false, - SurfaceFormat.Single, - DepthFormat.Depth24 - ); - } - - ColorRenderTarget = new RenderTarget2D( - graphicsDevice, - renderDimensionsX, - renderDimensionsY, - false, - SurfaceFormat.Color, - DepthFormat.Depth24, - 0, - RenderTargetUsage.PreserveContents - ); - - PointShadowCubeMap = new RenderTargetCube( - GraphicsDevice, - shadowMapSize, - false, - SurfaceFormat.Single, - DepthFormat.Depth24 - ); - SimpleDepthEffect = new SimpleDepthEffect(GraphicsDevice); LinearDepthEffect = new LinearDepthEffect(GraphicsDevice); DeferredPBREffect = new DeferredPBREffect(GraphicsDevice); @@ -95,7 +48,6 @@ namespace Kav DeferredAmbientLightEffect = new DeferredPBR_AmbientLightEffect(GraphicsDevice); DeferredPointLightEffect = new DeferredPBR_PointLightEffect(GraphicsDevice); DeferredDirectionalLightEffect = new DeferredPBR_DirectionalLightEffect(GraphicsDevice); - DeferredDirectionalLightEffect.ShadowMapSize = ShadowMapSize; ToneMapEffect = new Effect(graphicsDevice, Resources.ToneMapEffect); Deferred_ToonEffect = new Deferred_ToonEffect(GraphicsDevice); SkyboxEffect = new SkyboxEffect(GraphicsDevice); @@ -123,6 +75,33 @@ namespace Kav ); } + public static RenderTargetCube CreateShadowCubeMap( + GraphicsDevice graphicsDevice, + int shadowMapSize + ) { + return new RenderTargetCube( + graphicsDevice, + shadowMapSize, + false, + SurfaceFormat.Single, + DepthFormat.Depth24, + 0, + RenderTargetUsage.PreserveContents + ); + } + + public static DirectionalShadowMapData CreateDirectionalShadowMaps( + GraphicsDevice graphicsDevice, + int shadowMapSize, + int numCascades + ) { + return new DirectionalShadowMapData( + graphicsDevice, + shadowMapSize, + numCascades + ); + } + // TODO: we could make this a lot more efficient probably // draws mesh sprites with a forward rendered diffuse lighting technique public void MeshSpriteRender( @@ -338,7 +317,7 @@ namespace Kav } } - public void RenderDepth( + public void RenderDepthIndexed( RenderTarget2D renderTarget, PerspectiveCamera camera, IEnumerable<(T, Matrix)> drawableTransforms @@ -488,18 +467,16 @@ namespace Kav RenderFullscreenEffect(DeferredAmbientLightEffect); } - public void RenderPointLight( + public void RenderPointLight( RenderTarget2D renderTarget, Texture2D gPosition, Texture2D gAlbedo, Texture2D gNormal, Texture2D gMetallicRoughness, + TextureCube shadowMap, PerspectiveCamera camera, - IEnumerable<(T, Matrix)> modelTransforms, PointLight pointLight - ) where T : ICullable, IIndexDrawable { - RenderPointShadows(PointShadowCubeMap, camera, modelTransforms, pointLight); - + ) { GraphicsDevice.SetRenderTarget(renderTarget); GraphicsDevice.DepthStencilState = DepthStencilState.DepthRead; GraphicsDevice.BlendState = BlendState.Additive; @@ -508,7 +485,7 @@ namespace Kav DeferredPointLightEffect.GAlbedo = gAlbedo; DeferredPointLightEffect.GNormal = gNormal; DeferredPointLightEffect.GMetallicRoughness = gMetallicRoughness; - DeferredPointLightEffect.ShadowMap = PointShadowCubeMap; + DeferredPointLightEffect.ShadowMap = shadowMap; DeferredPointLightEffect.EyePosition = camera.Position; @@ -530,10 +507,8 @@ namespace Kav PerspectiveCamera camera, IEnumerable<(T, Matrix)> modelTransforms, DirectionalLight directionalLight, - int numShadowCascades + DirectionalShadowMapData shadowMapData ) where T : ICullable, IIndexDrawable { - //RenderDirectionalShadows(camera, modelTransforms, directionalLight, DeferredDirectionalLightEffect); - GraphicsDevice.SetRenderTarget(renderTarget); GraphicsDevice.DepthStencilState = DepthStencilState.DepthRead; GraphicsDevice.BlendState = BlendState.Additive; @@ -543,18 +518,25 @@ namespace Kav DeferredDirectionalLightEffect.GNormal = gNormal; DeferredDirectionalLightEffect.GMetallicRoughness = gMetallicRoughness; - DeferredDirectionalLightEffect.ShadowMapOne = ShadowRenderTargets[0]; - if (numShadowCascades > 1) + DeferredDirectionalLightEffect.ShadowMapSize = shadowMapData.ShadowMapSize; + + DeferredDirectionalLightEffect.ShadowMapOne = shadowMapData.ShadowMaps[0]; + DeferredDirectionalLightEffect.LightSpaceMatrixOne = shadowMapData.LightSpaceMatrixOne; + + if (shadowMapData.NumShadowCascades > 1) { - DeferredDirectionalLightEffect.ShadowMapTwo = ShadowRenderTargets[1]; + DeferredDirectionalLightEffect.ShadowMapTwo = shadowMapData.ShadowMaps[1]; + DeferredDirectionalLightEffect.LightSpaceMatrixTwo = shadowMapData.LightSpaceMatrixTwo; } - if (numShadowCascades > 2) + if (shadowMapData.NumShadowCascades > 2) { - DeferredDirectionalLightEffect.ShadowMapThree = ShadowRenderTargets[2]; + DeferredDirectionalLightEffect.ShadowMapThree = shadowMapData.ShadowMaps[2]; + DeferredDirectionalLightEffect.LightSpaceMatrixThree = shadowMapData.LightSpaceMatrixThree; } - if (numShadowCascades > 3) + if (shadowMapData.NumShadowCascades > 3) { - DeferredDirectionalLightEffect.ShadowMapFour = ShadowRenderTargets[3]; + DeferredDirectionalLightEffect.ShadowMapFour = shadowMapData.ShadowMaps[3]; + DeferredDirectionalLightEffect.LightSpaceMatrixFour = shadowMapData.LightSpaceMatrixFour; } DeferredDirectionalLightEffect.DirectionalLightDirection = directionalLight.Direction; @@ -573,14 +555,12 @@ namespace Kav Texture2D gAlbedo, Texture2D gNormal, Texture2D gMetallicRoughness, + DirectionalShadowMapData shadowMapData, PerspectiveCamera camera, IEnumerable<(T, Matrix)> modelTransforms, DirectionalLight directionalLight, - int numShadowCascades, bool ditheredShadows ) where T : ICullable, IIndexDrawable { - //RenderDirectionalShadows(camera, modelTransforms, directionalLight, Deferred_ToonEffect); - GraphicsDevice.SetRenderTarget(renderTarget); GraphicsDevice.DepthStencilState = DepthStencilState.DepthRead; GraphicsDevice.BlendState = BlendState.Additive; @@ -598,18 +578,23 @@ namespace Kav Deferred_ToonEffect.DirectionalLightColor = directionalLight.Color.ToVector3() * directionalLight.Intensity; - Deferred_ToonEffect.ShadowMapOne = ShadowRenderTargets[0]; - if (numShadowCascades > 1) + Deferred_ToonEffect.ShadowMapOne = shadowMapData.ShadowMaps[0]; + Deferred_ToonEffect.LightSpaceMatrixOne = shadowMapData.LightSpaceMatrixOne; + + if (shadowMapData.NumShadowCascades > 1) { - Deferred_ToonEffect.ShadowMapTwo = ShadowRenderTargets[1]; + Deferred_ToonEffect.ShadowMapTwo = shadowMapData.ShadowMaps[1]; + Deferred_ToonEffect.LightSpaceMatrixTwo = shadowMapData.LightSpaceMatrixTwo; } - if (numShadowCascades > 2) + if (shadowMapData.NumShadowCascades > 2) { - Deferred_ToonEffect.ShadowMapThree = ShadowRenderTargets[2]; + Deferred_ToonEffect.ShadowMapThree = shadowMapData.ShadowMaps[2]; + Deferred_ToonEffect.LightSpaceMatrixThree = shadowMapData.LightSpaceMatrixThree; } - if (numShadowCascades > 3) + if (shadowMapData.NumShadowCascades > 3) { - Deferred_ToonEffect.ShadowMapFour = ShadowRenderTargets[3]; + Deferred_ToonEffect.ShadowMapFour = shadowMapData.ShadowMaps[3]; + Deferred_ToonEffect.LightSpaceMatrixFour = shadowMapData.LightSpaceMatrixFour; } Deferred_ToonEffect.ViewMatrix = camera.View; @@ -617,17 +602,17 @@ namespace Kav RenderFullscreenEffect(Deferred_ToonEffect); } - private void RenderDirectionalShadows( + public void RenderDirectionalShadowsIndexed( + DirectionalShadowMapData shadowMapData, PerspectiveCamera camera, - IEnumerable<(Model, Matrix)> modelTransforms, - DirectionalLight directionalLight, - ShadowCascadeEffect effect + IEnumerable<(T, Matrix)> drawableTransforms, + DirectionalLight directionalLight ) where T : ICullable, IIndexDrawable { // render the individual shadow cascades var previousFarPlane = camera.NearPlane; - for (var i = 0; i < NumShadowCascades; i++) + for (var i = 0; i < shadowMapData.NumShadowCascades; i++) { - var farPlane = camera.FarPlane / (MathHelper.Max((NumShadowCascades - i - 1) * 2f, 1f)); + var farPlane = camera.FarPlane / (MathHelper.Max((shadowMapData.NumShadowCascades - i - 1) * 2f, 1f)); // divide the view frustum var shadowCamera = new PerspectiveCamera( @@ -640,23 +625,27 @@ namespace Kav farPlane ); - // TODO: This is tightly coupled to the effect and it sucks - RenderDirectionalShadowMap(shadowCamera, modelTransforms, directionalLight, effect, i); + RenderDirectionalShadowMapIndexed( + shadowMapData, + i, + shadowCamera, + drawableTransforms, + directionalLight + ); - effect.CascadeFarPlanes[i] = farPlane; + shadowMapData.CascadeFarPlanes[i] = farPlane; previousFarPlane = farPlane; } } - private void RenderDirectionalShadowMap( + public void RenderDirectionalShadowMapIndexed( + DirectionalShadowMapData shadowMapData, + int shadowCascadeIndex, PerspectiveCamera camera, - IEnumerable<(Model, Matrix)> modelTransforms, - DirectionalLight directionalLight, - ShadowCascadeEffect effect, - int shadowCascadeIndex - ) { - GraphicsDevice.SetRenderTarget(ShadowRenderTargets[shadowCascadeIndex]); - GraphicsDevice.Clear(Color.White); + IEnumerable<(T, Matrix)> drawableTransforms, + DirectionalLight directionalLight + ) where T : ICullable, IIndexDrawable { + GraphicsDevice.SetRenderTarget(shadowMapData.ShadowMaps[shadowCascadeIndex]); GraphicsDevice.DepthStencilState = DepthStencilState.Default; GraphicsDevice.BlendState = BlendState.Opaque; @@ -693,53 +682,25 @@ namespace Kav if (shadowCascadeIndex == 0) { - effect.LightSpaceMatrixOne = lightSpaceMatrix; + shadowMapData.LightSpaceMatrixOne = lightSpaceMatrix; } else if (shadowCascadeIndex == 1) { - effect.LightSpaceMatrixTwo = lightSpaceMatrix; + shadowMapData.LightSpaceMatrixTwo = lightSpaceMatrix; } else if (shadowCascadeIndex == 2) { - effect.LightSpaceMatrixThree = lightSpaceMatrix; + shadowMapData.LightSpaceMatrixThree = lightSpaceMatrix; } else if (shadowCascadeIndex == 3) { - effect.LightSpaceMatrixFour = lightSpaceMatrix; + shadowMapData.LightSpaceMatrixFour = lightSpaceMatrix; } - var boundingFrustum = new BoundingFrustum(lightSpaceMatrix); - - foreach (var (model, transform) in FrustumCull(boundingFrustum, modelTransforms)) - { - foreach (var modelMesh in model.Meshes) - { - foreach (var meshPart in modelMesh.MeshParts) - { - GraphicsDevice.SetVertexBuffer(meshPart.VertexBuffer); - GraphicsDevice.Indices = meshPart.IndexBuffer; - - SimpleDepthEffect.World = transform; - - foreach (var pass in SimpleDepthEffect.CurrentTechnique.Passes) - { - pass.Apply(); - - GraphicsDevice.DrawIndexedPrimitives( - PrimitiveType.TriangleList, - 0, - 0, - meshPart.VertexBuffer.VertexCount, - 0, - meshPart.Triangles.Length - ); - } - } - } - } + CullAndRenderIndexed(GraphicsDevice, camera, drawableTransforms, SimpleDepthEffect); } - private void RenderPointShadows( + public void RenderPointShadowsIndexed( RenderTargetCube pointShadowCubeMap, PerspectiveCamera camera, IEnumerable<(T, Matrix)> modelTransforms, -- 2.25.1 From 4d3c5fc31688d2e7da6d662b09c3e48af1a30cea Mon Sep 17 00:00:00 2001 From: cosmonaut Date: Tue, 8 Dec 2020 02:49:18 -0800 Subject: [PATCH 10/12] more shadow decoupling + change world instance to position instance --- EffectInterfaces/IHasTranslation.cs | 9 ++ EffectInterfaces/IHasWorldMatrix.cs | 2 +- Effects/FXB/DeferredPBR_GBufferEffect.fxb | 4 +- Effects/FXB/SimpleDepthEffect.fxb | 4 +- Effects/FXB/SimpleDepthEffectInstanced.fxb | 3 + Effects/HLSL/DeferredPBR_GBufferEffect.fx | 21 +-- Effects/HLSL/SimpleDepthEffect.fx | 12 +- Effects/HLSL/SimpleDepthEffectInstanced.fx | 45 ++++++ Effects/SimpleDepthEffect.cs | 28 ---- Effects/SimpleDepthEffectInstanced.cs | 56 +++++++ Geometry/Interfaces/IHasVertexPositions.cs | 9 ++ Geometry/MeshPart.cs | 2 +- Kav.Core.csproj | 3 + Kav.Framework.csproj | 3 + Renderer.cs | 151 ++++++++++++++---- Resources.cs | 13 ++ VertexDeclarations.cs | 7 +- ...nceVertex.cs => PositionInstanceVertex.cs} | 12 +- 18 files changed, 296 insertions(+), 88 deletions(-) create mode 100644 EffectInterfaces/IHasTranslation.cs create mode 100644 Effects/FXB/SimpleDepthEffectInstanced.fxb create mode 100644 Effects/HLSL/SimpleDepthEffectInstanced.fx create mode 100644 Effects/SimpleDepthEffectInstanced.cs create mode 100644 Geometry/Interfaces/IHasVertexPositions.cs rename Vertices/{GBufferInstanceVertex.cs => PositionInstanceVertex.cs} (57%) diff --git a/EffectInterfaces/IHasTranslation.cs b/EffectInterfaces/IHasTranslation.cs new file mode 100644 index 0000000..969cfdb --- /dev/null +++ b/EffectInterfaces/IHasTranslation.cs @@ -0,0 +1,9 @@ +using Microsoft.Xna.Framework; + +namespace Kav +{ + public interface IHasTranslation + { + Vector3 Translation { get; set; } + } +} diff --git a/EffectInterfaces/IHasWorldMatrix.cs b/EffectInterfaces/IHasWorldMatrix.cs index 7f87b42..e7d2bae 100644 --- a/EffectInterfaces/IHasWorldMatrix.cs +++ b/EffectInterfaces/IHasWorldMatrix.cs @@ -1,4 +1,4 @@ -using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework; namespace Kav { diff --git a/Effects/FXB/DeferredPBR_GBufferEffect.fxb b/Effects/FXB/DeferredPBR_GBufferEffect.fxb index 4ad7c73..2012ecb 100644 --- a/Effects/FXB/DeferredPBR_GBufferEffect.fxb +++ b/Effects/FXB/DeferredPBR_GBufferEffect.fxb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7c70594ec60f6f791f6d836d0ca1736284e8158f11ce439a18ad120fc440ad10 -size 9148 +oid sha256:240a1d0911f6bba0da34d5a158c5868e52f6612dc055cdc42d8cef2a5f3febaa +size 8908 diff --git a/Effects/FXB/SimpleDepthEffect.fxb b/Effects/FXB/SimpleDepthEffect.fxb index 8281157..fee70bc 100644 --- a/Effects/FXB/SimpleDepthEffect.fxb +++ b/Effects/FXB/SimpleDepthEffect.fxb @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e0984ae92245afe3e2bda5fab0135293b5121c3ee7b5f146e7d4ddd1684ee74b -size 848 +oid sha256:41083a1789c08363517ab1279e80e985e8fcfc3439411d13df4a5ea4667491e9 +size 1340 diff --git a/Effects/FXB/SimpleDepthEffectInstanced.fxb b/Effects/FXB/SimpleDepthEffectInstanced.fxb new file mode 100644 index 0000000..9c19b29 --- /dev/null +++ b/Effects/FXB/SimpleDepthEffectInstanced.fxb @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6f5eb937af7db2fd9a149ae06981af2a33043abaa5fbb72c8382b4b72097f98f +size 1008 diff --git a/Effects/HLSL/DeferredPBR_GBufferEffect.fx b/Effects/HLSL/DeferredPBR_GBufferEffect.fx index 13c48c2..52f911c 100644 --- a/Effects/HLSL/DeferredPBR_GBufferEffect.fx +++ b/Effects/HLSL/DeferredPBR_GBufferEffect.fx @@ -24,11 +24,6 @@ struct VertexInput float2 TexCoord : TEXCOORD; }; -struct InstanceInput -{ - float4x4 World : TEXCOORD2; -}; - struct PixelInput { float4 Position : SV_POSITION; @@ -61,15 +56,23 @@ PixelInput main_vs(VertexInput input) return output; } -PixelInput instanced_vs(VertexInput input, InstanceInput instanceInput) +PixelInput instanced_vs(VertexInput input, float3 Translation : TEXCOORD2) { PixelInput output; - output.PositionWorld = mul(input.Position, instanceInput.World).xyz; - output.NormalWorld = normalize(mul(input.Normal, instanceInput.World)); + float4x4 world = float4x4( + float4(1, 0, 0, 0), + float4(0, 1, 0, 0), + float4(0, 0, 1, 0), + float4(Translation.x, Translation.y, Translation.z, 1) + ); + + float4x4 worldViewProjection = mul(world, ViewProjection); + + output.PositionWorld = mul(input.Position, world); + output.NormalWorld = mul(input.Normal, world); output.TexCoord = input.TexCoord; - float4x4 worldViewProjection = mul(instanceInput.World, ViewProjection); output.Position = mul(input.Position, worldViewProjection); return output; diff --git a/Effects/HLSL/SimpleDepthEffect.fx b/Effects/HLSL/SimpleDepthEffect.fx index f813bd7..a4c3bbc 100644 --- a/Effects/HLSL/SimpleDepthEffect.fx +++ b/Effects/HLSL/SimpleDepthEffect.fx @@ -2,10 +2,11 @@ BEGIN_CONSTANTS - float4x4 ModelViewProjection _vs(c0) _cb(c0); - MATRIX_CONSTANTS + float4x4 World _vs(c0) _cb(c0); + float4x4 ViewProjection _vs(c4) _cb(c4); + END_CONSTANTS struct VertexShaderInput @@ -15,15 +16,16 @@ struct VertexShaderInput struct VertexShaderOutput { - float4 Position : SV_Position; - float Depth : TEXCOORD0; + float4 Position : SV_POSITION; + float Depth : DEPTH; }; VertexShaderOutput main_vs(VertexShaderInput input) { VertexShaderOutput output; - output.Position = mul(input.Position, ModelViewProjection); + float4x4 worldViewProjection = mul(World, ViewProjection); + output.Position = mul(input.Position, worldViewProjection); output.Depth = output.Position.z / output.Position.w; return output; diff --git a/Effects/HLSL/SimpleDepthEffectInstanced.fx b/Effects/HLSL/SimpleDepthEffectInstanced.fx new file mode 100644 index 0000000..f35471e --- /dev/null +++ b/Effects/HLSL/SimpleDepthEffectInstanced.fx @@ -0,0 +1,45 @@ +float4x4 ViewProjection; + +struct VertexShaderInput +{ + float4 Position : POSITION; +}; + +struct VertexShaderOutput +{ + float4 Position : POSITION0; + float4 ProjectedPosition : TEXCOORD0; +}; + +VertexShaderOutput instanced_vs(VertexShaderInput input, float3 Translation : TEXCOORD2) +{ + VertexShaderOutput output; + + float4x4 world = float4x4( + float4(1, 0, 0, 0), + float4(0, 1, 0, 0), + float4(0, 0, 1, 0), + float4(Translation.x, Translation.y, Translation.z, 1) + ); + + float4x4 worldViewProjection = mul(world, ViewProjection); + + output.Position = mul(input.Position, worldViewProjection); + output.ProjectedPosition = output.Position; + + return output; +} + +float4 main_ps(VertexShaderOutput input) : COLOR0 +{ + return float4(input.ProjectedPosition.z / input.ProjectedPosition.w, 0.0, 0.0, 0.0); +} + +Technique SimpleDepth +{ + Pass + { + VertexShader = compile vs_3_0 instanced_vs(); + PixelShader = compile ps_3_0 main_ps(); + } +} diff --git a/Effects/SimpleDepthEffect.cs b/Effects/SimpleDepthEffect.cs index 200d743..2020c11 100644 --- a/Effects/SimpleDepthEffect.cs +++ b/Effects/SimpleDepthEffect.cs @@ -7,12 +7,10 @@ namespace Kav { EffectParameter worldParam; EffectParameter viewProjectionParam; - EffectParameter vertexShaderIndexParam; Matrix world; Matrix view; Matrix projection; - bool hardwareInstancingEnabled = false; EffectDirtyFlags dirtyFlags = EffectDirtyFlags.All; @@ -46,19 +44,6 @@ namespace Kav } } - public bool HardwareInstancingEnabled - { - get { return hardwareInstancingEnabled; } - set - { - if (value != hardwareInstancingEnabled) - { - hardwareInstancingEnabled = value; - dirtyFlags |= EffectDirtyFlags.VertexShaderIndex; - } - } - } - public SimpleDepthEffect(GraphicsDevice graphicsDevice) : base(graphicsDevice, Resources.SimpleDepthEffect) { CacheEffectParameters(); @@ -80,25 +65,12 @@ namespace Kav dirtyFlags &= ~EffectDirtyFlags.ViewProj; } - - if ((dirtyFlags & EffectDirtyFlags.VertexShaderIndex) != 0) - { - int vertexShaderIndex = 0; - - if (hardwareInstancingEnabled) - { - vertexShaderIndex = 1; - } - - vertexShaderIndexParam.SetValue(vertexShaderIndex); - } } private void CacheEffectParameters() { worldParam = Parameters["World"]; viewProjectionParam = Parameters["ViewProjection"]; - vertexShaderIndexParam = Parameters["VertexShaderIndex"]; } } } diff --git a/Effects/SimpleDepthEffectInstanced.cs b/Effects/SimpleDepthEffectInstanced.cs new file mode 100644 index 0000000..52fc597 --- /dev/null +++ b/Effects/SimpleDepthEffectInstanced.cs @@ -0,0 +1,56 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; + +namespace Kav +{ + public class SimpleDepthEffectInstanced : Effect + { + EffectParameter viewProjectionParam; + + Matrix view; + Matrix projection; + + EffectDirtyFlags dirtyFlags = EffectDirtyFlags.All; + + public Matrix View + { + get { return view; } + set + { + view = value; + dirtyFlags |= EffectDirtyFlags.ViewProj; + } + } + + public Matrix Projection + { + get { return projection; } + set + { + projection = value; + dirtyFlags |= EffectDirtyFlags.ViewProj; + } + } + + public SimpleDepthEffectInstanced(GraphicsDevice graphicsDevice) : base(graphicsDevice, Resources.SimpleDepthEffectInstanced) + { + CacheEffectParameters(); + } + + protected override void OnApply() + { + if ((dirtyFlags & EffectDirtyFlags.ViewProj) != 0) + { + Matrix.Multiply(ref view, ref projection, out Matrix viewProjection); + viewProjectionParam.SetValue(viewProjection); + + dirtyFlags &= ~EffectDirtyFlags.ViewProj; + } + } + + private void CacheEffectParameters() + { + viewProjectionParam = Parameters["ViewProjection"]; + } + } +} diff --git a/Geometry/Interfaces/IHasVertexPositions.cs b/Geometry/Interfaces/IHasVertexPositions.cs new file mode 100644 index 0000000..e39483b --- /dev/null +++ b/Geometry/Interfaces/IHasVertexPositions.cs @@ -0,0 +1,9 @@ +using Microsoft.Xna.Framework; + +namespace Kav +{ + public interface IHasVertexPositions + { + Vector3[] Positions { get; } + } +} diff --git a/Geometry/MeshPart.cs b/Geometry/MeshPart.cs index c8d033b..80f52de 100644 --- a/Geometry/MeshPart.cs +++ b/Geometry/MeshPart.cs @@ -3,7 +3,7 @@ using Microsoft.Xna.Framework.Graphics; namespace Kav { - public class MeshPart : IIndexDrawable, IGBufferDrawable, ICullable + public class MeshPart : IIndexDrawable, IGBufferDrawable, ICullable, IHasVertexPositions { public IndexBuffer IndexBuffer { get; } public VertexBuffer VertexBuffer { get; } diff --git a/Kav.Core.csproj b/Kav.Core.csproj index 9cb9564..6077186 100644 --- a/Kav.Core.csproj +++ b/Kav.Core.csproj @@ -43,6 +43,9 @@ Kav.Resources.SimpleDepthEffect.fxb + + Kav.Resources.SimpleDepthEffectInstanced.fxb + Kav.Resources.LinearDepthEffect.fxb diff --git a/Kav.Framework.csproj b/Kav.Framework.csproj index d5c6c57..60a7849 100644 --- a/Kav.Framework.csproj +++ b/Kav.Framework.csproj @@ -43,6 +43,9 @@ Kav.Resources.SimpleDepthEffect.fxb + + Kav.Resources.SimpleDepthEffectInstanced.fxb + Kav.Resources.LinearDepthEffect.fxb diff --git a/Renderer.cs b/Renderer.cs index fb153dc..a3cb74a 100644 --- a/Renderer.cs +++ b/Renderer.cs @@ -9,7 +9,6 @@ namespace Kav public class Renderer { private const int MAX_INSTANCE_VERTEX_COUNT = 1000000; - private const int MAX_SHADOW_CASCADES = 4; private GraphicsDevice GraphicsDevice { get; } @@ -23,6 +22,7 @@ namespace Kav private DeferredPBR_DirectionalLightEffect DeferredDirectionalLightEffect { get; } private Deferred_ToonEffect Deferred_ToonEffect { get; } private SimpleDepthEffect SimpleDepthEffect { get; } + private SimpleDepthEffectInstanced SimpleDepthEffectInstanced { get; } private LinearDepthEffect LinearDepthEffect { get; } private Effect ToneMapEffect { get; } private SkyboxEffect SkyboxEffect { get; } @@ -30,10 +30,8 @@ namespace Kav private Kav.Model UnitCube { get; } - private SpriteBatch SpriteBatch { get; } - - private DynamicVertexBuffer GBufferInstanceVertexBuffer { get; } - private readonly GBufferInstanceVertex[] GBufferInstanceVertices = new GBufferInstanceVertex[MAX_INSTANCE_VERTEX_COUNT]; + private DynamicVertexBuffer PositionInstanceVertexBuffer { get; } + private readonly PositionInstanceVertex[] GBufferInstanceVertices = new PositionInstanceVertex[MAX_INSTANCE_VERTEX_COUNT]; public Renderer( GraphicsDevice graphicsDevice @@ -41,6 +39,7 @@ namespace Kav GraphicsDevice = graphicsDevice; SimpleDepthEffect = new SimpleDepthEffect(GraphicsDevice); + SimpleDepthEffectInstanced = new SimpleDepthEffectInstanced(GraphicsDevice); LinearDepthEffect = new LinearDepthEffect(GraphicsDevice); DeferredPBREffect = new DeferredPBREffect(GraphicsDevice); @@ -65,11 +64,9 @@ namespace Kav Smuggler.Importer.ImportGLB(GraphicsDevice, new MemoryStream(Resources.UnitCubeModel)) ); - SpriteBatch = new SpriteBatch(graphicsDevice); - - GBufferInstanceVertexBuffer = new DynamicVertexBuffer( + PositionInstanceVertexBuffer = new DynamicVertexBuffer( GraphicsDevice, - VertexDeclarations.GBufferInstanceDeclaration, + VertexDeclarations.PositionInstanceDeclaration, MAX_INSTANCE_VERTEX_COUNT, BufferUsage.WriteOnly ); @@ -203,13 +200,11 @@ namespace Kav // Effect must be pre-configured!! public static void CullAndRenderIndexed( GraphicsDevice graphicsDevice, - PerspectiveCamera camera, + BoundingFrustum boundingFrustum, IEnumerable<(T, Matrix)> drawableTransformPairs, U effect ) where T : IIndexDrawable, ICullable where U : Effect, IHasWorldMatrix { - var boundingFrustum = new BoundingFrustum(camera.View * camera.Projection); - foreach (var (drawable, transform) in FrustumCull(boundingFrustum, drawableTransformPairs)) { effect.World = transform; @@ -253,14 +248,14 @@ namespace Kav IEnumerable transforms, V[] vertexData, DynamicVertexBuffer dynamicVertexBuffer - ) where T : ICullable, IIndexDrawable where V : struct, IVertexType, IHasWorldMatrix + ) where T : ICullable, IIndexDrawable where V : struct, IVertexType, IHasTranslation { var boundingFrustum = new BoundingFrustum(camera.View * camera.Projection); int numInstances = 0; foreach (var transform in FrustumCull(boundingFrustum, drawable, transforms)) { - vertexData[numInstances].World = transform; + vertexData[numInstances].Translation = transform.Translation; numInstances += 1; } @@ -331,7 +326,7 @@ namespace Kav CullAndRenderIndexed( GraphicsDevice, - camera, + new BoundingFrustum(camera.View * camera.Projection), drawableTransforms, SimpleDepthEffect ); @@ -396,7 +391,7 @@ namespace Kav drawable, transforms, GBufferInstanceVertices, - GBufferInstanceVertexBuffer + PositionInstanceVertexBuffer ); RenderInstanced( @@ -407,12 +402,15 @@ namespace Kav ); // re-render to get depth - GraphicsDevice.SetRenderTarget(depthBuffer); + GraphicsDevice.SetRenderTargets(depthBuffer); + + SimpleDepthEffectInstanced.View = camera.View; + SimpleDepthEffectInstanced.Projection = camera.Projection; RenderInstanced( GraphicsDevice, drawable, - Deferred_GBufferEffect, + SimpleDepthEffectInstanced, numInstances ); } @@ -498,17 +496,16 @@ namespace Kav RenderFullscreenEffect(DeferredPointLightEffect); } - public void RenderDirectionalLight( + public void RenderDirectionalLight( RenderTarget2D renderTarget, Texture2D gPosition, Texture2D gAlbedo, Texture2D gNormal, Texture2D gMetallicRoughness, + DirectionalShadowMapData shadowMapData, PerspectiveCamera camera, - IEnumerable<(T, Matrix)> modelTransforms, - DirectionalLight directionalLight, - DirectionalShadowMapData shadowMapData - ) where T : ICullable, IIndexDrawable { + DirectionalLight directionalLight + ) { GraphicsDevice.SetRenderTarget(renderTarget); GraphicsDevice.DepthStencilState = DepthStencilState.DepthRead; GraphicsDevice.BlendState = BlendState.Additive; @@ -522,21 +519,25 @@ namespace Kav DeferredDirectionalLightEffect.ShadowMapOne = shadowMapData.ShadowMaps[0]; DeferredDirectionalLightEffect.LightSpaceMatrixOne = shadowMapData.LightSpaceMatrixOne; + DeferredDirectionalLightEffect.CascadeFarPlanes[0] = shadowMapData.CascadeFarPlanes[0]; if (shadowMapData.NumShadowCascades > 1) { DeferredDirectionalLightEffect.ShadowMapTwo = shadowMapData.ShadowMaps[1]; DeferredDirectionalLightEffect.LightSpaceMatrixTwo = shadowMapData.LightSpaceMatrixTwo; + DeferredDirectionalLightEffect.CascadeFarPlanes[1] = shadowMapData.CascadeFarPlanes[1]; } if (shadowMapData.NumShadowCascades > 2) { DeferredDirectionalLightEffect.ShadowMapThree = shadowMapData.ShadowMaps[2]; DeferredDirectionalLightEffect.LightSpaceMatrixThree = shadowMapData.LightSpaceMatrixThree; + DeferredDirectionalLightEffect.CascadeFarPlanes[2] = shadowMapData.CascadeFarPlanes[2]; } if (shadowMapData.NumShadowCascades > 3) { DeferredDirectionalLightEffect.ShadowMapFour = shadowMapData.ShadowMaps[3]; DeferredDirectionalLightEffect.LightSpaceMatrixFour = shadowMapData.LightSpaceMatrixFour; + DeferredDirectionalLightEffect.CascadeFarPlanes[3] = shadowMapData.CascadeFarPlanes[3]; } DeferredDirectionalLightEffect.DirectionalLightDirection = directionalLight.Direction; @@ -549,7 +550,7 @@ namespace Kav RenderFullscreenEffect(DeferredDirectionalLightEffect); } - public void RenderDirectionalLightToon( + public void RenderDirectionalLightToon( RenderTarget2D renderTarget, Texture2D gPosition, Texture2D gAlbedo, @@ -557,10 +558,9 @@ namespace Kav Texture2D gMetallicRoughness, DirectionalShadowMapData shadowMapData, PerspectiveCamera camera, - IEnumerable<(T, Matrix)> modelTransforms, DirectionalLight directionalLight, bool ditheredShadows - ) where T : ICullable, IIndexDrawable { + ) { GraphicsDevice.SetRenderTarget(renderTarget); GraphicsDevice.DepthStencilState = DepthStencilState.DepthRead; GraphicsDevice.BlendState = BlendState.Additive; @@ -697,10 +697,15 @@ namespace Kav shadowMapData.LightSpaceMatrixFour = lightSpaceMatrix; } - CullAndRenderIndexed(GraphicsDevice, camera, drawableTransforms, SimpleDepthEffect); + CullAndRenderIndexed( + GraphicsDevice, + new BoundingFrustum(lightSpaceMatrix), + drawableTransforms, + SimpleDepthEffect + ); } - public void RenderPointShadowsIndexed( + public void RenderPointShadowMapIndexed( RenderTargetCube pointShadowCubeMap, PerspectiveCamera camera, IEnumerable<(T, Matrix)> modelTransforms, @@ -770,13 +775,101 @@ namespace Kav CullAndRenderIndexed( GraphicsDevice, - camera, + new BoundingFrustum(LinearDepthEffect.View * LinearDepthEffect.Projection), modelTransforms, LinearDepthEffect ); } } + public void RenderPointShadowMapInstanced( + RenderTargetCube pointShadowCubeMap, + PerspectiveCamera camera, + T drawable, + IEnumerable modelTransforms, + PointLight pointLight + ) where T : ICullable, IIndexDrawable + { + GraphicsDevice.DepthStencilState = DepthStencilState.Default; + GraphicsDevice.BlendState = BlendState.Opaque; + + foreach (CubeMapFace face in Enum.GetValues(typeof(CubeMapFace))) + { + GraphicsDevice.SetRenderTarget(pointShadowCubeMap, face); + + Vector3 targetDirection; + Vector3 targetUpDirection; + switch(face) + { + case CubeMapFace.PositiveX: + targetDirection = Vector3.Right; + targetUpDirection = Vector3.Up; + break; + + case CubeMapFace.NegativeX: + targetDirection = Vector3.Left; + targetUpDirection = Vector3.Up; + break; + + case CubeMapFace.PositiveY: + targetDirection = Vector3.Up; + targetUpDirection = Vector3.Forward; + break; + + case CubeMapFace.NegativeY: + targetDirection = Vector3.Down; + targetUpDirection = Vector3.Backward; + break; + + case CubeMapFace.PositiveZ: + targetDirection = Vector3.Backward; + targetUpDirection = Vector3.Up; + break; + + case CubeMapFace.NegativeZ: + targetDirection = Vector3.Forward; + targetUpDirection = Vector3.Up; + break; + + default: + targetDirection = Vector3.Right; + targetUpDirection = Vector3.Up; + break; + } + + LinearDepthEffect.View = Matrix.CreateLookAt( + pointLight.Position, + pointLight.Position + targetDirection, + targetUpDirection + ); + LinearDepthEffect.Projection = Matrix.CreatePerspectiveFieldOfView( + MathHelper.PiOver2, + 1, + 0.1f, + 25f // FIXME: magic value + ); + LinearDepthEffect.FarPlane = 25f; + + LinearDepthEffect.LightPosition = pointLight.Position; + + // TODO: set up instancing + // var numInstances = FillAndSetBuffersForInstancing( + // GraphicsDevice, + // camera, + // drawable, + // transforms, + // VertexPos + // ); + + // RenderInstanced( + // GraphicsDevice, + // camera, + // modelTransforms, + // LinearDepthEffect + // ); + } + } + private static IEnumerable<(T, Matrix)> FrustumCull( BoundingFrustum boundingFrustum, IEnumerable<(T, Matrix)> cullableTransforms diff --git a/Resources.cs b/Resources.cs index 44c28f7..2924998 100644 --- a/Resources.cs +++ b/Resources.cs @@ -111,6 +111,18 @@ namespace Kav } } + public static byte[] SimpleDepthEffectInstanced + { + get + { + if (simpleDepthEffectInstanced == null) + { + simpleDepthEffectInstanced = GetResource("SimpleDepthEffectInstanced.fxb"); + } + return simpleDepthEffectInstanced; + } + } + public static byte[] LinearDepthEffect { get @@ -168,6 +180,7 @@ namespace Kav private static byte[] deferredPBREffect; private static byte[] pbrEffect; private static byte[] simpleDepthEffect; + private static byte[] simpleDepthEffectInstanced; private static byte[] linearDepthEffect; private static byte[] skyboxEffect; private static byte[] diffuseLitSpriteEffect; diff --git a/VertexDeclarations.cs b/VertexDeclarations.cs index d77327b..f8b073f 100644 --- a/VertexDeclarations.cs +++ b/VertexDeclarations.cs @@ -4,12 +4,9 @@ namespace Kav { public static class VertexDeclarations { - public static VertexDeclaration GBufferInstanceDeclaration = new VertexDeclaration + public static VertexDeclaration PositionInstanceDeclaration = new VertexDeclaration ( - new VertexElement(0, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 2), - new VertexElement(16, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 3), - new VertexElement(32, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 4), - new VertexElement(48, VertexElementFormat.Vector4, VertexElementUsage.TextureCoordinate, 5) + new VertexElement(0, VertexElementFormat.Vector3, VertexElementUsage.TextureCoordinate, 2) ); } } diff --git a/Vertices/GBufferInstanceVertex.cs b/Vertices/PositionInstanceVertex.cs similarity index 57% rename from Vertices/GBufferInstanceVertex.cs rename to Vertices/PositionInstanceVertex.cs index 32ae321..f173cef 100644 --- a/Vertices/GBufferInstanceVertex.cs +++ b/Vertices/PositionInstanceVertex.cs @@ -5,24 +5,24 @@ using Microsoft.Xna.Framework.Graphics; namespace Kav { [StructLayout(LayoutKind.Sequential, Pack = 1)] - public struct GBufferInstanceVertex : IVertexType, IHasWorldMatrix + public struct PositionInstanceVertex : IVertexType, IHasTranslation { VertexDeclaration IVertexType.VertexDeclaration { get { - return VertexDeclarations.GBufferInstanceDeclaration; + return VertexDeclarations.PositionInstanceDeclaration; } } - public Matrix World { get; set; } + public Vector3 Translation { get; set; } public static readonly VertexDeclaration VertexDeclaration; - public GBufferInstanceVertex( - Matrix world + public PositionInstanceVertex( + Vector3 translation ) { - World = world; + Translation = translation; } } } -- 2.25.1 From 4b7d31f2b2a841d2514092afa4f8f7e38a132d45 Mon Sep 17 00:00:00 2001 From: cosmonaut Date: Tue, 8 Dec 2020 03:07:41 -0800 Subject: [PATCH 11/12] refactor directional shadow data --- DirectionalShadowMapData.cs | 9 ++-- Renderer.cs | 93 +++++++++++++++++++------------------ 2 files changed, 52 insertions(+), 50 deletions(-) diff --git a/DirectionalShadowMapData.cs b/DirectionalShadowMapData.cs index 4eca964..455d7d1 100644 --- a/DirectionalShadowMapData.cs +++ b/DirectionalShadowMapData.cs @@ -9,10 +9,8 @@ namespace Kav public RenderTarget2D[] ShadowMaps { get; } - public Matrix LightSpaceMatrixOne { get; set; } - public Matrix LightSpaceMatrixTwo { get; set; } - public Matrix LightSpaceMatrixThree { get; set; } - public Matrix LightSpaceMatrixFour { get; set; } + public Matrix[] LightSpaceViews { get; } + public Matrix[] LightSpaceProjections { get; } public float[] CascadeFarPlanes { get; } @@ -27,6 +25,9 @@ namespace Kav ShadowMapSize = shadowMapSize; NumShadowCascades = (int)MathHelper.Clamp(numCascades, 1, MAX_SHADOW_CASCADES); + LightSpaceViews = new Matrix[4]; + LightSpaceProjections = new Matrix[4]; + ShadowMaps = new RenderTarget2D[NumShadowCascades]; for (var i = 0; i < NumShadowCascades; i++) diff --git a/Renderer.cs b/Renderer.cs index a3cb74a..2cc799f 100644 --- a/Renderer.cs +++ b/Renderer.cs @@ -518,25 +518,25 @@ namespace Kav DeferredDirectionalLightEffect.ShadowMapSize = shadowMapData.ShadowMapSize; DeferredDirectionalLightEffect.ShadowMapOne = shadowMapData.ShadowMaps[0]; - DeferredDirectionalLightEffect.LightSpaceMatrixOne = shadowMapData.LightSpaceMatrixOne; + DeferredDirectionalLightEffect.LightSpaceMatrixOne = shadowMapData.LightSpaceViews[0] * shadowMapData.LightSpaceProjections[0]; DeferredDirectionalLightEffect.CascadeFarPlanes[0] = shadowMapData.CascadeFarPlanes[0]; if (shadowMapData.NumShadowCascades > 1) { DeferredDirectionalLightEffect.ShadowMapTwo = shadowMapData.ShadowMaps[1]; - DeferredDirectionalLightEffect.LightSpaceMatrixTwo = shadowMapData.LightSpaceMatrixTwo; + DeferredDirectionalLightEffect.LightSpaceMatrixTwo = shadowMapData.LightSpaceViews[1] * shadowMapData.LightSpaceProjections[1]; DeferredDirectionalLightEffect.CascadeFarPlanes[1] = shadowMapData.CascadeFarPlanes[1]; } if (shadowMapData.NumShadowCascades > 2) { DeferredDirectionalLightEffect.ShadowMapThree = shadowMapData.ShadowMaps[2]; - DeferredDirectionalLightEffect.LightSpaceMatrixThree = shadowMapData.LightSpaceMatrixThree; + DeferredDirectionalLightEffect.LightSpaceMatrixThree = shadowMapData.LightSpaceViews[2] * shadowMapData.LightSpaceProjections[2]; DeferredDirectionalLightEffect.CascadeFarPlanes[2] = shadowMapData.CascadeFarPlanes[2]; } if (shadowMapData.NumShadowCascades > 3) { DeferredDirectionalLightEffect.ShadowMapFour = shadowMapData.ShadowMaps[3]; - DeferredDirectionalLightEffect.LightSpaceMatrixFour = shadowMapData.LightSpaceMatrixFour; + DeferredDirectionalLightEffect.LightSpaceMatrixFour = shadowMapData.LightSpaceViews[3] * shadowMapData.LightSpaceProjections[3]; DeferredDirectionalLightEffect.CascadeFarPlanes[3] = shadowMapData.CascadeFarPlanes[3]; } @@ -579,22 +579,22 @@ namespace Kav directionalLight.Color.ToVector3() * directionalLight.Intensity; Deferred_ToonEffect.ShadowMapOne = shadowMapData.ShadowMaps[0]; - Deferred_ToonEffect.LightSpaceMatrixOne = shadowMapData.LightSpaceMatrixOne; + Deferred_ToonEffect.LightSpaceMatrixOne = shadowMapData.LightSpaceViews[0] * shadowMapData.LightSpaceProjections[0]; if (shadowMapData.NumShadowCascades > 1) { Deferred_ToonEffect.ShadowMapTwo = shadowMapData.ShadowMaps[1]; - Deferred_ToonEffect.LightSpaceMatrixTwo = shadowMapData.LightSpaceMatrixTwo; + Deferred_ToonEffect.LightSpaceMatrixTwo = shadowMapData.LightSpaceViews[1] * shadowMapData.LightSpaceProjections[1]; } if (shadowMapData.NumShadowCascades > 2) { Deferred_ToonEffect.ShadowMapThree = shadowMapData.ShadowMaps[2]; - Deferred_ToonEffect.LightSpaceMatrixThree = shadowMapData.LightSpaceMatrixThree; + Deferred_ToonEffect.LightSpaceMatrixThree = shadowMapData.LightSpaceViews[1] * shadowMapData.LightSpaceProjections[2]; } if (shadowMapData.NumShadowCascades > 3) { Deferred_ToonEffect.ShadowMapFour = shadowMapData.ShadowMaps[3]; - Deferred_ToonEffect.LightSpaceMatrixFour = shadowMapData.LightSpaceMatrixFour; + Deferred_ToonEffect.LightSpaceMatrixFour = shadowMapData.LightSpaceViews[2] * shadowMapData.LightSpaceProjections[3]; } Deferred_ToonEffect.ViewMatrix = camera.View; @@ -602,13 +602,11 @@ namespace Kav RenderFullscreenEffect(Deferred_ToonEffect); } - public void RenderDirectionalShadowsIndexed( + public void PrepareDirectionalShadowData( DirectionalShadowMapData shadowMapData, PerspectiveCamera camera, - IEnumerable<(T, Matrix)> drawableTransforms, DirectionalLight directionalLight - ) where T : ICullable, IIndexDrawable { - // render the individual shadow cascades + ) { var previousFarPlane = camera.NearPlane; for (var i = 0; i < shadowMapData.NumShadowCascades; i++) { @@ -625,11 +623,10 @@ namespace Kav farPlane ); - RenderDirectionalShadowMapIndexed( - shadowMapData, - i, - shadowCamera, - drawableTransforms, + PrepareDirectionalShadowCascade( + shadowMapData, + i, + shadowCamera, directionalLight ); @@ -638,18 +635,13 @@ namespace Kav } } - public void RenderDirectionalShadowMapIndexed( + private void PrepareDirectionalShadowCascade( DirectionalShadowMapData shadowMapData, int shadowCascadeIndex, - PerspectiveCamera camera, - IEnumerable<(T, Matrix)> drawableTransforms, + PerspectiveCamera shadowCamera, DirectionalLight directionalLight - ) where T : ICullable, IIndexDrawable { - GraphicsDevice.SetRenderTarget(shadowMapData.ShadowMaps[shadowCascadeIndex]); - GraphicsDevice.DepthStencilState = DepthStencilState.Default; - GraphicsDevice.BlendState = BlendState.Opaque; - - var cameraBoundingFrustum = new BoundingFrustum(camera.View * camera.Projection); + ) { + var cameraBoundingFrustum = new BoundingFrustum(shadowCamera.View * shadowCamera.Projection); Vector3[] frustumCorners = cameraBoundingFrustum.GetCorners(); Vector3 frustumCenter = Vector3.Zero; @@ -668,8 +660,8 @@ namespace Kav BoundingBox lightBox = BoundingBox.CreateFromPoints(frustumCorners); - SimpleDepthEffect.View = lightView; - SimpleDepthEffect.Projection = Matrix.CreateOrthographicOffCenter( + shadowMapData.LightSpaceViews[shadowCascadeIndex] = lightView; + shadowMapData.LightSpaceProjections[shadowCascadeIndex] = Matrix.CreateOrthographicOffCenter( lightBox.Min.X, lightBox.Max.X, lightBox.Min.Y, @@ -677,29 +669,38 @@ namespace Kav -lightBox.Max.Z - 10f, // TODO: near clip plane needs scene AABB info to get rid of this magic value -lightBox.Min.Z ); + } - var lightSpaceMatrix = SimpleDepthEffect.View * SimpleDepthEffect.Projection; + public void RenderDirectionalShadowsIndexed( + DirectionalShadowMapData shadowMapData, + IEnumerable<(T, Matrix)> drawableTransforms + ) where T : ICullable, IIndexDrawable { + // render the individual shadow cascades + for (var i = 0; i < shadowMapData.NumShadowCascades; i++) + { + RenderDirectionalShadowMapIndexed( + shadowMapData, + i, + drawableTransforms + ); + } + } - if (shadowCascadeIndex == 0) - { - shadowMapData.LightSpaceMatrixOne = lightSpaceMatrix; - } - else if (shadowCascadeIndex == 1) - { - shadowMapData.LightSpaceMatrixTwo = lightSpaceMatrix; - } - else if (shadowCascadeIndex == 2) - { - shadowMapData.LightSpaceMatrixThree = lightSpaceMatrix; - } - else if (shadowCascadeIndex == 3) - { - shadowMapData.LightSpaceMatrixFour = lightSpaceMatrix; - } + public void RenderDirectionalShadowMapIndexed( + DirectionalShadowMapData shadowMapData, + int shadowCascadeIndex, + IEnumerable<(T, Matrix)> drawableTransforms + ) where T : ICullable, IIndexDrawable { + GraphicsDevice.SetRenderTarget(shadowMapData.ShadowMaps[shadowCascadeIndex]); + GraphicsDevice.DepthStencilState = DepthStencilState.Default; + GraphicsDevice.BlendState = BlendState.Opaque; + + SimpleDepthEffect.View = shadowMapData.LightSpaceViews[shadowCascadeIndex]; + SimpleDepthEffect.Projection = shadowMapData.LightSpaceProjections[shadowCascadeIndex]; CullAndRenderIndexed( GraphicsDevice, - new BoundingFrustum(lightSpaceMatrix), + new BoundingFrustum(SimpleDepthEffect.View * SimpleDepthEffect.Projection), drawableTransforms, SimpleDepthEffect ); -- 2.25.1 From 14e07c74768bb5a1432b27d089de28f1ec5c2710 Mon Sep 17 00:00:00 2001 From: cosmonaut Date: Tue, 8 Dec 2020 03:35:06 -0800 Subject: [PATCH 12/12] instanced directional shadows --- Renderer.cs | 61 +++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 54 insertions(+), 7 deletions(-) diff --git a/Renderer.cs b/Renderer.cs index 2cc799f..5eabb74 100644 --- a/Renderer.cs +++ b/Renderer.cs @@ -31,7 +31,7 @@ namespace Kav private Kav.Model UnitCube { get; } private DynamicVertexBuffer PositionInstanceVertexBuffer { get; } - private readonly PositionInstanceVertex[] GBufferInstanceVertices = new PositionInstanceVertex[MAX_INSTANCE_VERTEX_COUNT]; + private readonly PositionInstanceVertex[] PositionInstanceVertices = new PositionInstanceVertex[MAX_INSTANCE_VERTEX_COUNT]; public Renderer( GraphicsDevice graphicsDevice @@ -243,15 +243,13 @@ namespace Kav public static int FillAndSetBuffersForInstancing( GraphicsDevice graphicsDevice, - PerspectiveCamera camera, + BoundingFrustum boundingFrustum, T drawable, IEnumerable transforms, V[] vertexData, DynamicVertexBuffer dynamicVertexBuffer ) where T : ICullable, IIndexDrawable where V : struct, IVertexType, IHasTranslation { - var boundingFrustum = new BoundingFrustum(camera.View * camera.Projection); - int numInstances = 0; foreach (var transform in FrustumCull(boundingFrustum, drawable, transforms)) { @@ -387,10 +385,10 @@ namespace Kav var numInstances = FillAndSetBuffersForInstancing( GraphicsDevice, - camera, + new BoundingFrustum(camera.View * camera.Projection), drawable, transforms, - GBufferInstanceVertices, + PositionInstanceVertices, PositionInstanceVertexBuffer ); @@ -686,7 +684,7 @@ namespace Kav } } - public void RenderDirectionalShadowMapIndexed( + private void RenderDirectionalShadowMapIndexed( DirectionalShadowMapData shadowMapData, int shadowCascadeIndex, IEnumerable<(T, Matrix)> drawableTransforms @@ -706,6 +704,55 @@ namespace Kav ); } + public void RenderDirectionalShadowsInstanced( + DirectionalShadowMapData shadowMapData, + T drawable, + IEnumerable transforms + ) where T : ICullable, IIndexDrawable + { + // render the individual shadow cascades + for (var i = 0; i < shadowMapData.NumShadowCascades; i++) + { + RenderDirectionalShadowMapInstanced( + shadowMapData, + i, + drawable, + transforms + ); + } + } + + private void RenderDirectionalShadowMapInstanced( + DirectionalShadowMapData shadowMapData, + int shadowCascadeIndex, + T drawable, + IEnumerable transforms + ) where T : ICullable, IIndexDrawable + { + GraphicsDevice.SetRenderTarget(shadowMapData.ShadowMaps[shadowCascadeIndex]); + GraphicsDevice.DepthStencilState = DepthStencilState.Default; + GraphicsDevice.BlendState = BlendState.Opaque; + + SimpleDepthEffectInstanced.View = shadowMapData.LightSpaceViews[shadowCascadeIndex]; + SimpleDepthEffectInstanced.Projection = shadowMapData.LightSpaceProjections[shadowCascadeIndex]; + + var numInstances = FillAndSetBuffersForInstancing( + GraphicsDevice, + new BoundingFrustum(SimpleDepthEffectInstanced.View * SimpleDepthEffectInstanced.Projection), + drawable, + transforms, + PositionInstanceVertices, + PositionInstanceVertexBuffer + ); + + RenderInstanced( + GraphicsDevice, + drawable, + SimpleDepthEffectInstanced, + numInstances + ); + } + public void RenderPointShadowMapIndexed( RenderTargetCube pointShadowCubeMap, PerspectiveCamera camera, -- 2.25.1