Search code examples
c++quaternionsglm-math

How to use quaternions to store the rotation of a camera?


I'm trying to make a "6 degrees of freedom" camera like the ones used in space games. I would like to learn how to store camera rotation as a quaternion but I can't exactly find anything on the internet to help me (or maybe I don't know what keywords I should be using).

What I want to do is use a glm::quat to store the orientation of the camera but the parts that I'm having issues with is changing the pitch, yaw, roll and finding out how to get the new up, right and direction vectors needed for the glm::lookAt function to create a view matrix.

So far this is my code with the functions I need help with marked:

#include "camera.hpp"
#include <glad/glad.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtc/quaternion.hpp>

Camera::Camera(glm::vec3 position, glm::quat orientation, float zNear, float zFar)
{
    this->position = position;
    this->orientation = orientation;

    right     = glm::vec3( 1,  0,  0);
    up        = glm::vec3( 0,  1,  0);
    direction = glm::vec3( 0,  0, -1);

    this->zNear = zNear;
    this->zFar = zFar;

    updateViewMatrix();
}

Camera::Camera(glm::vec3 position, glm::vec3 orientation, float zNear, float zFar)
{
    this->position = position;
    this->orientation = glm::quat(glm::vec3(glm::radians(orientation.x), glm::radians(orientation.y), glm::radians(orientation.z)));

    right     = glm::vec3( 1,  0,  0);
    up        = glm::vec3( 0,  1,  0);
    direction = glm::vec3( 0,  0, -1);

    this->zNear = zNear;
    this->zFar = zFar;

    updateViewMatrix();
}

void Camera::setPosition(glm::vec3 position)
{
    this->position = position;
}

void Camera::setOrientation(glm::quat orientation)
{
    this->orientation = orientation;
}

void Camera::setOrientation(glm::vec3 orientation)
{
    glm::quat orientationQuat = glm::quat(orientation);
    this->orientation = orientationQuat;
}

void Camera::setPitch(float amount)
{
    // NEED HELP
    updateViewMatrix();
}

void Camera::setYaw(float amount)
{
    // NEED HELP
    updateViewMatrix();
}

void Camera::setRoll(float amount)
{
    // NEED HELP
    updateViewMatrix();
}

void Camera::setZNear(float zNear)
{
    this->zNear = zNear;
    updateProjectionMatrix();
}

void Camera::setZFar(float zFar)
{
    this->zFar = zFar;
    updateProjectionMatrix();
}

void Camera::move(glm::vec3 movement)
{
    position += right * movement.x + up * movement.y + direction * movement.z;
    updateViewMatrix();
}

void Camera::moveAxis(glm::vec3 translation)
{
    position += translation;
    updateViewMatrix();
}

void Camera::rotate(glm::quat rotation)
{
    // NEED HELP
}

void Camera::rotate(glm::vec3 rotation)
{
    glm::quat rotationQuat = glm::quat(rotation);
    // NEED HELP
}

void Camera::pitch(float amount)
{
    // NEED HELP
    updateViewMatrix();
}

void Camera::yaw(float amount)
{
    // NEED HELP
    updateViewMatrix();
}

void Camera::roll(float amount)
{
    // NEED HELP
    updateViewMatrix();
}
// Excluded a few get___() functions here
glm::mat4 Camera::getViewMatrix() const
{
    return viewMatrix;
}
glm::mat4 Camera::getProjectionMatrix() const
{
    return projectionMatrix;
}
glm::mat4 Camera::getViewProjectionMatrix() const
{
    return viewProjectionMatrix;
}
void Camera::updateViewMatrix()
{
    viewMatrix = glm::lookAt(position, position + direction, up/*glm::cross(right, direction)*/);
    viewProjectionMatrix = projectionMatrix * viewMatrix;
}

These are the relevant variables I create in my header file:

glm::vec3 position;
glm::quat orientation;
glm::vec3 direction; // Camera Direction / Camera View Facing
glm::vec3 right;
glm::vec3 up;

Solution

  • I found the answer to my problem of "How to find the right, up and direction vectors for the glm::lookat function"

    All I need to do now is change the world up, right and direction vectors by the orientation of the quaternion like so:

    right = glm::normalize(orientation * glm::vec3(1, 0, 0));
    up = glm::normalize(orientation * glm::vec3(0, 1, 0));
    direction = glm::normalize(orientation * glm::vec3(0, 0, -1));