9
\$\begingroup\$

As a hobby I am working on a game engine in order to learn C++ and graphics programming, now I have completed my first iteration of my camera system using OpengGL and GLM. Because I am mostly self taught I am searching for some feedback.

I am mostly searching for feedback regarding the following points:

  • Is the API easy to understand/implement by another user
  • Are there any obvious mistakes made regarding performance
  • Are there any missing features you would suspect to be in a camera controller
  • Is the API consistent regarding code style and practices

But of course any other feedback is also much appreciated!

Perspective Camera
Low level, responsible for the projection matrix

// PerspectiveCamera.h
#ifndef CHEETAH_ENGINE_RENDERER_PERSPECTIVECAMERA_H_
#define CHEETAH_ENGINE_RENDERER_PERSPECTIVECAMERA_H_

#include "Core/Core.h"
#include "Events/ApplicationEvents.h"
#include "Camera.h"

#include "glm/glm.hpp"
#include "glm/gtc/matrix_transform.hpp"

namespace cheetah
{
    struct PerspectiveCameraParams
    {
        const float radians = 45.0f;
        const float zNear = -1.0f;
        const float zFar = 1.0f;
        const float aspectRatio;
        const float zoom;
        const glm::vec3 position = glm::vec3(0.0f);
        const glm::vec3 rotationAxis = glm::vec3(1.0f);
        const float rotationDegrees = 0.0f;
    };

    class CH_API PerspectiveCamera : public Camera
    {
    public:
        PerspectiveCamera(const PerspectiveCameraParams& params);


        inline glm::mat4 getViewProjectionMatrix() const override { return m_viewProjectionMatrix; };
        inline glm::mat4 getProjectionMatrix() const override { return m_projectionMatrix; };
        inline glm::mat4 getViewMatrix() const override { return m_viewMatrix; };
        inline float getZoom() const override { return m_zoom; };
        inline float getAspectRatio() const override { return m_aspectRatio; };

        void setZoom(const float& zoom) override;
        void setAspectRatio(const float& aspectRatio) override;
        void setViewMatrix(const glm::mat4& viewMatrix) override;

        void recalculateViewProjectionMatrix() override;

    private:
        float m_aspectRatio;
        float m_zoom;
        float m_zNear;
        float m_zFar;
        float m_radians;
        glm::mat4 m_projectionMatrix;
        glm::mat4 m_viewMatrix;
        glm::mat4 m_viewProjectionMatrix;
    };
}

#endif // !CHEETAH_ENGINE_RENDERER_PERSPECTIVECAMERA_H_
// PerspectiveCamera.cpp
#include "PerspectiveCamera.h"

namespace cheetah
{
    PerspectiveCamera::PerspectiveCamera(const PerspectiveCameraParams& params)
        :
        m_projectionMatrix(glm::perspective(glm::radians(params.radians), params.aspectRatio, params.zNear, params.zFar)),
        m_viewMatrix(glm::rotate(glm::translate(glm::mat4(1.0f), params.position), params.rotationDegrees, params.rotationAxis)),
        m_viewProjectionMatrix(m_projectionMatrix* m_viewMatrix),
        m_aspectRatio(params.aspectRatio),
        m_zoom(params.zoom),
        m_zNear(params.zNear),
        m_zFar(params.zFar),
        m_radians(params.radians)
    {
    }

    void PerspectiveCamera::setViewMatrix(const glm::mat4& viewMatrix)
    {
        m_viewMatrix = viewMatrix;
        recalculateViewProjectionMatrix();
    }

    void PerspectiveCamera::setZoom(const float& zoom)
    {
        m_zoom = zoom;
        m_projectionMatrix = glm::perspective(glm::radians(m_radians += m_zoom), m_aspectRatio, m_zNear, m_zFar);
        recalculateViewProjectionMatrix();
    }

