1
$\begingroup$

I am creating Forward-Rendering DX11 engine and I have some troubles with shadow-mapping algorithm as it doesn't work as supposed.

Shadowmap texture

Rendered scene

As you can see - shadow is peter-panning and looks totally not releated. Basically as I have tested, comparision in PixelShader has no effect. Only projected shadowmap texture is returned, if statement doesn't do anything.

MyVertexShader:

PixelInputType ColorVertexShader(VertexInputType input)
{
    PixelInputType output;
    float4 worldPosition;

    input.position.w = 1.0f;
    worldPosition = mul(input.position, worldMatrix);
    output.normal = input.normal;

    // Calculate the position of the vertex against the world, view, and projection matrices.
    output.position = mul(input.position, worldMatrix);
    output.position = mul(output.position, viewMatrix);
    output.position = mul(output.position, projectionMatrix);

    //Calculate object seen by light
    output.lightViewPosition = mul(input.position, worldMatrix);
    output.lightViewPosition = mul(output.lightViewPosition, g_lightViewMatrix);
    output.lightViewPosition = mul(output.lightViewPosition, g_lightProjectionMatrix);

    //Calculate light-object vector
    output.lightPos = g_lightPosition.xyz - worldPosition.xyz;
    output.lightPos = normalize(output.lightPos);

    return output;
}

MyPixelShader:

float4 ColorPixelShader(PixelInputType input) : SV_TARGET
{
    float4 color = float4(0.0, 0.0, 0.0, 1.0);
    float depthValue;
    float lightDepthValue;
    float bias = 0.001f;
    float4 textureColor = float4(1.0, 1.0, 1.0, 1.0);
    float4 ambientColor = float4(1.0, 0.0, 1.0, 1.0);
    float2 tex;
    float lightIntensity = 0.0f;

    input.lightViewPosition.xyz /= input.lightViewPosition.w;

    tex.x = input.lightViewPosition.x / 2.0f + 0.5f;
    tex.y = -input.lightViewPosition.y / 2.0f + 0.5f;

    return depthValue = shadowMap.Sample(SampleType, tex).r;
    color = float4(depthValue, depthValue, depthValue, 1.0f);

    lightDepthValue = input.lightViewPosition.z;// / input.lightViewPosition.w;
    lightDepthValue = lightDepthValue - bias;
    if(lightDepthValue < depthValue)
    {
        lightIntensity = saturate(dot(input.normal, input.lightPos));

        if(lightIntensity > 0.0f)
        {
            // Determine the final diffuse color based on the diffuse color and the amount of light intensity.
            color += (ambientColor * lightIntensity);

            // Saturate the final light color.
            color = saturate(color);
        }
    }
    return color;
}
$\endgroup$
  • 1
    $\begingroup$ How is g_lightViewMatrix & g_lightProjectionMatrix calculated ? I would guess it has a inverse view-projection matrix to convert from camera to world space in there too ? $\endgroup$ – PaulHK Mar 13 at 8:25
1
$\begingroup$

I found out that simply removing minus sign in shader in converting coords to [0, 1] solved direction problem. But scale is still off - here is an example:

Wrong scale - peter panning

void LightClass::GenerateViewMatrix()
{
    XMVECTOR eyePos = { m_position.x, m_position.y, m_position.z };
    XMVECTOR focusPos = { m_lookAt.x, m_lookAt.y, m_lookAt.z };
    XMVECTOR upVec = { 0, 1, 0 };

    m_viewMatrix = XMMatrixLookAtLH(eyePos, focusPos, upVec);
}

void LightClass::GenerateProjectionMatrix(float screenDepth, float screenNear)
{
    float fieldOfView = (float)3.14f / 2.0f;
    float screenAspect = 16.0f / 9.0f;

    m_projectionMatrix = XMMatrixPerspectiveFovLH(fieldOfView, screenAspect, screenNear, screenDepth);
}

Edit [Actual solution - ignore previous posts]:

I followed PaulHK solution (thanks, it's second time you've helped me) about checking once again View/Projection matrix. Basically my calculations were wrong. I debugged my convertions from model to lightspace and changed Vertex Shader from:

output.lightViewPosition = mul(input.position, worldMatrix);
output.lightViewPosition = mul(output.lightViewPosition, g_lightViewMatrix);
output.lightViewPosition = mul(output.lightViewPosition, g_lightProjectionMatrix);

To correct:

matrix lightViewProj = mul(g_lightProjectionMatrix, g_lightViewMatrix);
output.lightViewPosition = mul(input.position, lightViewProj);

That simple changed fixed my results. With simple Pixel shader code below I am getting this results:

input.lightViewPosition.xyz /= input.lightViewPosition.w;

tex.x = input.lightViewPosition.x / 2.0f + 0.5f;
tex.y = -input.lightViewPosition.y / 2.0f + 0.5f;

depthValue = shadowMap.Sample(SampleType, tex).r;
return color = float4(depthValue, depthValue, depthValue, 1.0f);

Correct shadow-map However, even if it seems correct, my suspicion is that I need to compare my shadowmap to light Z-buffer so I modified my Pixel Shader and added little tint:

input.lightViewPosition.xyz /= input.lightViewPosition.w;

tex.x = input.lightViewPosition.x / 2.0f + 0.5f;
tex.y = -input.lightViewPosition.y / 2.0f + 0.5f;

depthValue = shadowMap.Sample(SampleType, tex).r;
color = float4(depthValue, depthValue, depthValue, 1.0f);

lightDepthValue = input.lightViewPosition.z - bias;
if(lightDepthValue < depthValue)
{
    lightIntensity = saturate(dot(input.normal, input.lightPos));

    if(lightIntensity > 0.0f)
    {
        // Determine the final diffuse color based on the diffuse color and the amount of light intensity.
        color += (ambientColor * lightIntensity);

        // Saturate the final light color.
        color = saturate(color);
    }
}
return color;

I may not be right, but without this checking, you would get errors with more complicated shadows. Because my previous PixelShader code basically just project shadowmap on plane without any actual depth checking. Therefore it would lay shadowmap on everything it can without even checking if that's correct.

Correct shadow-map with depth checking

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.