Класс камеры
This commit is contained in:
parent
d1ec60c285
commit
7e1ffdfdfb
|
@ -0,0 +1,58 @@
|
||||||
|
#ifndef CAMERA_H
|
||||||
|
#define CAMERA_H
|
||||||
|
|
||||||
|
#include <GLM/glm.hpp>
|
||||||
|
#include <GLM/gtx/euler_angles.hpp>
|
||||||
|
#include <GLM/gtc/matrix_transform.hpp>
|
||||||
|
#include <GLM/ext/matrix_transform.hpp>
|
||||||
|
|
||||||
|
#include "Model.h"
|
||||||
|
|
||||||
|
// Ближняя граница области отсечения
|
||||||
|
#define CAMERA_NEAR 0.1f
|
||||||
|
// Дальняя граница области отсечения
|
||||||
|
#define CAMERA_FAR 100.0f
|
||||||
|
// Вектор, задающий верх для камеры
|
||||||
|
#define CAMERA_UP_VECTOR glm::vec3(0.0f, 1.0f, 0.0f)
|
||||||
|
// Вектор, задающий стандартный поворот углами Эйлера (в положительном направлении оси Z)
|
||||||
|
#define CAMERA_DEFAULT_ROTATION glm::vec3(0.0f, 180.0f, 0.0f)
|
||||||
|
// Стандартный угол обзора
|
||||||
|
#define CAMERA_FOVy 60.0f
|
||||||
|
// Стандартная чувствительность
|
||||||
|
#define CAMERA_DEFAULT_SENSIVITY 0.005f
|
||||||
|
|
||||||
|
class Camera : public Node
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Camera(float aspect, const glm::vec3 &position = glm::vec3(0.0f), const glm::vec3 &initialRotation = CAMERA_DEFAULT_ROTATION, float fovy = CAMERA_FOVy); // Конструктор камеры с проекцией перспективы
|
||||||
|
Camera(float width, float height, const glm::vec3 &position = glm::vec3(0.0f), const glm::vec3 &initialRotation = CAMERA_DEFAULT_ROTATION); // Конструктор ортографической камеры
|
||||||
|
Camera(const Camera& copy); // Конструктор копирования камеры
|
||||||
|
Camera& operator=(const Camera& other); // Оператор присваивания
|
||||||
|
virtual ~Camera(); // Деструктор
|
||||||
|
|
||||||
|
const glm::mat4& getVP(); // Возвращает ссылку на константную матрицу произведения матриц вида и проекции
|
||||||
|
const glm::mat4& getProjection(); // Возвращает ссылку на константную матрицу проекции
|
||||||
|
const glm::mat4& getView(); // Возвращает ссылку на константную матрицу вида
|
||||||
|
|
||||||
|
void rotate(const glm::vec2 &xyOffset); // Поворачивает камеру на dx и dy пикселей с учетом чувствительности
|
||||||
|
|
||||||
|
void setPerspective(float fov, float aspect); // Устанавливает заданную матрицу перспективы
|
||||||
|
void setOrtho(float width, float height); // Устанавливает заданную ортографическую матрицу
|
||||||
|
void setSensitivity(float sensitivity); // Изменяет чувствительность мыши
|
||||||
|
const float& getSensitivity() const; // Возвращает чувствительность мыши
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Camera(const glm::vec3 &position, const glm::vec3 &initialRotation); // Защищенный (protected) конструктор камеры без перспективы
|
||||||
|
|
||||||
|
glm::mat4 view; // Матрица вида
|
||||||
|
glm::mat4 projection; // Матрица проекции
|
||||||
|
glm::mat4 vp; // Матрица произведения вида и проекции
|
||||||
|
bool requiredRecalcVP; // Необходимость пересчета матрицы вида и проекции камеры
|
||||||
|
|
||||||
|
float sensitivity; // Чувствительность мыши
|
||||||
|
|
||||||
|
virtual void recalcMatrices(); // Метод пересчета матрицы вида и произведения Вида*Проекции по необходимости, должен сбрасывать флаг changed
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // CAMERA_H
|
|
@ -0,0 +1,160 @@
|
||||||
|
#include "Camera.h"
|
||||||
|
|
||||||
|
// Защищенный (protected) конструктор камеры без перспективы
|
||||||
|
Camera::Camera(const glm::vec3 &pos, const glm::vec3 &initialRotation)
|
||||||
|
{
|
||||||
|
sensitivity = CAMERA_DEFAULT_SENSIVITY;
|
||||||
|
position = pos; // задаем позицию
|
||||||
|
// Определяем начальный поворот
|
||||||
|
glm::quat rotationAroundX = glm::angleAxis( glm::radians(initialRotation.x), glm::vec3(1.0f, 0.0f, 0.0f));
|
||||||
|
glm::quat rotationAroundY = glm::angleAxis(-glm::radians(initialRotation.y), glm::vec3(0.0f, 1.0f, 0.0f));
|
||||||
|
glm::quat rotationAroundZ = glm::angleAxis( glm::radians(initialRotation.z), glm::vec3(0.0f, 0.0f, 1.0f));
|
||||||
|
rotation = rotationAroundX * rotationAroundY * rotationAroundZ;
|
||||||
|
// Признак изменения
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Конструктор камеры с проекцией перспективы
|
||||||
|
Camera::Camera(float aspect, const glm::vec3 &position, const glm::vec3 &initialRotation, float fovy)
|
||||||
|
: Camera(position, initialRotation)
|
||||||
|
{
|
||||||
|
setPerspective(fovy, aspect);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Конструктор ортографической камеры
|
||||||
|
Camera::Camera(float width, float height, const glm::vec3 &position, const glm::vec3 &initialRotation)
|
||||||
|
: Camera(position, initialRotation)
|
||||||
|
{
|
||||||
|
setOrtho(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Конструктор копирования камеры
|
||||||
|
Camera::Camera(const Camera& copy)
|
||||||
|
: projection(copy.projection), requiredRecalcVP(copy.requiredRecalcVP), sensitivity(copy.sensitivity)
|
||||||
|
{
|
||||||
|
// Если у оригинала не было изменений - перепишем матрицу вида-проекции
|
||||||
|
if (!requiredRecalcVP)
|
||||||
|
vp = copy.vp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Оператор присваивания
|
||||||
|
Camera& Camera::operator=(const Camera& other)
|
||||||
|
{
|
||||||
|
projection = other.projection;
|
||||||
|
requiredRecalcVP = other.requiredRecalcVP;
|
||||||
|
sensitivity = other.sensitivity;
|
||||||
|
|
||||||
|
// Если у оригинала не было изменений - перепишем матрицу вида-проекции
|
||||||
|
if (!requiredRecalcVP)
|
||||||
|
vp = other.vp;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Деструктор
|
||||||
|
Camera::~Camera()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Возвращает ссылку на константную матрицу проекции
|
||||||
|
const glm::mat4& Camera::getProjection()
|
||||||
|
{
|
||||||
|
return projection;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Возвращает ссылку на константную матрицу вида
|
||||||
|
const glm::mat4& Camera::getView()
|
||||||
|
{
|
||||||
|
recalcMatrices();
|
||||||
|
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Возвращает ссылку на константную матрицу вида
|
||||||
|
const glm::mat4& Camera::getVP()
|
||||||
|
{
|
||||||
|
recalcMatrices();
|
||||||
|
|
||||||
|
return vp;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Устанавливает заданную матрицу перспективы
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Возвращает чувствительность мыши
|
||||||
|
const float& Camera::getSensitivity() const
|
||||||
|
{
|
||||||
|
return sensitivity;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Метод пересчета матрицы вида и произведения Вида*Проекции по необходимости, должен сбрасывать флаг changed
|
||||||
|
void Camera::recalcMatrices()
|
||||||
|
{
|
||||||
|
if (changed || parent_changed)
|
||||||
|
{
|
||||||
|
glm::vec3 _position = position;
|
||||||
|
glm::quat _rotation = rotation;
|
||||||
|
if (parent) // Если есть родитель
|
||||||
|
{
|
||||||
|
glm::mat4 normalized_transform = parent->getTransformMatrix();
|
||||||
|
for (int i = 0; i < 3; i++)
|
||||||
|
{
|
||||||
|
glm::vec3 axis = glm::vec3(normalized_transform[i]);
|
||||||
|
normalized_transform[i] = glm::vec4(glm::normalize(axis), normalized_transform[i].w);
|
||||||
|
}
|
||||||
|
glm::vec4 tmp = normalized_transform * glm::vec4(_position, 1.0f);
|
||||||
|
tmp /= tmp.w;
|
||||||
|
_position = glm::vec3(tmp);
|
||||||
|
_rotation = glm::quat_cast(normalized_transform) * _rotation;
|
||||||
|
}
|
||||||
|
glm::mat4 rotationMatrix = glm::mat4_cast(glm::conjugate(_rotation));
|
||||||
|
glm::mat4 translationMatrix = glm::translate(glm::mat4(1.0f), -_position);
|
||||||
|
view = rotationMatrix * translationMatrix;
|
||||||
|
requiredRecalcVP = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Node::recalcMatrices();
|
||||||
|
|
||||||
|
if (requiredRecalcVP)
|
||||||
|
{
|
||||||
|
vp = projection * view;
|
||||||
|
requiredRecalcVP = false; // Изменения применены
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Поворачивает камеру на dx и dy пикселей с учетом чувствительности
|
||||||
|
void Camera::rotate(const glm::vec2 &xyOffset)
|
||||||
|
{
|
||||||
|
// xyOffset - сдвиги координат мыши, xyOffset.x означает поворот вокруг оси Y, а xyOffset.y - поворот вокруг оси X
|
||||||
|
|
||||||
|
// Вращение вокруг оси Y
|
||||||
|
glm::quat qY = glm::angleAxis(-xyOffset.x * sensitivity, glm::vec3(0.0f, 1.0f, 0.0f));
|
||||||
|
|
||||||
|
// Вращение вокруг оси X
|
||||||
|
glm::quat qX = glm::angleAxis(xyOffset.y * sensitivity, glm::vec3(1.0f, 0.0f, 0.0f));
|
||||||
|
|
||||||
|
// Сначала применяем вращение вокруг Y, затем вокруг X
|
||||||
|
rotation = qY * rotation * qX;
|
||||||
|
|
||||||
|
changed = true;
|
||||||
|
invalidateParent(); // Проход потомков в глубину с изменением флага parent_changed
|
||||||
|
}
|
Loading…
Reference in New Issue