Класс узла и модели
This commit is contained in:
		
							parent
							
								
									f6ca722057
								
							
						
					
					
						commit
						71a0f73211
					
				
							
								
								
									
										8
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
								
							| @ -3,6 +3,12 @@ | ||||
|         "fstream": "cpp", | ||||
|         "iosfwd": "cpp", | ||||
|         "map": "cpp", | ||||
|         "atomic": "cpp" | ||||
|         "atomic": "cpp", | ||||
|         "iostream": "cpp", | ||||
|         "array": "cpp", | ||||
|         "functional": "cpp", | ||||
|         "tuple": "cpp", | ||||
|         "type_traits": "cpp", | ||||
|         "utility": "cpp" | ||||
|     } | ||||
| } | ||||
							
								
								
									
										75
									
								
								include/Model.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								include/Model.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,75 @@ | ||||
| #ifndef MODEL_H | ||||
| #define MODEL_H | ||||
| 
 | ||||
| #include "Buffers.h" | ||||
| 
 | ||||
| #include <GLM/glm.hpp> | ||||
| #include <GLM/gtc/quaternion.hpp> | ||||
| #include <GLM/gtc/matrix_transform.hpp> | ||||
| 
 | ||||
| #include <vector> | ||||
| 
 | ||||
| // Класс узла сцены
 | ||||
| class Node  | ||||
| { | ||||
|     public: | ||||
|         Node(Node* parent = NULL); // Конструктор с заданным родителем (по умолчанию NULL)
 | ||||
|         Node(const Node& copy); // Конструктор копирования
 | ||||
|         Node& operator=(const Node& other); // Оператор присваивания
 | ||||
|         virtual ~Node(); | ||||
| 
 | ||||
|         void setParent(Node * parent); // Устанавливает родителя для узла
 | ||||
| 
 | ||||
|         virtual const glm::mat4& getTransformMatrix(); // Возвращает матрицу трансформации модели
 | ||||
|         bool isChanged(); // Возвращает необходимость пересчета матрицы трансформации
 | ||||
| 
 | ||||
|         const glm::vec3& c_position() const; // Константный доступ к позиции
 | ||||
|         const glm::quat& c_rotation() const; // Константный доступ к повороту
 | ||||
|         const glm::vec3& c_scale() const; // Константный доступ к масштабированию
 | ||||
|         virtual glm::vec3& e_position(); // Неконстантная ссылка для изменений позиции
 | ||||
|         virtual glm::quat& e_rotation(); // Неконстантная ссылка для изменений поворота
 | ||||
|         virtual glm::vec3& e_scale(); // Неконстантная ссылка для изменений масштабирования 
 | ||||
| 
 | ||||
|         Node* getParent(); // Возвращает указатель на родителя
 | ||||
|         const std::vector<Node*>& getChildren() const; // Возвращает ссылку на вектор дочерних узлов
 | ||||
| 
 | ||||
|     protected: | ||||
|         Node *parent; // Родительский узел
 | ||||
|         std::vector<Node*> children; // Узлы-потомки !Не должны указывать на NULL!
 | ||||
| 
 | ||||
|         glm::vec3 position; // позиция модели
 | ||||
|         glm::quat rotation; // поворот модели
 | ||||
|         glm::vec3 scale;    // масштабирование модели
 | ||||
| 
 | ||||
|         bool changed; // Флаг необходимости пересчета матрицы трансформации
 | ||||
|         glm::mat4 transform; // Матрица трансформации модели
 | ||||
|         bool parent_changed; // Флаг изменений у родителя - необходимость пересчета итоговой трансформации
 | ||||
|         glm::mat4 result_transform; // Итоговая трансформация с учетом родительской
 | ||||
| 
 | ||||
|         virtual void recalcMatrices(); // Метод пересчета матрицы трансформации по необходимости, должен сбрасывать флаг changed
 | ||||
|         void invalidateParent(); // Проход потомков в глубину с изменением флага parent_changed
 | ||||
| }; | ||||
| 
 | ||||
| // Класс модели
 | ||||
