Arctic Pi
Arctic Pi

Reputation: 719

Incorrect render of a cube mesh in DirectX 11

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.

Upvotes: 1

Views: 318

Answers (1)

Chuck Walbourn
Chuck Walbourn

Reputation: 41127

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.

Upvotes: 1

Related Questions