    void PerspectiveCamera::setAspectRatio(const float& aspectRatio)
    {
        m_aspectRatio = aspectRatio;
        m_projectionMatrix = glm::perspective(glm::radians(m_radians), aspectRatio, m_zNear, m_zFar);
        recalculateViewProjectionMatrix();
    }

    void PerspectiveCamera::recalculateViewProjectionMatrix()
    {
        m_viewProjectionMatrix = m_projectionMatrix * m_viewMatrix;
    }
}

CameraController Higher level, doesn't care about camera type(ortho or perspective)

// CameraController.h
#ifndef CHEETAH_ENGINE_RENDERER_CAMERACONTROLLER_H_
#define CHEETAH_ENGINE_RENDERER_CAMERACONTROLLER_H_

#include "Core/Core.h"
#include "Camera.h"
#include "OrthoGraphicCamera.h"
#include "PerspectiveCamera.h"

#include <glm/gtc/matrix_transform.hpp>
#include <glm/glm.hpp>

#include <memory>

namespace cheetah
{
    class CH_API CameraController
    {
    public:
        CameraController(const OrthoGraphicCameraParams& params);
        CameraController(const PerspectiveCameraParams& params);

        // affect ProjectionMatrix
        void setZoom(const float& zoom);
        void setAspectRatio(const float& width, const float& height);

        // affect ViewMatrix
        void setPosition(const glm::vec3& position);
        void translate(const glm::vec3& position);
        void rotate(const float& degrees, const glm::vec3& axis);

        inline float getZoom() const { return m_camera->getZoom(); };
        inline float getAspectRatio() const { return m_camera->getAspectRatio(); };
        inline glm::vec3 getPosition() const { return m_position; };
        inline glm::vec3 getRotationAxis() const { return m_rotationAxis; };
        inline float getRotationDegrees() const { return m_rotationDegrees; };
        inline Camera& getCamera() const { return *m_camera; };
    private:
        float m_rotationDegrees;
        glm::vec3 m_rotationAxis;
        glm::vec3 m_position;
        std::unique_ptr<Camera> m_camera;
    };
}

#endif // !CHEETAH_ENGINE_RENDERER_CAMERACONTROLLER_H_
// CameraController.cpp
#include "CameraController.h"

namespace cheetah
{
    CameraController::CameraController(const OrthoGraphicCameraParams& params)
        :
        m_camera(std::make_unique<OrthoGraphicCamera>(params)),
        m_position(params.position),
        m_rotationAxis(params.rotationAxis),
        m_rotationDegrees(params.rotationDegrees)
    {
    }

    CameraController::CameraController(const PerspectiveCameraParams& params)
        :
        m_camera(std::make_unique<PerspectiveCamera>(params)),
        m_position(params.position),
        m_rotationAxis(params.rotationAxis),
        m_rotationDegrees(params.rotationDegrees)
    {
    }

    void CameraController::setZoom(const float& zoom)
    {
        m_camera->setZoom(zoom);
    }

    void CameraController::setAspectRatio(const float& width, const float& height)
    {
        m_camera->setAspectRatio(width / height);
    }

    void CameraController::setPosition(const glm::vec3& position)
    {
        m_position = position;
        m_camera->setViewMatrix(glm::rotate(glm::translate(glm::mat4(1.0f), position), m_rotationDegrees, m_rotationAxis));
    }

    void CameraController::translate(const glm::vec3& position)
    {
        m_position = position;
        m_camera->setViewMatrix(glm::translate(m_camera->getViewMatrix(), m_position));
    }

    void CameraController::rotate(const float& degrees, const glm::vec3& axis)
    {
        m_rotationDegrees = degrees;
        m_rotationAxis = axis;
        m_camera->setViewMatrix(glm::rotate(m_camera->getViewMatrix(), degrees, axis));
    }
}

Implementation
Here a possible way of implementing the CameraController

// MainCamera.h
#ifndef GAME_MAINCAMERA_H_
#define GAME_MAINCAMERA_H_

#include "Cheetah.h"

