0
\$\begingroup\$

I've run into an issue when trying to write a simple rendering program in D3D11. I'm 90% sure it's to do with some faulty matrix multiplication or generation, but I've tried debugging the values of the matrices and they seem fine to me.

The problem is that no matter where I move the eye position, the rendered cube always appears the same.

The resulting screen image is like this:

Colourful gradients

Each vertex of the cube has a different colour, and the pixel shader should be blending between them, so the gradient effect you can see is between four vertices of the cube.

Here's some of my code

eyePos = XMVectorSet(0.0f, 1.0f, -5.0f, 0.0f);
lookAtPos = XMVectorSet(0.0f,1.0f,0.0f,0.0f);
up = XMVectorSet(0.0f,1.0f,0.0f,0.0f);

world = XMMatrixIdentity();
view = XMMatrixLookAtLH(eyePos, lookAtPos, up);
projection = XMMatrixPerspectiveFovLH(XM_PIDIV2, 1000.0f / 680.0f, 0.01f, 100.0f);

_pIContext->IASetVertexBuffers(0, 1, &_vertexBuffer, &stride, &offset);
_pIContext->IASetIndexBuffer(_indexBuffer, DXGI_FORMAT_R16_UINT, 0);
_pIContext->VSSetConstantBuffers(0, 1, &_cbWorldBuffer);
_pIContext->VSSetConstantBuffers(1, 1, &_cbViewBuffer);
_pIContext->VSSetConstantBuffers(2, 1, &_cbProjBuffer);

And then for shader code, we've got...

cbuffer worldBuffer : register(b0) {
    matrix World;
    float t;
}

cbuffer viewBuffer : register(b1) {
    matrix View;
}

cbuffer projectionBuffer : register(b2) {
    matrix Projection;
}

PS_INPUT vs(float4 pos : POSITION, float4 col : COLOUR) {
    PS_INPUT output = (PS_INPUT)0;
    output.Pos = mul(pos, World);
    output.Pos = mul(pos, View);
    output.Pos = mul(pos, Projection);

    output.Colour = col;
    return output;
}

float4 ps(PS_INPUT input) : SV_TARGET{
    return input.Colour;
}

My gut tells me it's the projection matrix, although I've based this on another project I did, and comparing the code, I can't find out what I've done differently.

\$\endgroup\$

1 Answer 1

0
\$\begingroup\$

Your code overwrites output.Pos three times, so only the last write sticks. That last write was:

output.Pos = mul(pos, Projection);

Note that this is multiplying your input vertex position (in object space) by the projection matrix. So your resulting position depends only on the mesh and the projection, ignoring the object's world transformation and the camera's view.

It looks like you meant to write something more like this:

output.Pos = mul(pos, World);
output.Pos = mul(output.Pos, View);
output.Pos = mul(output.Pos, Projection);

Note that the input to the last two steps is the output from the previous step, so their work filters through to the final result.

But a more conventional solution would be to multiply these three matrices together on the CPU, and upload a single combined matrix to the GPU as one uniform variable or constant buffer entry: your WorldViewProjection matrix. Then in the shader you only need to do one matrix multiplication instead of chaining three dependent ones.

\$\endgroup\$
3
  • \$\begingroup\$ Oh my gosh you're right! I can't believe I didn't notice it, and yes thank you for the info on combining into the MVP matrix on CPU side. I uploaded them as three different Constant buffers as the projection would only need to be re-calculated if window is resized right? (Or fov / near / far changed). And then the view only needs to be recalculated if the camera (eye) moves or looks at another point \$\endgroup\$
    – vK 3 1 RON
    Nov 5 at 23:04
  • \$\begingroup\$ A single matrix multiplication is cheap, so it's worth paying the cost once every frame to avoid having to do it thousands of times across all your vertices. \$\endgroup\$
    – DMGregory
    Nov 5 at 23:20
  • \$\begingroup\$ Right okay sounds good, I'll go ahead and implement that too thanks :) \$\endgroup\$
    – vK 3 1 RON
    Nov 6 at 1:38

You must log in to answer this question.

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