Копия проекта с 09
This commit is contained in:
		
							parent
							
								
									abadef13ed
								
							
						
					
					
						commit
						f3f8fcc7af
					
				
							
								
								
									
										20
									
								
								.vscode/c_cpp_properties.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								.vscode/c_cpp_properties.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | ||||
| { | ||||
|     "configurations": [ | ||||
|         { | ||||
|             "name": "some_name", | ||||
|             "includePath": [ | ||||
|                 "${workspaceFolder}/include", | ||||
|                 "${workspaceFolder}/../dependencies/GLFW/include", | ||||
|                 "${workspaceFolder}/../dependencies/glad/include", | ||||
|                 "${workspaceFolder}/../dependencies/glm", | ||||
|                 "${workspaceFolder}/../dependencies/stb", | ||||
|                 "${workspaceFolder}/../dependencies/tinyobjloader" | ||||
|             ], | ||||
|             "compilerPath": "C:/MinGW/bin/g++.exe", | ||||
|             "cStandard": "c11", | ||||
|             "cppStandard": "c++11", | ||||
|             "intelliSenseMode": "gcc-x86" | ||||
|         } | ||||
|     ], | ||||
|     "version": 4 | ||||
| } | ||||
							
								
								
									
										46
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,46 @@ | ||||
| { | ||||
|     "files.associations": { | ||||
|         "fstream": "cpp", | ||||
|         "iosfwd": "cpp", | ||||
|         "map": "cpp", | ||||
|         "atomic": "cpp", | ||||
|         "array": "cpp", | ||||
|         "*.tcc": "cpp", | ||||
|         "cctype": "cpp", | ||||
|         "clocale": "cpp", | ||||
|         "cmath": "cpp", | ||||
|         "cstdarg": "cpp", | ||||
|         "cstddef": "cpp", | ||||
|         "cstdint": "cpp", | ||||
|         "cstdio": "cpp", | ||||
|         "cstdlib": "cpp", | ||||
|         "cstring": "cpp", | ||||
|         "cwchar": "cpp", | ||||
|         "cwctype": "cpp", | ||||
|         "deque": "cpp", | ||||
|         "unordered_map": "cpp", | ||||
|         "vector": "cpp", | ||||
|         "exception": "cpp", | ||||
|         "algorithm": "cpp", | ||||
|         "functional": "cpp", | ||||
|         "iterator": "cpp", | ||||
|         "memory": "cpp", | ||||
|         "memory_resource": "cpp", | ||||
|         "numeric": "cpp", | ||||
|         "random": "cpp", | ||||
|         "string": "cpp", | ||||
|         "system_error": "cpp", | ||||
|         "tuple": "cpp", | ||||
|         "type_traits": "cpp", | ||||
|         "utility": "cpp", | ||||
|         "initializer_list": "cpp", | ||||
|         "iostream": "cpp", | ||||
|         "istream": "cpp", | ||||
|         "limits": "cpp", | ||||
|         "ostream": "cpp", | ||||
|         "sstream": "cpp", | ||||
|         "stdexcept": "cpp", | ||||
|         "streambuf": "cpp", | ||||
|         "cinttypes": "cpp", | ||||
|         "typeinfo": "cpp" | ||||
| } | ||||
							
								
								
									
										32
									
								
								.vscode/tasks.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								.vscode/tasks.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,32 @@ | ||||
| { | ||||
|     "tasks": [ | ||||
|         { | ||||
|             "type": "cppbuild", | ||||
|             "label": "C/C++: make сборка", | ||||
|             "command": "make", | ||||
|             "args": [ | ||||
|                 "${input:target}" | ||||
|             ], | ||||
|             "options": { | ||||
|                 "cwd": "${workspaceRoot}" | ||||
|             }, | ||||
|             "problemMatcher": [ | ||||
|                 "$gcc" | ||||
|             ], | ||||
|             "group": { | ||||
|                 "kind": "build", | ||||
|                 "isDefault": true | ||||
|             }, | ||||
|             "detail": "Задача создана отладчиком." | ||||
|         } | ||||
|     ], | ||||
|     "inputs": [ | ||||
|         { | ||||
|             "id": "target", | ||||
|             "description": "Цель сборки (all, list, clean)", | ||||
|             "default": "all", | ||||
|             "type": "promptString" | ||||
|         }, | ||||
|     ], | ||||
|     "version": "2.0.0" | ||||
| } | ||||
							
								
								
									
										101
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,101 @@ | ||||
| # Компилятор и директория проекта
 | ||||
| ifeq ($(OS), Windows_NT) | ||||
| 	# С возможностью сборки x32 | ||||
| 	ifeq ($(MAKECMDGOALS), x32) | ||||
| 		CC = C:/MinGW/bin/g++.exe | ||||
| 	else | ||||
| 		CC = C:/MinGW64/bin/g++.exe | ||||
| 	endif | ||||
| 	PROJECT_DIR = $(shell echo %cd%) | ||||
| 	PATH_SEPARATOR = \\ | ||||
| 	# Имя исполняемого файла | ||||
| 	EXECUTABLE = $(notdir $(strip $(PROJECT_DIR))).exe | ||||
| else | ||||
| 	CC = g++ | ||||
| 	PROJECT_DIR = $(shell pwd) | ||||
| 	PATH_SEPARATOR = / | ||||
| 	# Имя исполняемого файла | ||||
| 	EXECUTABLE = $(notdir $(strip $(PROJECT_DIR))) | ||||
| endif | ||||
| 
 | ||||
| # Опции компилятора
 | ||||
| CFLAGS += -c | ||||
| CFLAGS += -I./include | ||||
| CFLAGS += -I../dependencies/GLFW/include | ||||
| CFLAGS += -I../dependencies/glad/include | ||||
| CFLAGS += -I../dependencies/glm | ||||
| CFLAGS += -I../dependencies/stb | ||||
| CFLAGS += -I../dependencies/tinyobjloader | ||||
| 
 | ||||
| # Опции линкера
 | ||||
| LDFLAGS += --std=c++11 | ||||
| # Архитектурозависимые опции линкера
 | ||||
| ifeq ($(OS), Windows_NT) | ||||
| 	# GLFW в зависимости от архитектуры | ||||
| 	ifeq ($(MAKECMDGOALS), x32) | ||||
| 		LDFLAGS += -L../dependencies/GLFW/lib-mingw | ||||
| 	else | ||||
| 		LDFLAGS += -L../dependencies/GLFW/lib-mingw-w64 | ||||
| 	endif | ||||
| 
 | ||||
| 	LDFLAGS += -static | ||||
| 	LDFLAGS += -lglfw3dll | ||||
| 	LDFLAGS += -lopengl32 | ||||
| else | ||||
| 	LDFLAGS += -lglfw | ||||
| 	LDFLAGS += -lGL | ||||
| endif | ||||
| 
 | ||||
| # Библиотека GLAD
 | ||||
| GLAD := ../dependencies/glad/src/glad.c | ||||
| GLAD_O := $(GLAD:.c=.o) | ||||
| 
 | ||||
| # Файлы из директории src
 | ||||
| SOURCES_C = $(wildcard src/*.c) | ||||
| SOURCES_CPP = $(wildcard src/*.cpp)  | ||||
| 
 | ||||
| # Директория с объектными файлами
 | ||||
| OBJ_DIR := Obj | ||||
| # Объектные файлы
 | ||||
| OBJECTS = $(addprefix $(OBJ_DIR)/,$(SOURCES_C:src/%.c=%.o) $(SOURCES_CPP:src/%.cpp=%.o)) | ||||
| 
 | ||||
| # Для x32 сборки под Windows
 | ||||
| ifeq ($(OS), Windows_NT) | ||||
| 	ifeq ($(MAKECMDGOALS), x32) | ||||
| x32: all | ||||
| 	endif | ||||
| endif | ||||
| 
 | ||||
| # Цель по умолчанию, зависит от EXECUTABLE
 | ||||
| all: $(EXECUTABLE) | ||||
| 
 | ||||
| # Цель сборки исполняемого файла, зависит от OBJ_DIR, OBJECTS и GLAD_O
 | ||||
| $(EXECUTABLE): $(OBJ_DIR) $(OBJECTS) $(GLAD_O) | ||||
| 	$(CC)  $(OBJECTS)  $(GLAD_O) $(LDFLAGS) -o $@ | ||||
| 
 | ||||
| # Цель для сборки GLAD
 | ||||
| $(GLAD_O): $(GLAD) | ||||
| 	$(CC) $(CFLAGS) $< -o $@ | ||||
| 
 | ||||
| # Цель для создания директории с объектными файлами
 | ||||
| $(OBJ_DIR): | ||||
| 	@mkdir $(OBJ_DIR) | ||||
| 
 | ||||
| # Цель сборки объектных файлов
 | ||||
| $(OBJ_DIR)/%.o: src/%.c | ||||
| 	$(CC) $(CFLAGS) $< -o $@ | ||||
| $(OBJ_DIR)/%.o: src/%.cpp | ||||
| 	$(CC) $(CFLAGS) $< -o $@ | ||||
| 
 | ||||
| # Цель вывода всех файлов, учавствтующих в сборке
 | ||||
| list: | ||||
| 	@echo "В сборке участвуют:" $(OBJECTS) | ||||
| 
 | ||||
| # Очистка
 | ||||
| ifeq ($(OS), Windows_NT) | ||||
| clean: $(OBJ_DIR) | ||||
| 	@rmdir /s /q $(OBJ_DIR) | ||||
| else | ||||
| clean: $(OBJ_DIR) | ||||
| 	@rm -f $(EXECUTABLE) $(OBJECTS) | ||||
| endif | ||||
							
								
								
									
										88
									
								
								include/Buffers.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								include/Buffers.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,88 @@ | ||||
| #ifndef BUFFERS_H | ||||
| #define BUFFERS_H | ||||
| 
 | ||||
| #include <glad/glad.h> | ||||
| 
 | ||||
| #include <map> | ||||
| 
 | ||||
| // Объект массива вершин
 | ||||
| class VAO | ||||
| { | ||||
|     public: | ||||
|         VAO(); // Создает VAO и активирует его
 | ||||
|         ~VAO(); // Уничтожает VAO
 | ||||
|         VAO(const VAO & copy); // Конструктор копирования
 | ||||
|         VAO& operator=(const VAO & other); // Оператор присваивания
 | ||||
| 
 | ||||
|         void use(); // Активация VAO
 | ||||
|         static void disable(); // Деактивация активного VAO
 | ||||
| 
 | ||||
|     private: | ||||
|         GLuint handler; // Дескриптор
 | ||||
|         static std::map<GLuint, GLuint> handler_count; // Счетчик использований дескриптора
 | ||||
| }; | ||||
| 
 | ||||
| // Тип буфера
 | ||||
| enum BUFFER_TYPE {  VERTEX = GL_ARRAY_BUFFER | ||||
|                   , ELEMENT = GL_ELEMENT_ARRAY_BUFFER | ||||
|                   , UNIFORM = GL_UNIFORM_BUFFER | ||||
|                  }; | ||||
| 
 | ||||
| // Объект вершинного буфера
 | ||||
| class BO | ||||
| { | ||||
|     public: | ||||
|         BO(BUFFER_TYPE type); // Создает пустой буфер заданного типа
 | ||||
|         BO(BUFFER_TYPE type, const void *data, int size); // Создает и загружает туда данные
 | ||||
|         ~BO(); // Уничтожает буфер
 | ||||
|         BO(const BO & copy); // Конструктор копирования
 | ||||
|         BO& operator=(const BO & other); // Оператор присваивания
 | ||||
| 
 | ||||
|         void load(const void *data, int size, GLuint mode = GL_STATIC_DRAW); // Загрузка данных в буфер
 | ||||
|         void use();  | ||||
| 
 | ||||
|     protected: | ||||
|         GLuint handler; // Дескриптор
 | ||||
|         BUFFER_TYPE type; // Тип буфера
 | ||||
|     private: | ||||
|         static std::map<GLuint, GLuint> handler_count; // Счетчик использований дескриптора
 | ||||
| }; | ||||
| 
 | ||||
| // Объект uniform-буфера
 | ||||
| class UBO : public BO | ||||
| { | ||||
|     public: | ||||
|         UBO(int size, int binding); // Создает пустой uniform-буфер заданного размера с автоматической привязкой
 | ||||
|         UBO(const void *data, int size, int binding); // Создает пустой uniform-буфер заданного размера с автоматической привязкой
 | ||||
| 
 | ||||
|         void rebind(int binding); // Перепривязка
 | ||||
|         void loadSub(const void *data, int size, int offset = 0); // Загрузка с отступом
 | ||||
| }; | ||||
| 
 | ||||
| // Объект буфера кадра
 | ||||
| class FBO | ||||
| { | ||||
|     public: | ||||
|         FBO(GLuint *attachments, int count); // Создает буфер кадра с нужным числом прикреплений текстур
 | ||||
|         ~FBO(); // Уничтожение буфера
 | ||||
| 
 | ||||
|         void use(GLuint mode = GL_FRAMEBUFFER); // Активирует буфер кадра в заданном режиме
 | ||||
|         static void useDefault(GLuint mode = GL_FRAMEBUFFER); // Активирует базовый буфер в заданном режиме
 | ||||
|         void assignRenderBuffer(GLuint hander, GLuint attachment = GL_DEPTH_ATTACHMENT); // Привязка рендер буфера
 | ||||
|     protected: | ||||
|         GLuint handler; // Дескриптор
 | ||||
| }; | ||||
| 
 | ||||
| // Объект буфера рендера
 | ||||
| class RBO | ||||
| { | ||||
|     public: | ||||
|         RBO(int w, int h, GLuint component = GL_DEPTH_COMPONENT); // Создает буфер рендера с заданными параметрами размеров и используемых компонент
 | ||||
|         ~RBO(); // Уничтожение буфера
 | ||||
| 
 | ||||
|         GLuint getHandler(); // Возвращает дескриптор буфера рендера
 | ||||
|     protected: | ||||
|         GLuint handler; // Дескриптор
 | ||||
| }; | ||||
| 
 | ||||
| #endif // BUFFERS_H
 | ||||
							
								
								
									
										73
									
								
								include/Camera.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								include/Camera.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,73 @@ | ||||
| #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 | ||||
| 
 | ||||
| // Данные о камере для шейдера
 | ||||
| struct CameraData | ||||
| { | ||||
|     glm::mat4 projection; | ||||
|     glm::mat4 view; | ||||
|     glm::vec3 position; | ||||
| }; | ||||
| 
 | ||||
| // Класс камеры
 | ||||
| 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(); // Ссылка на текущую используемую камеру
 | ||||
|          | ||||
|         CameraData& getData(); // Данные о камере для шейдера
 | ||||
|     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
									
								
								include/Lights.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								include/Lights.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,59 @@ | ||||
| #ifndef LIGHTS_H | ||||
| #define LIGHTS_H | ||||
| 
 | ||||
| #include <GLM/glm.hpp> | ||||
| 
 | ||||
| #include "Model.h" | ||||
| 
 | ||||
| // Максимальное число источников света
 | ||||
| #define MAX_LIGHTS 300 | ||||
| 
 | ||||
| // Точечный источник света
 | ||||
| struct LightData  | ||||
| { | ||||
|     alignas(16) glm::vec3 position; // Позиция
 | ||||
|     alignas(16) glm::vec3 color; // Цвет 
 | ||||
|     alignas(16) glm::vec3 attenuation; // Радиус действия источника, линейный и квадратичный коэф. угасания   
 | ||||
| }; | ||||
| 
 | ||||
| // Источник света
 | ||||
| class Light : public Node | ||||
| { | ||||
|     public: | ||||
|         static int getUBOsize(); // Возвращает размер буфера в байтах
 | ||||
|         static void upload(UBO& lights_data); // Загрузка данных в буфер
 | ||||
| 
 | ||||
|         static Light& getNew(); // Возвращает ссылку на новый источник света
 | ||||
|         void destroy(); // Уничтожает источник света
 | ||||
| 
 | ||||
|         const glm::vec3& c_color() const; // Константный доступ к цвету
 | ||||
|         glm::vec3& e_color(); // Неконстантная ссылка для изменений цвета
 | ||||
| 
 | ||||
|         const float& c_radius() const; // Константный доступ к радиусу
 | ||||
|         float& e_radius(); // Неконстантная ссылка для изменений радиуса
 | ||||
| 
 | ||||
|         static void render(ShaderProgram &shaderProgram, UBO &material_buffer); // Рисование отладочных лампочек
 | ||||
|     private: | ||||
|         Light(); // Конструктор без параметров
 | ||||
|         Light(const Light& copy) = delete; // Конструктор копирования ОТКЛЮЧЕН
 | ||||
|         Light& operator=(const Light& other); // Оператор  присваивания
 | ||||
|         virtual ~Light();  | ||||
| 
 | ||||
|         glm::vec3 color; // Цвет
 | ||||
|         float radius; // Радиус действия источника
 | ||||
| 
 | ||||
|         int index; // Индекс в массиве отправки (может не совпадать с lights) для дефрагментированного доступа
 | ||||
|         static Light& findByIndex(GLuint index); // Возвращает ссылку на источник с нужным индексом
 | ||||
| 
 | ||||
|         bool uploadReq; // Необходимость загрузки в следствии изменений
 | ||||
|         void check_id(); // Проверка что не взаимодествуем с пустым источником
 | ||||
|         void toData(); // Преобразует информацию об источнике в структуру LightData
 | ||||
| 
 | ||||
|         virtual void recalcMatrices(); // Метод пересчета матрицы трансформации по необходимости, должен сбрасывать флаг changed
 | ||||
| 
 | ||||
|         static GLuint count; // количество используемых источников (должно быть <= MAX_LIGHTS)
 | ||||
|         static LightData data[MAX_LIGHTS]; // Массив данных по источникам света
 | ||||
|         static Light lights[MAX_LIGHTS]; // Массив источников-узлов сцены
 | ||||
| }; | ||||
| 
 | ||||
| #endif // LIGHTS_H
 | ||||
							
								
								
									
										99
									
								
								include/Model.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								include/Model.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,99 @@ | ||||
| #ifndef MODEL_H | ||||
| #define MODEL_H | ||||
| 
 | ||||
| #include "Buffers.h" | ||||
| #include "Texture.h" | ||||
| #include "Shader.h" | ||||
| 
 | ||||
| #include <GLM/glm.hpp> | ||||
| #include <GLM/gtc/quaternion.hpp> | ||||
| #include <GLM/gtc/matrix_transform.hpp> | ||||
| 
 | ||||
| #include <vector> | ||||
| 
 | ||||
| class Model genShpere(float radius, int sectorsCount, class Node* parent = NULL); // Генерирует сферу заданного радиуса с определенным количеством сегментов
 | ||||
| 
 | ||||
| // Класс узла сцены
 | ||||
| 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
 | ||||
| }; | ||||
| 
 | ||||
| // Материал модели
 | ||||
| struct Material | ||||
| { | ||||
|     alignas(16) glm::vec3 ka; // коэф. фонового отражения (цвет фонового освещения)
 | ||||
|     alignas(16) glm::vec3 kd; // коэф. диффузного отражения (цвет объекта)
 | ||||
|     alignas(16) glm::vec3 ks; // коэф. зеркального блика
 | ||||
|     float p; // показатель глянцевости
 | ||||
|     // Значения по умолчанию
 | ||||
|     Material() : ka(0.2f), kd(0.2f), ks(0.2f), p(1) { }; | ||||
| }; | ||||
| 
 | ||||
| // Класс модели
 | ||||
| class Model : public Node | ||||
| { | ||||
|     public: | ||||
|         Model(Node *parent = NULL); // Конструктор по умолчанию
 | ||||
|         Model(const Model& copy); // Конструктор копирования
 | ||||
|         Model& operator=(const Model& other); // Оператор присваивания
 | ||||
|         virtual ~Model(); | ||||
| 
 | ||||
|         void render(); // Вызов отрисовки без uniform-данных
 | ||||
|         void render(ShaderProgram &shaderProgram, UBO &material_buffer); // Вызов отрисовки
 | ||||
| 
 | ||||
|         void load_verteces(glm::vec3* verteces, GLuint count); // Загрузка вершин в буфер
 | ||||
|         void load_indices(GLuint* indices, GLuint count); // Загрузка индексов в буфер
 | ||||
|         void load_texCoords(glm::vec2* texCoords, GLuint count); // Загрузка текстурных координат в буфер
 | ||||
|         void load_normals(glm::vec3* normals, GLuint count); // Загрузка нормалей в буфер
 | ||||
|         void set_index_range(size_t first_byteOffset, size_t count); // Ограничение диапазона из буфера индексов
 | ||||
|         void set_texture(Texture& texture); // Привязка текстуры к модели
 | ||||
|          | ||||
|         Material material; // Материал модели
 | ||||
|     private: | ||||
|         VAO vao; | ||||
|         BO vertex_vbo, index_vbo; // вершинный и индексный буферы
 | ||||
|         BO normals_vbo, texCoords_vbo; // буферы с нормалями и текстурными координатами
 | ||||
|         GLuint verteces_count; // Количество вершин
 | ||||
|         size_t first_index_byteOffset, indices_count; // Сдвиг в байтах для первого и количество индексов
 | ||||
|         Texture texture_diffuse; // Диффузная текстура
 | ||||
|         Texture texture_ambient; // Текстура фонового освщения
 | ||||
|         Texture texture_specular; // Текстура зеркального отражения
 | ||||
| }; | ||||
| 
 | ||||
| #endif // MODEL_H
 | ||||
							
								
								
									
										37
									
								
								include/Scene.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								include/Scene.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,37 @@ | ||||
| #ifndef SCENE_H | ||||
| #define SCENE_H | ||||
| 
 | ||||
| #include <list> | ||||
| 
 | ||||
| #include "Model.h" | ||||
| #include "Camera.h" | ||||
| 
 | ||||
| #define DEFAULT_MTL_DIR "./" | ||||
| class Scene loadOBJtoScene(const char* filename, const char* mtl_directory = DEFAULT_MTL_DIR, const char* texture_directory = DEFAULT_MTL_DIR); | ||||
| 
 | ||||
| // Класс сцены
 | ||||
| class Scene | ||||
| { | ||||
|     public: | ||||
|         Scene(); // Конструктор пустой сцены
 | ||||
|         Scene(const Scene ©); // Конструктор копирования
 | ||||
|         Scene& operator=(const Scene& other); // Оператор присваивания
 | ||||
| 
 | ||||
|         void render(ShaderProgram &shaderProgram, UBO &material_buffer); // Рендер сцены
 | ||||
| 
 | ||||
|         Node root; // Корневой узел
 | ||||
| 
 | ||||
|         // Списки объектов, выступающих узлами
 | ||||
|         std::list<Node> nodes; // Список пустых узлов
 | ||||
|         std::list<Model> models; // Список моделей для рендера
 | ||||
|         std::list<Camera> cameras; // Список камер
 | ||||
|      | ||||
|     protected: | ||||
|         void rebuld_tree(const Scene& from); // Перестройка дерева после копирования или присваивания
 | ||||
|         template <class T> | ||||
|         void rebuild_Nodes_list(T& nodes, const Scene& from); // Перестройка узлов выбранного списка
 | ||||
|         template <class T> | ||||
|         void move_parent(Node& for_node, const std::list<T>& from_nodes, std::list<T>& this_nodes); // Сдвигает родителя узла между двумя списками при условии его принадлежности к оригинальному
 | ||||
| }; | ||||
| 
 | ||||
| #endif // SCENE_H
 | ||||
							
								
								
									
										30
									
								
								include/Shader.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								include/Shader.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,30 @@ | ||||
| #ifndef SHADER_H | ||||
| #define SHADER_H | ||||
| 
 | ||||
| #include <glad/glad.h> | ||||
| 
 | ||||
| #include <map> | ||||
| #include <string> | ||||
| 
 | ||||
| // Класс шейдерной программы
 | ||||
| class ShaderProgram | ||||
| { | ||||
|     public: | ||||
|         ShaderProgram(); | ||||
|         ShaderProgram(const ShaderProgram ©); | ||||
|         ~ShaderProgram(); | ||||
|         ShaderProgram& operator=(const ShaderProgram& other); | ||||
| 
 | ||||
|         void use(); // Использование шейдеров
 | ||||
|         void load(GLuint type, const char* filename); // Функция для загрузки шейдеров
 | ||||
|         void link(); // Формирование программы из загруженных шейдеров
 | ||||
|         GLuint getUniformLoc(const char* name); // Возвращает местоположение uniform-переменной
 | ||||
|         void bindUniformBlock(const char* name, int binding); // Привязка uniform-блока
 | ||||
|         void bindTextures(const char* textures_base_shader_names[], int count); // Инициализация текстур на шейдере
 | ||||
|     private: | ||||
|         GLuint program; // Дескриптор
 | ||||
|         static std::map<int, int> handler_count; // Получение количества использований по дескриптору шейдера (Shared pointer)
 | ||||
|         std::map<const char*, GLuint> uniformLocations; // Местоположения uniform-переменных
 | ||||
| }; | ||||
| 
 | ||||
| #endif // SHADER_H
 | ||||
							
								
								
									
										37
									
								
								include/Texture.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								include/Texture.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,37 @@ | ||||
| #ifndef TEXTURE_H | ||||
| #define TEXTURE_H | ||||
| 
 | ||||
| #include <glad/glad.h> | ||||
| 
 | ||||
| #include <map> | ||||
| #include <string> | ||||
| 
 | ||||
| enum TexType { | ||||
|     TEX_DIFFUSE, | ||||
|     TEX_AMBIENT, | ||||
|     TEX_SPECULAR, | ||||
|     TEX_AVAILABLE_COUNT | ||||
| }; | ||||
| 
 | ||||
| class Texture | ||||
| { | ||||
|     public: | ||||
|         Texture(GLuint type = TEX_AVAILABLE_COUNT, const std::string& filename = ""); // Загрузка текстуры с диска или использование "пустой"
 | ||||
|         Texture(GLuint width, GLuint height, GLuint attachment, GLuint texType = TEX_DIFFUSE, GLint internalformat = GL_RGBA, GLint format = GL_RGBA, GLenum dataType = GL_FLOAT); // Конструктор текстуры заданного размера для использования в буфере
 | ||||
|         Texture(const Texture& other); // Конструктор копирования
 | ||||
|         ~Texture(); | ||||
| 
 | ||||
|         Texture& operator=(const Texture& other); // Оператор присваивания
 | ||||
| 
 | ||||
|         void use(); // Привязка текстуры
 | ||||
|         static void disable(GLuint type); // Отвязка текстуры по типу
 | ||||
|         GLuint getType(); // Возвращает тип текстуры
 | ||||
|         void setType(GLuint type); // Задает тип текстуры
 | ||||
|     private: | ||||
|         GLuint handler; // Дескриптор текстуры
 | ||||
|         GLuint type; // Тип текстуры, соответствует её слоту
 | ||||
|         static std::map<std::string, int> filename_handler; // Получение дескриптора текстуры по её имени
 | ||||
|         static std::map<int, int> handler_count; // Получение количества использований по дескриптору текстуры (Shared pointer)
 | ||||
| }; | ||||
| 
 | ||||
| #endif // TEXTURE_H
 | ||||
							
								
								
									
										16
									
								
								shaders/bulb.frag
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								shaders/bulb.frag
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | ||||
| #version 420 core  | ||||
| 
 | ||||
| layout(std140, binding = 1) uniform Material | ||||
| { | ||||
|     vec3 ka; | ||||
|     vec3 kd; | ||||
|     vec3 ks; | ||||
|     float p; | ||||
| }; | ||||
| 
 | ||||
| out vec4 color; | ||||
| 
 | ||||
| void main() | ||||
| {    | ||||
|     color = vec4(ka, 1); | ||||
| } | ||||
							
								
								
									
										17
									
								
								shaders/bulb.vert
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								shaders/bulb.vert
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,17 @@ | ||||
| #version 420 core  | ||||
| 
 | ||||
| layout(location = 0) in vec3 pos;  | ||||
| 
 | ||||
| layout(std140, binding = 0) uniform Camera | ||||
| { | ||||
|     mat4 projection; | ||||
|     mat4 view; | ||||
|     vec3 position; | ||||
| } camera; | ||||
| 
 | ||||
| uniform mat4 model; | ||||
| 
 | ||||
| void main()  | ||||
| {  | ||||
|     gl_Position = camera.projection * camera.view * model * vec4(pos, 1.0); | ||||
| }  | ||||
							
								
								
									
										38
									
								
								shaders/gshader.frag
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								shaders/gshader.frag
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,38 @@ | ||||
| #version 420 core  | ||||
| 
 | ||||
| layout(std140, binding = 1) uniform Material | ||||
| { | ||||
|     vec3 ka; | ||||
|     vec3 kd; | ||||
|     vec3 ks; | ||||
|     float p; | ||||
| }; | ||||
| 
 | ||||
| layout (location = 0) out vec3 gPosition; | ||||
| layout (location = 1) out vec3 gNormal; | ||||
| layout (location = 2) out vec4 gDiffuseP; | ||||
| layout (location = 3) out vec4 gAmbientSpecular; | ||||
| 
 | ||||
| in vec3 vertex; // Позиция вершины в пространстве | ||||
| in vec3 N; // Нормаль трансформированноая | ||||
| in vec2 texCoord; // Текстурные координаты | ||||
| 
 | ||||
| uniform sampler2D tex_diffuse; | ||||
| uniform sampler2D tex_ambient; | ||||
| uniform sampler2D tex_specular; | ||||
| 
 | ||||
| void main() | ||||
| {     | ||||
|     // Сохранение позиции фрагмента в G-буфере | ||||
|     gPosition = vertex; | ||||
|     // Сохранение нормали в G-буфере | ||||
|     gNormal = N; | ||||
|     // Сохранение диффузного цвета | ||||
|     gDiffuseP.rgb = texture(tex_diffuse, texCoord).rgb * kd; | ||||
|     // Сохранение глянцевости | ||||
|     gDiffuseP.a = p; | ||||
|     // Сохранение фоновой составляющей | ||||
|     gAmbientSpecular.rgb = texture(tex_ambient, texCoord).rgb * ka; | ||||
|     // Сохранение зеркальной составляющей | ||||
|     gAmbientSpecular.a = texture(tex_specular, texCoord).r * ks.r; | ||||
| } | ||||
							
								
								
									
										30
									
								
								shaders/gshader.vert
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								shaders/gshader.vert
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,30 @@ | ||||
| #version 420 core  | ||||
| 
 | ||||
| layout(location = 0) in vec3 pos;  | ||||
| layout(location = 1) in vec2 inTexCoord; | ||||
| layout(location = 2) in vec3 normals;  | ||||
| 
 | ||||
| layout(std140, binding = 0) uniform Camera | ||||
| { | ||||
|     mat4 projection; | ||||
|     mat4 view; | ||||
|     vec3 position; | ||||
| } camera; | ||||
| 
 | ||||
| uniform mat4 model; | ||||
| 
 | ||||
| out vec3 vertex; // Позиция вершины в пространстве | ||||
| out vec3 N; // Нормаль трансформированноая | ||||
| out vec2 texCoord; // Текстурные координаты | ||||
| 
 | ||||
| void main()  | ||||
| {  | ||||
|     vec4 P = model * vec4(pos, 1.0); // трансформация вершины | ||||
|     vertex = P.xyz; | ||||
| 
 | ||||
|     N = normalize(mat3(model) * normals); // трансформация нормали | ||||
| 
 | ||||
|     texCoord = inTexCoord; // Текстурные координаты | ||||
| 
 | ||||
|     gl_Position = camera.projection * camera.view * P; | ||||
| }  | ||||
							
								
								
									
										85
									
								
								shaders/lighting.frag
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								shaders/lighting.frag
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,85 @@ | ||||
| #version 420 core  | ||||
| 
 | ||||
| in vec2 texCoord; | ||||
| 
 | ||||
| layout(std140, binding = 0) uniform Camera | ||||
| { | ||||
|     mat4 projection; | ||||
|     mat4 view; | ||||
|     vec3 position; | ||||
| } camera; | ||||
| 
 | ||||
| struct LightData | ||||
| { | ||||
|     vec3 position; | ||||
|     vec3 color; | ||||
|     vec3 attenuation; | ||||
| }; | ||||
| 
 | ||||
| layout(std140, binding = 2) uniform Light | ||||
| { | ||||
|     LightData data[300]; | ||||
|     int count; | ||||
| } light_f; | ||||
| 
 | ||||
| uniform sampler2D gPosition; | ||||
| uniform sampler2D gNormal; | ||||
| uniform sampler2D gDiffuseP; | ||||
| uniform sampler2D gAmbientSpecular; | ||||
| 
 | ||||
| out vec4 color;  | ||||
| 
 | ||||
| void main()  | ||||
| {  | ||||
|     // Получим данные из текстур буфера | ||||
|     vec3 fragPos = texture(gPosition, texCoord).rgb; | ||||
|     vec3 N = texture(gNormal, texCoord).rgb; | ||||
|     vec3 kd = texture(gDiffuseP, texCoord).rgb; | ||||
|     vec3 ka = texture(gAmbientSpecular, texCoord).rgb; | ||||
|     float ks = texture(gAmbientSpecular, texCoord).a; | ||||
|     float p = texture(gDiffuseP, texCoord).a; | ||||
|      | ||||
|     // Переменные используемые в цикле: | ||||
|     vec3 L_vertex; // Данные об источнике относительно фрагмента | ||||
|     vec3 Cam_vertex = normalize(camera.position - fragPos); // Данные о камере относительно фрагмента | ||||
|     float diffuse; // Диффузная составляющая | ||||
|     vec3 H; // Вектор половины пути | ||||
|     float specular; // Зеркальная составляющая | ||||
|     float L_distance; // Расстояние от поверхности до источника | ||||
|     float attenuation; // Коэф. угасания | ||||
|      | ||||
|     // Фоновая освещенность | ||||
|     color = vec4(ka, 1); | ||||
| 
 | ||||
|     // Цикл по источникам света | ||||
|     int i; | ||||
|     for (i = 0; i < light_f.count; i++) | ||||
|     { | ||||
|         // Данные об источнике относительно фрагмента | ||||
|         L_vertex = light_f.data[i].position - fragPos; | ||||
| 
 | ||||
|         // Расстояние от поверхности до источника | ||||
|         L_distance = length(L_vertex); | ||||
|          | ||||
|         // Проверка на дистанцию | ||||
|         if (L_distance < light_f.data[i].attenuation.r) | ||||
|         { | ||||
|             // Нормирование вектора | ||||
|             L_vertex = normalize(L_vertex); | ||||
| 
 | ||||
|             // Диффузная составляющая | ||||
|             diffuse = max(dot(L_vertex, N), 0.0); // скалярное произведение с отсеканием значений < 0 | ||||
|              | ||||
|             // Вектор половины пути | ||||
|             H = normalize(L_vertex + Cam_vertex); | ||||
|             // Зеркальная составляющая | ||||
|             specular = pow(max(dot(H, N), 0.0), p*4); // скалярное произведение с отсеканием значений < 0 в степени p | ||||
| 
 | ||||
|             // Угасание с учетом расстояния | ||||
|             attenuation = 1 / (1 + light_f.data[i].attenuation[1] * L_distance + light_f.data[i].attenuation[2] * L_distance * L_distance); | ||||
| 
 | ||||
|             color += vec4(light_f.data[i].color*kd*diffuse  * attenuation, 1)  | ||||
|                   +  vec4(light_f.data[i].color*ks*specular * attenuation, 1); | ||||
|         } | ||||
|     } | ||||
| }  | ||||
							
								
								
									
										11
									
								
								shaders/quad.vert
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								shaders/quad.vert
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | ||||
| #version 420 core  | ||||
| 
 | ||||
| layout(location = 0) in vec3 pos;  | ||||
| 
 | ||||
| out vec2 texCoord; | ||||
| 
 | ||||
| void main()  | ||||
| {  | ||||
|     gl_Position = vec4(pos, 1.0); | ||||
|     texCoord = (pos.xy + vec2(1.0)) / 2; // Переход от [-1;1] к [0;1] | ||||
| } | ||||
							
								
								
									
										196
									
								
								src/Buffers.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										196
									
								
								src/Buffers.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,196 @@ | ||||
| #include "Buffers.h" | ||||
| 
 | ||||
| // Счетчики использований дескрипторов
 | ||||
| std::map<GLuint, GLuint> VAO::handler_count;  | ||||
| std::map<GLuint, GLuint> BO::handler_count;  | ||||
| 
 | ||||
| // Создает VAO и активирует его
 | ||||
| VAO::VAO() | ||||
| {  | ||||
|     glGenVertexArrays(1, &handler); // Генерация одного объекта массива вершин
 | ||||
|     glBindVertexArray(handler);     // Привязка для использования
 | ||||
|     handler_count[handler] = 1;     // Инициализация счетчика для дескриптора 
 | ||||
| } | ||||
| 
 | ||||
| // Уничтожает VAO
 | ||||
| VAO::~VAO() | ||||
| { | ||||
|     // Если дескриптор никем не используется - освободим его
 | ||||
|     if (!--handler_count[handler]) | ||||
|     { | ||||
|         glDeleteVertexArrays(1, &handler); | ||||
|         handler_count.erase(handler); // Удаление из словаря
 | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| // Конструктор копирования
 | ||||
| VAO::VAO(const VAO & copy) : handler(copy.handler) | ||||
| { | ||||
|     handler_count[handler]++; | ||||
| } | ||||
| 
 | ||||
| // Оператор присваивания
 | ||||
| VAO& VAO::operator=(const VAO & other)  | ||||
| { | ||||
|     // Если это разные дескрипторы
 | ||||
|     if (handler != other.handler) | ||||
|     { // то следуюет удалить текущий перед заменой
 | ||||
|         this->~VAO();  | ||||
|         handler = other.handler; | ||||
|         handler_count[handler]++; | ||||
|     } | ||||
| 
 | ||||
|     return *this; | ||||
| } | ||||
| 
 | ||||
| // Активация VAO
 | ||||
| void VAO::use() | ||||
| { | ||||
|     glBindVertexArray(handler); // Привязка VAO для использования
 | ||||
| } | ||||
| 
 | ||||
| // Деактивация активного VAO
 | ||||
| void VAO::disable() | ||||
| { | ||||
|     glBindVertexArray(0);       // Отключение VAO
 | ||||
| } | ||||
| 
 | ||||
| // Создает пустой буфер заданного типа
 | ||||
| BO::BO(BUFFER_TYPE t) : type(t) | ||||
| { | ||||
|     glGenBuffers(1, &handler); // Генерация одного объекта буфера
 | ||||
|     handler_count[handler] = 1; | ||||
|     use(); // Привязка буфера
 | ||||
| } | ||||
| 
 | ||||
| // Создает и загружает туда данные
 | ||||
| BO::BO(BUFFER_TYPE t, const void *data, int size) : BO(t) | ||||
| { | ||||
|     load(data, size); | ||||
| } | ||||
| 
 | ||||
| // Уничтожает буфер
 | ||||
| BO::~BO() | ||||
| { | ||||
|     if (handler) // Если буфер был создан
 | ||||
|     { | ||||
|         // Если дескриптор никем не используется - освободим его
 | ||||
|         if (!--handler_count[handler]) | ||||
|         { | ||||
|             glDeleteBuffers(1, &handler); | ||||
|             handler_count.erase(handler); // Удаление из словаря
 | ||||
|         } | ||||
|         handler = 0; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| // Конструктор копирования
 | ||||
| BO::BO(const BO & copy) : handler(copy.handler), type(copy.type) | ||||
| { | ||||
|     handler_count[handler]++; | ||||
| } | ||||
| 
 | ||||
| // Оператор присваивания
 | ||||
| BO& BO::operator=(const BO & other) | ||||
| { | ||||
|     // Если это разные дескрипторы
 | ||||
|     if (handler != other.handler) | ||||
|     { // то следуюет удалить текущий перед заменой
 | ||||
|         this->~BO();  | ||||
|         handler = other.handler; | ||||
|         handler_count[handler]++; | ||||
|     } | ||||
|     // Изменим тип
 | ||||
|     type = other.type; | ||||
| 
 | ||||
|     return *this; | ||||
| } | ||||
| 
 | ||||
| // Загрузка вершин в буфер
 | ||||
| void BO::load(const void *data, int size, GLuint mode) | ||||
| { | ||||
|     use(); // Привязка буфера
 | ||||
|     glBufferData(type, size, data, mode); | ||||
| } | ||||
| 
 | ||||
| void BO::use() | ||||
| { | ||||
|     glBindBuffer(type, handler); // Привязка элементного буфера
 | ||||
| } | ||||
| 
 | ||||
| // Создает пустой uniform-буфер заданного размера с автоматической привязкой
 | ||||
| UBO::UBO(int size, int binding) : BO(UNIFORM, 0, size) | ||||
| { | ||||
|     rebind(binding); | ||||
| } | ||||
| 
 | ||||
| // Создает пустой uniform-буфер заданного размера с автоматической привязкой
 | ||||
| UBO::UBO(const void *data, int size, int binding) : BO(UNIFORM, data, size) | ||||
| { | ||||
|     rebind(binding); | ||||
| } | ||||
| 
 | ||||
| // перепривязка
 | ||||
| void UBO::rebind(int binding) | ||||
| { | ||||
|     glBindBufferBase(type, binding, handler);  | ||||
| } | ||||
| 
 | ||||
| // Загрузка с отступом
 | ||||
| void UBO::loadSub(const void *data, int size, int offset) | ||||
| { | ||||
|     use(); | ||||
|     glBufferSubData(type, offset, size, data); | ||||
| } | ||||
| 
 | ||||
| // Создает буфер кадра с нужным числом прикреплений текстур
 | ||||
| FBO::FBO(GLuint *attachments, int count) | ||||
| { | ||||
|     glGenFramebuffers(1, &handler); | ||||
|     use(); | ||||
|     glDrawBuffers(count, attachments); | ||||
| } | ||||
| 
 | ||||
| // Уничтожение буфера
 | ||||
| FBO::~FBO() | ||||
| { | ||||
|     glDeleteFramebuffers(1, &handler); | ||||
| } | ||||
| 
 | ||||
| // Активирует буфер кадра в заданном режиме
 | ||||
| void FBO::use(GLuint mode)  | ||||
| { | ||||
|     glBindFramebuffer(mode, handler); | ||||
| } | ||||
| 
 | ||||
| // Активирует базовый буфер в заданном режиме
 | ||||
| void FBO::useDefault(GLuint mode) | ||||
| { | ||||
|     glBindFramebuffer(mode, 0); | ||||
| }  | ||||
| 
 | ||||
| // Привязка рендер буфера
 | ||||
| void FBO::assignRenderBuffer(GLuint hander, GLuint attachment) | ||||
| { | ||||
|     glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, hander); | ||||
| } | ||||
| 
 | ||||
| // Создает буфер рендера с заданными параметрами размеров и используемых компонент
 | ||||
| RBO::RBO(int w, int h, GLuint component) | ||||
| { | ||||
|     glGenRenderbuffers(1, &handler); | ||||
|     glBindRenderbuffer(GL_RENDERBUFFER, handler); | ||||
|     glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, w, h); | ||||
| } | ||||
| 
 | ||||
| // Уничтожение буфера
 | ||||
| RBO::~RBO() | ||||
| { | ||||
|     glDeleteRenderbuffers(1, &handler); | ||||
| } | ||||
| 
 | ||||
| // Возвращает дескриптор буфера рендера
 | ||||
| GLuint RBO::getHandler() | ||||
| { | ||||
|     return handler; | ||||
| } | ||||
							
								
								
									
										189
									
								
								src/Camera.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										189
									
								
								src/Camera.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,189 @@ | ||||
| #include "Camera.h" | ||||
| 
 | ||||
| // Указатель на текущую используемую камеру
 | ||||
| Camera* Camera::p_current = NULL;  | ||||
| 
 | ||||
| // Защищенный (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()  | ||||
| {  | ||||
|     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; | ||||
| } | ||||
| 
 | ||||
| // Данные о камере для шейдера
 | ||||
| CameraData& Camera::getData() | ||||
| { | ||||
|     static CameraData data; | ||||
|     data = {getProjection(), getView(), position}; | ||||
|     return data; | ||||
| } | ||||
							
								
								
									
										217
									
								
								src/Lights.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										217
									
								
								src/Lights.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,217 @@ | ||||
| #include "Lights.h" | ||||
| 
 | ||||
| #include "Scene.h" // Для отладочного вывода лампочек
 | ||||
| 
 | ||||
| #include <stdexcept> | ||||
| 
 | ||||
| GLuint Light::count = 0; // количество используемых источников (должно быть <= MAX_LIGHTS)
 | ||||
| LightData Light::data[MAX_LIGHTS]; // Массив данных по источникам света
 | ||||
| Light Light::lights[MAX_LIGHTS]; // Массив источников-узлов сцены
 | ||||
| 
 | ||||
| // возвращает размер буфера в байтах
 | ||||
| int Light::getUBOsize() | ||||
| { | ||||
|     return sizeof(LightData) * MAX_LIGHTS + sizeof(GLuint); | ||||
| } | ||||
| 
 | ||||
| // Загрузка данных в буфер
 | ||||
| void Light::upload(UBO& lights_data) | ||||
| { | ||||
|     GLuint LightDataSize = sizeof(LightData); // Одного экземпляра структуры LightData
 | ||||
|     int first = MAX_LIGHTS, last = -1; // Начало и конец диапазона загрузки источников
 | ||||
|     static GLuint prev_count = -1; // Кол-во источников в прошлую посылку
 | ||||
| 
 | ||||
|     if (count) | ||||
|     { | ||||
|         for (int i = 0; i < MAX_LIGHTS; i++) | ||||
|         { | ||||
|             lights[i].recalcMatrices(); // Пересчитаем матрицы по необходимости (проверка внутри метода)
 | ||||
| 
 | ||||
|             // Если требуется загрузка
 | ||||
|             if (lights[i].uploadReq) | ||||
|             { | ||||
|                 lights[i].toData(); // Перевод ноды в данные для шейдера
 | ||||
| 
 | ||||
|                 // Определение диапазона загрузки 
 | ||||
|                 if (first > lights[i].index) | ||||
|                     first = lights[i].index; | ||||
|                 if (last < lights[i].index) | ||||
|                     last = lights[i].index;  | ||||
| 
 | ||||
|                 lights[i].uploadReq = false; // Сброс флага
 | ||||
|             } | ||||
|         } | ||||
|          | ||||
|         // Если есть что загрузить (определен диапазон)
 | ||||
|         if (last > -1) | ||||
|             lights_data.loadSub(data + first, LightDataSize*(last - first +1), LightDataSize*(first)); // Загрузка данных об источниках
 | ||||
|     } | ||||
| 
 | ||||
|     // Если кол-во изменилось
 | ||||
|     if (prev_count != count) | ||||
|     { | ||||
|         prev_count = count; | ||||
| 
 | ||||
|         // Загружаем кол-во источников
 | ||||
|         lights_data.loadSub(&count, sizeof(count), LightDataSize*MAX_LIGHTS); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| // Метод пересчета матрицы трансформации по необходимости, должен сбрасывать флаг changed
 | ||||
| void Light::recalcMatrices() | ||||
| { | ||||
|     // Если были изменения - необходимо загрузить данные
 | ||||
|     if (changed || parent_changed) | ||||
|         uploadReq = true; | ||||
|      | ||||
|     // Выполняем вычисление матриц методом родительского класса
 | ||||
|     Node::recalcMatrices();  | ||||
| } | ||||
| 
 | ||||
| // Константный доступ к цвету
 | ||||
| const glm::vec3& Light::c_color() const | ||||
| { | ||||
|     return color; | ||||
| } | ||||
| 
 | ||||
| // Неконстантная ссылка для изменений цвета
 | ||||
| glm::vec3& Light::e_color() | ||||
| { | ||||
|     uploadReq = true; | ||||
| 
 | ||||
|     return color; | ||||
| } | ||||
| 
 | ||||
| // Проверка что не взаимодествуем с пустым источником
 | ||||
| void Light::check_id() | ||||
| { | ||||
|     if (index < 0 | ||||
|     ||  index >= count) | ||||
|         throw std::runtime_error("Попытка использовать ссылку на пустой или некорректный источник"); | ||||
| } | ||||
| 
 | ||||
| // Преобразует информацию об источнике в структуру LightData
 | ||||
| void Light::toData() | ||||
| { | ||||
|     check_id(); // Проверка на работу с корректным индексом
 | ||||
| 
 | ||||
|     data[index].position = glm::vec3(result_transform[3]); // Позиция из матрицы трансформации
 | ||||
|     data[index].color = color; // Цвет
 | ||||
|     // Если радиус изменился
 | ||||
|     if (data[index].attenuation.r != radius) | ||||
|     { | ||||
|         data[index].attenuation.r  = radius; // Радиус действия источника
 | ||||
|         data[index].attenuation[1] = 4.5/radius;      // Линейный коэф. угасания
 | ||||
|         data[index].attenuation[2] = 4 * data[index].attenuation[1] * data[index].attenuation[1]; // Квадратичный коэф. угасания
 | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| // Возвращает ссылку на новый источник света
 | ||||
| Light& Light::getNew()  | ||||
| { | ||||
|     Light& refNew = findByIndex(-1); | ||||
| 
 | ||||
|     refNew.index = count++; | ||||
|     refNew.uploadReq = true; | ||||
| 
 | ||||
|     return refNew; | ||||
| } | ||||
| 
 | ||||
| // Уничтожает источник света
 | ||||
| void Light::destroy() | ||||
| { | ||||
|     check_id(); // Проверка на работу с корректным индексом
 | ||||
|     // Если удаляемый элемент не последний
 | ||||
|     if (count-1 != index) | ||||
|     { | ||||
|         // Найдем элемент для замены
 | ||||
|         Light& replace = findByIndex(--count); | ||||
| 
 | ||||
|         replace.uploadReq = true; // Требуется загрузить данные
 | ||||
|         replace.index = index; // Заменяем индекс данных
 | ||||
|     } | ||||
|      | ||||
|     operator=(Light()); // Обнулим источник путем замены на новый
 | ||||
| } | ||||
| 
 | ||||
| // Возвращает ссылку на источник с нужным индексом
 | ||||
| Light& Light::findByIndex(GLuint index) | ||||
| { | ||||
|     // Если нет источников - возвращаем нулевой
 | ||||
|     if (!count) | ||||
|         return lights[0]; | ||||
| 
 | ||||
|     // Цикл по перебору источников
 | ||||
|     for (int i = 0; i < MAX_LIGHTS; i++) | ||||
|         if (lights[i].index == index) | ||||
|             return lights[i]; | ||||
| 
 | ||||
|     throw std::runtime_error("Запрашиваемый источник освещения не найден, либо достигнут лимит"); | ||||
| } | ||||
| 
 | ||||
| // Конструктор без параметров
 | ||||
| Light::Light() : Node(), index(-1), uploadReq(false), color(1.0f), radius(10.0f) | ||||
| { | ||||
|      | ||||
| } | ||||
| 
 | ||||
| // Оператор  присваивания
 | ||||
| Light& Light::operator=(const Light& other) | ||||
| { | ||||
|     // Проверка на самоприсваивание
 | ||||
|     if (this != &other)  | ||||
|     { | ||||
|         index = other.index; // Переносим индекс
 | ||||
|         uploadReq = other.uploadReq; // Необходимость загрузки 
 | ||||
|         color = other.color; | ||||
|         radius = other.radius; | ||||
| 
 | ||||
|         Node::operator=(other); | ||||
|     } | ||||
|     return *this; | ||||
| } | ||||
| 
 | ||||
| Light::~Light() | ||||
| { | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| // Рисование отладочных лампочек
 | ||||
| void Light::render(ShaderProgram &shaderProgram, UBO &material_buffer) | ||||
| { | ||||
|     // Загрузка модели лампочки при первом вызове функции
 | ||||
|     static Scene bulb = loadOBJtoScene("../resources/models/bulb.obj", "../resources/models/", "../resources/textures/"); | ||||
|     static Model sphere = genShpere(1, 16, &bulb.root); | ||||
| 
 | ||||
|     // Цикл по источникам света
 | ||||
|     for (int i = 0; i < count; i++) | ||||
|     { | ||||
|         // Сдвиг на позицию источника
 | ||||
|         bulb.root.e_position() = data[i].position; | ||||
|         sphere.e_scale() = glm::vec3(data[i].attenuation.r); // Масштабирование сферы
 | ||||
|         // Задание цвета
 | ||||
|         bulb.models.begin()->material.ka = sphere.material.ka = data[i].color; | ||||
| 
 | ||||
|         // Вызов отрисовки
 | ||||
|         bulb.render(shaderProgram, material_buffer);     | ||||
| 
 | ||||
|         // Рисование сферы покрытия источника в режиме линий
 | ||||
|         glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); | ||||
|         sphere.render(shaderProgram, material_buffer); | ||||
|         glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| // Константный доступ к радиусу
 | ||||
| const float& Light::c_radius() const | ||||
| { | ||||
|     return radius; | ||||
| } | ||||
| 
 | ||||
| // Неконстантная ссылка для изменений радиуса
 | ||||
| float& Light::e_radius() | ||||
| { | ||||
|     uploadReq = true; | ||||
| 
 | ||||
|     return radius; | ||||
| } | ||||
							
								
								
									
										478
									
								
								src/Model.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										478
									
								
								src/Model.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,478 @@ | ||||
| #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), normals_vbo(VERTEX), texCoords_vbo(VERTEX) | ||||
| { | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| // Конструктор копирования
 | ||||
| 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), normals_vbo(copy.normals_vbo), texCoords_vbo(copy.texCoords_vbo), | ||||
| texture_diffuse(copy.texture_diffuse), texture_ambient(copy.texture_ambient), texture_specular(copy.texture_specular),  | ||||
| material(copy.material) | ||||
| { | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| // Оператор присваивания
 | ||||
| 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; | ||||
|     texCoords_vbo = other.texCoords_vbo; | ||||
| 
 | ||||
|     texture_diffuse = other.texture_diffuse; | ||||
|     texture_ambient = other.texture_ambient; | ||||
|     texture_specular = other.texture_specular; | ||||
|      | ||||
|     material = other.material; | ||||
| 
 | ||||
|     return *this; | ||||
| } | ||||
| 
 | ||||
| Model::~Model() | ||||
| { | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| // Вызов отрисовки без uniform-данных
 | ||||
| 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 Model::render(ShaderProgram &shaderProgram, UBO &material_buffer)  | ||||
| { | ||||
|     // Расчитаем матрицу трансформации
 | ||||
|     glUniformMatrix4fv(shaderProgram.getUniformLoc("model"), 1, GL_FALSE, &this->getTransformMatrix()[0][0]); | ||||
| 
 | ||||
|     // Подключаем текстуры
 | ||||
|     texture_diffuse.use(); | ||||
|     texture_ambient.use(); | ||||
|     texture_specular.use(); | ||||
|      | ||||
| 
 | ||||
|     // Загружаем данные о материале
 | ||||
|     material_buffer.load(&material, sizeof(material)); | ||||
| 
 | ||||
|     render(); | ||||
| } | ||||
| 
 | ||||
| // Функция для конфигурации атрибута вершинного буфера
 | ||||
| void vertex_attrib_config() | ||||
| { | ||||
|     // Включаем необходимый атрибут у выбранного VAO
 | ||||
|     glEnableVertexAttribArray(0); | ||||
|     // Устанавливаем связь между VAO и привязанным VBO
 | ||||
|     glVertexAttribPointer(  0         // индекс атрибута, должен совпадать с Layout шейдера
 | ||||
|                           , 3         // количество компонент одного элемента
 | ||||
|                           , GL_FLOAT  // тип
 | ||||
|                           , GL_FALSE  // нормализованность значений
 | ||||
|                           , 0         // шаг
 | ||||
|                           , (void *)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 texCoords_attrib_config() | ||||
| { | ||||
|     // Включаем необходимый атрибут у выбранного VAO
 | ||||
|     glEnableVertexAttribArray(1); | ||||
|     // Устанавливаем связь между VAO и привязанным VBO
 | ||||
|     glVertexAttribPointer(  1         // индекс атрибута, должен совпадать с Layout шейдера
 | ||||
|                           , 2         // количество компонент одного элемента
 | ||||
|                           , GL_FLOAT  // тип
 | ||||
|                           , GL_FALSE  // нормализованность значений
 | ||||
|                           , 0         // шаг
 | ||||
|                           , (void *)0 // отступ с начала массива
 | ||||
|                          ); | ||||
| }  | ||||
| 
 | ||||
| // Загрузка текстурных координат в буфер
 | ||||
| void Model::load_texCoords(glm::vec2* texCoords, GLuint count) | ||||
| { | ||||
|     // Подключаем VAO
 | ||||
|     vao.use(); | ||||
| 
 | ||||
|     texCoords_vbo.use(); | ||||
| 
 | ||||
|     // Загрузка вершин в память буфера
 | ||||
|     texCoords_vbo.load(texCoords, sizeof(glm::vec2)*count); | ||||
|     texCoords_attrib_config(); | ||||
| } | ||||
| 
 | ||||
| // Функция для конфигурации атрибута вершинного буфера
 | ||||
| void normals_attrib_config() | ||||
| { | ||||
|     // Включаем необходимый атрибут у выбранного VAO
 | ||||
|     glEnableVertexAttribArray(2); | ||||
|     // Устанавливаем связь между VAO и привязанным VBO
 | ||||
|     glVertexAttribPointer(  2         // индекс атрибута, должен совпадать с Layout шейдера
 | ||||
|                           , 3         // количество компонент одного элемента
 | ||||
|                           , GL_FLOAT  // тип
 | ||||
|                           , GL_FALSE  // нормализованность значений
 | ||||
|                           , 0         // шаг
 | ||||
|                           , (void *)0 // отступ с начала массива
 | ||||
|                          ); | ||||
| }  | ||||
| 
 | ||||
| // Загрузка нормалей в буфер
 | ||||
| void Model::load_normals(glm::vec3* normals, GLuint count)  | ||||
| { | ||||
|     // Подключаем VAO
 | ||||
|     vao.use(); | ||||
| 
 | ||||
|     normals_vbo.use(); | ||||
| 
 | ||||
|     // Загрузка вершин в память буфера
 | ||||
|     normals_vbo.load(normals, sizeof(glm::vec3)*count); | ||||
|     normals_attrib_config(); | ||||
| } | ||||
| 
 | ||||
| // Ограничение диапазона из буфера индексов
 | ||||
| void Model::set_index_range(size_t first_byteOffset, size_t count) | ||||
| { | ||||
|     first_index_byteOffset = first_byteOffset; | ||||
|     indices_count = count; | ||||
| }  | ||||
| 
 | ||||
| // Привязка текстуры к модели
 | ||||
| void Model::set_texture(Texture& texture) | ||||
| { | ||||
|     GLuint type = texture.getType(); | ||||
|     switch(type) | ||||
|     { | ||||
|         case TEX_DIFFUSE: | ||||
|             texture_diffuse = texture; | ||||
|             break; | ||||
|         case TEX_AMBIENT: | ||||
|             texture_ambient = texture; | ||||
|             break; | ||||
|         case TEX_SPECULAR: | ||||
|             texture_specular = texture; | ||||
|             break; | ||||
|     }; | ||||
| } | ||||
| 
 | ||||
| // Генерирует сферу заданного радиуса с определенным количеством сегментов
 | ||||
| Model genShpere(float radius, int sectorsCount, Node* parent) | ||||
| { | ||||
|     Model result(parent); | ||||
| 
 | ||||
|     std::vector<glm::vec3> vertices; | ||||
|     std::vector<glm::vec3> normals; | ||||
|     std::vector<GLuint> indices; | ||||
| 
 | ||||
|     float x, y, z, xy; // Позиция вершины
 | ||||
|     float nx, ny, nz, lengthInv = 1.0f / radius; // Нормаль вершины
 | ||||
|     float PI = 3.14159265; | ||||
|     float sectorStep = PI / sectorsCount; // Шаг сектора
 | ||||
|     float longAngle, latAngle; // Углы
 | ||||
| 
 | ||||
|     for(int i = 0; i <= sectorsCount; ++i) | ||||
|     { | ||||
|         latAngle = PI / 2 - i * sectorStep; // Начиная с pi/2 до -pi/2
 | ||||
|         xy = radius * cos(latAngle); // r * cos(lat)
 | ||||
|         z = radius * sin(latAngle); // r * sin(lat)
 | ||||
| 
 | ||||
|         // добавляем (sectorCount+1) вершин на сегмент
 | ||||
|         // Последняя и первая вершины имеют одинаковые нормали и координаты
 | ||||
|         for(int j = 0; j <= sectorsCount; ++j) | ||||
|         { | ||||
|             longAngle = j * 2 * sectorStep; // Начиная с 0 до 2*pi
 | ||||
| 
 | ||||
|             // Положение вершины (x, y, z)
 | ||||
|             x = xy * cos(longAngle); // r * cos(lat) * cos(long)
 | ||||
|             y = xy * sin(longAngle); // r * cos(lat) * sin(long)
 | ||||
|             vertices.push_back({x, y, z}); | ||||
| 
 | ||||
|             // Нормали (nx, ny, nz)
 | ||||
|             nx = x * lengthInv; | ||||
|             ny = y * lengthInv; | ||||
|             nz = z * lengthInv; | ||||
|             normals.push_back({nx, ny, nz}); | ||||
|         } | ||||
|     } | ||||
|     int k1, k2; | ||||
|     for(int i = 0; i < sectorsCount; ++i) | ||||
|     { | ||||
|         k1 = i * (sectorsCount + 1); // начало текущего сегмента
 | ||||
|         k2 = k1 + sectorsCount + 1; // начало следующего сегмента
 | ||||
| 
 | ||||
|         for(int j = 0; j < sectorsCount; ++j, ++k1, ++k2) | ||||
|         { | ||||
|             // 2 треугольника на один сегмент
 | ||||
|             // k1, k2, k1+1
 | ||||
|             if(i != 0) | ||||
|             { | ||||
|                 indices.push_back(k1); | ||||
|                 indices.push_back(k2); | ||||
|                 indices.push_back(k1 + 1); | ||||
|             } | ||||
| 
 | ||||
|             // k1+1, k2, k2+1
 | ||||
|             if(i != (sectorsCount-1)) | ||||
|             { | ||||
|                 indices.push_back(k1 + 1); | ||||
|                 indices.push_back(k2); | ||||
|                 indices.push_back(k2 + 1); | ||||
|             } | ||||
| 
 | ||||
|         } | ||||
|     } | ||||
|     // Загрузка в модель
 | ||||
|     result.load_verteces(&vertices[0], vertices.size()); | ||||
|     result.load_normals(&normals[0], normals.size()); | ||||
|     result.load_indices(&indices[0], indices.size()); | ||||
| 
 | ||||
|     return result; | ||||
| } | ||||
							
								
								
									
										224
									
								
								src/Scene.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										224
									
								
								src/Scene.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,224 @@ | ||||
| #include "Scene.h" | ||||
| 
 | ||||
| // Конструктор пустой сцены
 | ||||
| Scene::Scene() | ||||
| { | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| // Конструктор копирования
 | ||||
| Scene::Scene(const Scene ©): root(copy.root),  | ||||
| nodes(copy.nodes), models(copy.models), cameras(copy.cameras) | ||||
| { | ||||
|     rebuld_tree(copy); | ||||
| }  | ||||
| 
 | ||||
| // Оператор присваивания
 | ||||
| Scene& Scene::operator=(const Scene& other)  | ||||
| { | ||||
|     root = other.root; | ||||
|     nodes = other.nodes; | ||||
|     models = other.models; | ||||
|     cameras = other.cameras; | ||||
| 
 | ||||
|     rebuld_tree(other); | ||||
| 
 | ||||
|     return *this; | ||||
| }  | ||||
| 
 | ||||
| // Рендер сцены
 | ||||
| void Scene::render(ShaderProgram &shaderProgram, UBO &material_buffer)  | ||||
| { | ||||
|     for (auto & model : models) | ||||
|         model.render(shaderProgram, material_buffer); | ||||
| } | ||||
| 
 | ||||
| // Перестройка узлов выбранного списка
 | ||||
| template <class T> | ||||
| void Scene::rebuild_Nodes_list(T& nodes, const Scene& from) | ||||
| { | ||||
|     for (auto it = nodes.begin(); it != nodes.end(); it++) | ||||
|     { | ||||
|         // Берем родителя, который указывает на оригинальный объект
 | ||||
|         Node* parent = it->getParent(); | ||||
|          | ||||
|         // Если родитель - оригинальный корневой узел, то меняем на собственный корневой узел
 | ||||
|         if (parent == &from.root)  | ||||
|         { | ||||
|             it->setParent(&root); | ||||
|             continue; | ||||
|         } | ||||
| 
 | ||||
|         // Если можно привести к модели, то ищем родителя среди моделей
 | ||||
|         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); | ||||
|              | ||||
|         // Не нашли родителя - значит он не часть этой сцены 
 | ||||
|         // и изменений по нему не требуется
 | ||||
|     } | ||||
| }  | ||||
| 
 | ||||
| // Сдвигает родителя узла между двумя списками при условии его принадлежности к оригинальному
 | ||||
| template <class T> | ||||
| void Scene::move_parent(Node& for_node, const std::list<T>& from_nodes, std::list<T>& this_nodes) | ||||
| { | ||||
|     // Возьмем адрес родителя
 | ||||
|     Node* parent = for_node.getParent(); | ||||
|     // Цикл по элементам списков для перемещения родителя
 | ||||
|     // Списки в процессе копирования идеинтичные, вторая проверка не требуется
 | ||||
|     for (auto it_from = from_nodes.begin(), it_this = this_nodes.begin(); it_from != from_nodes.end(); ++it_from, ++it_this) | ||||
|         // Если адрес объекта, на который указывает итератор, совпадает с родителем - меняем родителя по второму итератору (it_this)
 | ||||
|         if (&(*it_from) == parent) | ||||
|             for_node.setParent(&(*it_this)); | ||||
| } | ||||
| 
 | ||||
| // Перестройка дерева после копирования или присваивания
 | ||||
| void Scene::rebuld_tree(const Scene& from) | ||||
| {     | ||||
|     // Восстановим родителей в пустых узлах для копии
 | ||||
|     rebuild_Nodes_list(nodes, from); | ||||
|     rebuild_Nodes_list(models, from); | ||||
|     rebuild_Nodes_list(cameras, from); | ||||
| } | ||||
| 
 | ||||
| #define TINYOBJLOADER_IMPLEMENTATION | ||||
| #include "tiny_obj_loader.h" | ||||
| 
 | ||||
| #include <functional> | ||||
| 
 | ||||
| inline void hash_combine(std::size_t& seed) { } | ||||
| 
 | ||||
| template <typename T, typename... Rest> | ||||
| inline void hash_combine(std::size_t& seed, const T& v, Rest... rest) { | ||||
|     std::hash<T> hasher; | ||||
|     seed ^= hasher(v) + 0x9e3779b9 + (seed<<6) + (seed>>2); | ||||
|     hash_combine(seed, rest...); | ||||
| } | ||||
| 
 | ||||
| Scene loadOBJtoScene(const char* filename, const char* mtl_directory, const char* texture_directory) | ||||
| { | ||||
|     Scene result; | ||||
|     Model model; | ||||
|     // Все модели образованные на основании этой модели будут иметь общего родителя
 | ||||
|     model.setParent(&result.root);  | ||||
| 
 | ||||
|     tinyobj::attrib_t attrib; | ||||
|     std::vector<tinyobj::shape_t> shapes; | ||||
|     std::vector<tinyobj::material_t> materials; | ||||
| 
 | ||||
|     std::string err; | ||||
| 
 | ||||
|     // Если в процессе загрузки возникли ошибки - выдадим исключение
 | ||||
|     if (!tinyobj::LoadObj(&attrib, &shapes, &materials, &err, filename, mtl_directory)) | ||||
|         throw std::runtime_error(err); | ||||
|   | ||||
|     std::vector<GLuint>    indices;  // индексы модели
 | ||||
|     std::vector<glm::vec3> verteces; // вершины
 | ||||
|     std::vector<glm::vec3> normals; // нормали
 | ||||
|     std::vector<glm::vec2> texCords; // текстурные координаты
 | ||||
|     size_t hash; // Для уникальных вершин
 | ||||
|     std::map <int, int> uniqueVerteces; // словарь для уникальных вершин: ключ - хеш, значение - индекс вершины
 | ||||
|      | ||||
|     int last_material_index = 0; // индекс последнего материала (для группировки моделей)
 | ||||
|     int count = 0, offset; // для индексов начала и конца в индексном буфере
 | ||||
|     std::vector<int> materials_range; // хранилище индексов
 | ||||
|     std::vector<int> materials_ids; // индексы материалов
 | ||||
| 
 | ||||
|     materials_range.push_back(count); // Закидываем начало отрезка в индексном буфере
 | ||||
|     // Цикл по считанным моделям
 | ||||
|     for (const auto& shape : shapes)  | ||||
|     { | ||||
|         offset = count;  // Переменная для 
 | ||||
|         last_material_index = shape.mesh.material_ids[(count - offset)/3]; // Запоминаем индекс материала
 | ||||
| 
 | ||||
|         // Цикл по индексам модели
 | ||||
|         for (const auto& index : shape.mesh.indices)  | ||||
|         { | ||||
|             hash = 0; | ||||
|             hash_combine( hash | ||||
|                         , attrib.vertices[3 * index.vertex_index + 0], attrib.vertices[3 * index.vertex_index + 1], attrib.vertices[3 * index.vertex_index + 2] | ||||
|                         , attrib.normals[3 * index.normal_index + 0], attrib.normals[3 * index.normal_index + 1], attrib.normals[3 * index.normal_index + 2] | ||||
|                         , attrib.texcoords[2 * index.texcoord_index + 0], attrib.texcoords[2 * index.texcoord_index + 1]); | ||||
|          | ||||
|             if (!uniqueVerteces.count(hash)) | ||||
|             { | ||||
|                 uniqueVerteces[hash] = verteces.size(); | ||||
|                  | ||||
|                 // группируем вершины в массив на основании индексов
 | ||||
|                 verteces.push_back({  attrib.vertices[3 * index.vertex_index + 0] | ||||
|                                                 , attrib.vertices[3 * index.vertex_index + 1] | ||||
|                                                 , attrib.vertices[3 * index.vertex_index + 2] | ||||
|                                             }); | ||||
|                 // группируем нормали в массив на основании индексов
 | ||||
|                 normals.push_back({  attrib.normals[3 * index.normal_index + 0] | ||||
|                                                 , attrib.normals[3 * index.normal_index + 1] | ||||
|                                                 , attrib.normals[3 * index.normal_index + 2] | ||||
|                                             }); | ||||
|                 // группируем текстурные координаты в массив на основании индексов
 | ||||
|                 texCords.push_back({  attrib.texcoords[2 * index.texcoord_index + 0] | ||||
|                                                 , 1-attrib.texcoords[2 * index.texcoord_index + 1] | ||||
|                                             }); | ||||
|             } | ||||
|             // Сохраняем индекс в массив
 | ||||
|             indices.push_back(uniqueVerteces[hash]); | ||||
|              | ||||
|             // Если индекс последнего материала изменился, то необходимо сохранить его
 | ||||
|             if (last_material_index != shape.mesh.material_ids[(count - offset)/3]) | ||||
|             { | ||||
|                 materials_range.push_back(count); // как конец отрезка
 | ||||
|                 materials_ids.push_back(last_material_index); // как используемый материал
 | ||||
|                 last_material_index = shape.mesh.material_ids[(count - offset)/3]; | ||||
|             } | ||||
|             count++;  | ||||
|         } // for (const auto& index : shape.mesh.indices) 
 | ||||
|          | ||||
|         // Если последний материал не загружен - загружаем его
 | ||||
|         if (materials_range[materials_range.size()-1] != count-1) | ||||
|         { | ||||
|             materials_range.push_back(count); // последний конец отрезка
 | ||||
|             materials_ids.push_back(last_material_index); // последний используемый материал
 | ||||
|         } | ||||
|     } // for (const auto& shape : shapes) 
 | ||||
| 
 | ||||
|      | ||||
| 
 | ||||
|     // Загрузка в буферы
 | ||||
|     model.load_verteces (&verteces[0], verteces.size()); | ||||
|     model.load_normals  (&normals[0],  normals.size()); | ||||
|     model.load_texCoords(&texCords[0], texCords.size()); | ||||
|     // Загрузка индексного буфера
 | ||||
|     model.load_indices  (&indices[0],  indices.size()); | ||||
| 
 | ||||
| 
 | ||||
|     // Создаем копии модели, которые будут рендериться в заданном диапазоне
 | ||||
|     // И присваиваем текстуры копиям на основании материала
 | ||||
|     for (int i = 0; i < materials_range.size()-1; i++) | ||||
|     { | ||||
|         result.models.push_back(model); // Создание копии с общим VAO
 | ||||
|         auto s = --result.models.end(); | ||||
|         s->set_index_range(materials_range[i]*sizeof(GLuint), materials_range[i+1]-materials_range[i]); | ||||
| 
 | ||||
|         // Текстуры
 | ||||
|         Texture diffuse(TEX_DIFFUSE, texture_directory + materials[materials_ids[i]].diffuse_texname); | ||||
|         s->set_texture(diffuse); | ||||
|         Texture ambient(TEX_AMBIENT, texture_directory + materials[materials_ids[i]].ambient_texname); | ||||
|         s->set_texture(ambient); | ||||
|         Texture specular(TEX_SPECULAR, texture_directory + materials[materials_ids[i]].specular_texname); | ||||
|         s->set_texture(specular); | ||||
| 
 | ||||
|         // Материал
 | ||||
|         s->material.ka = glm::vec3(materials[materials_ids[i]].ambient[0],  materials[materials_ids[i]].ambient[1],  materials[materials_ids[i]].ambient[2]); | ||||
|         s->material.kd = glm::vec3(materials[materials_ids[i]].diffuse[0],  materials[materials_ids[i]].diffuse[1],  materials[materials_ids[i]].diffuse[2]); | ||||
|         s->material.ks = glm::vec3(materials[materials_ids[i]].specular[0], materials[materials_ids[i]].specular[1], materials[materials_ids[i]].specular[2]); | ||||
|         s->material.p  = (materials[materials_ids[i]].shininess > 0.0f) ? 1000.0f / materials[materials_ids[i]].shininess : 1000.0f; | ||||
|     }     | ||||
| 
 | ||||
|     return result; | ||||
| } | ||||
							
								
								
									
										154
									
								
								src/Shader.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								src/Shader.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,154 @@ | ||||
| #include "Shader.h" | ||||
| 
 | ||||
| #include <iostream> | ||||
| #include <fstream> | ||||
| #include <sstream> | ||||
| 
 | ||||
| std::map<int, int> ShaderProgram::handler_count; // Получение количества использований по дескриптору ШП (Shared pointer)
 | ||||
| 
 | ||||
| ShaderProgram::ShaderProgram() | ||||
| { | ||||
|     program = glCreateProgram(); | ||||
|     handler_count[program] = 1; | ||||
| } | ||||
| 
 | ||||
| ShaderProgram::ShaderProgram(const ShaderProgram ©) : program(copy.program) | ||||
| { | ||||
|     handler_count[program]++; | ||||
| } | ||||
| 
 | ||||
| ShaderProgram::~ShaderProgram() | ||||
| { | ||||
|     if (!--handler_count[program]) // Если количество ссылок = 0
 | ||||
|     { | ||||
|         // Удаление шейдерной программы
 | ||||
|         glDeleteProgram(program); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| // Оператор присваивания
 | ||||
| ShaderProgram& ShaderProgram::operator=(const ShaderProgram& other) | ||||
| { | ||||
|     // Если это разные шейдерные программы
 | ||||
|     if (program != other.program) | ||||
|     { | ||||
|         this->~ShaderProgram(); // Уничтожаем имеющуюся
 | ||||
|         // Заменяем новой
 | ||||
|         program = other.program; | ||||
|         handler_count[program]++; | ||||
|     } | ||||
|     return *this; | ||||
| } | ||||
| 
 | ||||
| // Использование шейдеров
 | ||||
| void ShaderProgram::use() | ||||
| { | ||||
|     glUseProgram(program); | ||||
| } | ||||
| 
 | ||||
| // Функция чтения шейдера из файла
 | ||||
| std::string readFile(const char* filename) | ||||
| { | ||||
|     std::string text; | ||||
| 	std::ifstream file(filename, std::ios::in); // Открываем файл на чтение
 | ||||
| 	// Если файл доступен и успешно открыт
 | ||||
|     if (file.is_open())  | ||||
|     {  | ||||
| 		std::stringstream sstr; // Буфер для чтения
 | ||||
| 		sstr << file.rdbuf(); // Считываем файл
 | ||||
| 		text = sstr.str(); // Преобразуем буфер к строке
 | ||||
| 		file.close(); // Закрываем файл
 | ||||
| 	} | ||||
| 
 | ||||
|     return text; | ||||
| } | ||||
| 
 | ||||
| // Функция для загрузки шейдеров
 | ||||
| void ShaderProgram::load(GLuint type, const char* filename) | ||||
| { | ||||
|     // Создание дескрипторов шейдера
 | ||||
|     GLuint handler = glCreateShader(type); | ||||
| 
 | ||||
|     // Переменные под результат компиляции
 | ||||
|     GLint result = GL_FALSE; | ||||
|     int infoLogLength; | ||||
| 
 | ||||
|     // Считываем текст вершинного шейдера
 | ||||
|     std::string code = readFile(filename); | ||||
|     const char* pointer = code.c_str(); // Преобразование к указателю на const char, так как функция принимает массив си-строк
 | ||||
| 
 | ||||
|     // Компиляция кода вершинного шейдера
 | ||||
|     glShaderSource(handler, 1, &pointer, NULL); | ||||
|     glCompileShader(handler); | ||||
| 
 | ||||
|     // Проверка результата компиляции
 | ||||
|     glGetShaderiv(handler, GL_COMPILE_STATUS, &result); | ||||
|     glGetShaderiv(handler, GL_INFO_LOG_LENGTH, &infoLogLength); | ||||
|     if (infoLogLength > 0) | ||||
|     { | ||||
|         char* errorMessage = new char[infoLogLength + 1]; | ||||
|         glGetShaderInfoLog(handler, infoLogLength, NULL, errorMessage); | ||||
|         std::cout << errorMessage; | ||||
|         delete errorMessage; | ||||
|     } | ||||
| 
 | ||||
|     // Привязка скомпилированного шейдера
 | ||||
|     glAttachShader(program, handler); | ||||
|      | ||||
|     // Освобождение дескриптора шейдера
 | ||||
|     glDeleteShader(handler); | ||||
| } | ||||
| 
 | ||||
| // Формирование программы из загруженных шейдеров
 | ||||
| void ShaderProgram::link() | ||||
| { | ||||
|     // Переменные под результат компиляции
 | ||||
|     GLint result = GL_FALSE; | ||||
|     int infoLogLength; | ||||
| 
 | ||||
|     // Формирование программы из привязанных шейдеров
 | ||||
|     glLinkProgram(program); | ||||
| 
 | ||||
|     // Проверка программы
 | ||||
|     glGetProgramiv(program, GL_LINK_STATUS, &result); | ||||
|     glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLogLength); | ||||
|     if (infoLogLength > 0) | ||||
|     { | ||||
|         char* errorMessage = new char[infoLogLength + 1]; | ||||
|         glGetProgramInfoLog(program, infoLogLength, NULL, errorMessage); | ||||
|         std::cout << errorMessage; | ||||
|         delete errorMessage; | ||||
|     } | ||||
| 
 | ||||
|     // Используем шейдерную программу объекта из которого вызван метод
 | ||||
|     this->use();  | ||||
| } | ||||
| 
 | ||||
| // Возвращает местоположение uniform-переменной
 | ||||
| GLuint ShaderProgram::getUniformLoc(const char* name)  | ||||
| { | ||||
|     GLuint result; // Результат
 | ||||
|     // Если такую переменную ещё не искали - найдем, иначе вернем уже известный дескриптор
 | ||||
|     if (!uniformLocations.count(name)) | ||||
|         uniformLocations[name] = result = glGetUniformLocation(program, name); | ||||
|     else | ||||
|         result = uniformLocations[name]; | ||||
| 
 | ||||
|     return result; | ||||
| } | ||||
| 
 | ||||
| // Привязка uniform-блока
 | ||||
| void ShaderProgram::bindUniformBlock(const char* name, int binding)  | ||||
| { | ||||
|     glUniformBlockBinding( program | ||||
|                          , glGetUniformBlockIndex(program, name) | ||||
|                          , binding); | ||||
| } | ||||
| 
 | ||||
| // Инициализация текстур на шейдере
 | ||||
| void ShaderProgram::bindTextures(const char* textures_base_shader_names[], int count) | ||||
| { | ||||
|     // Цикл по всем доступным текстурам
 | ||||
|     for (int i = 0; i < count; i++) | ||||
|         glUniform1i(getUniformLoc(textures_base_shader_names[i]), i); | ||||
| } | ||||
							
								
								
									
										142
									
								
								src/Texture.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										142
									
								
								src/Texture.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,142 @@ | ||||
| #include "Texture.h" | ||||
| 
 | ||||
| #define STB_IMAGE_IMPLEMENTATION | ||||
| #include <stb_image.h> | ||||
| 
 | ||||
| std::map<std::string, int> Texture::filename_handler; // Получение дескриптора текстуры по её имени
 | ||||
| std::map<int, int> Texture::handler_count; // Получение количества использований по дескриптору текстуры (Shared pointer)
 | ||||
| 
 | ||||
| // Загрузка текстуры с диска или использование "пустой"
 | ||||
| Texture::Texture(GLuint t, const std::string& filename) : type(t) | ||||
| { | ||||
|     if (!filename_handler.count(filename)) | ||||
|     { | ||||
|         std::string empty = ""; | ||||
|         int width, height, channels; // Ширина, высота и цветовые каналы текстуры
 | ||||
|         unsigned char* image = stbi_load(filename.c_str(), &width, &height, &channels, STBI_default); // Загрузка в оперативную память изображения
 | ||||
|         // Если изображение успешно счиитано с диска или отсутствует пустая текстура
 | ||||
|         if (image || !filename_handler.count(empty)) | ||||
|         { | ||||
|             glActiveTexture(type + GL_TEXTURE0); | ||||
|             glGenTextures(1, &handler); // Генерация одной текстуры
 | ||||
|             glBindTexture(GL_TEXTURE_2D, handler); // Привязка текстуры как активной
 | ||||
| 
 | ||||
|             filename_handler[filename] = handler; // Запоминим её дескриптор для этого имени файла
 | ||||
|             handler_count[handler] = 0; // Создадим счетчик использований дескриптора, который будет изменен в конце
 | ||||
| 
 | ||||
|             // Если изображение успешно считано
 | ||||
|             if (image) | ||||
|             { | ||||
|                 // Загрузка данных с учетом прозрачности
 | ||||
|                 if (channels == 3) // RGB
 | ||||
|                     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image); | ||||
|                 else if (channels == 4) // RGBA
 | ||||
|                     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image); | ||||
| 
 | ||||
|                 glGenerateMipmap(GL_TEXTURE_2D); // Генерация мипмапа для активной текстуры
 | ||||
|                 glBindTexture(GL_TEXTURE_2D, 0); // Отвязка активной текстуры
 | ||||
|                  | ||||
|                 stbi_image_free(image); // Освобождение оперативной памяти
 | ||||
|             } | ||||
|             // Иначе изображение не считано и надо создать пустую текстуру
 | ||||
|             else | ||||
|             { | ||||
|                 image = new unsigned char[3] {255,255,255}; // RGB по 1 байту на 
 | ||||
|                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, image); // Загрузка данных на видеокарту
 | ||||
|                 delete image; // Освобождение оперативной памяти
 | ||||
|                  | ||||
|                 filename_handler[empty] = handler; // Запоминим дополнительно её дескриптор для NULL-строки
 | ||||
|             } | ||||
|         } | ||||
|         // Иначе используем существующую пустую текстуру (текстура не загружена, пустую создавать не нужно)
 | ||||
|         else | ||||
|             handler = filename_handler[empty]; | ||||
|     } | ||||
|     // Иначе используем уже существующую по имени файла
 | ||||
|     else | ||||
|         handler = filename_handler[filename]; | ||||
|          | ||||
|     handler_count[handler]++; | ||||
| } | ||||
| 
 | ||||
| // Конструктор текстуры заданного размера для использования в буфере
 | ||||
| Texture::Texture(GLuint width, GLuint height, GLuint attachment, GLuint texType, GLint internalformat, GLint format, GLenum dataType) : type(texType) | ||||
| { | ||||
|     // Генерация текстуры заданного размера
 | ||||
|     glGenTextures(1, &handler); | ||||
|     glBindTexture(GL_TEXTURE_2D, handler); | ||||
|     glTexImage2D(GL_TEXTURE_2D, 0, internalformat, width, height, 0, format, dataType, NULL); | ||||
|     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | ||||
|     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | ||||
| 
 | ||||
|     // Привязка к буферу кадра
 | ||||
|     glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, handler, 0); | ||||
| 
 | ||||
|     // Создаем счетчик использований дескриптора
 | ||||
|     handler_count[handler] = 1; | ||||
| } | ||||
| 
 | ||||
| // Конструктор копирования
 | ||||
| Texture::Texture(const Texture& other) : handler(other.handler), type(other.type) | ||||
| { | ||||
|     // Делаем копию и увеличиваем счетчик
 | ||||
|     handler_count[handler]++; | ||||
| } | ||||
| 
 | ||||
| // Оператор присваивания
 | ||||
| Texture& Texture::operator=(const Texture& other) | ||||
| { | ||||
|     // Если это разные текстуры
 | ||||
|     if (handler != other.handler) | ||||
|     { | ||||
|         this->~Texture(); // Уничтожаем имеющуюся
 | ||||
|         // Заменяем новой
 | ||||
|         handler = other.handler; | ||||
|         handler_count[handler]++; | ||||
|     } | ||||
|     type = other.type; | ||||
| 
 | ||||
|     return *this; | ||||
| } | ||||
| 
 | ||||
| Texture::~Texture() | ||||
| { | ||||
|     if (!--handler_count[handler]) // Если количество ссылок = 0
 | ||||
|     { | ||||
|         glDeleteTextures(1, &handler); // Удаление текстуры
 | ||||
|         // Удаление из словаря имен файлов и дескрипторов
 | ||||
|         for (auto it = filename_handler.begin(); it != filename_handler.end();) | ||||
|         { | ||||
|             if (it->second == handler)  | ||||
|                 it = filename_handler.erase(it); | ||||
|             else | ||||
|                 it++; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| // Привязка текстуры
 | ||||
| void Texture::use() | ||||
| { | ||||
|     glActiveTexture(type + GL_TEXTURE0); | ||||
|     glBindTexture(GL_TEXTURE_2D, handler); // Привязка текстуры как активной
 | ||||
| } | ||||
| 
 | ||||
| // Отвязка текстуры по типу
 | ||||
| void Texture::disable(GLuint type) | ||||
| { | ||||
|     glActiveTexture(type + GL_TEXTURE0); | ||||
|     glBindTexture(GL_TEXTURE_2D, 0); // Отвязка текстуры
 | ||||
| } | ||||
| 
 | ||||
| // Возвращает тип текстуры
 | ||||
| GLuint Texture::getType() | ||||
| { | ||||
|     return type; | ||||
| } | ||||
| 
 | ||||
| // Задает тип текстуры
 | ||||
| void Texture::setType(GLuint type) | ||||
| { | ||||
|     this->type = type; | ||||
| } | ||||
							
								
								
									
										215
									
								
								src/main.cpp
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										215
									
								
								src/main.cpp
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,215 @@ | ||||
| 
 | ||||
| #include <glad/glad.h> | ||||
| #include <GLFW/glfw3.h> | ||||
| #include <GLM/glm.hpp> | ||||
| 
 | ||||
| #include <iostream> | ||||
| 
 | ||||
| #include "Scene.h" | ||||
| #include "Shader.h" | ||||
| #include "Lights.h" | ||||
| 
 | ||||
| #define WINDOW_WIDTH 800 | ||||
| #define WINDOW_HEIGHT 600 | ||||
| #define WINDOW_CAPTION "OPENGL notes on rekovalev.site" | ||||
| 
 | ||||
| // Функция-callback для изменения размеров буфера кадра в случае изменения размеров поверхности окна
 | ||||
| void framebuffer_size_callback(GLFWwindow* window, int width, int height) | ||||
| { | ||||
|     glViewport(0, 0, width, height); | ||||
| } | ||||
|   | ||||
| 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
 | ||||
| 
 | ||||
|     // Инициализация GLFW3
 | ||||
|     if (!glfwInit()) | ||||
|     { | ||||
|         std::cout << "GLFW init error\n"; | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     // Завершение работы с GLFW3 перед выходом
 | ||||
|     atexit(glfwTerminate); | ||||
| 
 | ||||
|     glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); // Мажорная версия спецификаций OpenGL
 | ||||
|     glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6); // Минорная версия спецификаций OpenGL
 | ||||
|     glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // Контекст OpenGL, который поддерживает только основные функции
 | ||||
|   | ||||
|     // Создание окна GLFW3 с заданными шириной, высотой и заголовком окна
 | ||||
|     window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_CAPTION, NULL, NULL); | ||||
|     if (!window) | ||||
|     { | ||||
|         std::cout << "GLFW create window error\n"; | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     // Установка основного контекста окна
 | ||||
|     glfwMakeContextCurrent(window); | ||||
|     // Установка callback-функции для изменения размеров окна и буфера кадра
 | ||||
|     glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); | ||||
|      | ||||
|     glfwSwapInterval(1); // Вертикальная синхронизация
 | ||||
| 
 | ||||
|     // Установка callback-функции для мыши и камеры
 | ||||
|     glfwSetCursorPosCallback(window, mouse_callback); | ||||
| 
 | ||||
|     // Загрузка функций OpenGL с помощью GLAD
 | ||||
|     if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) | ||||
|     { | ||||
|         std::cout << "GLAD load GL error\n"; | ||||
|         return -1; | ||||
|     } | ||||
| 
 | ||||
|     // Включаем проверку по буферу глубины
 | ||||
|     glEnable(GL_DEPTH_TEST); | ||||
| 
 | ||||
|     // Шейдер для G-буфера
 | ||||
|     ShaderProgram gShader; | ||||
|     // Загрузка и компиляция шейдеров
 | ||||
|     gShader.load(GL_VERTEX_SHADER, "shaders/gshader.vert"); | ||||
|     gShader.load(GL_FRAGMENT_SHADER, "shaders/gshader.frag"); | ||||
|     gShader.link(); | ||||
|     // Установим значения текстур
 | ||||
|     const char* textures_base_shader_names[] = {"tex_diffuse", "tex_ambient", "tex_specular"}; | ||||
|     gShader.bindTextures(textures_base_shader_names, sizeof(textures_base_shader_names)/sizeof(const char*)); | ||||
| 
 | ||||
|     // Загрузка сцены из obj файла
 | ||||
|     Scene scene = loadOBJtoScene("../resources/models/blob.obj", "../resources/models/", "../resources/textures/");  | ||||
|     scene.root.e_scale() = glm::vec3(0.01); | ||||
|     scene.root.e_position().z = 1; | ||||
|     scene.models.begin()->material.kd = {0.5,0.5,0.5}; | ||||
|     scene.models.begin()->material.ka = {0.2,0.2,0.2}; | ||||
|      | ||||
|     // Установка цвета очистки буфера цвета
 | ||||
|     glClearColor(0.0f, 0.0f, 0.0f, 1.0f); | ||||
| 
 | ||||
|     // Источники света
 | ||||
|     Light& first = Light::getNew(); | ||||
|     first.e_color() = {1.0f, 0.0f, 0.0f}; // цвет
 | ||||
|     first.e_position() = {0.3f, 0.1f, 0.5f}; // Позиция
 | ||||
|     Light& second = Light::getNew(); | ||||
|     second.e_color() = {0.0f, 0.0f, 1.0f}; // цвет
 | ||||
|     second.e_position() = {-0.3f, -0.1f, 0.5f}; // Позиция
 | ||||
| 
 | ||||
|     // Uniform-буферы
 | ||||
|     UBO cameraUB(sizeof(CameraData), 0); | ||||
|     UBO material_data(sizeof(Material), 1); | ||||
|     UBO light_data(Light::getUBOsize(), 2); | ||||
| 
 | ||||
|     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); // Использование уменьшенных версий mipmap  
 | ||||
| 
 | ||||
|     // Создадим G-буфер с данными о используемых привязках
 | ||||
|     GLuint attachments[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3 }; | ||||
|     FBO gbuffer(attachments, sizeof(attachments) / sizeof(GLuint)); | ||||
|     // Создадим текстуры для буфера кадра
 | ||||
|     Texture gPosition(WINDOW_WIDTH, WINDOW_HEIGHT, GL_COLOR_ATTACHMENT0, 0, GL_RGB32F, GL_RGB); // Позиция вершины
 | ||||
|     Texture gNormal(WINDOW_WIDTH, WINDOW_HEIGHT, GL_COLOR_ATTACHMENT1, 1, GL_RGB16F, GL_RGB); // Нормали
 | ||||
|     Texture gDiffuseP(WINDOW_WIDTH, WINDOW_HEIGHT, GL_COLOR_ATTACHMENT2, 2, GL_RGBA16F); // Диффузная составляющая и коэф. глянцевости
 | ||||
|     Texture gAmbientSpecular(WINDOW_WIDTH, WINDOW_HEIGHT, GL_COLOR_ATTACHMENT3, 3); // Фоновая составляющая и один канал зеркальной
 | ||||
|     // Создадим буфер рендера под буфер глубины и привяжем его
 | ||||
|     RBO grbo(WINDOW_WIDTH, WINDOW_HEIGHT); | ||||
|     gbuffer.assignRenderBuffer(grbo.getHandler()); | ||||
|     // Активируем базовый буфер кадра
 | ||||
|     FBO::useDefault(); | ||||
| 
 | ||||
|     // Шейдер для расчета освещенности
 | ||||
|     ShaderProgram lightShader; | ||||
|     // Загрузка и компиляция шейдеров
 | ||||
|     lightShader.load(GL_VERTEX_SHADER, "shaders/quad.vert"); | ||||
|     lightShader.load(GL_FRAGMENT_SHADER, "shaders/lighting.frag"); | ||||
|     lightShader.link(); | ||||
|     const char* gtextures_shader_names[]  = {"gPosition", "gNormal", "gDiffuseP", "gAmbientSpecular"}; | ||||
|     lightShader.bindTextures(gtextures_shader_names, sizeof(gtextures_shader_names)/sizeof(const char*)); | ||||
| 
 | ||||
|     glm::vec3 quadVertices[] = { {-1.0f,  1.0f, 0.0f} | ||||
|                                , {-1.0f, -1.0f, 0.0f} | ||||
|                                , { 1.0f,  1.0f, 0.0f} | ||||
|                                , { 1.0f, -1.0f, 0.0f} | ||||
|                                }; | ||||
| 
 | ||||
|     GLuint quadIndices[] = {0,1,2,2,1,3}; | ||||
| 
 | ||||
|     Model quadModel; | ||||
|     quadModel.load_verteces(quadVertices, 4); | ||||
|     quadModel.load_indices(quadIndices, 6); | ||||
| 
 | ||||
|     // Шейдер для рисования отладочных лампочек
 | ||||
|     ShaderProgram bulbShader; | ||||
|     // Загрузка и компиляция шейдеров
 | ||||
|     bulbShader.load(GL_VERTEX_SHADER, "shaders/bulb.vert"); | ||||
|     bulbShader.load(GL_FRAGMENT_SHADER, "shaders/bulb.frag"); | ||||
|     bulbShader.link(); | ||||
|      | ||||
|     // Пока не произойдет событие запроса закрытия окна
 | ||||
|     while(!glfwWindowShouldClose(window)) | ||||
|     { | ||||
|         // Загрузка данных о камере
 | ||||
|         cameraUB.loadSub(&Camera::current().getData(), sizeof(CameraData)); | ||||
|         // Загрузим информацию об источниках света
 | ||||
|         Light::upload(light_data); | ||||
| 
 | ||||
|         // Активируем G-кадра
 | ||||
|         gbuffer.use(); | ||||
|         // Используем шейдер с освещением
 | ||||
|         gShader.use(); | ||||
|         // Очистка буфера цвета и глубины
 | ||||
|         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | ||||
| 
 | ||||
|         // Тут производится рендер
 | ||||
|         scene.render(gShader, material_data); | ||||
| 
 | ||||
|         // Активируем базовый буфер кадра
 | ||||
|         FBO::useDefault(); | ||||
|         // Подключаем шейдер для прямоугольника
 | ||||
|         lightShader.use(); | ||||
|         // Очистка буфера цвета и глубины
 | ||||
|         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | ||||
|         // Подключаем текстуры G-буфера
 | ||||
|         gPosition.use(); | ||||
|         gNormal.use(); | ||||
|         gDiffuseP.use(); | ||||
|         gAmbientSpecular.use(); | ||||
|         // Рендерим прямоугольник с расчетом освещения
 | ||||
|         quadModel.render(); | ||||
| 
 | ||||
|         // Перенос буфера глубины
 | ||||
|         FBO::useDefault(GL_DRAW_FRAMEBUFFER); // Базовый в режиме записи
 | ||||
|         gbuffer.use(GL_READ_FRAMEBUFFER); // Буфер геометрии в режиме чтения
 | ||||
|         // Копирование значений глубины 
 | ||||
|         glBlitFramebuffer(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, GL_DEPTH_BUFFER_BIT, GL_NEAREST); | ||||
|         FBO::useDefault(); // Использование базового буфера для дальнейших работ
 | ||||
| 
 | ||||
|         // Отрисовка отладочных лампочек со специальным шейдером
 | ||||
|         bulbShader.use(); | ||||
|         Light::render(bulbShader, material_data); | ||||
| 
 | ||||
|         // Представление содержимого буфера цепочки показа на окно
 | ||||
|         glfwSwapBuffers(window); | ||||
|         // Обработка системных событий
 | ||||
|         glfwPollEvents(); | ||||
|     } | ||||
| 
 | ||||
|     // Отключение атрибутов
 | ||||
|     glDisableVertexAttribArray(0); | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user