class MainCamera : public cheetah::CameraController
{
public:
    MainCamera(const cheetah::PerspectiveCameraParams& params);
    void onUpdate(const float& deltaTime);
    bool onWindowResize(const cheetah::WindowResizeEvent& event);
private:
    void handleKeyInput(const float& deltaTime);
};

#endif // !GAME_MAINCAMERA_H_

// MainCamera.cpp
#include "MainCamera.h"

using namespace cheetah;
using namespace math;
using namespace input;

MainCamera::MainCamera(const cheetah::PerspectiveCameraParams& params)
    : CameraController(params)
{
}

bool MainCamera::onWindowResize(const WindowResizeEvent& event)
{
    setAspectRatio((float)event.m_width, (float)event.m_height);
    return true;
}

void MainCamera::onUpdate(const float& deltaTime)
{
    handleKeyInput(deltaTime);
}

void MainCamera::handleKeyInput(const float& deltaTime)
{
    // reset
    if (Input::isKeyPressed(keys::R))
    {
        setPosition(vec3(0.0f, 0.0f, 0.0));
    }

    // moving
    if (Input::isKeyPressed(keys::W))
    {
        translate(vec3(0.0f, -(0.001f * deltaTime), 0.0f));
    }
    if (Input::isKeyPressed(keys::A))
    {
        translate(vec3(-(0.001f * deltaTime), 0.0f, 0.0f));
    }
    if (Input::isKeyPressed(keys::S))
    {
        translate(vec3(0.0f, 0.001f * deltaTime, 0.0f));
    }
    if (Input::isKeyPressed(keys::D))
    {
        translate(vec3(0.001f * deltaTime, 0.0f, 0.0f));
    }

    // rotating
    if (Input::isKeyPressed(keys::Q))
    {
        rotate(-(0.001f * deltaTime), vec3(0, 1, 0));
    }
    if (Input::isKeyPressed(keys::E))
    {
        rotate(0.001f * deltaTime, vec3(0, 1, 0));
    }
    if (Input::isKeyPressed(keys::Z))
    {
        translate(vec3(0.0f, 0.0f, 0.001f * deltaTime));
    }
    if (Input::isKeyPressed(keys::X))
    {
        translate(vec3(0.0f, 0.0f, -(0.001f * deltaTime)));
    }
}
\$\endgroup\$
10
\$\begingroup\$

Is the API easy to understand/implement by another user

It depends on how it will be used I think. Maybe the API is just what you need in your project, but another user might want to have a function like lookAt(const glm::vec3 &position) to point the camera at a specific point, or perhaps wants to set the field of view of a perspective camera as an angle, instead of having to specify a "zoom" level.

In particular, some functions set something to an absolute value, like setPosition(), others only do relative changes, like rotate(). It would be nice to have both relative and absolute setters for all parameters.

Are there any obvious mistakes made regarding performance

I don't see any big performance issues. However, consider that once you construct a CameraController, you cannot change the type of the camera (i.e., if you constructed a perspective one, it will always be a perspective camera). So m_camera is always the same during the lifetime of a Camera. If it was not a pointer, but an actual Camera instead, you wouldn't have to pay the price of indirection.

You can do this by making CameraController templated, like so:

template<typename CameraType>
class CameraController {
    public:
    CameraController(const CameraType::Params &params);
    ...

    private:
    CameraType m_camera;
};

To handle the constructor taking different types of parameters, you have to define the parameter structs inside the implementation of the Camera classes, like so:

class PerspectiveCamera: public Camera {
    public:
    struct Params {
        ...
    };

    PerspectiveCamera(const Params &params);
    ...
};

But perhaps even better, just forget about class CameraController, and move its functionality into the base class Camera.

Are there any missing features you would suspect to be in a camera controller

As mentioned above, a lookAt() function, setFOV() and setRotation(). Also, rotating based on an axis and an angle works for simple rotations, but as soon as you are combining rotations in different axes, things get weird. For a first-person shooter, you probably want to separate the rotation into an angle for the compass direction you are looking at (yaw), one for whether you are looking up or down (pitch), and finally one for how your head is tilted (roll). You want to keep these three values, and construct the rotation matrix from them using glm::gtx::euler_angles::eulerAngleYXZ.

