From ee8b0c5ee840bf180f1498a0cd9e81b94e4598cd Mon Sep 17 00:00:00 2001 From: cosmonaut Date: Mon, 7 Dec 2020 01:30:09 -0800 Subject: [PATCH] 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; + } + } +}