1
\$\begingroup\$

I am trying to implement shadow maps in my Dx11 rendering engine. I created a shadow map texture2d, a shader resource view, a depth stencil, a viewport, and a rasterizer state, as recommended by microsoft's guide. I used the Visual Studio graphics debugger and found out that the depth buffer is purely red. Does anyone have any suggestions on why this might be happening? Note-I am using a directional light to calculate the view and projection matrices.

This is my C++ code for creating all directx resources

D3D11_TEXTURE2D_DESC shadowMapDesc;
ZeroMemory(&shadowMapDesc, sizeof(D3D11_TEXTURE2D_DESC));
shadowMapDesc.Width = 1024;
shadowMapDesc.Height = 1024;
shadowMapDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL | D3D11_BIND_SHADER_RESOURCE;
shadowMapDesc.Format = DXGI_FORMAT_R32_TYPELESS;
shadowMapDesc.ArraySize = 1;
shadowMapDesc.MipLevels = 1;
shadowMapDesc.CPUAccessFlags = 0;
shadowMapDesc.MiscFlags = 0;
shadowMapDesc.SampleDesc.Count = 1;
shadowMapDesc.SampleDesc.Quality = 0;
shadowMapDesc.Usage = D3D11_USAGE_DEFAULT;

//creating a texture
device->CreateTexture2D(&shadowMapDesc, nullptr, &shadowMapTexture);

//description for depth stencil view
D3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc;
ZeroMemory(&depthStencilViewDesc, sizeof(D3D11_DEPTH_STENCIL_VIEW_DESC));
depthStencilViewDesc.Format = DXGI_FORMAT_D32_FLOAT;
depthStencilViewDesc.Texture2D.MipSlice = 0;
depthStencilViewDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;

device->CreateDepthStencilView(shadowMapTexture, &depthStencilViewDesc, &shadowDepthStencil);

//creating a shader resource view
D3D11_SHADER_RESOURCE_VIEW_DESC shadowSRVDesc;
ZeroMemory(&shadowSRVDesc, sizeof(D3D11_SHADER_RESOURCE_VIEW_DESC));
shadowSRVDesc.Format = DXGI_FORMAT_R32_FLOAT;
shadowSRVDesc.Texture2D.MipLevels = 1;
shadowSRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;

device->CreateShaderResourceView(shadowMapTexture, &shadowSRVDesc, &shadowSRV);

//setting up the shadow viewport
ZeroMemory(&shadowViewport, sizeof(D3D11_VIEWPORT));
shadowViewport.Width = 1024.0f;
shadowViewport.Height = 1024.0f;
shadowViewport.MinDepth = 0.0f;
shadowViewport.MaxDepth = 1.0f;
shadowViewport.TopLeftX = 0.0f;
shadowViewport.TopLeftY = 0.0f;

//rasterizer for pixel shader
D3D11_RASTERIZER_DESC shadowRasterizerDesc;
ZeroMemory(&shadowRasterizerDesc,sizeof(D3D11_RASTERIZER_DESC));
shadowRasterizerDesc.FillMode = D3D11_FILL_SOLID;
shadowRasterizerDesc.CullMode = D3D11_CULL_BACK;
shadowRasterizerDesc.DepthClipEnable = true;
shadowRasterizerDesc.FrontCounterClockwise = false;

//creating this rasterizer
device->CreateRasterizerState(&shadowRasterizerDesc, &shadowRasterizerState);

//sampler for the shadow texture
D3D11_SAMPLER_DESC shadowSamplerDesc;
memset(&shadowSamplerDesc, 0, sizeof(shadowSamplerDesc));
shadowSamplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_BORDER;
shadowSamplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_BORDER;
shadowSamplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_BORDER;
shadowSamplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
shadowSamplerDesc.MaxLOD = D3D11_FLOAT32_MAX;
shadowSamplerDesc.BorderColor[0] = 1.0f;
shadowSamplerDesc.BorderColor[1] = 1.0f;
shadowSamplerDesc.BorderColor[2] = 1.0f;
shadowSamplerDesc.BorderColor[3] = 1.0f;
shadowSamplerDesc.Filter = D3D11_FILTER_COMPARISON_MIN_MAG_MIP_LINEAR;
shadowSamplerDesc.ComparisonFunc = D3D11_COMPARISON_LESS;

device->CreateSamplerState(&shadowSamplerDesc, &shadowSamplerState);

This is how I am rendering everything to the buffer

    UINT stride = sizeof(Vertex);
