started adding support for instanced draws + started decoupling API

instancing
cosmonaut 2020-12-07 01:30:09 -08:00
parent c9a4e35816
commit ee8b0c5ee8
13 changed files with 353 additions and 92 deletions

View File

@ -17,6 +17,7 @@ namespace Kav
EffectParameter metallicParam; EffectParameter metallicParam;
EffectParameter roughnessParam; EffectParameter roughnessParam;
EffectParameter vertexShaderIndexParam;
EffectParameter shaderIndexParam; EffectParameter shaderIndexParam;
Matrix world = Matrix.Identity; Matrix world = Matrix.Identity;
@ -30,6 +31,7 @@ namespace Kav
bool albedoTextureEnabled = false; bool albedoTextureEnabled = false;
bool metallicRoughnessMapEnabled = false; bool metallicRoughnessMapEnabled = false;
bool normalMapEnabled = false; bool normalMapEnabled = false;
bool hardwareInstancingEnabled = false;
EffectDirtyFlags dirtyFlags = EffectDirtyFlags.All; EffectDirtyFlags dirtyFlags = EffectDirtyFlags.All;
@ -100,7 +102,7 @@ namespace Kav
{ {
albedoTextureParam.SetValue(value); albedoTextureParam.SetValue(value);
albedoTextureEnabled = value != null; albedoTextureEnabled = value != null;
dirtyFlags |= EffectDirtyFlags.ShaderIndex; dirtyFlags |= EffectDirtyFlags.PixelShaderIndex;
} }
} }
@ -111,7 +113,7 @@ namespace Kav
{ {
normalTextureParam.SetValue(value); normalTextureParam.SetValue(value);
normalMapEnabled = value != null; normalMapEnabled = value != null;
dirtyFlags |= EffectDirtyFlags.ShaderIndex; dirtyFlags |= EffectDirtyFlags.PixelShaderIndex;
} }
} }
@ -122,7 +124,20 @@ namespace Kav
{ {
metallicRoughnessTextureParam.SetValue(value); metallicRoughnessTextureParam.SetValue(value);
metallicRoughnessMapEnabled = value != null; 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; 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; int shaderIndex = 0;
@ -217,7 +237,7 @@ namespace Kav
shaderIndexParam.SetValue(shaderIndex); shaderIndexParam.SetValue(shaderIndex);
dirtyFlags &= ~EffectDirtyFlags.ShaderIndex; dirtyFlags &= ~EffectDirtyFlags.PixelShaderIndex;
} }
} }
@ -235,7 +255,8 @@ namespace Kav
metallicParam = Parameters["MetallicValue"]; metallicParam = Parameters["MetallicValue"];
roughnessParam = Parameters["RoughnessValue"]; roughnessParam = Parameters["RoughnessValue"];
shaderIndexParam = Parameters["ShaderIndex"]; shaderIndexParam = Parameters["PixelShaderIndex"];
vertexShaderIndexParam = Parameters["VertexShaderIndex"];
} }
} }
} }

View File

@ -40,7 +40,7 @@ namespace Kav
if (normalMapEnabled != value) if (normalMapEnabled != value)
{ {
normalMapEnabled = value; normalMapEnabled = value;
dirtyFlags |= EffectDirtyFlags.ShaderIndex; dirtyFlags |= EffectDirtyFlags.PixelShaderIndex;
} }
} }
} }
@ -142,7 +142,7 @@ namespace Kav
dirtyFlags &= ~EffectDirtyFlags.WorldViewProj; dirtyFlags &= ~EffectDirtyFlags.WorldViewProj;
} }
if ((dirtyFlags & EffectDirtyFlags.ShaderIndex) != 0) if ((dirtyFlags & EffectDirtyFlags.PixelShaderIndex) != 0)
{ {
int shaderIndex = 0; int shaderIndex = 0;

View File

@ -8,7 +8,8 @@ namespace Kav
WorldViewProj = 1, WorldViewProj = 1,
World = 2, World = 2,
EyePosition = 4, EyePosition = 4,
ShaderIndex = 8, VertexShaderIndex = 8,
PixelShaderIndex = 16,
All = -1 All = -1
} }
} }

