I'm following the Rastertek tutorials. I'm unable to get diffuse lighting working from http://www.rastertek.com/dx11tut06.html.

I think the NaNs in the following screenshots is just from stuff getting optimized out. I have found that I can run the same vertex and pixel shader frame through Visual Studio's Graphics Analyzer and sometimes get different values. 9/10 the values below are what's shown.

The vertex shader looks like its filling out the normal vector. It found the normal to be <0, -1, 0>, but I don't know if that's right.

The pixel shader is apparently getting a <0, 0, 0> vector.

Here's the vertex shader code. I skipped around Rastertek tutorials, which definitely is hurting now that I missed this 'basic' lighting problem.

cbuffer MatrixBuffer
    matrix worldMatrix;
    matrix viewMatrix;
    matrix projectionMatrix;

struct VertexInputType
    float4 position : POSITION;
    float2 tex : TEXCOORD0;
    float3 normal : NORMAL;

struct PixelInputType
    float4 position : SV_POSITION;
    float2 tex : TEXCOORD0;
    float3 normal : NORMAL;

PixelInputType LightVertexShader(VertexInputType input)
    PixelInputType output;

    // Change the position vector to be 4 units for proper matrix calculations.
    input.position.w = 1.0f;

    // 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);

    // Store the texture coordinates for the pixel shader.
    output.tex = input.tex;

    // Calculate the normal vector against the world matrix only.
    output.normal = mul(input.normal, (float3x3)worldMatrix);

    // Normalize the normal vector.
    output.normal = normalize(output.normal);

    return output;

And the pixel shader.

Texture2D shaderTexture;
SamplerState SampleType;

cbuffer LightBuffer
    float4 ambientColor;
    float4 diffuseColor;
    float3 lightDirection;
    float padding;

struct PixelInputType
    float4 position : SV_POSITION;
    float2 tex : TEXCOORD0;
    float3 normal : NORMAL;

float4 LightPixelShader(PixelInputType input) : SV_TARGET
    float4 textureColor;
    float3 lightDir;
    float lightIntensity;
    float4 color;

    textureColor = shaderTexture.Sample(SampleType, input.tex);

    // Set the default output color to the ambient light value for all pixels.
    color = ambientColor;

    // Invert the light direction for calculations.
    lightDir = -lightDirection;

    // Calculate the amount of light on this pixel.
    lightIntensity = saturate(dot(input.normal, lightDir));

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

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

    // Multiply the texture pixel and the final diffuse color to get the final pixel color result.
    color = color * textureColor;

    return color;

Here are the hardcoded vertices for the triangle.

vertices[0].position = DirectX::XMFLOAT3(-1.0f, -1.0f, 0.0f);  // Bottom left.
vertices[0].texture = DirectX::XMFLOAT2(0.0f, 1.0f);
vertices[0].normal = DirectX::XMFLOAT3(0.0f, 0.0f, -1.0f);

vertices[1].position = DirectX::XMFLOAT3(0.0f, 1.0f, 0.0f);  // Top middle.
vertices[1].texture = DirectX::XMFLOAT2(0.5f, 0.0f);
vertices[1].normal = DirectX::XMFLOAT3(0.0f, 0.0f, -1.0f);

vertices[2].position = DirectX::XMFLOAT3(1.0f, -1.0f, 0.0f);  // Bottom right.
vertices[2].texture = DirectX::XMFLOAT2(1.0f, 1.0f);
vertices[2].normal = DirectX::XMFLOAT3(0.0f, 0.0f, -1.0f);

If there's some other piece of code you think is relevant let me know. I just didn't want to overload this post with code.

Edit 3/17/2015 Here is the input layout.

HRESULT result; // FAILED(result) checks have been omitted.
ID3D10Blob* errorMessage = 0;
ID3D10Blob* vertexShaderBuffer = 0;
ID3D10Blob* pixelShaderBuffer = 0;
D3D11_INPUT_ELEMENT_DESC polygonLayout[3];
unsigned int numElements;
D3D11_BUFFER_DESC matrixBufferDesc;
D3D11_SAMPLER_DESC samplerDesc;
D3D11_BUFFER_DESC lightBufferDesc;

result = D3DCompileFromFile(vsFilename, NULL, NULL, "LightVertexShader", "vs_5_0", D3D10_SHADER_ENABLE_STRICTNESS | D3DCOMPILE_DEBUG, 0, &vertexShaderBuffer, &errorMessage);
result = D3DCompileFromFile(psFilename, NULL, NULL, "LightPixelShader", "ps_5_0", D3D10_SHADER_ENABLE_STRICTNESS | D3DCOMPILE_DEBUG, 0, &pixelShaderBuffer, &errorMessage);
result = device->CreateVertexShader(vertexShaderBuffer->GetBufferPointer(), vertexShaderBuffer->GetBufferSize(), NULL, &mVertexShader);
result = device->CreatePixelShader(pixelShaderBuffer->GetBufferPointer(), pixelShaderBuffer->GetBufferSize(), NULL, &mPixelShader);

// Setup the layout of data that goes into the shader.
// This setup needs to match the VertexType structure in the model and in the shader.
polygonLayout[0].SemanticName = "POSITION";
polygonLayout[0].SemanticIndex = 0;
polygonLayout[0].Format = DXGI_FORMAT_R32G32B32_FLOAT;
polygonLayout[0].InputSlot = 0;
polygonLayout[0].AlignedByteOffset = 0;
polygonLayout[0].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
polygonLayout[0].InstanceDataStepRate = 0;

