toon shadows

pull/3/head
cosmonaut 2020-10-02 12:28:28 -07:00
parent 632f0a5b06
commit d370d4e2e4
6 changed files with 250 additions and 45 deletions

View File

@ -0,0 +1,14 @@
using Microsoft.Xna.Framework;
namespace Kav
{
public interface ShadowCascadeEffect
{
Matrix LightSpaceMatrixOne { get; set; }
Matrix LightSpaceMatrixTwo { get; set; }
Matrix LightSpaceMatrixThree { get; set; }
Matrix LightSpaceMatrixFour { get; set; }
float[] CascadeFarPlanes { get; }
}
}

View File

@ -3,7 +3,7 @@ using Microsoft.Xna.Framework.Graphics;
namespace Kav
{
public class DeferredPBR_DirectionalLightEffect : Effect
public class DeferredPBR_DirectionalLightEffect : Effect, ShadowCascadeEffect
{
EffectParameter gPositionParam;
EffectParameter gAlbedoParam;
@ -46,7 +46,7 @@ namespace Kav
public Vector3 DirectionalLightDirection { get; set; }
public Vector3 DirectionalLightColor { get; set; }
public readonly float[] CascadeFarPlanes;
public float[] CascadeFarPlanes { get; }
public int ShadowMapSize { get; set; }
@ -147,7 +147,6 @@ namespace Kav
directionalLightColorParam = Parameters["DirectionalLightColor"];
cascadeFarPlanesParam = Parameters["CascadeFarPlanes"];
shadowMapSizeParam = Parameters["ShadowMapSize"];
lightSpaceMatrixOneParam = Parameters["LightSpaceMatrixOne"];

View File

@ -3,30 +3,61 @@ using Microsoft.Xna.Framework.Graphics;
namespace Kav
{
public class Deferred_ToonEffect : Effect
public class Deferred_ToonEffect : Effect, ShadowCascadeEffect
{
EffectParameter gPositionParam;
EffectParameter gAlbedoParam;
EffectParameter gNormalParam;
EffectParameter shadowMapOneParam;
EffectParameter shadowMapTwoParam;
EffectParameter shadowMapThreeParam;
EffectParameter shadowMapFourParam;
EffectParameter eyePositionParam;
EffectParameter directionalLightDirectionParam;
EffectParameter directionalLightColorParam;
EffectParameter softnessParam;
EffectParameter cascadeFarPlanesParam;
EffectParameter shadowMapSizeParam;
EffectParameter lightSpaceMatrixOneParam;
EffectParameter lightSpaceMatrixTwoParam;
EffectParameter lightSpaceMatrixThreeParam;
EffectParameter lightSpaceMatrixFourParam;
EffectParameter viewMatrixParam;
public Texture2D GPosition { get; set; }
public Texture2D GAlbedo { get; set; }
public Texture2D GNormal { get; set; }
public Texture2D ShadowMapOne { get; set; }
public Texture2D ShadowMapTwo { get; set; }
public Texture2D ShadowMapThree { get; set; }
public Texture2D ShadowMapFour { get; set; }
public Vector3 EyePosition { get; set; }
public Vector3 DirectionalLightDirection { get; set; }
public Vector3 DirectionalLightColor { get; set; }
public float Softness { get; set; }
public float[] CascadeFarPlanes { get; }
public float ShadowMapSize { get; set; }
public Matrix LightSpaceMatrixOne { get; set; }
public Matrix LightSpaceMatrixTwo { get; set; }
public Matrix LightSpaceMatrixThree { get; set; }
public Matrix LightSpaceMatrixFour { get; set; }
public Matrix ViewMatrix { get; set; }
public Deferred_ToonEffect(GraphicsDevice graphicsDevice) : base(graphicsDevice, Resources.Deferred_ToonEffect)
{
CascadeFarPlanes = new float[4];
CacheEffectParameters();
}
@ -36,11 +67,26 @@ namespace Kav
gAlbedoParam.SetValue(GAlbedo);
gNormalParam.SetValue(GNormal);
shadowMapOneParam.SetValue(ShadowMapOne);
shadowMapTwoParam.SetValue(ShadowMapTwo);
shadowMapThreeParam.SetValue(ShadowMapThree);
shadowMapFourParam.SetValue(ShadowMapFour);
eyePositionParam.SetValue(EyePosition);
directionalLightDirectionParam.SetValue(DirectionalLightDirection);
directionalLightColorParam.SetValue(DirectionalLightColor);
softnessParam.SetValue(Softness);
cascadeFarPlanesParam.SetValue(CascadeFarPlanes);
shadowMapSizeParam.SetValue(ShadowMapSize);
lightSpaceMatrixOneParam.SetValue(LightSpaceMatrixOne);
lightSpaceMatrixTwoParam.SetValue(LightSpaceMatrixTwo);
lightSpaceMatrixThreeParam.SetValue(LightSpaceMatrixThree);
lightSpaceMatrixFourParam.SetValue(LightSpaceMatrixFour);
viewMatrixParam.SetValue(ViewMatrix);
}
void CacheEffectParameters()
@ -49,11 +95,26 @@ namespace Kav
gAlbedoParam = Parameters["gAlbedo"];
gNormalParam = Parameters["gNormal"];
shadowMapOneParam = Parameters["shadowMapOne"];
shadowMapTwoParam = Parameters["shadowMapTwo"];
shadowMapThreeParam = Parameters["shadowMapThree"];
shadowMapFourParam = Parameters["shadowMapFour"];
eyePositionParam = Parameters["EyePosition"];
directionalLightDirectionParam = Parameters["DirectionalLightDirection"];
directionalLightColorParam = Parameters["DirectionalLightColor"];
softnessParam = Parameters["Softness"];
cascadeFarPlanesParam = Parameters["CascadeFarPlanes"];
shadowMapSizeParam = Parameters["ShadowMapSize"];
lightSpaceMatrixOneParam = Parameters["LightSpaceMatrixOne"];
lightSpaceMatrixTwoParam = Parameters["LightSpaceMatrixTwo"];
lightSpaceMatrixThreeParam = Parameters["LightSpaceMatrixThree"];
lightSpaceMatrixFourParam = Parameters["LightSpaceMatrixFour"];
viewMatrixParam = Parameters["ViewMatrix"];
}
}
}

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

