FPSCamera.h#

Parent directory (cameras)

A class representing a First person camera and functionality to manipulate it.

Includes#

  • PVRCore/glm.h

Namespaces#

Classes#

Source Code#

#pragma once
#include "PVRCore/glm.h"

namespace pvr {
class FPSCamera
{
public:
    FPSCamera() : _yaw(0.f), _pos(0.f), _isPosDirty(true), _isOrientationDirty(true), _moveZ(0.f), _moveX(0.f), _pitch(0.f)
    {
        _right = glm::vec3(1.f, 0.0f, 0.0f);
        _up = glm::vec3(0.f, 1.0f, 0.0f);
        _look = glm::vec3(0.f, 0.0f, -1.0f);
    }

    void moveZ(float z)
    {
        _moveZ += z;
        _isPosDirty = true;
    }

    void moveX(float x)
    {
        _moveX += x;
        _isPosDirty = true;
    }

    void set(const glm::vec3& camPos, float yaw, float pitch)
    {
        setPosition(camPos);
        setOrientation(yaw, pitch);
    }

    void setPosition(const glm::vec3& camPos)
    {
        _pos = camPos;
        _isPosDirty = true;
    }

    void setOrientation(float yaw, float pitch)
    {
        _yaw = _pitch = 0.f;
        orientate(yaw, pitch);
    }

    void yaw(float yaw)
    {
        _yaw += yaw;
        if (_yaw <= -180.f) { _yaw += 360.f; }
        if (_yaw > 180.f) { _yaw -= 360.f; }
        _isOrientationDirty = true;
    }

    void reset(const glm::vec3& pos, float yaw, float pitch)
    {
        _pos = pos;
        _isPosDirty = true;
        _pitch = 0.0f;
        _yaw = 0.0f;
        orientate(yaw, pitch);
    }

    void pitch(float pitch)
    {
        _pitch += pitch;
        _pitch = glm::clamp(_pitch, -90.f, 90.f);
        _isOrientationDirty = true;
    }

    void orientate(float yaw, float pitch)
    {
        _isOrientationDirty = true;
        _pitch += pitch;
        _pitch = glm::clamp(_pitch, -90.f, 90.f);
        this->yaw(yaw);
    }

    const glm::vec3& getPosition()
    {
        updateRUL();
        updatePos();
        return _pos;
    }

    glm::mat4 getViewMatrix() const
    {
        updateRUL();
        updatePos();
        // Create a 4x4 view matrix from the right, up, forward and eye position vectors
        glm::mat4 viewMatrix = { glm::vec4(_right.x, _up.x, _look.x, 0), glm::vec4(_right.y, _up.y, _look.y, 0), glm::vec4(_right.z, _up.z, _look.z, 0),
            glm::vec4(-glm::dot(_right, _pos), -glm::dot(_up, _pos), -glm::dot(_look, _pos), 1) };
        return viewMatrix;
    }

private:
    void updateRUL() const
    {
        if (_isOrientationDirty)
        {
            // If the pitch and yaw angles are in degrees,
            // they need to be converted to radians. Here
            // I assume the values are already converted to radians.
            const float cosPitch = cos(glm::radians(_pitch));
            const float sinPitch = sin(glm::radians(_pitch));
            const float cosYaw = cos(glm::radians(_yaw));
            const float sinYaw = sin(glm::radians(_yaw));

            _right = { cosYaw, 0, -sinYaw };
            _up = { sinYaw * sinPitch, cosPitch, cosYaw * sinPitch };
            _look = { sinYaw * cosPitch, -sinPitch, cosPitch * cosYaw };
            _isOrientationDirty = false;
        }
    }

    void updatePos() const
    {
        if (_isPosDirty)
        {
            _pos += _moveZ * _look;
            _isPosDirty = false;
            _moveZ = 0.0f;
        }
    }

    mutable glm::vec3 _pos;
    mutable float _moveZ, _moveX;
    float _yaw, _pitch;
    mutable glm::vec3 _right, _look, _up;
    mutable glm::mat4 _viewX;
    mutable bool _isPosDirty;
    mutable bool _isOrientationDirty;
};
} // namespace pvr