shadow refactor

instancing
cosmonaut 2020-12-07 21:36:16 -08:00
parent 84601379b5
commit 96f6d22896
2 changed files with 146 additions and 127 deletions

View File

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

View File

@ -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<T>(
public void RenderDepthIndexed<T>(
RenderTarget2D renderTarget,
PerspectiveCamera camera,
IEnumerable<(T, Matrix)> drawableTransforms
@ -488,18 +467,16 @@ namespace Kav
RenderFullscreenEffect(DeferredAmbientLightEffect);
}
public void RenderPointLight<T>(
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<T>(
public void RenderDirectionalShadowsIndexed<T>(
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<T>(
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<T>(
public void RenderPointShadowsIndexed<T>(
RenderTargetCube pointShadowCubeMap,
PerspectiveCamera camera,
IEnumerable<(T, Matrix)> modelTransforms,