For some applications, for example where you want to be able to rotate a sphere by clicking on a point an dragging it to a new position, you probably want to use quaternions to represent the current rotation.

Is the API consistent regarding code style and practices

Apart from possible different ways to structure your code as mentioned above, it looks fine. Good use of const, references (except for the floats) and smart pointers.

| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ Thanks, I like your suggestion of moving it to the base class, this seems a better and clean solution. I'll take a look at the proposed functionality, the lookat seems like something I would definitly use in the future. \$\endgroup\$ – Rick Nijhuis Mar 29 at 19:23
10
\$\begingroup\$

Your header files seem to be including unnecessary things, apparently for convenience. A header should only include the files required for that header to compile. Anything else just adds to the compile overhead for files that include the header but don't need those details.

float parameters should be passed to functions by value, not reference. Passing by value will allow them to be passed in registers, while reference needs both a memory location and a register to hold the address.

You don't need to use the inline keyword when defining a member function in a class, as those are implicitly inline.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Thanks, is passing by value better for any primitive type? or is it more dependent on the size of the type? \$\endgroup\$ – Rick Nijhuis Mar 30 at 9:20
  • \$\begingroup\$ Passing by reference is not the same as passing by pointer. You should by default pass everything by reference. \$\endgroup\$ – rav_kr Mar 30 at 11:26
  • \$\begingroup\$ @rav_kr We are not discussing passing by reference or pointer, but passing by reference or value. I know I should default pass everything by reference, but the answer above provides a reason why that is not always the case and why it could be better to pass by value. \$\endgroup\$ – Rick Nijhuis Mar 30 at 12:27
  • 1
    \$\begingroup\$ @RickNijhuis Typically the built-in types are passed by value. User types are passed by value or reference depending on how they are used. \$\endgroup\$ – 1201ProgramAlarm Mar 30 at 20:11
4
\$\begingroup\$

Dirty Flag Pattern

In all the getSomethingMatrix() you can apply the Dirty Flag Pattern described in the book Game Programming Patterns. This one ensure that calculations are only performed when they are needed. And, additionally, you will be able to reduce most of the code duplication inside setter functions. For example:

class CH_API PerspectiveCamera : public Camera 
{
public:
    // ... 
    private:
    // ...
    bool m_dirty = true;
};

.

void PerspectiveCamera::setZoom(const float& zoom)
{
    m_zoom  = zoom;
    m_dirty = true;
}

