initial soft shadow implementation
parent
7ea2b57315
commit
7e82f2f32e
|
@ -22,6 +22,8 @@ namespace Kav
|
||||||
|
|
||||||
EffectParameter cascadeFarPlanesParam;
|
EffectParameter cascadeFarPlanesParam;
|
||||||
|
|
||||||
|
EffectParameter shadowMapSizeParam;
|
||||||
|
|
||||||
EffectParameter lightSpaceMatrixOneParam;
|
EffectParameter lightSpaceMatrixOneParam;
|
||||||
EffectParameter lightSpaceMatrixTwoParam;
|
EffectParameter lightSpaceMatrixTwoParam;
|
||||||
EffectParameter lightSpaceMatrixThreeParam;
|
EffectParameter lightSpaceMatrixThreeParam;
|
||||||
|
@ -46,6 +48,8 @@ namespace Kav
|
||||||
|
|
||||||
public readonly float[] CascadeFarPlanes;
|
public readonly float[] CascadeFarPlanes;
|
||||||
|
|
||||||
|
public int ShadowMapSize { get; set; }
|
||||||
|
|
||||||
public Matrix LightSpaceMatrixOne { get; set; }
|
public Matrix LightSpaceMatrixOne { get; set; }
|
||||||
public Matrix LightSpaceMatrixTwo { get; set; }
|
public Matrix LightSpaceMatrixTwo { get; set; }
|
||||||
public Matrix LightSpaceMatrixThree { get; set; }
|
public Matrix LightSpaceMatrixThree { get; set; }
|
||||||
|
@ -82,6 +86,8 @@ namespace Kav
|
||||||
CascadeFarPlanes[i] = cloneSource.CascadeFarPlanes[i];
|
CascadeFarPlanes[i] = cloneSource.CascadeFarPlanes[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ShadowMapSize = cloneSource.ShadowMapSize;
|
||||||
|
|
||||||
LightSpaceMatrixOne = cloneSource.LightSpaceMatrixOne;
|
LightSpaceMatrixOne = cloneSource.LightSpaceMatrixOne;
|
||||||
LightSpaceMatrixTwo = cloneSource.LightSpaceMatrixTwo;
|
LightSpaceMatrixTwo = cloneSource.LightSpaceMatrixTwo;
|
||||||
LightSpaceMatrixThree = cloneSource.LightSpaceMatrixThree;
|
LightSpaceMatrixThree = cloneSource.LightSpaceMatrixThree;
|
||||||
|
@ -113,6 +119,7 @@ namespace Kav
|
||||||
directionalLightColorParam.SetValue(DirectionalLightColor);
|
directionalLightColorParam.SetValue(DirectionalLightColor);
|
||||||
|
|
||||||
cascadeFarPlanesParam.SetValue(CascadeFarPlanes);
|
cascadeFarPlanesParam.SetValue(CascadeFarPlanes);
|
||||||
|
shadowMapSizeParam.SetValue(ShadowMapSize);
|
||||||
|
|
||||||
lightSpaceMatrixOneParam.SetValue(LightSpaceMatrixOne);
|
lightSpaceMatrixOneParam.SetValue(LightSpaceMatrixOne);
|
||||||
lightSpaceMatrixTwoParam.SetValue(LightSpaceMatrixTwo);
|
lightSpaceMatrixTwoParam.SetValue(LightSpaceMatrixTwo);
|
||||||
|
@ -141,6 +148,8 @@ namespace Kav
|
||||||
|
|
||||||
cascadeFarPlanesParam = Parameters["CascadeFarPlanes"];
|
cascadeFarPlanesParam = Parameters["CascadeFarPlanes"];
|
||||||
|
|
||||||
|
shadowMapSizeParam = Parameters["ShadowMapSize"];
|
||||||
|
|
||||||
lightSpaceMatrixOneParam = Parameters["LightSpaceMatrixOne"];
|
lightSpaceMatrixOneParam = Parameters["LightSpaceMatrixOne"];
|
||||||
lightSpaceMatrixTwoParam = Parameters["LightSpaceMatrixTwo"];
|
lightSpaceMatrixTwoParam = Parameters["LightSpaceMatrixTwo"];
|
||||||
lightSpaceMatrixThreeParam = Parameters["LightSpaceMatrixThree"];
|
lightSpaceMatrixThreeParam = Parameters["LightSpaceMatrixThree"];
|
||||||
|
|
Binary file not shown.
|
@ -21,18 +21,40 @@ BEGIN_CONSTANTS
|
||||||
|
|
||||||
float CascadeFarPlanes[NUM_SHADOW_CASCADES] _ps(c3) _cb(c3);
|
float CascadeFarPlanes[NUM_SHADOW_CASCADES] _ps(c3) _cb(c3);
|
||||||
|
|
||||||
|
float ShadowMapSize _ps(c7) _cb(c7);
|
||||||
|
|
||||||
MATRIX_CONSTANTS
|
MATRIX_CONSTANTS
|
||||||
|
|
||||||
float4x4 LightSpaceMatrixOne _ps(c7) _cb(c7);
|
float4x4 LightSpaceMatrixOne _ps(c8) _cb(c8);
|
||||||
float4x4 LightSpaceMatrixTwo _ps(c11) _cb(c11);
|
float4x4 LightSpaceMatrixTwo _ps(c12) _cb(c12);
|
||||||
float4x4 LightSpaceMatrixThree _ps(c15) _cb(c15);
|
float4x4 LightSpaceMatrixThree _ps(c16) _cb(c16);
|
||||||
float4x4 LightSpaceMatrixFour _ps(c19) _cb(c19);
|
float4x4 LightSpaceMatrixFour _ps(c20) _cb(c20);
|
||||||
|
|
||||||
// used to select shadow cascade
|
// used to select shadow cascade
|
||||||
float4x4 ViewMatrix _ps(c23) _cb(c23);
|
float4x4 ViewMatrix _ps(c24) _cb(c24);
|
||||||
|
|
||||||
END_CONSTANTS
|
END_CONSTANTS
|
||||||
|
|
||||||
|
static float2 poissonDisk[16] =
|
||||||
|
{
|
||||||
|
float2( -0.94201624, -0.39906216 ),
|
||||||
|
float2( 0.94558609, -0.76890725 ),
|
||||||
|
float2( -0.094184101, -0.92938870 ),
|
||||||
|
float2( 0.34495938, 0.29387760 ),
|
||||||
|
float2( -0.91588581, 0.45771432 ),
|
||||||
|
float2( -0.81544232, -0.87912464 ),
|
||||||
|
float2( -0.38277543, 0.27676845 ),
|
||||||
|
float2( 0.97484398, 0.75648379 ),
|
||||||
|
float2( 0.44323325, -0.97511554 ),
|
||||||
|
float2( 0.53742981, -0.47373420 ),
|
||||||
|
float2( -0.26496911, -0.41893023 ),
|
||||||
|
float2( 0.79197514, 0.19090188 ),
|
||||||
|
float2( -0.24188840, 0.99706507 ),
|
||||||
|
float2( -0.81409955, 0.91437590 ),
|
||||||
|
float2( 0.19984126, 0.78641367 ),
|
||||||
|
float2( 0.14383161, -0.14100790 )
|
||||||
|
};
|
||||||
|
|
||||||
struct VertexInput
|
struct VertexInput
|
||||||
{
|
{
|
||||||
float4 Position : POSITION;
|
float4 Position : POSITION;
|
||||||
|
@ -57,6 +79,30 @@ PixelInput main_vs(VertexInput input)
|
||||||
|
|
||||||
// Pixel Shader
|
// Pixel Shader
|
||||||
|
|
||||||
|
// Returns a random number based on a vec3 and an int.
|
||||||
|
float random(float3 seed, int i){
|
||||||
|
float4 seed4 = float4(seed, i);
|
||||||
|
float dot_product = dot(seed4, float4(12.9898,78.233,45.164,94.673));
|
||||||
|
return frac(sin(dot_product) * 43758.5453);
|
||||||
|
}
|
||||||
|
|
||||||
|
float PoissonCoord(sampler shadowMap, float3 worldPosition, float2 texCoord, float fragmentDepth, float bias)
|
||||||
|
{
|
||||||
|
float visibility = 1.0;
|
||||||
|
|
||||||
|
for (int i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
int index = int(16.0 * random(floor(worldPosition * 1000.0), i)) % 16;
|
||||||
|
|
||||||
|
if (tex2D(shadowMap, texCoord + poissonDisk[i] / 700.0).r < fragmentDepth - bias)
|
||||||
|
{
|
||||||
|
visibility -= 0.2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return visibility;
|
||||||
|
}
|
||||||
|
|
||||||
float ComputeShadow(float3 positionWorldSpace, float3 N, float3 L)
|
float ComputeShadow(float3 positionWorldSpace, float3 N, float3 L)
|
||||||
{
|
{
|
||||||
float bias = 0.005 * tan(acos(dot(N, L)));
|
float bias = 0.005 * tan(acos(dot(N, L)));
|
||||||
|
@ -104,42 +150,58 @@ float ComputeShadow(float3 positionWorldSpace, float3 N, float3 L)
|
||||||
projectionCoords.y *= -1;
|
projectionCoords.y *= -1;
|
||||||
// in XNA clip z is 0 to 1 already
|
// in XNA clip z is 0 to 1 already
|
||||||
|
|
||||||
float inc = 1.0 / 1024.0;
|
if (projectionCoords.z > 1.0)
|
||||||
|
{
|
||||||
|
return 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float inc = 1.0 / ShadowMapSize; // TODO: shadow map size uniform
|
||||||
|
|
||||||
|
// PCF + Poisson soft shadows
|
||||||
|
float visibility = 0.0;
|
||||||
|
// for (int row = -1; row <= 1; row++)
|
||||||
|
// {
|
||||||
|
// for (int col = -1; col <= 1; col++)
|
||||||
|
// {
|
||||||
|
// if (shadowCascadeIndex == 0)
|
||||||
|
// {
|
||||||
|
// visibility += PoissonCoord(SAMPLER(shadowMapOne), positionWorldSpace, projectionCoords.xy + float2(row, col) * inc, projectionCoords.z, bias);
|
||||||
|
// }
|
||||||
|
// else if (shadowCascadeIndex == 1)
|
||||||
|
// {
|
||||||
|
// visibility += PoissonCoord(SAMPLER(shadowMapTwo), positionWorldSpace, projectionCoords.xy + float2(row, col) * inc, projectionCoords.z, bias);
|
||||||
|
// }
|
||||||
|
// else if (shadowCascadeIndex == 2)
|
||||||
|
// {
|
||||||
|
// visibility += PoissonCoord(SAMPLER(shadowMapThree), positionWorldSpace, projectionCoords.xy + float2(row, col) * inc, projectionCoords.z, bias);
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// visibility += PoissonCoord(SAMPLER(shadowMapFour), positionWorldSpace, projectionCoords.xy + float2(row, col) * inc, projectionCoords.z, bias);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// visibility /= 9.0;
|
||||||
|
|
||||||
float shadowFactor = 0;
|
|
||||||
for (int row = -1; row <= 1; row++)
|
|
||||||
{
|
|
||||||
for (int col = -1; col <= 1; col++)
|
|
||||||
{
|
|
||||||
float closestDepth;
|
|
||||||
if (shadowCascadeIndex == 0)
|
if (shadowCascadeIndex == 0)
|
||||||
{
|
{
|
||||||
closestDepth = SAMPLE_TEXTURE(shadowMapOne, projectionCoords.xy + float2(row, col) * inc).r;
|
visibility = PoissonCoord(SAMPLER(shadowMapOne), positionWorldSpace, projectionCoords.xy, projectionCoords.z, bias);
|
||||||
}
|
}
|
||||||
else if (shadowCascadeIndex == 1)
|
else if (shadowCascadeIndex == 1)
|
||||||
{
|
{
|
||||||
closestDepth = SAMPLE_TEXTURE(shadowMapTwo, projectionCoords.xy + float2(row, col) * inc).r;
|
visibility = PoissonCoord(SAMPLER(shadowMapTwo), positionWorldSpace, projectionCoords.xy, projectionCoords.z, bias);
|
||||||
}
|
}
|
||||||
else if (shadowCascadeIndex == 2)
|
else if (shadowCascadeIndex == 2)
|
||||||
{
|
{
|
||||||
closestDepth = SAMPLE_TEXTURE(shadowMapThree, projectionCoords.xy + float2(row, col) * inc).r;
|
visibility = PoissonCoord(SAMPLER(shadowMapThree), positionWorldSpace, projectionCoords.xy, projectionCoords.z, bias);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
closestDepth = SAMPLE_TEXTURE(shadowMapFour, projectionCoords.xy + float2(row, col) * inc).r;
|
visibility = PoissonCoord(SAMPLER(shadowMapFour), positionWorldSpace, projectionCoords.xy, projectionCoords.z, bias);
|
||||||
}
|
|
||||||
shadowFactor += projectionCoords.z - bias > closestDepth ? 1.0 : 0.0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
shadowFactor /= 9.0;
|
return visibility;
|
||||||
|
|
||||||
if (projectionCoords.z > 1.0)
|
|
||||||
{
|
|
||||||
shadowFactor = 1.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return shadowFactor;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float4 ComputeColor(
|
float4 ComputeColor(
|
||||||
|
@ -159,7 +221,7 @@ float4 ComputeColor(
|
||||||
float3 radiance = DirectionalLightColor;
|
float3 radiance = DirectionalLightColor;
|
||||||
|
|
||||||
float shadow = ComputeShadow(worldPosition, N, L);
|
float shadow = ComputeShadow(worldPosition, N, L);
|
||||||
float3 color = ComputeLight(L, radiance, F0, V, N, albedo, metallic, roughness, (1.0 - shadow));
|
float3 color = ComputeLight(L, radiance, F0, V, N, albedo, metallic, roughness, shadow);
|
||||||
|
|
||||||
return float4(color, 1.0);
|
return float4(color, 1.0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,7 @@ float3 ComputeLight(
|
||||||
float3 albedo,
|
float3 albedo,
|
||||||
float metallic,
|
float metallic,
|
||||||
float roughness,
|
float roughness,
|
||||||
float shadow
|
float visibility
|
||||||
) {
|
) {
|
||||||
float3 H = normalize(V + L);
|
float3 H = normalize(V + L);
|
||||||
|
|
||||||
|
@ -67,5 +67,5 @@ float3 ComputeLight(
|
||||||
kD *= 1.0 - metallic;
|
kD *= 1.0 - metallic;
|
||||||
|
|
||||||
float NdotL = max(dot(N, L), 0.0);
|
float NdotL = max(dot(N, L), 0.0);
|
||||||
return (kD * albedo / PI + specular) * radiance * NdotL * shadow;
|
return (kD * albedo / PI + specular) * radiance * NdotL * visibility;
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,4 +54,5 @@
|
||||||
#define SAMPLE_TEXTURE(Name, texCoord) tex2D(Name##Sampler, texCoord)
|
#define SAMPLE_TEXTURE(Name, texCoord) tex2D(Name##Sampler, texCoord)
|
||||||
#define SAMPLE_CUBEMAP(Name, texCoord) texCUBE(Name##Sampler, texCoord)
|
#define SAMPLE_CUBEMAP(Name, texCoord) texCUBE(Name##Sampler, texCoord)
|
||||||
#define SAMPLE_CUBEMAP_LOD(Name, texCoord) texCUBElod(Name##Sampler, texCoord)
|
#define SAMPLE_CUBEMAP_LOD(Name, texCoord) texCUBElod(Name##Sampler, texCoord)
|
||||||
|
#define SAMPLER(Name) Name##Sampler
|
||||||
#endif
|
#endif
|
||||||
|
|
18
Renderer.cs
18
Renderer.cs
|
@ -7,6 +7,7 @@ namespace Kav
|
||||||
public class Renderer
|
public class Renderer
|
||||||
{
|
{
|
||||||
private const int MAX_SHADOW_CASCADES = 4;
|
private const int MAX_SHADOW_CASCADES = 4;
|
||||||
|
private int ShadowMapSize { get; }
|
||||||
|
|
||||||
private GraphicsDevice GraphicsDevice { get; }
|
private GraphicsDevice GraphicsDevice { get; }
|
||||||
private int RenderDimensionsX { get; }
|
private int RenderDimensionsX { get; }
|
||||||
|
@ -34,12 +35,19 @@ namespace Kav
|
||||||
|
|
||||||
private SpriteBatch SpriteBatch { get; }
|
private SpriteBatch SpriteBatch { get; }
|
||||||
|
|
||||||
public Renderer(GraphicsDevice graphicsDevice, int renderDimensionsX, int renderDimensionsY, int numShadowCascades)
|
public Renderer(
|
||||||
{
|
GraphicsDevice graphicsDevice,
|
||||||
|
int renderDimensionsX,
|
||||||
|
int renderDimensionsY,
|
||||||
|
int numShadowCascades,
|
||||||
|
int shadowMapSize
|
||||||
|
) {
|
||||||
GraphicsDevice = graphicsDevice;
|
GraphicsDevice = graphicsDevice;
|
||||||
RenderDimensionsX = renderDimensionsX;
|
RenderDimensionsX = renderDimensionsX;
|
||||||
RenderDimensionsY = renderDimensionsY;
|
RenderDimensionsY = renderDimensionsY;
|
||||||
|
|
||||||
|
ShadowMapSize = shadowMapSize;
|
||||||
|
|
||||||
NumShadowCascades = (int)MathHelper.Clamp(numShadowCascades, 1, MAX_SHADOW_CASCADES);
|
NumShadowCascades = (int)MathHelper.Clamp(numShadowCascades, 1, MAX_SHADOW_CASCADES);
|
||||||
ShadowRenderTargets = new RenderTarget2D[numShadowCascades];
|
ShadowRenderTargets = new RenderTarget2D[numShadowCascades];
|
||||||
|
|
||||||
|
@ -47,8 +55,8 @@ namespace Kav
|
||||||
{
|
{
|
||||||
ShadowRenderTargets[i] = new RenderTarget2D(
|
ShadowRenderTargets[i] = new RenderTarget2D(
|
||||||
GraphicsDevice,
|
GraphicsDevice,
|
||||||
1024,
|
ShadowMapSize,
|
||||||
1024,
|
ShadowMapSize,
|
||||||
false,
|
false,
|
||||||
SurfaceFormat.Single,
|
SurfaceFormat.Single,
|
||||||
DepthFormat.Depth24
|
DepthFormat.Depth24
|
||||||
|
@ -126,6 +134,8 @@ namespace Kav
|
||||||
DeferredPointLightEffect = new DeferredPBR_PointLightEffect(GraphicsDevice);
|
DeferredPointLightEffect = new DeferredPBR_PointLightEffect(GraphicsDevice);
|
||||||
DeferredDirectionalLightEffect = new DeferredPBR_DirectionalLightEffect(GraphicsDevice);
|
DeferredDirectionalLightEffect = new DeferredPBR_DirectionalLightEffect(GraphicsDevice);
|
||||||
|
|
||||||
|
DeferredDirectionalLightEffect.ShadowMapSize = ShadowMapSize;
|
||||||
|
|
||||||
FullscreenTriangle = new VertexBuffer(GraphicsDevice, typeof(VertexPositionTexture), 3, BufferUsage.WriteOnly);
|
FullscreenTriangle = new VertexBuffer(GraphicsDevice, typeof(VertexPositionTexture), 3, BufferUsage.WriteOnly);
|
||||||
FullscreenTriangle.SetData(new VertexPositionTexture[3] {
|
FullscreenTriangle.SetData(new VertexPositionTexture[3] {
|
||||||
new VertexPositionTexture(new Vector3(-1, -3, 0), new Vector2(0, 2)),
|
new VertexPositionTexture(new Vector3(-1, -3, 0), new Vector2(0, 2)),
|
||||||
|
|
Loading…
Reference in New Issue