Search code examples
c++matrixdirectx-9

Calculation for View Matrix in C++ DirectX 9


I'm trying to create a first-person shooter camera for my DirectX game. But I'm struggling in trying to get my view matrix right. At the moment I have only got a triangle to display on the screen, but when I rotate the camera and move forward it seems like the triangle is rotating around the camera instead. Here is the code I have done for the Camera Class

Camera.h

#pragma once

#include"Window.h"
#include"Matrix.h"
#include "Vector3.h"

class Camera
{
public:
    Camera();
    Camera(float pitch, float yaw, Vector3 position);
    ~Camera();

    void Update();

    D3DXMATRIX BuildViewMatrix();

    Vector3 GetPosition() const { return position; }
    void SetPosition(Vector3 val) { position = val; }

protected:
    float yaw;
    float pitch;
    Vector3 position;
};

Camera.cpp

#include"Camera.h"
Camera::Camera()
{
    yaw = 0.0f;
    pitch = 0.0f;
}

Camera::Camera(float pitch, float yaw, Vector3 position)
{
    this->pitch = pitch;
    this->yaw = yaw;
    this->position = position;
}

Camera::~Camera()
{
}

void Camera::Update()
{
    pitch = min(pitch, 90.0f);
    pitch = max(pitch, -90.0f);

    if(yaw < 0)
        yaw += 360.0f;

    if( yaw > 360.0f)
        yaw -= 360.0f;


    if(Window::GetKeyboard()->KeyDown(KEYBOARD_W))
    {
        D3DXMATRIX translateMat;
        D3DXMatrixTranslation(&translateMat, position.x, position.y, position.z);

        D3DXMATRIX rotationMat;
        D3DXMatrixRotationY(&rotationMat, D3DXToRadian(yaw));

        D3DXMATRIX forwardMat;
        D3DXMatrixTranslation(&forwardMat, 0.0f, 0.0f, 10.0f);

        D3DXMATRIX transformMat = translateMat * rotationMat * forwardMat;

        position.x = transformMat._41;
        position.y = transformMat._42;
        position.z = transformMat._43;

        std::cout << "X: " << transformMat._41 << std::endl;
        std::cout << "Y: " << transformMat._42 << std::endl;
        std::cout << "Z: " << transformMat._43 << std::endl;
    }
    else if(Window::GetKeyboard()->KeyDown(KEYBOARD_S))
    {
    D3DXMATRIX translateMat;
    D3DXMatrixTranslation(&translateMat, position.x, position.y, position.z);

    D3DXMATRIX rotationMat;
    D3DXMatrixRotationY(&rotationMat, D3DXToRadian(yaw));

    D3DXMATRIX forwardMat;
    D3DXMatrixTranslation(&forwardMat, 0.0f, 0.0f, -10.0f);

    D3DXMATRIX transformMat = translateMat * rotationMat * forwardMat;

    position.x = transformMat._41;
    position.y = transformMat._42;
    position.z = transformMat._43;

    std::cout << "X: " << transformMat._41 << std::endl;
    std::cout << "Y: " << transformMat._42 << std::endl;
    std::cout << "Z: " << transformMat._43 << std::endl;
    }


    if(Window::GetKeyboard()->KeyDown(KEYBOARD_Q))
    {
        yaw = yaw - 1.0f;
    }

    if(Window::GetKeyboard()->KeyDown(KEYBOARD_E))
    {
        yaw = yaw + 1.0f;
    }
}

D3DXMATRIX Camera::BuildViewMatrix()
{
    D3DXMATRIX translationMat;
    D3DXMatrixTranslation(&translationMat, (position.x * -1.0f), (position.y * -1.0f), (position.z * -1.0f));

    D3DXMATRIX yawMat;
    D3DXMatrixRotationY(&yawMat, D3DXToRadian((yaw * -1.0f)));

    D3DXMATRIX pitchMat;
    D3DXMatrixRotationX(&pitchMat, D3DXToRadian((pitch * -1.0f)));

    D3DXMATRIX viewMat = pitchMat * yawMat * translationMat;

    return viewMat;
}

I'm using device->SetTransform(D3DTS_VIEW, &camera->BuildViewMatrix()); to send the view matrix to directX. What exactly am I doing wrong? Please help

UPDATE:

I have change the code and tried to use the D3DXMatrixLookAtLH function (doesn't use the Camera at all), but this time, it doesn't do anything - the triangle stays in the same position no matter how I change the LookAt parameter on the function. Here is the code for it:

void Renderer::Render()
{
    device->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(40, 40, 40), 1.0f, 0);

    device->BeginScene(); //Must be used as it tells DirectX we're starting to draw stuff.

    D3DXMATRIX worldMat;
    D3DXMatrixTranslation(&worldMat, 0.0f, 0.0f, 0.0f);
    device->SetTransform(D3DTS_WORLD, &worldMat);

    D3DXMATRIX viewMatrix;
    D3DXMatrixLookAtLH( &viewMatrix, 
                        &D3DXVECTOR3(0.0f, -100.0f, 1000.0f), //position
                        &D3DXVECTOR3(0.0f, 1.0f, 0.0f), //Look at
                        &D3DXVECTOR3(0.0f, 1.0f, 0.0f));
    device->SetTransform(D3DTS_VIEW, &viewMatrix);
    //device->SetTransform(D3DTS_VIEW, &camera->BuildViewMatrix());

    D3DXMATRIX projMatrix;
    D3DXMatrixPerspectiveFovLH( &projMatrix,
                                D3DXToRadian(45),
                                (float)width/(float)height,
                                1.0f,
                                10000.0f);
    device->SetTransform(D3DTS_PROJECTION, &projMatrix);

    device->SetFVF(VERTEXFORMAT);
    device->SetStreamSource(0, vertexBuffer, 0, sizeof(VERTEX));
    device->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1);

    device->EndScene(); //Thank you for waiting, I have finished drawing stuff on the screen, please handle the rest Mr DirectX.

    device->Present(NULL, NULL, NULL, NULL);
}