| class Model : public Node | ||||
| { | ||||
|     public: | ||||
|         Model(Node *parent = NULL); // Конструктор по умолчанию
 | ||||
|         Model(const Model& copy); // Конструктор копирования
 | ||||
|         Model& operator=(const Model& other); // Оператор присваивания
 | ||||
|         virtual ~Model(); | ||||
| 
 | ||||
|         void render(); // Вызов отрисовки
 | ||||
| 
 | ||||
|         void load_verteces(glm::vec3* verteces, GLuint count); // Загрузка вершин в буфер
 | ||||
|         void load_indices(GLuint* indices, GLuint count); // Загрузка индексов в буфер
 | ||||
|         void set_index_range(size_t first_byteOffset, size_t count); // Ограничение диапазона из буфера индексов
 | ||||
| 
 | ||||
|     private: | ||||
|         VAO vao; | ||||
|         BO vertex_vbo, index_vbo; // вершинный и индексный буферы
 | ||||
|         GLuint verteces_count; // Количество вершин
 | ||||
|         size_t first_index_byteOffset, indices_count; // Сдвиг в байтах для первого и количество индексов
 | ||||
| }; | ||||
| 
 | ||||
| #endif // MODEL_H
 | ||||
							
								
								
									
										303
									
								
								src/Model.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										303
									
								
								src/Model.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,303 @@ | ||||
| #include "Model.h" | ||||
| 
 | ||||
| #include <algorithm> | ||||
| 
 | ||||
| // Конструктор с заданным родителем (по умолчанию NULL)
 | ||||
| Node::Node(Node* parent_) : parent(parent_), result_transform(1), parent_changed(false), | ||||
| position(0), rotation(1.0f, 0.0f, 0.0f, 0.0f), scale(1), changed(false), transform(1) | ||||
| { | ||||
|     if (parent) | ||||
|     { | ||||
|         // Запишем себя в потомки
 | ||||
|         parent->children.push_back(this); | ||||
|         parent_changed = true; | ||||
|     } | ||||
| }  | ||||
| 
 | ||||
| // Конструктор копирования
 | ||||
| Node::Node(const Node& copy): position(copy.position), rotation(copy.position), scale(copy.scale), | ||||
| parent(copy.parent), parent_changed(copy.parent_changed), transform(1), result_transform(1) | ||||
| { | ||||
|     // Запишем себя в потомки
 | ||||
|     if (parent) | ||||
|         parent->children.push_back(this); | ||||
|     // Если у оригинала не было изменений - перепишем матрицу трансформации
 | ||||
|     if (!changed) | ||||
|         transform = copy.transform; | ||||
|     // Если у родителя не было изменений для оригинала - перепишем результирующую матрицу трансформации
 | ||||
|     if (!parent_changed) | ||||
|         result_transform = copy.result_transform; | ||||
| } | ||||
| 
 | ||||
| Node::~Node() | ||||
| { | ||||
|     setParent(NULL); // Удаляем себя из потомков
 | ||||
|     // Сообщаем потомкам об удалении родителя
 | ||||
|     for (Node* child : children) | ||||
|         child->setParent(NULL); | ||||
| } | ||||
| 
 | ||||
| // Возвращает необходимость пересчета матрицы трансформации
 | ||||
| bool Node::isChanged()  | ||||
| {  | ||||
|     return changed;  | ||||
| }  | ||||
| 
 | ||||
| // Константный доступ к позиции
 | ||||
| const glm::vec3& Node::c_position() const  | ||||
| {  | ||||
|     return position;  | ||||
| }  | ||||
| 
 | ||||
| // Константный доступ к повороту
 | ||||
| const glm::quat& Node::c_rotation() const  | ||||
| {  | ||||
|     return rotation;  | ||||
| }  | ||||
| 
 | ||||
| // Константный доступ к масштабированию
 | ||||
| const glm::vec3& Node::c_scale() const  | ||||
| {  | ||||
|     return scale;  | ||||
| }  | ||||
| 
 | ||||
| // Неконстантная ссылка для изменений позиции
 | ||||
| glm::vec3& Node::e_position()  | ||||
| {  | ||||
|     changed = true; // Флаг о изменении
 | ||||
|     invalidateParent(); // Проход потомков в глубину с изменением флага parent_changed
 | ||||
|     return position;  | ||||
| }  | ||||
| 
 | ||||
| // Неконстантная ссылка для изменений поворота
 | ||||
| glm::quat& Node::e_rotation()  | ||||
| {  | ||||
|     changed = true; // Флаг о изменении
 | ||||
|     invalidateParent(); // Проход потомков в глубину с изменением флага parent_changed
 | ||||
|     return rotation;  | ||||
| }  | ||||
| 
 | ||||
| // Неконстантная ссылка для изменений масштабирования         
 | ||||
| glm::vec3& Node::e_scale()  | ||||
| {  | ||||
|     changed = true; // Флаг о изменении
 | ||||
|     invalidateParent(); // Проход потомков в глубину с изменением флага parent_changed
 | ||||
|     return scale;  | ||||
| }  | ||||
| 
 | ||||