Binary file not shown.

View File

@ -1,17 +1,37 @@
#include "Macros.fxh"
#include "Shadow.fxh"
static const int NUM_SHADOW_CASCADES = 4;
DECLARE_TEXTURE(gPosition, 0);
DECLARE_TEXTURE(gAlbedo, 1);
DECLARE_TEXTURE(gNormal, 2);
DECLARE_TEXTURE(shadowMapOne, 4);
DECLARE_TEXTURE(shadowMapTwo, 5);
DECLARE_TEXTURE(shadowMapThree, 6);
DECLARE_TEXTURE(shadowMapFour, 7);
BEGIN_CONSTANTS
float3 EyePosition _ps(c0) _cb(c0);
float3 EyePosition _ps(c0) _cb(c0);
float3 DirectionalLightDirection _ps(c1) _cb(c1);
float3 DirectionalLightColor _ps(c2) _cb(c2);
float3 DirectionalLightDirection _ps(c1) _cb(c1);
float3 DirectionalLightColor _ps(c2) _cb(c2);
float Softness _ps(c3) _cb(c3);
float Softness _ps(c3) _cb(c3);
float CascadeFarPlanes[NUM_SHADOW_CASCADES] _ps(c4) _cb(c4);
float ShadowMapSize _ps(c8) _cb(c8);
MATRIX_CONSTANTS
float4x4 LightSpaceMatrixOne _ps(c9) _cb(c9);
float4x4 LightSpaceMatrixTwo _ps(c13) _cb(c13);
float4x4 LightSpaceMatrixThree _ps(c17) _cb(c17);
float4x4 LightSpaceMatrixFour _ps(c21) _cb(c21);
float4x4 ViewMatrix _ps(c25) _cb(c25);
END_CONSTANTS
@ -37,6 +57,88 @@ PixelInput main_vs(VertexInput input)
return output;
}
float ComputeShadow(float3 positionWorldSpace, float3 N, float3 L)
{
float4 positionCameraSpace = mul(float4(positionWorldSpace, 1.0), ViewMatrix);
int shadowCascadeIndex = 0; // 0 is closest
for (int i = 0; i < NUM_SHADOW_CASCADES; i++)
{
if (abs(positionCameraSpace.z) < CascadeFarPlanes[i])
{
shadowCascadeIndex = i;
break;
}
}
float4x4 lightSpaceMatrix;
if (shadowCascadeIndex == 0)
{
lightSpaceMatrix = LightSpaceMatrixOne;
}
else if (shadowCascadeIndex == 1)
{
lightSpaceMatrix = LightSpaceMatrixTwo;
}
else if (shadowCascadeIndex == 2)
{
lightSpaceMatrix = LightSpaceMatrixThree;
}
else
{
lightSpaceMatrix = LightSpaceMatrixFour;
}
// PCF + Poisson soft shadows
if (shadowCascadeIndex == 0)
{
return PoissonShadow(
positionWorldSpace,
N,
L,
lightSpaceMatrix,
SAMPLER(shadowMapOne),
ShadowMapSize
);
}
else if (shadowCascadeIndex == 1)
{
return PoissonShadow(
positionWorldSpace,
N,
L,
lightSpaceMatrix,
SAMPLER(shadowMapTwo),
ShadowMapSize
);
}
else if (shadowCascadeIndex == 2)
{
return PoissonShadow(
positionWorldSpace,
N,
L,
lightSpaceMatrix,
SAMPLER(shadowMapThree),
ShadowMapSize
);
}
else
{
return PoissonShadow(
positionWorldSpace,
N,
L,
lightSpaceMatrix,
SAMPLER(shadowMapFour),
ShadowMapSize
);
}
}
// FIXME: organize this
float4 main_ps(PixelInput input) : SV_TARGET0
{
float3 worldPosition = SAMPLE_TEXTURE(gPosition, input.TexCoord).rgb;
@ -76,7 +178,8 @@ float4 main_ps(PixelInput input) : SV_TARGET0
rimIntensity = smoothstep(rimAmount - 0.01, rimAmount + 0.01, rimIntensity);
float3 rim = rimIntensity * rimColor;
float3 color = albedo * (light + specular + rim);
float shadow = ComputeShadow(worldPosition, N, L);
float3 color = albedo * (light + specular + rim) * shadow;
return float4(color, 1.0);
}