UINT offset = 0;

//set depth stencil view to render everything to the shadow depth buffer
//context->ClearRenderTargetView(backBufferRTV, color);
context->ClearDepthStencilView(shadowDepthStencil, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);
context->OMSetRenderTargets(0, nullptr, shadowDepthStencil);

context->RSSetViewports(1, &shadowViewport);
context->RSSetState(shadowRasterizerState);

XMFLOAT3 directionLightPosition;
XMFLOAT3 center(0.0f, 0.0f, 0.0f);
XMFLOAT3 up(0.0f, 1.0f, 0.0f);

//taking the center of the camera and backing up from the direction of the light
//this is the position of the light
XMStoreFloat3(&directionLightPosition, XMLoadFloat3(&center) + XMLoadFloat3(&directionalLight.direction) * 1000.f);
//creating the camera look to matrix
auto tempLightView = XMMatrixLookToLH(XMLoadFloat3(&directionLightPosition), 
    XMLoadFloat3(&directionalLight.direction), XMLoadFloat3(&up));

//storing the light view matrix
XMFLOAT4X4 lightView;
XMStoreFloat4x4(&lightView, XMMatrixTranspose(tempLightView));

//calculating projection matrix
XMFLOAT4X4 lightProjection;
XMMATRIX tempLightProjection = XMMatrixOrthographicLH((float)shadowViewport.Width,(float)shadowViewport.Height,
    0.0f,10000.0f);
XMStoreFloat4x4(&lightProjection, XMMatrixTranspose(tempLightProjection));

shadowVertexShader->SetShader();
context->PSSetShader(nullptr, nullptr, 0);

for (size_t i = 0; i < entities.size(); i++)
{
    auto tempVertexBuffer = entities[i]->GetMesh()->GetVertexBuffer();
    shadowVertexShader->SetMatrix4x4("view", lightView);
    shadowVertexShader->SetMatrix4x4("projection", lightProjection);
    shadowVertexShader->SetMatrix4x4("worldMatrix", entities[i]->GetModelMatrix());
    shadowVertexShader->CopyAllBufferData();
    context->IASetVertexBuffers(0, 1, &tempVertexBuffer, &stride, &offset);
    context->IASetIndexBuffer(entities[i]->GetMesh()->GetIndexBuffer(), DXGI_FORMAT_R32_UINT, 0);

    //drawing the entity
    context->DrawIndexed(entities[i]->GetMesh()->GetIndexCount(), 0, 0);
}

This is my pixel shader for creating the shadow map

float4 main(VertexShaderInput input): SV_POSITION
{

    matrix worldViewProj = mul(mul(worldMatrix,view),projection);

    //transforming the point
    float4 outpos = mul(float4(input.position,1.0f),worldViewProj);

    return outpos; //returning the position

}

\$\endgroup\$
2
\$\begingroup\$

When rendering a shadow map, you are rendering the scene geometry from the perspective of the light and the only thing you are trying to get from it is the depth of the scene.

Your pixel shader is set up like a vertex shader. Make your "pixel shader" be a vertex shader, and then you can either set your pixel shader to NULL or you can make a void pixel shader if you want to check something on the pixel before adding it. For example, a texture might have a low alpha channel indicating it is see through, so clipping it will make it not show up in the depth buffer.

A void pixel shader looks like this:

void SHADOW_PS (VertexShaderOutput input)
{
    //bHasTexture is a Constant Buffer value set per model section
    if (bHasTexture > 0)
    {
        //ObjTexture is a Texture2D, ObjSamplerState is a Sampler State
        float4 texColor = ObjTexture.Sample(ObjSamplerState, input.TexCoord);

        //if alpha of texture is too low, clip it
        clip(texColor.a - 0.2f);
    }
//note there is no return statement as there is no output
}

The improper setup of the vertex/pixel shaders is the most likely cause in your case of why you aren't getting anything. One other important thing to note is that you can't have the Shader Resource View (SRV) for a texture and a Render Target View (RTV)/Depth Stencil View (DSV) for the same texture bound to the graphics pipeline at the same time. After rendering the shadow map, you need to unbind the shadow DSV before binding the shadow SRV. Then, next frame, you need to unbind the shadow SRV before binding the shadow DSV again.

If you create your directx device with the debug flag enabled, in Visual Studios' debug output window (view->output), if there are any issues occurring with the graphics pipeline, messages detailing the issue will pop up there. It is an invaluable tool for debugging.

\$\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.