BIN
Effects/FXB/DeferredPBR_GBufferEffect.fxb (Stored with Git LFS)

Binary file not shown.

View File

@ -25,6 +25,13 @@ struct VertexInput
float2 TexCoord : TEXCOORD0; float2 TexCoord : TEXCOORD0;
}; };
struct InstanceInput
{
float4x4 World : TEXCOORD0;
float4x4 WorldInverseTranspose : TEXCOORD1;
float4x4 WorldViewProjection : TEXCOORD2;
};
struct PixelInput struct PixelInput
{ {
float4 Position : SV_POSITION; float4 Position : SV_POSITION;
@ -55,6 +62,18 @@ PixelInput main_vs(VertexInput input)
return output; 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 // Pixel Shaders
// Easy trick to get tangent-normals to world-space to keep PBR code simplified. // Easy trick to get tangent-normals to world-space to keep PBR code simplified.
@ -171,6 +190,19 @@ PixelOutput AlbedoMetallicRoughnessNormalMapPS(PixelInput input)
return output; 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] = PixelShader PSArray[8] =
{ {
compile ps_3_0 NonePS(), compile ps_3_0 NonePS(),
@ -191,13 +223,13 @@ int PSIndices[8] =
0, 1, 2, 3, 4, 5, 6, 7 0, 1, 2, 3, 4, 5, 6, 7
}; };
int ShaderIndex = 0; int PixelShaderIndex = 0;
Technique GBuffer Technique GBuffer
{ {
Pass Pass
{ {
VertexShader = compile vs_3_0 main_vs(); VertexShader = (VSArray[VSIndices[VertexShaderIndex]]);
PixelShader = (PSArray[PSIndices[ShaderIndex]]); PixelShader = (PSArray[PSIndices[PixelShaderIndex]]);
} }
} }

View File

@ -130,7 +130,7 @@ namespace Kav
{ {
albedoTextureParam.SetValue(value); albedoTextureParam.SetValue(value);
albedoTextureEnabled = value != null; albedoTextureEnabled = value != null;
dirtyFlags |= EffectDirtyFlags.ShaderIndex; dirtyFlags |= EffectDirtyFlags.PixelShaderIndex;
} }
} }
@ -141,7 +141,7 @@ namespace Kav
{ {
normalTextureParam.SetValue(value); normalTextureParam.SetValue(value);
normalMapEnabled = value != null; normalMapEnabled = value != null;
dirtyFlags |= EffectDirtyFlags.ShaderIndex; dirtyFlags |= EffectDirtyFlags.PixelShaderIndex;
} }
} }
@ -164,7 +164,7 @@ namespace Kav
{ {
metallicRoughnessTextureParam.SetValue(value); metallicRoughnessTextureParam.SetValue(value);
metallicRoughnessMapEnabled = value != null; metallicRoughnessMapEnabled = value != null;
dirtyFlags |= EffectDirtyFlags.ShaderIndex; dirtyFlags |= EffectDirtyFlags.PixelShaderIndex;
} }
} }
@ -266,7 +266,7 @@ namespace Kav
dirtyFlags &= ~EffectDirtyFlags.EyePosition; dirtyFlags &= ~EffectDirtyFlags.EyePosition;
} }
if ((dirtyFlags & EffectDirtyFlags.ShaderIndex) != 0) if ((dirtyFlags & EffectDirtyFlags.PixelShaderIndex) != 0)
{ {
int shaderIndex = 0; int shaderIndex = 0;
@ -301,7 +301,7 @@ namespace Kav
shaderIndexParam.SetValue(shaderIndex); shaderIndexParam.SetValue(shaderIndex);
dirtyFlags &= ~EffectDirtyFlags.ShaderIndex; dirtyFlags &= ~EffectDirtyFlags.PixelShaderIndex;
} }
} }

View File

@ -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; }
}
}

View File

@ -0,0 +1,10 @@
using Microsoft.Xna.Framework.Graphics;
namespace Kav
{
public interface IIndexDrawable
{
VertexBuffer VertexBuffer { get; }
IndexBuffer IndexBuffer { get; }
}
}

View File

