diff --git a/include/Camera.h b/include/Camera.h new file mode 100644 index 0000000..3357cba --- /dev/null +++ b/include/Camera.h @@ -0,0 +1,49 @@ +#ifndef CAMERA_H +#define CAMERA_H + +#include + +// Ближняя граница области отсечения +#define CAMERA_NEAR 0.1f +// Дальняя граница области отсечения +#define CAMERA_FAR 100.0f +// Вектор, задающий верх для камеры +#define CAMERA_UP_VECTOR glm::vec3(0.0f, 1.0f, 0.0f) +// Стандартный угол обзора +#define CAMERA_FOVy 60.0f + +class Camera +{ + public: + Camera(float aspect, const glm::vec3 &position = glm::vec3(0.0f, 0.0f, 0.0f), const glm::vec2 &xyOffset = glm::vec2(90.0f, 0.0f), float fovy = CAMERA_FOVy); // Конструктор камеры с проекцией перспективы + Camera(float width, float height, const glm::vec3 &position = glm::vec3(0.0f, 0.0f, 0.0f), const glm::vec2 &xyOffset = glm::vec2(90.0f, 0.0f)); // Конструктор ортографической камеры + virtual ~Camera(); // Деструктор + const glm::mat4& getVP(); // Возвращает ссылку на константную матрицу произведения матриц вида и проекции + const glm::mat4& getProjection(); // Возвращает ссылку на константную матрицу проекции + const glm::mat4& getView(); // Возвращает ссылку на константную матрицу вида + void rotate(const glm::vec2 &xyOffset); // Поворачивает камеру на dx и dy пикселей + void move(const glm::vec3 &posOffset); // Сдвигает камеру на указанный вектор (dx,dy,dz) + void setPosition(const glm::vec3 &position); // Устанавливает местоположение + void setRotation(const glm::vec2 &xyOffset); // Устанавливает угол поворота камеры + void setPerspective(float fov, float aspect); // Устанавливает заданную матрицу перспективы + void setOrtho(float width, float height); // Устанавливает заданную ортографическую матрицу + void setSensitivity(float sensitivity); // Изменяет чувствительность мыши + protected: + Camera(const glm::vec3 &position, const glm::vec2 &xyOffset); // Защищенный (protected) констуктор камеры без перспективы + void recalcTarget(); // Пересчет цели, на которую смотрит камера + void recalcView(); // Пересчет матрицы вида + void recalcVP(); // Пересчет произведения матриц + + glm::vec3 position; // Местоположение камеры + glm::vec3 target; // Цель, на которую смотрит камера + glm::vec2 currentRotation; // Текущий поворот камеры + glm::mat4 projection; // Матрица проекции + glm::mat4 view; // Матрица вида + glm::mat4 vp; // Матрица произведения вида и проекции + bool requiredRecalcVP; // Необходимость пересчета матрицы вида и проекции камеры + bool requiredRecalcView; // Необходимость пересчета матрицы вида камеры + float sensitivity; // Чувствительность мыши +}; + + +#endif // CAMERA_H \ No newline at end of file diff --git a/src/Camera.cpp b/src/Camera.cpp new file mode 100644 index 0000000..d1f6431 --- /dev/null +++ b/src/Camera.cpp @@ -0,0 +1,141 @@ +#include "Camera.h" + +#include +#include + +// Защищенный (protected) конструктор камеры без перспективы +Camera::Camera(const glm::vec3 &pos, const glm::vec2 &xyOffset) +: position(pos), currentRotation(xyOffset) +{ + sensitivity = 0.05; + recalcTarget(); +} + +// Конструктор камеры с проекцией перспективы +Camera::Camera(float aspect, const glm::vec3 &position, const glm::vec2 &xyOffset, float fovy) +: Camera(position, xyOffset) +{ + setPerspective(fovy, aspect); +} + +// Конструктор ортографической камеры +Camera::Camera(float width, float height, const glm::vec3 &position, const glm::vec2 &xyOffset) +: Camera(position, xyOffset) +{ + setOrtho(width, height); +} + +// Деструктор +Camera::~Camera() { } + +// Пересчет цели, на которую смотрит камера +void Camera::recalcTarget() +{ + if(currentRotation.y > 89.0f) + currentRotation.y = 89.0f; + if(currentRotation.y < -89.0f) + currentRotation.y = -89.0f; + + target.x = cos(glm::radians(currentRotation.x)) * cos(glm::radians(currentRotation.y)); + target.y = sin(glm::radians(currentRotation.y)); + target.z = sin(glm::radians(currentRotation.x)) * cos(glm::radians(currentRotation.y)); + + requiredRecalcView = true; + requiredRecalcVP = true; +} + +// Пересчет матрицы вида +void Camera::recalcView() +{ + view = glm::lookAt(position, position + target, CAMERA_UP_VECTOR); + requiredRecalcView = false; +} + +// Пересчет произведения матриц +void Camera::recalcVP() +{ + vp = projection * view; + requiredRecalcVP = false; +} + +// Возвращает ссылку на константную матрицу проекции +const glm::mat4& Camera::getProjection() +{ + return projection; +} + +// Возвращает ссылку на константную матрицу вида +const glm::mat4& Camera::getView() +{ + if (requiredRecalcView) + recalcView(); + return view; +} + +// Возвращает ссылку на константную матрицу вида +const glm::mat4& Camera::getVP() +{ + if (requiredRecalcVP) + { + if (requiredRecalcView) + recalcView(); + recalcVP(); + } + return vp; +} + +// Поворачивает камеру на dx и dy пикселей +void Camera::rotate(const glm::vec2 &xyOffset) +{ + currentRotation += xyOffset * sensitivity; + + recalcTarget(); + requiredRecalcView = true; + requiredRecalcVP = true; +} + +// Сдвигает камеру на указанный вектор (dx,dy,dz) +void Camera::move(const glm::vec3 &posOffset) +{ + position += posOffset; + + requiredRecalcView = true; + requiredRecalcVP = true; +} + +// Устанавливает местоположение +void Camera::setPosition(const glm::vec3 &pos) +{ + position = pos; + + requiredRecalcView = true; + requiredRecalcVP = true; +} + +// Устанавливает угол поворота камеры +void Camera::setRotation(const glm::vec2 &xyOffset) +{ + currentRotation = xyOffset; + recalcTarget(); +} + +// Устанавливает заданную матрицу перспективы +void Camera::setPerspective(float fovy, float aspect) +{ + projection = glm::perspective(glm::radians(fovy), aspect, CAMERA_NEAR, CAMERA_FAR); + requiredRecalcVP = true; +} + +// Устанавливает заданную ортографическую матрицу +void Camera::setOrtho(float width, float height) +{ + const float aspect = width / height; + projection = glm::ortho(-1.0f, 1.0f, -1.0f/aspect, 1.0f/aspect, CAMERA_NEAR, CAMERA_FAR); + requiredRecalcVP = true; +} + +// Изменяет чувствительность мыши +void Camera::setSensitivity(float sens) +{ + sensitivity = sens; +}