polygonLayout[1].SemanticName = "TEXCOORD";
polygonLayout[1].SemanticIndex = 0;
polygonLayout[1].Format = DXGI_FORMAT_R32G32B32_FLOAT;
polygonLayout[1].InputSlot = 0;
polygonLayout[1].AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT;
polygonLayout[1].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
polygonLayout[1].InstanceDataStepRate = 0;

polygonLayout[2].SemanticName = "NORMAL";
polygonLayout[2].SemanticIndex = 0;
polygonLayout[2].Format = DXGI_FORMAT_R32G32B32_FLOAT;
polygonLayout[2].InputSlot = 0;
polygonLayout[2].AlignedByteOffset = D3D11_APPEND_ALIGNED_ELEMENT;
polygonLayout[2].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
polygonLayout[2].InstanceDataStepRate = 0;

numElements = sizeof(polygonLayout) / sizeof(polygonLayout[0]);

result = device->CreateInputLayout(polygonLayout, numElements, vertexShaderBuffer->GetBufferPointer(), vertexShaderBuffer->GetBufferSize(), &mLayout);

vertexShaderBuffer = 0;

pixelShaderBuffer = 0;

samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
samplerDesc.MipLODBias = 0.0f;
samplerDesc.MaxAnisotropy = 1;
samplerDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
samplerDesc.BorderColor[0] = 0;
samplerDesc.BorderColor[1] = 0;
samplerDesc.BorderColor[2] = 0;
samplerDesc.BorderColor[3] = 0;
samplerDesc.MinLOD = 0;
samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;

result = device->CreateSamplerState(&samplerDesc, &mSampleState);
if (FAILED(result))
    return false;

// Setup the description of the dynamic matrix const buffer that is in the vertex shader.
matrixBufferDesc.Usage = D3D11_USAGE_DYNAMIC;
matrixBufferDesc.ByteWidth = sizeof(MatrixBufferType);
matrixBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
matrixBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
matrixBufferDesc.MiscFlags = 0;
matrixBufferDesc.StructureByteStride = 0;

result = device->CreateBuffer(&matrixBufferDesc, NULL, &mMatrixBuffer);
if (FAILED(result))
    return false;

lightBufferDesc.Usage = D3D11_USAGE_DYNAMIC;
lightBufferDesc.ByteWidth = sizeof(LightBufferType);
lightBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
lightBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
lightBufferDesc.MiscFlags = 0;
lightBufferDesc.StructureByteStride = 0;

result = device->CreateBuffer(&lightBufferDesc, NULL, &mLightBuffer);

Struct that is given to the vertex shader.

struct VertexType
    DirectX::XMFLOAT3 position;
    DirectX::XMFLOAT2 texture;
    DirectX::XMFLOAT3 normal;

Setting the shader parameters.

HRESULT result;
D3D11_MAPPED_SUBRESOURCE mappedResource;
MatrixBufferType* dataPtr;
LightBufferType* dataPtr2;
unsigned int bufferNumber;

// Lock the const buffer so it can be written to.
result = deviceContext->Map(mMatrixBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
if (FAILED(result))
    return false;

dataPtr = (MatrixBufferType*)mappedResource.pData;

dataPtr->world = DirectX::XMMatrixTranspose(worldMatrix);
dataPtr->view = DirectX::XMMatrixTranspose(viewMatrix);
dataPtr->projection = DirectX::XMMatrixTranspose(projectionMatrix);

// Unlock.
deviceContext->Unmap(mMatrixBuffer, 0);

bufferNumber = 0;

deviceContext->VSSetConstantBuffers(bufferNumber, 1, &mMatrixBuffer);

deviceContext->PSSetShaderResources(0, 1, &texture);

result = deviceContext->Map(mLightBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
if (FAILED(result))
    return false;

dataPtr2 = (LightBufferType*)mappedResource.pData;

dataPtr2->ambientColor = ambientColor;
dataPtr2->diffuseColor = diffuseColor;
dataPtr2->lightDirection = lightDirection;
dataPtr2->padding = 0.0f;

deviceContext->Unmap(mLightBuffer, 0);

bufferNumber = 0;

deviceContext->PSSetConstantBuffers(bufferNumber, 1, &mLightBuffer);
  • 1
    \$\begingroup\$ Where is your input layout setup? \$\endgroup\$ – Chuck Walbourn Mar 17 '15 at 7:10
  • \$\begingroup\$ When stepping through possibly optimized code no matter which platform, consider looking at the assembly code instead and stepping that, as debuggers will happily lie to you. \$\endgroup\$ – Lars Viklund Mar 17 '15 at 12:44
  • \$\begingroup\$ @ChuckWalbourn Just added the code I'm using to setup the input layout. \$\endgroup\$ – Banath Mar 17 '15 at 22:09
  • \$\begingroup\$ @LarsViklund I will keep that in mind, thank you :). I'm not going to get started with assembly now, but will make sure to learn how to step through optimized code in assembly in the coming weeks. Without knowing assembly, I can roll back my changes in the tutorial series until the lighting works. \$\endgroup\$ – Banath Mar 17 '15 at 22:12
  • \$\begingroup\$ You should make sure to check the HRESULT for every function that returns one. if (FAILED(hr)) or DX::ThrowIfFailed(hr); \$\endgroup\$ – Chuck Walbourn Mar 17 '15 at 22:37

My lighting problem was caused by two things.

1.) My input layout's TEXCOORD was set to DXGI_FORMAT_R32G32B32_FLOAT instead of DXGI_FORMAT_R32G32_FLOAT. I suspect that this was behind the weird debug output I was seeing from my shaders, but I'm not sure.

and 2.) My light was facing down the negative z axis, instead of the positive z axis.

Either of these fixes alone had no effect visually, but together fixed the diffuse lighting!


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.