Класс камеры

This commit is contained in:
2022-12-15 13:43:53 +03:00
parent d1ec60c285
commit 7e1ffdfdfb
2 changed files with 218 additions and 0 deletions

160
src/Camera.cpp Normal file
View File

@@ -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
}