| // Возвращает матрицу трансформации модели
 | ||||
| const glm::mat4& Node::getTransformMatrix()  | ||||
| { | ||||
|     // Если требуется - пересчитаем матрицу
 | ||||
|     recalcMatrices(); | ||||
|          | ||||
|     return result_transform; | ||||
| } | ||||
| 
 | ||||
| // Пересчет матрицы трансформации модели, если это требуется
 | ||||
| void Node::recalcMatrices()  | ||||
| { | ||||
|     // Если было изменение по векторам позиции, поворота и масштабирования
 | ||||
|     if  (changed) | ||||
|     { | ||||
|         transform = glm::mat4(1.0f); | ||||
|         // Перемещение модели
 | ||||
|         transform = glm::translate(transform, position); | ||||
|         // Поворот модели
 | ||||
|         transform = transform * glm::mat4_cast(rotation); | ||||
|         // Масштабирование
 | ||||
|         transform = glm::scale(transform, scale);   | ||||
|     } | ||||
| 
 | ||||
|     // Если собственная или родительская матрицы менялись - необходимо пересчитать итоговую
 | ||||
|     if (changed || parent_changed) | ||||
|     { | ||||
|         if (parent) // Если есть родитель
 | ||||
|             result_transform = parent->getTransformMatrix() * transform; | ||||
|         else // Если нет родителя
 | ||||
|             result_transform = transform; | ||||
| 
 | ||||
|         parent_changed = changed = false; // Изменения применены
 | ||||
|     } | ||||
| }  | ||||
| 
 | ||||
| // Проход потомков в глубину с изменением флага parent_changed
 | ||||
