Reputation: 683
I've got a problem with my point light shadows.
I've seen several articles, videos, questions:
and I wrote this (pseudo) code:
struct PointShadowMatrix
{
glm::mat4 viewProjection[6];
};
const glm::mat4 shadowProj = glm::perspective(Math::HALF_PI, 1.0f, 25.0f, 1.0f);
const glm::vec3 lightPos = light.getPosition();
PointShadowMatrix shadowData;
shadowData.viewProjection[0] = shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3(1.0, 0.0, 0.0), glm::vec3(0.0, 1.0, 0.0));
shadowData.viewProjection[1] = shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3(-1.0, 0.0, 0.0), glm::vec3(0.0, 1.0, 0.0));
shadowData.viewProjection[2] = shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3(0.0, 1.0, 0.0), glm::vec3(0.0, 0.0, -1.0));
shadowData.viewProjection[3] = shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3(0.0, -1.0, 0.0), glm::vec3(0.0, 0.0, 1.0));
shadowData.viewProjection[4] = shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3(0.0, 0.0, 1.0), glm::vec3(0.0, 1.0, 0.0));
shadowData.viewProjection[5] = shadowProj * glm::lookAt(lightPos, lightPos + glm::vec3(0.0, 0.0, -1.0), glm::vec3(0.0, 1.0, 0.0));
shadowConstantBuffer.AddData(shadowData);
auto textureCube = TextureCube(
.Width = 1024,
.Height = 1024,
.MipLevels = 1,
.Format = DXGI_FORMAT_R24G8_TYPELESS,
.BindFlags = D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE
);
auto cubeDepthRenderTarget = CubeRenderTarget(
.resource = textureCube,
.FirstArraySlice = 0,
.MipSlice = 0
);
auto shader = Shader(.path = "PointShadowShader.hlsl");
shader.Bind();
cubeDepthRenderTarget.Bind();
shadowConstantBuffer.Bind();
SetViewport(.w = 1024, .h = 1024);
ClearDepth(cubeDepthRenderTarget, 0.0f);
DrawDepth();
PointShadowShader:
struct VertexInput
{
float3 position : POSITION;
nointerpolation float4 modelToWorld1 : I_MODEL_TO_WORLD_ONE;
nointerpolation float4 modelToWorld2 : I_MODEL_TO_WORLD_TWO;
nointerpolation float4 modelToWorld3 : I_MODEL_TO_WORLD_THREE;
nointerpolation float4 modelToWorld4 : I_MODEL_TO_WORLD_FOUR;
};
float4 VSMain(VertexInput input) : SV_POSITION
{
float4x4 model = float4x4(input.modelToWorld1, input.modelToWorld2, input.modelToWorld3, input.modelToWorld4);
return mul(float4(input.position, 1.0f), model);
}
cbuffer PointShadowData : register(b4)
{
row_major float4x4 pointShadowViewProjection[6];
};
struct GS_OUTPUT
{
float4 position : SV_POSITION;
float3 worldPosition : WORLD_POSITION;
uint RTIndex : SV_RenderTargetArrayIndex;
};
[maxvertexcount(18)]
void GSMain(triangle float4 position[3] : SV_POSITION, inout TriangleStream<GS_OUTPUT> OutStream)
{
for (uint face = 0; face < 6; ++face)
{
GS_OUTPUT output;
output.RTIndex = face;
for (uint v = 0; v < 3; ++v)
{
output.worldPosition = position[v].xyz;
output.position = mul(position[v], pointShadowViewProjection[face]);
OutStream.Append(output);
}
OutStream.RestartStrip();
}
}
cbuffer LightInfo : register(b1)
{
float3 lightPos;
};
struct PixelInput
{
float4 position : SV_POSITION;
float3 worldPosition : WORLD_POSITION;
};
float PSMain(PixelInput input) : SV_DEPTH
{
//I tried input.position instead of input.worldPosition, it didn't fixed the problem
//I tried NVidia's approach to calculate squared distance instead of length
//I tried using just a length, without dividing by far plane
//Nothing fixed the problem
return length(input.worldPosition - lightPos) / 25.0f;
}
The depth pass looks good to me (light space perspective):
but the shading version does not:
the shpere in the middle is a light "visualizer".
Another screenshot, now from behind of the wall:
the way I use the depth map to calculate shadows:
float PointLightShadows(float3 worldPosition, float3 lightPosition)
{
float3 fragToLight = worldPosition - lightPosition;
float distance = length(fragToLight);
return t_pointShadowMap.SampleCmpLevelZero(g_shadowBorder, float4(fragToLight, lightIndex), distance / 25.0f);}
sampler:
Sampler shadowBorder {
D3D11_SAMPLER_DESC
{
.Filter = D3D11_FILTER_COMPARISON_MIN_MAG_LINEAR_MIP_POINT,
.AddressU = D3D11_TEXTURE_ADDRESS_BORDER,
.AddressV = D3D11_TEXTURE_ADDRESS_BORDER,
.AddressW = D3D11_TEXTURE_ADDRESS_BORDER,
.ComparisonFunction = D3D11_COMPARISON_GREATER,
.BorderColor = 1.0f
}
};
As I wrote before, I've seen all these articles and I tried every approach authors show there, nothing worked.
Depth buffer is cleared to 0
, depth function is GREATER
what is wrong with my code? How can I fix it? What things should I consider checking while debugging this problem?
Upvotes: 1
Views: 97
Reputation: 683
I've cleared the depth buffer to 1.0f
, set depthFunc
to LESS
, and sampler ComparisonFunction
to LESS
and it works now. My question is why? What was wrong with the reversed depth version?
Upvotes: 0