glm::mat4 PerspectiveCamera::getProjectionMatrix() 
{
    if(m_dirty)
    {
        recalculateViewProjectionMatrix();
    }
    return m_projectionMatrix;


glm::mat4 PerspectiveCamera::getViewProjectionMatrix() 
{
    if(m_dirty) 
    {
        recalculateViewProjectionMatrix();
    }
    return m_viewProjectionMatrix;
}   

void PerspectiveCamera::recalculateViewProjectionMatrix() 
{
    m_projectionMatrix = glm::perspective(glm::radians(m_fov/m_zoom), m_aspectRatio, m_zNear, m_zFar);
    m_viewProjectionMatrix = m_projectionMatrix * m_viewMatrix;
    m_dirty = false;
}

Note that this enforce you to remove the const statement of getter functions or make the matrix variables to be mutable.

It also would be nice if you have a class Transform with everything related to position, rotation and scale. That way, the CameraController becomes a generic TransformController (with additional methods to control camera specific fields) and the logic inside MainCamera::handleKeyInput could be applied to any object. This class may be used to get any object model matrix in your game engine. It also makes possible to have transform hierarchies, like a camera attached to a player.

| improve this answer | |
\$\endgroup\$
1
\$\begingroup\$

Using the above answers I have refactored my code and added some functionality.

Refactors:

  • Made all floats passed by value instead of reference(answer of @1201ProgramAlarm)
  • Removed CameraController class and moved logic to Camera base class(answer of @G. Sliepen)
  • More specific includes, instead of including glm.hpp now includes only needed definitions like glm/vec3.hpp(answer of @1201ProgramAlarm)
  • Renamed "radians" in PerspectiveCameraParams to "fov" for more clarity

New features

  • Added lookAt functionality(answer of @G. Sliepen)
  • Added for all functions setting an absolute value also a relative function, per example setRotation and rotate(answer of @G. Sliepen)
  • Added setFOV function for changing fov(answer of @G. Sliepen)

Some features, specially regarding rotations still need to be added, I will update this answer when new features are added.

Camera
At first a pure interface, now contains shared logic of both types of camera's(perspective/orthographic)

// Camera.h
#ifndef CHEETAH_ENGINE_RENDERER_CAMERA_H_
#define CHEETAH_ENGINE_RENDERER_CAMERA_H_

#include "Core/Core.h"

#include <glm/mat4x4.hpp>
#include <glm/vec3.hpp>

namespace cheetah
{
    class CH_API Camera
    {
    public:
        Camera(const glm::vec3& position, const::glm::vec3& rotationAxis, const float rotationDegrees, const glm::vec3& up = glm::vec3(0.0f, 1.0f, 0.0f));
        virtual ~Camera() = default;

        // perspective/orthographic specific responsibilities
        virtual glm::mat4 getViewProjectionMatrix() const = 0;
        virtual glm::mat4 getProjectionMatrix() const = 0;
        virtual glm::mat4 getViewMatrix() const = 0;
        virtual float getFOV() const = 0;
        virtual float getZoom() const = 0;
        virtual float getAspectRatio() const = 0;

        virtual void setFOV(const float fov) = 0;
        virtual void setZoom(const float zoom) = 0;
        virtual void setAspectRatio(const float aspectRatio) = 0;
        virtual void setViewMatrix(const glm::mat4& viewMatrix) = 0;
        virtual void recalculateViewProjectionMatrix() = 0;

        virtual void zoom(const float zoom) = 0;

        // shared logic
        void setUp(const glm::vec3& up);
        void setPosition(const glm::vec3& position);
        void setRotation(const float degrees, const glm::vec3& axis);
        void translate(const glm::vec3& position);
        void rotate(const float degrees, const glm::vec3& axis);
        void lookAt(const glm::vec3& target);

        inline glm::vec3 getUp() const { return m_up; };
        inline glm::vec3 getPosition() const { return m_position; };
        inline glm::vec3 getRotationAxis() const { return m_rotationAxis; };
        inline float getRotationDegrees() const { return m_rotationDegrees; };

    private:
        float m_rotationDegrees;
        glm::vec3 m_rotationAxis;
        glm::vec3 m_position;
        glm::vec3 m_up;
    };
}

#endif // !CHEETAH_ENGINE_RENDERER_CAMERA_H_
// Camera.cpp
#include "Camera.h"

#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/rotate_vector.hpp>

namespace cheetah
{
    Camera::Camera(const glm::vec3& position, const::glm::vec3& rotationAxis, const float rotationDegrees, const glm::vec3& up)
        : 
        m_position(position),
        m_rotationAxis(rotationAxis),
        m_rotationDegrees(rotationDegrees),
        m_up(up)
    {
    }

    void Camera::setUp(const glm::vec3& up)
    {
        m_up = up;
    }

    void Camera::setPosition(const glm::vec3& position)
    {
        m_position = position;
        setViewMatrix(glm::translate(glm::mat4(1.0f), position));
    }

    void Camera::setRotation(const float degrees, const glm::vec3& axis)
    {
        m_rotationAxis = axis;
        setViewMatrix(glm::rotate(getViewMatrix(), degrees - m_rotationDegrees, axis));
        m_rotationDegrees = degrees;
    }


    void Camera::translate(const glm::vec3& position)
    {
        m_position = position;
        setViewMatrix(glm::translate(getViewMatrix(), m_position));
    }

    void Camera::rotate(const float degrees, const glm::vec3& axis)
    {
        m_rotationDegrees += degrees;
        m_rotationAxis = axis;
        setViewMatrix(glm::rotate(getViewMatrix(), degrees, axis));
    }

    void Camera::lookAt(const glm::vec3& target)
    {
        setViewMatrix(glm::lookAt(m_position, target, m_up));
    }
}

PerspectiveCamera
Low level, responsible for camera specific projection matrix

// PerspectiveCamera.h
#ifndef CHEETAH_ENGINE_RENDERER_PERSPECTIVECAMERA_H_
#define CHEETAH_ENGINE_RENDERER_PERSPECTIVECAMERA_H_

#include "Core/Core.h"
#include "Camera.h"

#include <glm/vec3.hpp>
#include <glm/mat4x4.hpp>

namespace cheetah
{
    struct PerspectiveCameraParams
    {
        const float zNear = -1.0f;
        const float zFar = 1.0f;
        const float aspectRatio;
        const float zoom = 1.0f;
        const float fov = 45.0f;
        const glm::vec3 position = glm::vec3(0.0f);
        const glm::vec3 rotationAxis = glm::vec3(1.0f);
        const float rotationDegrees = 0.0f;
    };

    class CH_API PerspectiveCamera : public Camera
    {
    public:
        PerspectiveCamera(const PerspectiveCameraParams& params, const glm::vec3& up = glm::vec3(0.0f, 1.0f, 0.0f));


        inline glm::mat4 getViewProjectionMatrix() const override { return m_viewProjectionMatrix; };
        inline glm::mat4 getProjectionMatrix() const override { return m_projectionMatrix; };
        inline glm::mat4 getViewMatrix() const override { return m_viewMatrix; };
        inline float getFOV() const override { return m_fov; };
        inline float getZoom() const override { return m_zoom; };
        inline float getAspectRatio() const override { return m_aspectRatio; };

        void setFOV(const float fov) override;
        void setZoom(const float zoom) override;
        void setAspectRatio(const float aspectRatio) override;
        void setViewMatrix(const glm::mat4& viewMatrix) override;

        void zoom(const float zoom) override;

        void recalculateViewProjectionMatrix() override;

    private:
        float m_aspectRatio;
        float m_zoom;
        float m_zNear;
        float m_zFar;
        float m_fov;
        glm::mat4 m_projectionMatrix;
        glm::mat4 m_viewMatrix;
        glm::mat4 m_viewProjectionMatrix;
    };
}

#endif // !CHEETAH_ENGINE_RENDERER_PERSPECTIVECAMERA_H_
#include "PerspectiveCamera.h"

#include <glm/gtc/matrix_transform.hpp>

namespace cheetah
{
    PerspectiveCamera::PerspectiveCamera(const PerspectiveCameraParams& params, const glm::vec3& up)
        :
        Camera(params.position, params.rotationAxis, params.rotationDegrees, up),
        m_projectionMatrix(glm::perspective(glm::radians(params.fov / params.zoom), params.aspectRatio, params.zNear, params.zFar)),
        m_viewMatrix(glm::rotate(glm::translate(glm::mat4(1.0f), params.position), params.rotationDegrees, params.rotationAxis)),
        m_viewProjectionMatrix(m_projectionMatrix* m_viewMatrix),
        m_aspectRatio(params.aspectRatio),
        m_zoom(params.zoom),
        m_zNear(params.zNear),
        m_zFar(params.zFar),
        m_fov(params.fov)
    {
    }

    void PerspectiveCamera::setViewMatrix(const glm::mat4& viewMatrix)
    {
        m_viewMatrix = viewMatrix;
        recalculateViewProjectionMatrix();
    }

    void PerspectiveCamera::setFOV(const float fov)
    {
        m_fov = fov;
        m_projectionMatrix = glm::perspective(glm::radians(m_fov / m_zoom), m_aspectRatio, m_zNear, m_zFar);
        recalculateViewProjectionMatrix();
    }

    void PerspectiveCamera::setZoom(const float zoom)
    {
        m_zoom = zoom;
        m_projectionMatrix = glm::perspective(glm::radians(m_fov / m_zoom), m_aspectRatio, m_zNear, m_zFar);
        recalculateViewProjectionMatrix();
    }

    void PerspectiveCamera::zoom(const float zoom)
    {
        m_zoom += zoom;
        m_projectionMatrix = glm::perspective(glm::radians(m_fov / m_zoom), m_aspectRatio, m_zNear, m_zFar);
        recalculateViewProjectionMatrix();
    }

    void PerspectiveCamera::setAspectRatio(const float aspectRatio)
    {
        m_aspectRatio = aspectRatio;
        m_projectionMatrix = glm::perspective(glm::radians(m_fov / m_zoom), aspectRatio, m_zNear, m_zFar);
        recalculateViewProjectionMatrix();
    }

    void PerspectiveCamera::recalculateViewProjectionMatrix()
    {
        m_viewProjectionMatrix = m_projectionMatrix * m_viewMatrix;
    }
}

Implementation
Possible way of implementation

// MainCamera.h
#ifndef GAME_MAINCAMERA_H_
#define GAME_MAINCAMERA_H_

#include "Cheetah.h"

class MainCamera : public cheetah::PerspectiveCamera
{
public:
    MainCamera(const cheetah::PerspectiveCameraParams& params);
    void onUpdate(const float deltaTime);
    bool onWindowResize(const cheetah::WindowResizeEvent& event);
private:
    void handleKeyInput(const float deltaTime);
};

#endif // !GAME_MAINCAMERA_H_
// MainCamera.cpp
#include "MainCamera.h"

using namespace cheetah;
using namespace math;
using namespace input;

MainCamera::MainCamera(const cheetah::PerspectiveCameraParams& params)
    : PerspectiveCamera(params)
{
}

bool MainCamera::onWindowResize(const WindowResizeEvent& event)
{
    setAspectRatio(static_cast<float>(event.m_width) / static_cast<float>(event.m_height));
    return true;
}

void MainCamera::onUpdate(const float deltaTime)
{
    handleKeyInput(deltaTime);
}

void MainCamera::handleKeyInput(const float deltaTime)
{
    // reset
    if (Input::isKeyPressed(keys::R))
    {
        lookAt(vec3(0.0f, 0.0f, -20.0f));
    }

    // moving
    if (Input::isKeyPressed(keys::W))
    {
        translate(vec3(0.0f, -(0.01f * deltaTime), 0.0f));
    }
    if (Input::isKeyPressed(keys::A))
    {
        translate(vec3(-(0.001f * deltaTime), 0.0f, 0.0f));
    }
    if (Input::isKeyPressed(keys::S))
    {
        translate(vec3(0.0f, 0.01f * deltaTime, 0.0f));
    }
    if (Input::isKeyPressed(keys::D))
    {
        translate(vec3(0.001f * deltaTime, 0.0f, 0.0f));
    }
    if (Input::isKeyPressed(keys::Z))
    {
        translate(vec3(0.0f, 0.0f, 0.01f * deltaTime));
    }
    if (Input::isKeyPressed(keys::X))
    {
        translate(vec3(0.0f, 0.0f, -(0.01f * deltaTime)));
    }

    // rotating
    if (Input::isKeyPressed(keys::Q))
    {
        rotate(-(0.01f * deltaTime), vec3(0, 1, 0));
    }
    if (Input::isKeyPressed(keys::E))
    {
        rotate(0.01f * deltaTime, vec3(0, 1, 0));
    }

    // zooming
    if (Input::isKeyPressed(keys::C))
    {
        zoom(-(0.01f * deltaTime));
    }
    if (Input::isKeyPressed(keys::V))
    {
        zoom(0.01f * deltaTime);
    }
}

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.