| void Node::invalidateParent() | ||||
| { | ||||
|     // Цикл по потомкам
 | ||||
|     for (Node* child : children) | ||||
|     { | ||||
|         child->parent_changed = true; // Флаг 
 | ||||
|         child->invalidateParent(); // Рекурсивный вызов для потомков выбранного потомка
 | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| // Устанавливает родителя для узла
 | ||||
| void Node::setParent(Node * parent) | ||||
| { | ||||
|     // Если замена происходит на другого родителя
 | ||||
|     if (parent != this->parent) | ||||
|     { | ||||
|         Node* tmp = parent; | ||||
|         // Проверка на зацикливание об самого себя
 | ||||
|         while (tmp) | ||||
|         { | ||||
|             if (tmp == this) | ||||
|                 return; // Можно выдать exception
 | ||||
|             tmp = tmp->parent; | ||||
|         } | ||||
|         // Если есть старый родитель - удалим себя из его потомков
 | ||||
|         if (this->parent) | ||||
|         { | ||||
|             // Поиск в списке родительских потомков
 | ||||
|             auto position = std::find(this->parent->children.begin(), this->parent->children.end(), this); | ||||
|             // Если итератор указывает в конец - ничего не найдено
 | ||||
|             if (position != this->parent->children.end())  | ||||
|                 this->parent->children.erase(position); // Само удаление
 | ||||
|         } | ||||
|          | ||||
|         this->parent = parent; // Заменяем указатель на родителя
 | ||||
|         // Если родитель не NULL - добавляем себя в детей
 | ||||
|         if (parent)  | ||||
|             parent->children.push_back(this); | ||||
|         // В любом случае необходимо пересчитать собственную итоговую матрицу
 | ||||
|         parent_changed = true; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| // Возвращает указатель на родителя
 | ||||
| Node* Node::getParent()  | ||||
| {  | ||||
|     return parent;  | ||||
| } | ||||
| 
 | ||||
| // Возвращает ссылку на вектор дочерних узлов
 | ||||
| const std::vector<Node*>& Node::getChildren() const  | ||||
| {  | ||||
|     return children;  | ||||
| } | ||||
| 
 | ||||
| // Оператор присваивания
 | ||||
| Node& Node::operator=(const Node& other) | ||||
| { | ||||
|     position = other.position; | ||||
|     rotation = other.rotation; | ||||
|     scale = other.scale; | ||||
|     changed = other.changed; | ||||
| 
 | ||||
|     if (!changed) | ||||
|         transform = other.transform; | ||||
|          | ||||
|     setParent(other.parent); | ||||
|      | ||||
|     // Если у other флаг parent_changed == false, то можно переписать матрицу результата с него
 | ||||
|     if (!other.parent_changed) | ||||
|     { | ||||
|         result_transform = other.result_transform; | ||||
|         parent_changed = false; // Сбрасываем флаг после смены родителя
 | ||||
|     } | ||||
| 
 | ||||
|     return *this; | ||||
| } | ||||
| 
 | ||||
| // Конструктор по умолчанию
 | ||||
| Model::Model(Node *parent) : Node(parent), verteces_count(0), first_index_byteOffset(0), indices_count(0),  | ||||
| vertex_vbo(VERTEX), index_vbo(ELEMENT) | ||||
| { | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| // Конструктор копирования
 | ||||
| Model::Model(const Model& copy) : Node(copy), | ||||
| vao(copy.vao),  | ||||
| verteces_count(copy.verteces_count), first_index_byteOffset(copy.first_index_byteOffset), indices_count(copy.indices_count),  | ||||
| vertex_vbo(copy.vertex_vbo), index_vbo(copy.index_vbo) | ||||
| { | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| // Оператор присваивания
 | ||||
| Model& Model::operator=(const Model& other) | ||||
| { | ||||
|     Node::operator=(other); // Явный вызов родительского оператора копирования
 | ||||
|      | ||||
|     vao = other.vao;  | ||||
|     verteces_count = other.verteces_count; | ||||
|     first_index_byteOffset = other.first_index_byteOffset; | ||||
|     indices_count = other.indices_count; | ||||
|      | ||||
|     vertex_vbo = other.vertex_vbo; | ||||
|     index_vbo = other.index_vbo; | ||||
|      | ||||
|     return *this; | ||||
| } | ||||
| 
 | ||||
| Model::~Model() | ||||
| { | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| // Вызов отрисовки
 | ||||
| void Model::render()  | ||||
| { | ||||
|     // Подключаем VAO
 | ||||
|     vao.use(); | ||||
|     // Если есть индексы - рисуем с их использованием
 | ||||
|     if (indices_count) | ||||
|     { | ||||
|         index_vbo.use(); | ||||
|         glDrawElements(GL_TRIANGLES, indices_count, GL_UNSIGNED_INT, (void*)(first_index_byteOffset)); | ||||
|     } | ||||
|     // Если есть вершины - рисуем на основании массива вершин
 | ||||
|     else if (verteces_count) | ||||
|         glDrawArrays(GL_TRIANGLES, 0, verteces_count); | ||||
| } | ||||
| 
 | ||||
| // Функция для конфигурации атрибута вершинного буфера
 | ||||
| void vertex_attrib_config() | ||||
| { | ||||
|     // Определим спецификацию атрибута
 | ||||
|     glVertexAttribPointer(  0         // индекс атрибута, должен совпадать с Layout шейдера
 | ||||
|                           , 3         // количество компонент одного элемента
 | ||||
|                           , GL_FLOAT  // тип
 | ||||
|                           , GL_FALSE  // необходимость нормировать значения
 | ||||
|                           , 0         // шаг
 | ||||
|                           , (void *)0 // отступ с начала массива
 | ||||
|                          ); | ||||
|     // Включаем необходимый атрибут у выбранного VAO
 | ||||
|     glEnableVertexAttribArray(0); | ||||
| } | ||||
| 
 | ||||
| // Загрузка вершин в буфер
 | ||||
| void Model::load_verteces(glm::vec3* verteces, GLuint count) | ||||
| { | ||||
|     // Подключаем VAO и вершинный буфер
 | ||||
|     vao.use(); | ||||
|     vertex_vbo.use(); | ||||
| 
 | ||||
|     // Загрузка вершин в память буфера
 | ||||
|     vertex_vbo.load(verteces, sizeof(glm::vec3)*count); | ||||
|     vertex_attrib_config(); | ||||
|     // Запоминаем количество вершин для отрисовки
 | ||||
|     verteces_count = count; | ||||
| } | ||||
| 
 | ||||
| // Загрузка индексов в буфер
 | ||||
| void Model::load_indices(GLuint* indices, GLuint count)  | ||||
| { | ||||
|     // Подключаем VAO и индексный буфер
 | ||||
|     vao.use(); | ||||
|     index_vbo.use(); | ||||
| 
 | ||||
|     // Загрузка вершин в память буфера
 | ||||
|     index_vbo.load(indices, sizeof(GLuint)*count); | ||||
|     // Запоминаем количество вершин для отрисовки
 | ||||
|     indices_count = count; | ||||
| } | ||||
| 
 | ||||
| // Ограничение диапазона из буфера индексов
 | ||||
| void Model::set_index_range(size_t first_byteOffset, size_t count) | ||||
| { | ||||
|     first_index_byteOffset = first_byteOffset; | ||||
|     indices_count = count; | ||||
| }  | ||||
							
								
								
									
										43
									
								
								src/main.cpp
									
									
									
									
									
								
							
							
						
						
									
										43
									
								
								src/main.cpp
									
									
									
									
									
								
							| @ -5,7 +5,7 @@ | ||||
| 
 | ||||
| #include <iostream> | ||||
| 
 | ||||
| #include "Buffers.h" | ||||
| #include "Model.h" | ||||
| 
 | ||||
| #define WINDOW_WIDTH 800 | ||||
| #define WINDOW_HEIGHT 600 | ||||
| @ -112,21 +112,6 @@ GLuint LoadShaders(const char *vertex_file, const char *fragment_file) | ||||
|     return programID; | ||||
| } | ||||
| 
 | ||||
| // Функция для конфигурации атрибутов
 | ||||
| void attrib_config() | ||||
| { | ||||
|     // Определим спецификацию атрибута
 | ||||
|     glVertexAttribPointer(  0         // индекс атрибута, должен совпадать с Layout шейдера
 | ||||
|                           , 3         // количество компонент одного элемента
 | ||||
|                           , GL_FLOAT  // тип
 | ||||
|                           , GL_FALSE  // необходимость нормировать значения
 | ||||
|                           , 0         // шаг
 | ||||
|                           , (void *)0 // отступ с начала массива
 | ||||
|                          ); | ||||
|     // Включаем необходимый атрибут у выбранного VAO
 | ||||
|     glEnableVertexAttribArray(0); | ||||
| } | ||||
| 
 | ||||
| int main(void) | ||||
| { | ||||
|     GLFWwindow* window; // Указатель на окно GLFW3
 | ||||
| @ -172,29 +157,23 @@ int main(void) | ||||
|     // Активация шейдера
 | ||||
|     glUseProgram(shaderProgram); | ||||
| 
 | ||||
|     // Вершины треугольника
 | ||||
|     // Вершины прямоугольника
 | ||||
|     glm::vec3 verticies[] = {  {-0.5f, -0.5f, 0.0f} | ||||
|                              , { 0.5f, -0.5f, 0.0f} | ||||
|                              , { 0.5f,  0.5f, 0.0f} | ||||
|                              , {-0.5f,  0.5f, 0.0f} | ||||
|                             }; | ||||
| 
 | ||||
|     // VAO
 | ||||
|     VAO vao; | ||||
|     // VBO вершинный
 | ||||
|     BO vbo_vert(VERTEX); | ||||
|     attrib_config(); // Конфигурация аттрибутов
 | ||||
|     // Загрузка вершин в используемый буфер вершин
 | ||||
|     vbo_vert.load(verticies, sizeof(verticies)); | ||||
|     // Модель прямоугольника
 | ||||
|     Model rectangle;  | ||||
|      | ||||
|     // Загрузка вершин модели
 | ||||
|     rectangle.load_verteces(verticies, sizeof(verticies)/sizeof(glm::vec3)); | ||||
|      | ||||
|     // индексы вершин
 | ||||
|     GLuint indices[] = {0, 1, 2, 2, 3, 0};  | ||||
| 
 | ||||
|     // VBO элементный (индексы вершин)
 | ||||
|     BO vbo_elem(ELEMENT); | ||||
|      | ||||
|     // Загрузка индексов в используемый элементный буфер
 | ||||
|     vbo_elem.load(indices, sizeof(indices)); | ||||
|     // Загрузка индексов модели
 | ||||
|     rectangle.load_indices(indices, sizeof(indices)); | ||||
|      | ||||
|     // Установка цвета очистки буфера цвета
 | ||||
|     glClearColor(0.0f, 0.0f, 0.0f, 1.0f); | ||||
| @ -207,9 +186,7 @@ int main(void) | ||||
|         glClear(GL_COLOR_BUFFER_BIT); | ||||
| 
 | ||||
|         // Тут производится рендер
 | ||||
|         vao.use(); | ||||
|         glDrawElements(GL_TRIANGLES, sizeof(indices)/sizeof(GLuint), GL_UNSIGNED_INT, (void*)0); | ||||
|         vao.disable(); | ||||
|         rectangle.render(); | ||||
| 
 | ||||
|         // Представление содержимого буфера цепочки показа на окно
 | ||||
|         glfwSwapBuffers(window); | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user