Compare commits
5 Commits
Author | SHA1 | Date |
---|---|---|
Ковалев Роман Евгеньевич | 4b43d0efad | |
Ковалев Роман Евгеньевич | e64d62b56f | |
Ковалев Роман Евгеньевич | 795aac516d | |
Ковалев Роман Евгеньевич | 7dba133763 | |
Ковалев Роман Евгеньевич | 7e1ffdfdfb |
|
@ -0,0 +1,62 @@
|
|||
#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; // Возвращает чувствительность мыши
|
||||
|
||||
void use(); // Использование этой камеры как текущей
|
||||
static Camera& current(); // Ссылка на текущую используемую камеру
|
||||
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
|
||||
|
||||
static Camera* p_current; // Указатель на текущую используемую камеру
|
||||
};
|
||||
|
||||
|
||||
#endif // CAMERA_H
|
|
@ -59,7 +59,7 @@ class Model : public Node
|
|||
Model& operator=(const Model& other); // Оператор присваивания
|
||||
virtual ~Model();
|
||||
|
||||
void render(); // Вызов отрисовки
|
||||
void render(const GLuint &model_uniform); // Вызов отрисовки
|
||||
|
||||
void load_verteces(glm::vec3* verteces, GLuint count); // Загрузка вершин в буфер
|
||||
void load_indices(GLuint* indices, GLuint count); // Загрузка индексов в буфер
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <list>
|
||||
|
||||
#include "Model.h"
|
||||
#include "Camera.h"
|
||||
|
||||
// Класс сцены
|
||||
class Scene
|
||||
|
@ -13,13 +14,14 @@ class Scene
|
|||
Scene(const Scene ©); // Конструктор копирования
|
||||
Scene& operator=(const Scene& other); // Оператор присваивания
|
||||
|
||||
void render(); // Рендер сцены
|
||||
void render(const GLuint &model_uniform); // Рендер сцены
|
||||
|
||||
Node root; // Корневой узел
|
||||
|
||||
// Списки объектов, выступающих узлами
|
||||
std::list<Node> nodes; // Список пустых узлов
|
||||
std::list<Model> models; // Список моделей для рендера
|
||||
std::list<Camera> cameras; // Список камер
|
||||
|
||||
protected:
|
||||
void rebuld_tree(const Scene& from); // Перестройка дерева после копирования или присваивания
|
||||
|
|
|
@ -2,8 +2,10 @@
|
|||
|
||||
layout(location = 0) in vec3 pos;
|
||||
|
||||
uniform mat4 vp;
|
||||
uniform mat4 model;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position.xyz = pos;
|
||||
gl_Position.w = 1.0;
|
||||
gl_Position = vp * model * vec4(pos, 1.0);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,183 @@
|
|||
#include "Camera.h"
|
||||
|
||||
// Указатель на текущую используемую камеру
|
||||
Camera* Camera::p_current = NULL;
|
||||
|
||||
// Защищенный (protected) конструктор камеры без перспективы
|
||||
Camera::Camera(const glm::vec3 &pos, const glm::vec3 &initialRotation) : Node(NULL) // Пусть по умолчанию камера не относится к сцене
|
||||
{
|
||||
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)
|
||||
: Node(copy), projection(copy.projection), requiredRecalcVP(copy.requiredRecalcVP), sensitivity(copy.sensitivity)
|
||||
{
|
||||
// Если у оригинала не было изменений - перепишем матрицу вида-проекции
|
||||
if (!requiredRecalcVP)
|
||||
vp = copy.vp;
|
||||
}
|
||||
|
||||
// Оператор присваивания
|
||||
Camera& Camera::operator=(const Camera& other)
|
||||
{
|
||||
Node::operator=(other); // Вызов родительского оператора= для переноса узла
|
||||
|
||||
projection = other.projection;
|
||||
requiredRecalcVP = other.requiredRecalcVP;
|
||||
sensitivity = other.sensitivity;
|
||||
|
||||
// Если у оригинала не было изменений - перепишем матрицу вида-проекции
|
||||
if (!requiredRecalcVP)
|
||||
vp = other.vp;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Деструктор
|
||||
Camera::~Camera()
|
||||
{
|
||||
if (p_current == this)
|
||||
p_current = NULL;
|
||||
}
|
||||
|
||||
// Возвращает ссылку на константную матрицу проекции
|
||||
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
|
||||
}
|
||||
|
||||
// Использование этой камеры как текущей
|
||||
void Camera::use()
|
||||
{
|
||||
p_current = this;
|
||||
}
|
||||
|
||||
// Ссылка на текущую используемую камеру
|
||||
Camera& Camera::current()
|
||||
{
|
||||
static Camera default_cam(800.0f/600.0f);
|
||||
|
||||
if (!p_current)
|
||||
return default_cam;
|
||||
else
|
||||
return *p_current;
|
||||
}
|
|
@ -238,8 +238,11 @@ Model::~Model()
|
|||
}
|
||||
|
||||
// Вызов отрисовки
|
||||
void Model::render()
|
||||
void Model::render(const GLuint &model_uniform)
|
||||
{
|
||||
// Загрузим матрицу трансформации
|
||||
glUniformMatrix4fv(model_uniform, 1, GL_FALSE, &getTransformMatrix()[0][0]);
|
||||
|
||||
// Подключаем VAO
|
||||
vao.use();
|
||||
// Если есть индексы - рисуем с их использованием
|
||||
|
|
|
@ -8,7 +8,7 @@ Scene::Scene()
|
|||
|
||||
// Конструктор копирования
|
||||
Scene::Scene(const Scene ©): root(copy.root),
|
||||
nodes(copy.nodes), models(copy.models)
|
||||
nodes(copy.nodes), models(copy.models), cameras(copy.cameras)
|
||||
{
|
||||
rebuld_tree(copy);
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ Scene& Scene::operator=(const Scene& other)
|
|||
root = other.root;
|
||||
nodes = other.nodes;
|
||||
models = other.models;
|
||||
cameras = other.cameras;
|
||||
|
||||
rebuld_tree(other);
|
||||
|
||||
|
@ -26,10 +27,10 @@ Scene& Scene::operator=(const Scene& other)
|
|||
}
|
||||
|
||||
// Рендер сцены
|
||||
void Scene::render()
|
||||
void Scene::render(const GLuint &model_uniform)
|
||||
{
|
||||
for (auto & model : models)
|
||||
model.render();
|
||||
model.render(model_uniform);
|
||||
}
|
||||
|
||||
// Перестройка узлов выбранного списка
|
||||
|
@ -51,6 +52,10 @@ void Scene::rebuild_Nodes_list(T& nodes, const Scene& from)
|
|||
// Если можно привести к модели, то ищем родителя среди моделей
|
||||
if (dynamic_cast<Model*>(parent))
|
||||
move_parent(*it, from.models, this->models);
|
||||
else
|
||||
// Иначе проверяем на принадлежность к камерам
|
||||
if (dynamic_cast<Camera*>(parent))
|
||||
move_parent(*it, from.cameras, this->cameras);
|
||||
// Иначе это пустой узел
|
||||
else
|
||||
move_parent(*it, from.nodes, this->nodes);
|
||||
|
@ -80,4 +85,5 @@ void Scene::rebuld_tree(const Scene& from)
|
|||
// Восстановим родителей в пустых узлах для копии
|
||||
rebuild_Nodes_list(nodes, from);
|
||||
rebuild_Nodes_list(models, from);
|
||||
rebuild_Nodes_list(cameras, from);
|
||||
}
|
||||
|
|
35
src/main.cpp
35
src/main.cpp
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include <iostream>
|
||||
|
||||
#include "Camera.h"
|
||||
#include "Model.h"
|
||||
|
||||
#define WINDOW_WIDTH 800
|
||||
|
@ -112,6 +113,26 @@ GLuint LoadShaders(const char *vertex_file, const char *fragment_file)
|
|||
return programID;
|
||||
}
|
||||
|
||||
|
||||
bool firstMouse = true;
|
||||
float lastX, lastY;
|
||||
|
||||
void mouse_callback(GLFWwindow* window, double xpos, double ypos)
|
||||
{
|
||||
if (firstMouse)
|
||||
{
|
||||
lastX = xpos;
|
||||
lastY = ypos;
|
||||
firstMouse = false;
|
||||
}
|
||||
|
||||
glm::vec2 offset(xpos - lastX, lastY - ypos);
|
||||
lastX = xpos;
|
||||
lastY = ypos;
|
||||
|
||||
Camera::current().rotate(offset);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
GLFWwindow* window; // Указатель на окно GLFW3
|
||||
|
@ -145,6 +166,9 @@ int main(void)
|
|||
|
||||
glfwSwapInterval(1); // Вертикальная синхронизация
|
||||
|
||||
// Установка callback-функции для мыши и камеры
|
||||
glfwSetCursorPosCallback(window, mouse_callback);
|
||||
|
||||
// Загрузка функций OpenGL с помощью GLAD
|
||||
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
|
||||
{
|
||||
|
@ -175,18 +199,27 @@ int main(void)
|
|||
// Загрузка индексов модели
|
||||
rectangle.load_indices(indices, sizeof(indices));
|
||||
|
||||
rectangle.e_position().z = 2;
|
||||
rectangle.e_rotation() = {0.733f, 0.462f, 0.191f, 0.462f};
|
||||
|
||||
// Установка цвета очистки буфера цвета
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
// Расположение Uniform-переменной
|
||||
GLuint vp_uniform = glGetUniformLocation(shaderProgram, "vp");
|
||||
GLuint model_uniform = glGetUniformLocation(shaderProgram, "model");
|
||||
|
||||
// Пока не произойдет событие запроса закрытия окна
|
||||
while(!glfwWindowShouldClose(window))
|
||||
{
|
||||
// Загрузим матрицу проекции*вида
|
||||
glUniformMatrix4fv(vp_uniform, 1, GL_FALSE, &Camera::current().getVP()[0][0]);
|
||||
|
||||
// Очистка буфера цвета
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
// Тут производится рендер
|
||||
rectangle.render();
|
||||
rectangle.render(model_uniform);
|
||||
|
||||
// Представление содержимого буфера цепочки показа на окно
|
||||
glfwSwapBuffers(window);
|
||||
|
|
Loading…
Reference in New Issue