Solution

  • Found out the problem, the matrices I've calculated isn't correct as well as the view matrix. the fixed it by adding the following codes:

    Camera.h

    #pragma once
    
    #pragma comment(lib, "d3dx9.lib")
    #include<d3dx9math.h>
    
    #include"Window.h"
    
    class Camera
    {
    public:
        Camera();
        Camera(float pitch, float yaw, D3DXVECTOR3 position);
        ~Camera();
    
        void Update();
    
        D3DXMATRIX BuildViewMatrix();
    
        inline D3DXVECTOR3 GetPosition() const { return position; }
        inline void SetPosition(D3DXVECTOR3 position){ this->position = position;}
    
    protected:
        float yaw;
        float pitch;
        float roll;
        D3DXVECTOR3 position;
    
    private:
        D3DXVECTOR3 xAxis;
        D3DXVECTOR3 yAxis;
        D3DXVECTOR3 zAxis;
    };
    

    Camera.cpp

    #include"Camera.h"
    Camera::Camera()
    {
        yaw = 0.0f;
        pitch = 0.0f;
        roll = 0.0f;
    }
    
    //yaw = head twist
    //pitch = head tilt
    Camera::Camera(float pitch, float yaw, D3DXVECTOR3 position)
    {
        this->pitch = pitch;
        this->yaw = yaw;
        roll = 0.0f;
        this->position = position;
    
        xAxis = D3DXVECTOR3(1.0f, 0.0f, 0.0f);
        yAxis = D3DXVECTOR3(0.0f, 1.0f, 0.0f);
        zAxis = D3DXVECTOR3(0.0f, 0.0f, 1.0f);
    }
    
    Camera::~Camera()
    {
    
    }
    
    void Camera::Update()
    {
    
        if(Window::GetKeyboard()->KeyDown(KEYBOARD_Q)){
            yaw -= 1.0f;
        }
        else if(Window::GetKeyboard()->KeyDown(KEYBOARD_E)){
            yaw += 1.0f;
        }
    
        if(Window::GetKeyboard()->KeyDown(KEYBOARD_Z)){
            pitch += 1.0f;
        }
        else if(Window::GetKeyboard()->KeyDown(KEYBOARD_X)){
            pitch -= 1.0f;
        }
    
        pitch = min(pitch, 90.0f);
        pitch = max(pitch, -90.0f);
    
        if(yaw < 0.0f)
            yaw += 360.0f;
    
        if( yaw > 360.0f)
            yaw -= 360.0f;
    
    
        D3DXMATRIX yawMat;
        D3DXMatrixRotationAxis(&yawMat, &yAxis, D3DXToRadian(yaw));
        D3DXVec3TransformCoord(&zAxis, &zAxis, &yawMat);
        D3DXVec3TransformCoord(&xAxis, &xAxis, &yawMat);
    
        D3DXMATRIX pitchMat;
        D3DXMatrixRotationAxis(&pitchMat, &xAxis, D3DXToRadian(pitch));
        D3DXVec3TransformCoord(&zAxis, &zAxis, &pitchMat);
        D3DXVec3TransformCoord(&yAxis, &yAxis, &pitchMat);
    
        D3DXMATRIX rollMat;
        D3DXMatrixRotationAxis(&rollMat, &zAxis, D3DXToRadian(0.0f));
        D3DXVec3TransformCoord(&xAxis, &xAxis, &rollMat);
        D3DXVec3TransformCoord(&yAxis, &yAxis, &rollMat);
    
        if(Window::GetKeyboard()->KeyDown(KEYBOARD_W))
        {
            position = position + (zAxis * -1) * 10.0f;
        }
        else if(Window::GetKeyboard()->KeyDown(KEYBOARD_S))
        {
            position = position + zAxis * 10.0f;
        }
    
        if(Window::GetKeyboard()->KeyDown(KEYBOARD_A))
        {
            position = position + xAxis * 10.0f;
        }
        else if(Window::GetKeyboard()->KeyDown(KEYBOARD_D))
        {
            position = position - xAxis * 10.0f;
        }
    
        yaw = 0.0f;
        pitch = 0.0f;
        roll = 0.0f;
    }
    
    D3DXMATRIX Camera::BuildViewMatrix()
    {
        D3DXMATRIX viewMatrix;
        D3DXMatrixIdentity(&viewMatrix);
    
        viewMatrix._11 = xAxis.x;
        viewMatrix._21 = xAxis.y;
        viewMatrix._31 = xAxis.z;
    
        viewMatrix._12 = yAxis.x;
        viewMatrix._22 = yAxis.y;
        viewMatrix._32 = yAxis.z;
    
        viewMatrix._13 = zAxis.x;
        viewMatrix._23 = zAxis.y;
        viewMatrix._33 = zAxis.z;
    
        viewMatrix._41 = D3DXVec3Dot(&position, &xAxis);
        viewMatrix._42 = D3DXVec3Dot(&position, &yAxis);
        viewMatrix._43 = D3DXVec3Dot(&position, &zAxis);
    
        return viewMatrix;
    }