1

I am practicing DirectX 11 following Frank Luna's book.

I have implemented a demo that renders a cube, but the result is not correct.

https://i.imgur.com/2uSkEiq.gif

As I hope you can see from the image (I apologize for the low quality), it seems like the camera is "trapped" inside the cube even when I move it away. There is also a camera frustum clipping problem.

I think the problem is therefore in the definition of the projection matrix.

Here is the cube vertices definition.

std::vector<Vertex> vertices =
{
    {XMFLOAT3(-1, -1, -1), XMFLOAT4(1, 1, 1, 1)},
    {XMFLOAT3(-1, +1, -1), XMFLOAT4(0, 0, 0, 1)},
    {XMFLOAT3(+1, +1, -1), XMFLOAT4(1, 0, 0, 1)},
    {XMFLOAT3(+1, -1, -1), XMFLOAT4(0, 1, 0, 1)},
    {XMFLOAT3(-1, -1, +1), XMFLOAT4(0, 0, 1, 1)},
    {XMFLOAT3(-1, +1, +1), XMFLOAT4(1, 1, 0, 1)},
    {XMFLOAT3(+1, +1, +1), XMFLOAT4(0, 1, 1, 1)},
    {XMFLOAT3(+1, -1, +1), XMFLOAT4(1, 0, 1, 1)},
};

Here is how I calculate the view and projection matrices.

void TestApp::OnResize()
{
    D3DApp::OnResize();
    mProj = XMMatrixPerspectiveFovLH(XM_PIDIV4, AspectRatio(), 1, 1000);
}

void TestApp::UpdateScene(float dt)
{
    float x = mRadius * std::sin(mPhi) * std::cos(mTheta);
    float y = mRadius * std::cos(mPhi);
    float z = mRadius * std::sin(mPhi) * std::sin(mTheta);
    
    XMVECTOR EyePosition   = XMVectorSet(x, y, z, 1);
    XMVECTOR FocusPosition = XMVectorZero();
    XMVECTOR UpDirection   = XMVectorSet(0, 1, 0, 0);

    mView = XMMatrixLookAtLH(EyePosition, FocusPosition, UpDirection);
}

And here is how I update the camera position on mouse move.

glfwSetCursorPosCallback(mMainWindow, [](GLFWwindow* window, double xpos, double ypos)
{
    TestApp* app = reinterpret_cast<TestApp*>(glfwGetWindowUserPointer(window));

    if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS)
    {
        float dx = 0.25f * XMConvertToRadians(xpos - app->mLastMousePos.x);
        float dy = 0.25f * XMConvertToRadians(ypos - app->mLastMousePos.y);

        app->mTheta += dx;
        app->mPhi   += dy;

        app->mPhi = std::clamp(app->mPhi, 0.1f, XM_PI - 0.1f);
    }
    else if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS)
    {
        float dx = 0.05f * XMConvertToRadians(xpos - app->mLastMousePos.x);
        float dy = 0.05f * XMConvertToRadians(ypos - app->mLastMousePos.y);

        app->mRadius += (dx - dy);

        app->mRadius = std::clamp(app->mRadius, 3.f, 15.f);
    }

    app->mLastMousePos = XMFLOAT2(xpos, ypos);
});

Thanks.

Chuck Walbourn
  • 38,259
  • 2
  • 58
  • 81
Arctic Pi
  • 669
  • 5
  • 19
  • 1
    What about your shader and updating the constant buffer? It looks like something is wrong with the transform, but it could be in your shader. BTW, you may want to look at [DirectX Tool Kit for DX11](https://github.com/microsoft/DirectXTK/wiki/Getting-Started) – Chuck Walbourn Jul 26 '20 at 03:34
  • Thanks so much. You got that right, the problem was in the constant buffer. I use the `ID3D11DeviceContext::UpdateSubresource` method to copy the buffer to VRAM, which appears to transpose the matrix during the copy, transposing the matrix in the shader again solves the problem. – Arctic Pi Jul 26 '20 at 10:21

1 Answers1

1

The root problem here was in the constant buffer vs. CPU update.

HLSL defaults to column-major matrix definitions per Microsoft Docs. DirectXMath uses row-major matrices, so you have to transpose while updating the Constant Buffer.

Alternatively, you can declare the HLSL matrix with the row_major keyword, #pragma pack_matrix, or the /Zpr compiler switch.

Chuck Walbourn
  • 38,259
  • 2
  • 58
  • 81