2
\$\begingroup\$

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->Release();
vertexShaderBuffer = 0;

pixelShaderBuffer->Release();
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);
\$\endgroup\$
7
  • 1
    \$\begingroup\$ Where is your input layout setup? \$\endgroup\$ Commented Mar 17, 2015 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\$ Commented Mar 17, 2015 at 12:44
  • \$\begingroup\$ @ChuckWalbourn Just added the code I'm using to setup the input layout. \$\endgroup\$
    – Banath
    Commented Mar 17, 2015 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
    Commented Mar 17, 2015 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\$ Commented Mar 17, 2015 at 22:37

1 Answer 1

0
\$\begingroup\$

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!

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .