major API refactor

instancing
cosmonaut 2020-12-07 20:10:27 -08:00
parent fe222e266f
commit 84601379b5
5 changed files with 282 additions and 260 deletions

View File

@ -0,0 +1,9 @@
using Microsoft.Xna.Framework;
namespace Kav
{
public interface IHasWorldMatrix
{
Matrix World { get; set; }
}
}

View File

@ -3,28 +3,28 @@ using Microsoft.Xna.Framework.Graphics;
namespace Kav namespace Kav
{ {
public class LinearDepthEffect : Effect public class LinearDepthEffect : Effect, IHasWorldMatrix
{ {
EffectParameter modelParam; EffectParameter worldParam;
EffectParameter modelViewProjectionParam; EffectParameter worldViewProjectionParam;
EffectParameter lightPositionParam; EffectParameter lightPositionParam;
EffectParameter farPlaneParam; EffectParameter farPlaneParam;
EffectDirtyFlags dirtyFlags = EffectDirtyFlags.All; EffectDirtyFlags dirtyFlags = EffectDirtyFlags.All;
Matrix model; Matrix world;
Matrix view; Matrix view;
Matrix projection; Matrix projection;
public Vector3 LightPosition { get; set; } public Vector3 LightPosition { get; set; }
public float FarPlane { get; set; } public float FarPlane { get; set; }
public Matrix Model public Matrix World
{ {
get { return model; } get { return world; }
set set
{ {
model = value; world = value;
dirtyFlags |= EffectDirtyFlags.World; dirtyFlags |= EffectDirtyFlags.World;
dirtyFlags |= EffectDirtyFlags.WorldViewProj; dirtyFlags |= EffectDirtyFlags.WorldViewProj;
} }
@ -60,16 +60,16 @@ namespace Kav
if ((dirtyFlags & EffectDirtyFlags.WorldViewProj) != 0) if ((dirtyFlags & EffectDirtyFlags.WorldViewProj) != 0)
{ {
Matrix.Multiply(ref view, ref projection, out Matrix viewProjection); 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; dirtyFlags &= ~EffectDirtyFlags.WorldViewProj;
} }
if ((dirtyFlags & EffectDirtyFlags.World) != 0) if ((dirtyFlags & EffectDirtyFlags.World) != 0)
{ {
modelParam.SetValue(model); worldParam.SetValue(world);
dirtyFlags &= ~EffectDirtyFlags.World; dirtyFlags &= ~EffectDirtyFlags.World;
} }
@ -80,8 +80,8 @@ namespace Kav
private void CacheEffectParameters() private void CacheEffectParameters()
{ {
modelParam = Parameters["Model"]; worldParam = Parameters["Model"];
modelViewProjectionParam = Parameters["ModelViewProjection"]; worldViewProjectionParam = Parameters["ModelViewProjection"];
lightPositionParam = Parameters["LightPosition"]; lightPositionParam = Parameters["LightPosition"];
farPlaneParam = Parameters["FarPlane"]; farPlaneParam = Parameters["FarPlane"];

View File

@ -3,23 +3,26 @@ using Microsoft.Xna.Framework.Graphics;
namespace Kav 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 view;
Matrix projection; Matrix projection;
bool hardwareInstancingEnabled = false;
EffectDirtyFlags dirtyFlags = EffectDirtyFlags.All; EffectDirtyFlags dirtyFlags = EffectDirtyFlags.All;
public Matrix Model public Matrix World
{ {
get { return model; } get { return world; }
set set
{ {
model = value; world = value;
dirtyFlags |= EffectDirtyFlags.WorldViewProj; dirtyFlags |= EffectDirtyFlags.World;
} }
} }
@ -29,7 +32,7 @@ namespace Kav
set set
{ {
view = value; view = value;
dirtyFlags |= EffectDirtyFlags.WorldViewProj; dirtyFlags |= EffectDirtyFlags.ViewProj;
} }
} }
@ -39,7 +42,20 @@ namespace Kav
set set
{ {
projection = value; 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() 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 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() private void CacheEffectParameters()
{ {
modelViewProjectionParam = Parameters["ModelViewProjection"]; worldParam = Parameters["World"];
viewProjectionParam = Parameters["ViewProjection"];
vertexShaderIndexParam = Parameters["VertexShaderIndex"];
} }
} }
} }

View File

@ -220,48 +220,145 @@ namespace Kav
} }
} }
public void DepthRender( // Renders a series of drawable-transform pairs using an effect that has a World matrix.
RenderTarget2D renderTarget, // Effect must be pre-configured!!
public static void CullAndRenderIndexed<T, U>(
GraphicsDevice graphicsDevice,
PerspectiveCamera camera, PerspectiveCamera camera,
IEnumerable<(Model, Matrix)> modelTransforms IEnumerable<(T, Matrix)> drawableTransformPairs,
) { U effect
GraphicsDevice.SetRenderTarget(renderTarget); ) where T : IIndexDrawable, ICullable where U : Effect, IHasWorldMatrix
GraphicsDevice.DepthStencilState = DepthStencilState.Default; {
var boundingFrustum = new BoundingFrustum(camera.View * 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, drawableTransformPairs))
{ {
foreach (var modelMesh in model.Meshes) effect.World = transform;
{
foreach (var meshPart in modelMesh.MeshParts)
{
SimpleDepthEffect.World = transform;
SimpleDepthEffect.View = camera.View;
SimpleDepthEffect.Projection = camera.Projection;
GraphicsDevice.SetVertexBuffer(meshPart.VertexBuffer); RenderIndexed(
GraphicsDevice.Indices = meshPart.IndexBuffer; graphicsDevice,
drawable,
foreach (var pass in SimpleDepthEffect.CurrentTechnique.Passes) effect
{ );
pass.Apply();
GraphicsDevice.DrawIndexedPrimitives(
PrimitiveType.TriangleList,
0,
0,
meshPart.VertexBuffer.VertexCount,
0,
meshPart.Triangles.Length
);
}
}
}
} }
} }
public void SkyboxRender( public static void RenderIndexed<T, U>(
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<T, V>(
GraphicsDevice graphicsDevice,
PerspectiveCamera camera,
T drawable,
IEnumerable<Matrix> 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<T, U>(
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<T>(
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, RenderTarget2D renderTarget,
PerspectiveCamera camera, PerspectiveCamera camera,
TextureCube skybox TextureCube skybox
@ -274,41 +371,29 @@ namespace Kav
var view = camera.View; var view = camera.View;
view.Translation = Vector3.Zero; view.Translation = Vector3.Zero;
SkyboxEffect.View = view;
SkyboxEffect.View = view;
SkyboxEffect.Projection = camera.Projection; SkyboxEffect.Projection = camera.Projection;
GraphicsDevice.SetVertexBuffer(UnitCube.Meshes[0].MeshParts[0].VertexBuffer); RenderIndexed(
GraphicsDevice.Indices = UnitCube.Meshes[0].MeshParts[0].IndexBuffer; 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; GraphicsDevice.RasterizerState.CullMode = CullMode.CullCounterClockwiseFace;
} }
/// <summary> /// <summary>
/// GBuffer binding must have 4 render targets. /// GBuffer binding must have 4 render targets.
/// </summary> /// </summary>
public void InstancedGBufferRender<T>( public void RenderGBufferInstanced<T>(
RenderTargetBinding[] gBuffer, RenderTargetBinding[] gBuffer,
RenderTarget2D depthBuffer, RenderTarget2D depthBuffer,
PerspectiveCamera camera, PerspectiveCamera camera,
T drawable, T drawable,
IEnumerable<Matrix> transforms IEnumerable<Matrix> transforms
) where T : ICullable, IIndexDrawable, IGBufferDrawable { ) where T : ICullable, IIndexDrawable, IGBufferDrawable {
int numInstances = 0;
GraphicsDevice.SetRenderTargets(gBuffer); GraphicsDevice.SetRenderTargets(gBuffer);
GraphicsDevice.DepthStencilState = DepthStencilState.Default; GraphicsDevice.DepthStencilState = DepthStencilState.Default;
GraphicsDevice.BlendState = BlendState.Opaque; GraphicsDevice.BlendState = BlendState.Opaque;
@ -326,132 +411,67 @@ namespace Kav
Deferred_GBufferEffect.View = camera.View; Deferred_GBufferEffect.View = camera.View;
Deferred_GBufferEffect.Projection = camera.Projection; Deferred_GBufferEffect.Projection = camera.Projection;
var boundingFrustum = new BoundingFrustum(camera.View * camera.Projection); var numInstances = FillAndSetBuffersForInstancing(
GraphicsDevice,
foreach (var transform in FrustumCull(boundingFrustum, drawable, transforms)) camera,
{ drawable,
GBufferInstanceVertices[numInstances].World = transform; transforms,
numInstances += 1;
}
if (numInstances == 0) { return; }
GBufferInstanceVertexBuffer.SetData(
GBufferInstanceVertices, GBufferInstanceVertices,
0, GBufferInstanceVertexBuffer
numInstances,
SetDataOptions.Discard
); );
GraphicsDevice.SetVertexBuffers( RenderInstanced(
drawable.VertexBuffer, GraphicsDevice,
new VertexBufferBinding(GBufferInstanceVertexBuffer, 0, 1) 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); GraphicsDevice.SetRenderTarget(depthBuffer);
foreach (var pass in Deferred_GBufferEffect.CurrentTechnique.Passes) RenderInstanced(
{ GraphicsDevice,
pass.Apply(); drawable,
GraphicsDevice.DrawInstancedPrimitives( Deferred_GBufferEffect,
PrimitiveType.TriangleList, numInstances
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( public void RenderGBufferIndexed<T>(
RenderTargetBinding[] gBuffer, RenderTargetBinding[] gBuffer,
PerspectiveCamera camera, PerspectiveCamera camera,
IEnumerable<(Model, Matrix)> modelTransforms IEnumerable<(T, Matrix)> drawableTransforms
) { ) where T : ICullable, IIndexDrawable, IGBufferDrawable {
GraphicsDevice.SetRenderTargets(gBuffer); GraphicsDevice.SetRenderTargets(gBuffer);
GraphicsDevice.DepthStencilState = DepthStencilState.Default; GraphicsDevice.DepthStencilState = DepthStencilState.Default;
GraphicsDevice.BlendState = BlendState.Opaque; 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); 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) Deferred_GBufferEffect.World = transform;
{
foreach (var meshPart in modelMesh.MeshParts)
{
Deferred_GBufferEffect.World = transform;
Deferred_GBufferEffect.View = camera.View;
Deferred_GBufferEffect.Projection = camera.Projection;
Deferred_GBufferEffect.HardwareInstancingEnabled = false; Deferred_GBufferEffect.HardwareInstancingEnabled = false;
Deferred_GBufferEffect.Albedo = meshPart.Albedo; Deferred_GBufferEffect.Albedo = drawable.Albedo;
Deferred_GBufferEffect.Metallic = meshPart.Metallic; Deferred_GBufferEffect.Metallic = drawable.Metallic;
Deferred_GBufferEffect.Roughness = meshPart.Roughness; Deferred_GBufferEffect.Roughness = drawable.Roughness;
Deferred_GBufferEffect.AlbedoTexture = meshPart.AlbedoTexture; Deferred_GBufferEffect.AlbedoTexture = drawable.AlbedoTexture;
Deferred_GBufferEffect.NormalTexture = meshPart.NormalTexture; Deferred_GBufferEffect.NormalTexture = drawable.NormalTexture;
Deferred_GBufferEffect.MetallicRoughnessTexture = meshPart.MetallicRoughnessTexture; Deferred_GBufferEffect.MetallicRoughnessTexture = drawable.MetallicRoughnessTexture;
GraphicsDevice.SetVertexBuffer(meshPart.VertexBuffer); RenderIndexed(GraphicsDevice, drawable, Deferred_GBufferEffect);
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
);
}
}
}
} }
} }
public void AmbientLightRender( public void RenderAmbientLight(
RenderTarget2D renderTarget, RenderTarget2D renderTarget,
Texture2D gPosition, Texture2D gPosition,
Texture2D gAlbedo, Texture2D gAlbedo,
@ -465,25 +485,20 @@ namespace Kav
DeferredAmbientLightEffect.GAlbedo = gAlbedo; DeferredAmbientLightEffect.GAlbedo = gAlbedo;
DeferredAmbientLightEffect.AmbientColor = ambientLight.Color.ToVector3(); DeferredAmbientLightEffect.AmbientColor = ambientLight.Color.ToVector3();
foreach (var pass in DeferredAmbientLightEffect.CurrentTechnique.Passes) RenderFullscreenEffect(DeferredAmbientLightEffect);
{
pass.Apply();
GraphicsDevice.SetVertexBuffer(FullscreenTriangle);
GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, 1);
}
} }
public void PointLightRender( public void RenderPointLight<T>(
RenderTarget2D renderTarget, RenderTarget2D renderTarget,
Texture2D gPosition, Texture2D gPosition,
Texture2D gAlbedo, Texture2D gAlbedo,
Texture2D gNormal, Texture2D gNormal,
Texture2D gMetallicRoughness, Texture2D gMetallicRoughness,
PerspectiveCamera camera, PerspectiveCamera camera,
IEnumerable<(Model, Matrix)> modelTransforms, IEnumerable<(T, Matrix)> modelTransforms,
PointLight pointLight PointLight pointLight
) { ) where T : ICullable, IIndexDrawable {
RenderPointShadows(camera, modelTransforms, pointLight); RenderPointShadows(PointShadowCubeMap, camera, modelTransforms, pointLight);
GraphicsDevice.SetRenderTarget(renderTarget); GraphicsDevice.SetRenderTarget(renderTarget);
GraphicsDevice.DepthStencilState = DepthStencilState.DepthRead; GraphicsDevice.DepthStencilState = DepthStencilState.DepthRead;
@ -503,26 +518,21 @@ namespace Kav
DeferredPointLightEffect.FarPlane = 25f; // FIXME: magic value DeferredPointLightEffect.FarPlane = 25f; // FIXME: magic value
foreach (var pass in DeferredPointLightEffect.CurrentTechnique.Passes) RenderFullscreenEffect(DeferredPointLightEffect);
{
pass.Apply();
GraphicsDevice.SetVertexBuffer(FullscreenTriangle);
GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, 1);
}
} }
public void DirectionalLightRender( public void RenderDirectionalLight<T>(
RenderTarget2D renderTarget, RenderTarget2D renderTarget,
Texture2D gPosition, Texture2D gPosition,
Texture2D gAlbedo, Texture2D gAlbedo,
Texture2D gNormal, Texture2D gNormal,
Texture2D gMetallicRoughness, Texture2D gMetallicRoughness,
PerspectiveCamera camera, PerspectiveCamera camera,
IEnumerable<(Model, Matrix)> modelTransforms, IEnumerable<(T, Matrix)> modelTransforms,
DirectionalLight directionalLight, DirectionalLight directionalLight,
int numShadowCascades int numShadowCascades
) { ) where T : ICullable, IIndexDrawable {
RenderDirectionalShadows(camera, modelTransforms, directionalLight, DeferredDirectionalLightEffect); //RenderDirectionalShadows(camera, modelTransforms, directionalLight, DeferredDirectionalLightEffect);
GraphicsDevice.SetRenderTarget(renderTarget); GraphicsDevice.SetRenderTarget(renderTarget);
GraphicsDevice.DepthStencilState = DepthStencilState.DepthRead; GraphicsDevice.DepthStencilState = DepthStencilState.DepthRead;
@ -554,27 +564,22 @@ namespace Kav
DeferredDirectionalLightEffect.ViewMatrix = camera.View; DeferredDirectionalLightEffect.ViewMatrix = camera.View;
DeferredDirectionalLightEffect.EyePosition = camera.Position; DeferredDirectionalLightEffect.EyePosition = camera.Position;
foreach (EffectPass pass in DeferredDirectionalLightEffect.CurrentTechnique.Passes) RenderFullscreenEffect(DeferredDirectionalLightEffect);
{
pass.Apply();
GraphicsDevice.SetVertexBuffer(FullscreenTriangle);
GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, 1);
}
} }
public void DirectionalLightToonRender( public void RenderDirectionalLightToon<T>(
RenderTarget2D renderTarget, RenderTarget2D renderTarget,
Texture2D gPosition, Texture2D gPosition,
Texture2D gAlbedo, Texture2D gAlbedo,
Texture2D gNormal, Texture2D gNormal,
Texture2D gMetallicRoughness, Texture2D gMetallicRoughness,
PerspectiveCamera camera, PerspectiveCamera camera,
IEnumerable<(Model, Matrix)> modelTransforms, IEnumerable<(T, Matrix)> modelTransforms,
DirectionalLight directionalLight, DirectionalLight directionalLight,
int numShadowCascades, int numShadowCascades,
bool ditheredShadows bool ditheredShadows
) { ) where T : ICullable, IIndexDrawable {
RenderDirectionalShadows(camera, modelTransforms, directionalLight, Deferred_ToonEffect); //RenderDirectionalShadows(camera, modelTransforms, directionalLight, Deferred_ToonEffect);
GraphicsDevice.SetRenderTarget(renderTarget); GraphicsDevice.SetRenderTarget(renderTarget);
GraphicsDevice.DepthStencilState = DepthStencilState.DepthRead; GraphicsDevice.DepthStencilState = DepthStencilState.DepthRead;
@ -609,20 +614,15 @@ namespace Kav
Deferred_ToonEffect.ViewMatrix = camera.View; Deferred_ToonEffect.ViewMatrix = camera.View;
foreach (EffectPass pass in Deferred_ToonEffect.CurrentTechnique.Passes) RenderFullscreenEffect(Deferred_ToonEffect);
{
pass.Apply();
GraphicsDevice.SetVertexBuffer(FullscreenTriangle);
GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, 1);
}
} }
private void RenderDirectionalShadows( private void RenderDirectionalShadows<T>(
PerspectiveCamera camera, PerspectiveCamera camera,
IEnumerable<(Model, Matrix)> modelTransforms, IEnumerable<(Model, Matrix)> modelTransforms,
DirectionalLight directionalLight, DirectionalLight directionalLight,
ShadowCascadeEffect effect ShadowCascadeEffect effect
) { ) where T : ICullable, IIndexDrawable {
// render the individual shadow cascades // render the individual shadow cascades
var previousFarPlane = camera.NearPlane; var previousFarPlane = camera.NearPlane;
for (var i = 0; i < NumShadowCascades; i++) for (var i = 0; i < NumShadowCascades; i++)
@ -739,26 +739,18 @@ namespace Kav
} }
} }
private void RenderPointShadows( private void RenderPointShadows<T>(
RenderTargetCube pointShadowCubeMap,
PerspectiveCamera camera, PerspectiveCamera camera,
IEnumerable<(Model, Matrix)> modelTransforms, IEnumerable<(T, Matrix)> modelTransforms,
PointLight pointLight PointLight pointLight
) { ) where T : ICullable, IIndexDrawable {
GraphicsDevice.DepthStencilState = DepthStencilState.Default; GraphicsDevice.DepthStencilState = DepthStencilState.Default;
GraphicsDevice.BlendState = BlendState.Opaque; 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))) foreach (CubeMapFace face in Enum.GetValues(typeof(CubeMapFace)))
{ {
GraphicsDevice.SetRenderTarget(PointShadowCubeMap, face); GraphicsDevice.SetRenderTarget(pointShadowCubeMap, face);
Vector3 targetDirection; Vector3 targetDirection;
Vector3 targetUpDirection; Vector3 targetUpDirection;
@ -805,36 +797,22 @@ namespace Kav
pointLight.Position + targetDirection, pointLight.Position + targetDirection,
targetUpDirection 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)) CullAndRenderIndexed(
{ GraphicsDevice,
foreach (var modelMesh in model.Meshes) camera,
{ modelTransforms,
foreach (var meshPart in modelMesh.MeshParts) LinearDepthEffect
{ );
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
);
}
}
}
}
} }
} }

View File

@ -5,7 +5,7 @@ using Microsoft.Xna.Framework.Graphics;
namespace Kav namespace Kav
{ {
[StructLayout(LayoutKind.Sequential, Pack = 1)] [StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct GBufferInstanceVertex : IVertexType public struct GBufferInstanceVertex : IVertexType, IHasWorldMatrix
{ {
VertexDeclaration IVertexType.VertexDeclaration VertexDeclaration IVertexType.VertexDeclaration
{ {