@ -3,7 +3,7 @@ using Microsoft.Xna.Framework.Graphics;
namespace Kav namespace Kav
{ {
public class MeshPart public class MeshPart : IIndexDrawable
{ {
public IndexBuffer IndexBuffer { get; } public IndexBuffer IndexBuffer { get; }
public VertexBuffer VertexBuffer { get; } public VertexBuffer VertexBuffer { get; }
@ -11,27 +11,27 @@ namespace Kav
public Vector3[] Positions { get; } public Vector3[] Positions { get; }
public BoundingBox BoundingBox { get; } public BoundingBox BoundingBox { get; }
private Texture2D albedoTexture = null; private Texture2D albedoTexture = null;
private Texture2D normalTexture = null; private Texture2D normalTexture = null;
private Texture2D metallicRoughnessTexture = null; private Texture2D metallicRoughnessTexture = null;
public Texture2D AlbedoTexture public Texture2D AlbedoTexture
{ {
get { return DisableAlbedoMap ? null : albedoTexture; } get { return DisableAlbedoMap ? null : albedoTexture; }
set { albedoTexture = value; } set { albedoTexture = value; }
} }
public Texture2D NormalTexture public Texture2D NormalTexture
{ {
get { return DisableNormalMap ? null : normalTexture; } get { return DisableNormalMap ? null : normalTexture; }
set { normalTexture = value; } set { normalTexture = value; }
} }
public Texture2D MetallicRoughnessTexture public Texture2D MetallicRoughnessTexture
{ {
get { return DisableMetallicRoughnessMap ? null : metallicRoughnessTexture; } get { return DisableMetallicRoughnessMap ? null : metallicRoughnessTexture; }
set { metallicRoughnessTexture = value; } set { metallicRoughnessTexture = value; }
} }
public Vector3 Albedo { get; set; } = Vector3.One; public Vector3 Albedo { get; set; } = Vector3.One;

View File

@ -4,7 +4,7 @@ using Microsoft.Xna.Framework.Graphics;
namespace Kav namespace Kav
{ {
public class MeshSprite : ICullable public class MeshSprite : ICullable, IIndexDrawable
{ {
private static readonly int PixelScale = 40; private static readonly int PixelScale = 40;
private static readonly short[] Indices = new short[] private static readonly short[] Indices = new short[]

View File

@ -8,18 +8,16 @@ namespace Kav
{ {
public class Renderer public class Renderer
{ {
private const int MAX_INSTANCE_VERTEX_COUNT = 1000000;
private const int MAX_SHADOW_CASCADES = 4; private const int MAX_SHADOW_CASCADES = 4;
private int ShadowMapSize { get; } private int ShadowMapSize { get; }
private GraphicsDevice GraphicsDevice { get; } private GraphicsDevice GraphicsDevice { get; }
private int RenderDimensionsX { get; }
private int RenderDimensionsY { get; }
private VertexBuffer FullscreenTriangle { get; } private VertexBuffer FullscreenTriangle { get; }
private int NumShadowCascades { get; } private int NumShadowCascades { get; }
private RenderTarget2D ColorRenderTarget { get; } private RenderTarget2D ColorRenderTarget { get; }
private RenderTarget2D DirectionalRenderTarget { get; }
private RenderTarget2D[] ShadowRenderTargets { get; } private RenderTarget2D[] ShadowRenderTargets { get; }
private DeferredPBREffect DeferredPBREffect { get; } private DeferredPBREffect DeferredPBREffect { get; }
@ -35,10 +33,10 @@ namespace Kav
private SkyboxEffect SkyboxEffect { get; } private SkyboxEffect SkyboxEffect { get; }
private DiffuseLitSpriteEffect DiffuseLitSpriteEffect { get; } private DiffuseLitSpriteEffect DiffuseLitSpriteEffect { get; }
private RenderTarget2D gPosition { get; } private RenderTarget2D GPosition { get; }
private RenderTarget2D gNormal { get; } private RenderTarget2D GNormal { get; }
private RenderTarget2D gAlbedo { get; } private RenderTarget2D GAlbedo { get; }
private RenderTarget2D gMetallicRoughness { get; } private RenderTarget2D GMetallicRoughness { get; }
private RenderTargetCube PointShadowCubeMap { get; } private RenderTargetCube PointShadowCubeMap { get; }
private RenderTargetBinding[] GBuffer { get; } private RenderTargetBinding[] GBuffer { get; }
@ -47,6 +45,9 @@ namespace Kav
private SpriteBatch SpriteBatch { get; } private SpriteBatch SpriteBatch { get; }
private DynamicVertexBuffer GBufferInstanceVertexBuffer { get; }
private readonly GBufferInstanceVertex[] GBufferInstanceVertices = new GBufferInstanceVertex[MAX_INSTANCE_VERTEX_COUNT];
public Renderer( public Renderer(
GraphicsDevice graphicsDevice, GraphicsDevice graphicsDevice,
int renderDimensionsX, int renderDimensionsX,
@ -55,8 +56,6 @@ namespace Kav
int shadowMapSize int shadowMapSize
) { ) {
GraphicsDevice = graphicsDevice; GraphicsDevice = graphicsDevice;
RenderDimensionsX = renderDimensionsX;
RenderDimensionsY = renderDimensionsY;
ShadowMapSize = shadowMapSize; ShadowMapSize = shadowMapSize;
@ -86,18 +85,7 @@ namespace Kav
RenderTargetUsage.PreserveContents RenderTargetUsage.PreserveContents
); );
DirectionalRenderTarget = new RenderTarget2D( GPosition = new RenderTarget2D(
graphicsDevice,
renderDimensionsX,
renderDimensionsY,
false,
SurfaceFormat.Color,
DepthFormat.None,
0,
RenderTargetUsage.PreserveContents
);
gPosition = new RenderTarget2D(
GraphicsDevice, GraphicsDevice,
renderDimensionsX, renderDimensionsX,
renderDimensionsY, renderDimensionsY,
@ -106,7 +94,7 @@ namespace Kav
DepthFormat.Depth24 DepthFormat.Depth24
); );
gNormal = new RenderTarget2D( GNormal = new RenderTarget2D(
GraphicsDevice, GraphicsDevice,
renderDimensionsX, renderDimensionsX,
renderDimensionsY, renderDimensionsY,
@ -115,7 +103,7 @@ namespace Kav
DepthFormat.None DepthFormat.None
); );
gAlbedo = new RenderTarget2D( GAlbedo = new RenderTarget2D(
GraphicsDevice, GraphicsDevice,
renderDimensionsX, renderDimensionsX,
renderDimensionsY, renderDimensionsY,
@ -124,7 +112,7 @@ namespace Kav
DepthFormat.None DepthFormat.None
); );
gMetallicRoughness = new RenderTarget2D( GMetallicRoughness = new RenderTarget2D(
GraphicsDevice, GraphicsDevice,
renderDimensionsX, renderDimensionsX,
renderDimensionsY, renderDimensionsY,
@ -134,10 +122,10 @@ namespace Kav
); );
GBuffer = new RenderTargetBinding[4] { GBuffer = new RenderTargetBinding[4] {
new RenderTargetBinding(gPosition), new RenderTargetBinding(GPosition),
new RenderTargetBinding(gNormal), new RenderTargetBinding(GNormal),
new RenderTargetBinding(gAlbedo), new RenderTargetBinding(GAlbedo),
new RenderTargetBinding(gMetallicRoughness) new RenderTargetBinding(GMetallicRoughness)
}; };
PointShadowCubeMap = new RenderTargetCube( PointShadowCubeMap = new RenderTargetCube(
@ -175,6 +163,13 @@ namespace Kav
); );
SpriteBatch = new SpriteBatch(graphicsDevice); SpriteBatch = new SpriteBatch(graphicsDevice);
GBufferInstanceVertexBuffer = new DynamicVertexBuffer(
GraphicsDevice,
VertexDeclarations.GBufferInstanceDeclaration,
MAX_INSTANCE_VERTEX_COUNT,
BufferUsage.WriteOnly
);
} }
public void DeferredRender( public void DeferredRender(
@ -185,23 +180,47 @@ namespace Kav
IEnumerable<PointLight> pointLights, IEnumerable<PointLight> pointLights,
DirectionalLight? directionalLight DirectionalLight? directionalLight
) { ) {
GBufferRender(camera, modelTransforms); GBufferRender(GBuffer, camera, modelTransforms);
GraphicsDevice.SetRenderTarget(ColorRenderTarget); GraphicsDevice.SetRenderTarget(ColorRenderTarget);
GraphicsDevice.Clear(Color.Black); GraphicsDevice.Clear(Color.Black);
AmbientLightRender(ambientLight); AmbientLightRender(
ColorRenderTarget,
GPosition,
GAlbedo,
ambientLight
);
DeferredPointLightEffect.EyePosition = camera.Position; DeferredPointLightEffect.EyePosition = camera.Position;
foreach (var pointLight in pointLights) foreach (var pointLight in pointLights)
{ {
PointLightRender(camera, modelTransforms, pointLight); PointLightRender(
ColorRenderTarget,
GPosition,
GAlbedo,
GNormal,
GMetallicRoughness,
camera,
modelTransforms,
pointLight
);
} }
if (directionalLight.HasValue) if (directionalLight.HasValue)
{ {
DirectionalLightRender(camera, modelTransforms, directionalLight.Value); DirectionalLightRender(
ColorRenderTarget,
GPosition,
GAlbedo,
GNormal,
GMetallicRoughness,
camera,
modelTransforms,
directionalLight.Value,
NumShadowCascades
);
} }
GraphicsDevice.SetRenderTarget(renderTarget); GraphicsDevice.SetRenderTarget(renderTarget);
@ -219,7 +238,7 @@ namespace Kav
DirectionalLight? directionalLight, DirectionalLight? directionalLight,
TextureCube skybox TextureCube skybox
) { ) {
GBufferRender(camera, modelTransforms); GBufferRender(GBuffer, camera, modelTransforms);
GraphicsDevice.SetRenderTarget(ColorRenderTarget); GraphicsDevice.SetRenderTarget(ColorRenderTarget);
GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.Black, 1f, 0); GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.Black, 1f, 0);
@ -228,18 +247,44 @@ namespace Kav
DepthRender(camera, modelTransforms); DepthRender(camera, modelTransforms);
GraphicsDevice.DepthStencilState = DepthStencilState.DepthRead; GraphicsDevice.DepthStencilState = DepthStencilState.DepthRead;
AmbientLightRender(ambientLight); AmbientLightRender(
ColorRenderTarget,
GPosition,
GAlbedo,
ambientLight
);
foreach (var pointLight in pointLights) foreach (var pointLight in pointLights)
{ {
PointLightRender(camera, modelTransforms, pointLight); PointLightRender(
ColorRenderTarget,
GPosition,
GAlbedo,
GNormal,
GMetallicRoughness,
camera,
modelTransforms,
pointLight
);
} }
if (directionalLight.HasValue) 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); GraphicsDevice.SetRenderTarget(renderTarget);
SpriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Opaque, null, null, null, null); SpriteBatch.Begin(SpriteSortMode.Deferred, BlendState.Opaque, null, null, null, null);
@ -394,9 +439,11 @@ namespace Kav
} }
private void SkyboxRender( private void SkyboxRender(
RenderTarget2D renderTarget,
PerspectiveCamera camera, PerspectiveCamera camera,
TextureCube skybox TextureCube skybox
) { ) {
GraphicsDevice.SetRenderTarget(renderTarget);
GraphicsDevice.RasterizerState.CullMode = CullMode.CullClockwiseFace; GraphicsDevice.RasterizerState.CullMode = CullMode.CullClockwiseFace;
SkyboxEffect.Skybox = skybox; SkyboxEffect.Skybox = skybox;
@ -425,12 +472,68 @@ namespace Kav
GraphicsDevice.RasterizerState.CullMode = CullMode.CullCounterClockwiseFace; GraphicsDevice.RasterizerState.CullMode = CullMode.CullCounterClockwiseFace;
} }
private void GBufferRender( /// <summary>
/// GBuffer binding must have 4 render targets.
/// </summary>
public void InstancedGBufferRender<T>(
RenderTargetBinding[] gBuffer,
PerspectiveCamera camera,
T drawable,
int numInstances,
IEnumerable<Matrix> 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, PerspectiveCamera camera,
IEnumerable<(Model, Matrix)> modelTransforms IEnumerable<(Model, Matrix)> modelTransforms
) { ) {
GraphicsDevice.SetRenderTargets(GBuffer); GraphicsDevice.SetRenderTargets(gBuffer);
GraphicsDevice.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.Black, 1f, 0);
GraphicsDevice.DepthStencilState = DepthStencilState.Default; GraphicsDevice.DepthStencilState = DepthStencilState.Default;
GraphicsDevice.BlendState = BlendState.Opaque; GraphicsDevice.BlendState = BlendState.Opaque;
@ -475,9 +578,13 @@ namespace Kav
} }
} }
private void AmbientLightRender(AmbientLight ambientLight) public void AmbientLightRender(
{ RenderTarget2D renderTarget,
GraphicsDevice.SetRenderTarget(ColorRenderTarget); Texture2D gPosition,
Texture2D gAlbedo,
AmbientLight ambientLight
) {
GraphicsDevice.SetRenderTarget(renderTarget);
GraphicsDevice.BlendState = BlendState.Opaque; GraphicsDevice.BlendState = BlendState.Opaque;
DeferredAmbientLightEffect.GPosition = gPosition; 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, PerspectiveCamera camera,
IEnumerable<(Model, Matrix)> modelTransforms, IEnumerable<(Model, Matrix)> modelTransforms,
PointLight pointLight PointLight pointLight
) { ) {
RenderPointShadows(camera, modelTransforms, pointLight); RenderPointShadows(camera, modelTransforms, pointLight);
GraphicsDevice.SetRenderTarget(ColorRenderTarget); GraphicsDevice.SetRenderTarget(renderTarget);
GraphicsDevice.DepthStencilState = DepthStencilState.DepthRead; GraphicsDevice.DepthStencilState = DepthStencilState.DepthRead;
GraphicsDevice.BlendState = BlendState.Additive; 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, PerspectiveCamera camera,
IEnumerable<(Model, Matrix)> modelTransforms, IEnumerable<(Model, Matrix)> modelTransforms,
DirectionalLight directionalLight DirectionalLight directionalLight,
int numShadowCascades
) { ) {
RenderDirectionalShadows(camera, modelTransforms, directionalLight, DeferredDirectionalLightEffect); RenderDirectionalShadows(camera, modelTransforms, directionalLight, DeferredDirectionalLightEffect);
GraphicsDevice.SetRenderTarget(renderTarget);
GraphicsDevice.DepthStencilState = DepthStencilState.DepthRead;
GraphicsDevice.BlendState = BlendState.Additive;
DeferredDirectionalLightEffect.GPosition = gPosition; DeferredDirectionalLightEffect.GPosition = gPosition;
DeferredDirectionalLightEffect.GAlbedo = gAlbedo; DeferredDirectionalLightEffect.GAlbedo = gAlbedo;
DeferredDirectionalLightEffect.GNormal = gNormal; DeferredDirectionalLightEffect.GNormal = gNormal;
DeferredDirectionalLightEffect.GMetallicRoughness = gMetallicRoughness; DeferredDirectionalLightEffect.GMetallicRoughness = gMetallicRoughness;
DeferredDirectionalLightEffect.ShadowMapOne = ShadowRenderTargets[0]; DeferredDirectionalLightEffect.ShadowMapOne = ShadowRenderTargets[0];
if (NumShadowCascades > 1) if (numShadowCascades > 1)
{ {
DeferredDirectionalLightEffect.ShadowMapTwo = ShadowRenderTargets[1]; DeferredDirectionalLightEffect.ShadowMapTwo = ShadowRenderTargets[1];
} }
if (NumShadowCascades > 2) if (numShadowCascades > 2)
{ {
DeferredDirectionalLightEffect.ShadowMapThree = ShadowRenderTargets[2]; DeferredDirectionalLightEffect.ShadowMapThree = ShadowRenderTargets[2];
} }
if (NumShadowCascades > 3) if (numShadowCascades > 3)
{ {
DeferredDirectionalLightEffect.ShadowMapFour = ShadowRenderTargets[3]; DeferredDirectionalLightEffect.ShadowMapFour = ShadowRenderTargets[3];
} }
@ -556,9 +678,6 @@ namespace Kav
DeferredDirectionalLightEffect.ViewMatrix = camera.View; DeferredDirectionalLightEffect.ViewMatrix = camera.View;
DeferredDirectionalLightEffect.EyePosition = camera.Position; DeferredDirectionalLightEffect.EyePosition = camera.Position;
GraphicsDevice.SetRenderTarget(ColorRenderTarget);
GraphicsDevice.BlendState = BlendState.Additive;
foreach (EffectPass pass in DeferredDirectionalLightEffect.CurrentTechnique.Passes) foreach (EffectPass pass in DeferredDirectionalLightEffect.CurrentTechnique.Passes)
{ {
pass.Apply(); pass.Apply();
@ -568,13 +687,20 @@ namespace Kav
} }
private void DirectionalLightToonRender( private void DirectionalLightToonRender(
RenderTarget2D renderTarget,
Texture2D gPosition,
Texture2D gAlbedo,
Texture2D gNormal,
Texture2D gMetallicRoughness,
PerspectiveCamera camera, PerspectiveCamera camera,
IEnumerable<(Model, Matrix)> modelTransforms, IEnumerable<(Model, Matrix)> modelTransforms,
DirectionalLight directionalLight DirectionalLight directionalLight,
int numShadowCascades,
bool ditheredShadows
) { ) {
RenderDirectionalShadows(camera, modelTransforms, directionalLight, Deferred_ToonEffect); RenderDirectionalShadows(camera, modelTransforms, directionalLight, Deferred_ToonEffect);
GraphicsDevice.SetRenderTarget(ColorRenderTarget); GraphicsDevice.SetRenderTarget(renderTarget);
GraphicsDevice.DepthStencilState = DepthStencilState.DepthRead; GraphicsDevice.DepthStencilState = DepthStencilState.DepthRead;
GraphicsDevice.BlendState = BlendState.Additive; GraphicsDevice.BlendState = BlendState.Additive;
@ -583,7 +709,7 @@ namespace Kav
Deferred_ToonEffect.GNormal = gNormal; Deferred_ToonEffect.GNormal = gNormal;
Deferred_ToonEffect.GMetallicRoughness = gMetallicRoughness; Deferred_ToonEffect.GMetallicRoughness = gMetallicRoughness;
Deferred_ToonEffect.DitheredShadows = false; Deferred_ToonEffect.DitheredShadows = ditheredShadows;
Deferred_ToonEffect.EyePosition = camera.Position; Deferred_ToonEffect.EyePosition = camera.Position;
@ -592,15 +718,15 @@ namespace Kav
directionalLight.Color.ToVector3() * directionalLight.Intensity; directionalLight.Color.ToVector3() * directionalLight.Intensity;
Deferred_ToonEffect.ShadowMapOne = ShadowRenderTargets[0]; Deferred_ToonEffect.ShadowMapOne = ShadowRenderTargets[0];
if (NumShadowCascades > 1) if (numShadowCascades > 1)
{ {
Deferred_ToonEffect.ShadowMapTwo = ShadowRenderTargets[1]; Deferred_ToonEffect.ShadowMapTwo = ShadowRenderTargets[1];
} }
if (NumShadowCascades > 2) if (numShadowCascades > 2)
{ {
Deferred_ToonEffect.ShadowMapThree = ShadowRenderTargets[2]; Deferred_ToonEffect.ShadowMapThree = ShadowRenderTargets[2];
} }
if (NumShadowCascades > 3) if (numShadowCascades > 3)
{ {
Deferred_ToonEffect.ShadowMapFour = ShadowRenderTargets[3]; Deferred_ToonEffect.ShadowMapFour = ShadowRenderTargets[3];
} }

23
VertexDeclarations.cs Normal file
View File

@ -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)
);
}
}

View File

@ -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;
}
}
}