#include "Camera.h" #include #include // Границы каскадов const float camera_cascade_distances[] = {CAMERA_NEAR, CAMERA_FAR / 50.0f, CAMERA_FAR / 10.0f, CAMERA_FAR / 3.0f, CAMERA_FAR}; // Защищенный (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; requiredRecalcCoords = true; } // Сдвигает камеру на указанный вектор (dx,dy,dz) void Camera::move(const glm::vec3 &posOffset) { position += posOffset; requiredRecalcView = true; requiredRecalcVP = true; requiredRecalcCoords = true; } // Устанавливает местоположение void Camera::setPosition(const glm::vec3 &pos) { position = pos; requiredRecalcView = true; requiredRecalcVP = true; requiredRecalcCoords = true; } // Устанавливает угол поворота камеры void Camera::setRotation(const glm::vec2 &xyOffset) { currentRotation = xyOffset; recalcTarget(); requiredRecalcCoords = true; } // Устанавливает заданную матрицу перспективы void Camera::setPerspective(float fovy, float aspect) { projection = glm::perspective(glm::radians(fovy), aspect, CAMERA_NEAR, CAMERA_FAR); requiredRecalcVP = true; requiredRecalcCoords = true; for (int cascade = 0; cascade < CAMERA_CASCADE_COUNT; cascade++) cascade_proj[cascade] = glm::perspective(glm::radians(fovy), aspect, camera_cascade_distances[cascade], camera_cascade_distances[cascade+1]); } // Устанавливает заданную ортографическую матрицу 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; requiredRecalcCoords = true; for (int cascade = 0; cascade < CAMERA_CASCADE_COUNT; cascade++) cascade_proj[cascade] = glm::ortho(-1.0f, 1.0f, -1.0f/aspect, 1.0f/aspect, camera_cascade_distances[cascade], camera_cascade_distances[cascade+1]); } // Изменяет чувствительность мыши void Camera::setSensitivity(float sens) { sensitivity = sens; } // Данные о камере для шейдера CameraData& Camera::getData() { static CameraData data; data = {getProjection(), getView(), position}; return data; } // Доступ к координатам проекции const glm::vec4 (*Camera::getProjCoords())[8] { if (requiredRecalcCoords) { glm::vec4 typical_points[8] = { { 1, 1, 1,1} , { 1, 1,-1,1} , { 1,-1, 1,1} , { 1,-1,-1,1} , {-1, 1, 1,1} , {-1, 1,-1,1} , {-1,-1, 1,1} , {-1,-1,-1,1}}; for (int cascade = 0; cascade < CAMERA_CASCADE_COUNT; cascade++) { glm::mat4 inv = glm::inverse(cascade_proj[cascade] * getView()); for (int i = 0; i < 8; i++) { coords[cascade][i] = inv * typical_points[i]; coords[cascade][i] /= coords[cascade][i].w; } } requiredRecalcCoords = false; } return coords; }