View File

@ -195,11 +195,7 @@ namespace Kav
GraphicsDevice.Clear(Color.Black);
AmbientLightRender(ambientLight);
Deferred_ToonEffect.GPosition = gPosition;
Deferred_ToonEffect.GAlbedo = gAlbedo;
Deferred_ToonEffect.GNormal = gNormal;
DirectionalLightToonRender(camera, directionalLight);
DirectionalLightToonRender(camera, modelTransforms, directionalLight);
GraphicsDevice.SetRenderTarget(null);
GraphicsDevice.Clear(Color.Black);
@ -298,28 +294,7 @@ namespace Kav
IEnumerable<(Model, Matrix)> modelTransforms,
DirectionalLight directionalLight
) {
// render the individual shadow cascades
var previousFarPlane = camera.NearPlane;
for (var i = 0; i < NumShadowCascades; i++)
{
var farPlane = camera.FarPlane / (MathHelper.Max((NumShadowCascades - i - 1) * 2f, 1f));
// divide the view frustum
var shadowCamera = new PerspectiveCamera(
camera.Position,
camera.Forward,
camera.Up,
camera.FieldOfView,
camera.AspectRatio,
previousFarPlane,
farPlane
);
// TODO: This is tightly coupled to the effect and it sucks
RenderShadowMap(shadowCamera, modelTransforms, directionalLight, i);
previousFarPlane = farPlane;
}
RenderShadows(camera, modelTransforms, directionalLight, DeferredDirectionalLightEffect);
DeferredDirectionalLightEffect.GPosition = gPosition;
DeferredDirectionalLightEffect.GAlbedo = gAlbedo;
@ -345,7 +320,7 @@ namespace Kav
directionalLight.Color.ToVector3() * directionalLight.Intensity;
DeferredDirectionalLightEffect.ViewMatrix = camera.View;
DeferredDirectionalLightEffect.EyePosition = Matrix.Invert(camera.View).Translation;
DeferredDirectionalLightEffect.EyePosition = camera.Position;
GraphicsDevice.SetRenderTarget(ColorRenderTarget);
GraphicsDevice.BlendState = BlendState.Additive;
@ -360,11 +335,18 @@ namespace Kav
private void DirectionalLightToonRender(
PerspectiveCamera camera,
IEnumerable<(Model, Matrix)> modelTransforms,
DirectionalLight directionalLight
) {
RenderShadows(camera, modelTransforms, directionalLight, Deferred_ToonEffect);
GraphicsDevice.SetRenderTarget(ColorRenderTarget);
GraphicsDevice.BlendState = BlendState.Additive;
Deferred_ToonEffect.GPosition = gPosition;
Deferred_ToonEffect.GAlbedo = gAlbedo;
Deferred_ToonEffect.GNormal = gNormal;
Deferred_ToonEffect.EyePosition = camera.Position;
Deferred_ToonEffect.DirectionalLightDirection = directionalLight.Direction;
Deferred_ToonEffect.DirectionalLightColor =
@ -372,6 +354,22 @@ namespace Kav
Deferred_ToonEffect.Softness = 0.01f;
Deferred_ToonEffect.ShadowMapOne = ShadowRenderTargets[0];
if (NumShadowCascades > 1)
{
Deferred_ToonEffect.ShadowMapTwo = ShadowRenderTargets[1];
}
if (NumShadowCascades > 2)
{
Deferred_ToonEffect.ShadowMapThree = ShadowRenderTargets[2];
}
if (NumShadowCascades > 3)
{
Deferred_ToonEffect.ShadowMapFour = ShadowRenderTargets[3];
}
Deferred_ToonEffect.ViewMatrix = camera.View;
foreach (EffectPass pass in Deferred_ToonEffect.CurrentTechnique.Passes)
{
pass.Apply();
@ -380,10 +378,42 @@ namespace Kav
}
}
private void RenderShadows(
PerspectiveCamera camera,
IEnumerable<(Model, Matrix)> modelTransforms,
DirectionalLight directionalLight,
ShadowCascadeEffect effect
) {
// render the individual shadow cascades
var previousFarPlane = camera.NearPlane;
for (var i = 0; i < NumShadowCascades; i++)
{
var farPlane = camera.FarPlane / (MathHelper.Max((NumShadowCascades - i - 1) * 2f, 1f));
// divide the view frustum
var shadowCamera = new PerspectiveCamera(
camera.Position,
camera.Forward,
camera.Up,
camera.FieldOfView,
camera.AspectRatio,
previousFarPlane,
farPlane
);
// TODO: This is tightly coupled to the effect and it sucks
RenderShadowMap(shadowCamera, modelTransforms, directionalLight, effect, i);
effect.CascadeFarPlanes[i] = farPlane;
previousFarPlane = farPlane;
}
}
private void RenderShadowMap(
PerspectiveCamera camera,
IEnumerable<(Model, Matrix)> modelTransforms,
DirectionalLight directionalLight,
ShadowCascadeEffect effect,
int shadowCascadeIndex
) {
GraphicsDevice.SetRenderTarget(ShadowRenderTargets[shadowCascadeIndex]);
@ -424,23 +454,21 @@ namespace Kav
if (shadowCascadeIndex == 0)
{
DeferredDirectionalLightEffect.LightSpaceMatrixOne = lightSpaceMatrix;
effect.LightSpaceMatrixOne = lightSpaceMatrix;
}
else if (shadowCascadeIndex == 1)
{
DeferredDirectionalLightEffect.LightSpaceMatrixTwo = lightSpaceMatrix;
effect.LightSpaceMatrixTwo = lightSpaceMatrix;
}
else if (shadowCascadeIndex == 2)
{
DeferredDirectionalLightEffect.LightSpaceMatrixThree = lightSpaceMatrix;
effect.LightSpaceMatrixThree = lightSpaceMatrix;
}
else if (shadowCascadeIndex == 3)
{
DeferredDirectionalLightEffect.LightSpaceMatrixFour = lightSpaceMatrix;
effect.LightSpaceMatrixFour = lightSpaceMatrix;
}
DeferredDirectionalLightEffect.CascadeFarPlanes[shadowCascadeIndex] = camera.FarPlane;
foreach (var (model, transform) in modelTransforms)
{
foreach (var modelMesh in model.Meshes)