Копия с 17
This commit is contained in:
		
							parent
							
								
									4d833f85d9
								
							
						
					
					
						commit
						e1287a4ef1
					
				
							
								
								
									
										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 = 0, int count = 0); // Создает буфер кадра с нужным числом прикреплений текстур
 | ||||||
|  |         ~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
 | ||||||
							
								
								
									
										82
									
								
								include/Camera.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								include/Camera.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,82 @@ | |||||||
|  | #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 | ||||||
|  | // Количество каскадов для карт теней
 | ||||||
|  | #define CAMERA_CASCADE_COUNT 4 | ||||||
|  | 
 | ||||||
|  | // Данные о дистанциях каскадов 
 | ||||||
|  | extern const float camera_cascade_distances[]; // src/Camera.cpp
 | ||||||
|  | 
 | ||||||
|  | // Данные о камере для шейдера
 | ||||||
|  | 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(); // Данные о камере для шейдера
 | ||||||
|  |         std::pair<bool, const glm::vec4(*)[8]> getProjCoords(); // Доступ к координатам с флагом изменения, описывающим пространство вида с пересчетом, если это требуется
 | ||||||
|  |     protected: | ||||||
|  |         Camera(const glm::vec3 &position, const glm::vec3 &initialRotation); // Защищенный (protected) конструктор камеры без перспективы 
 | ||||||
|  | 
 | ||||||
|  |         glm::mat4 view; // Матрица вида
 | ||||||
|  |         glm::mat4 projection; // Матрица проекции
 | ||||||
|  |         glm::mat4 vp; // Матрица произведения вида и проекции
 | ||||||
|  |         bool requiredRecalcVP; // Необходимость пересчета матрицы вида и проекции камеры
 | ||||||
|  |         bool requiredRecalcCoords; // Необходимость пересчета точек, описывающих пространство камеры
 | ||||||
|  |         glm::vec4 coords[CAMERA_CASCADE_COUNT][8]; // Координаты, описывающие пространство камеры
 | ||||||
|  |         glm::mat4 cascade_proj[CAMERA_CASCADE_COUNT]; // Матрицы проекций каскадов
 | ||||||
|  | 
 | ||||||
|  |         float sensitivity; // Чувствительность мыши
 | ||||||
|  |          | ||||||
|  |         virtual void recalcMatrices(); // Метод пересчета матрицы вида и произведения Вида*Проекции по необходимости, должен сбрасывать флаг changed
 | ||||||
|  | 
 | ||||||
|  |         static Camera* p_current; // Указатель на текущую используемую камеру
 | ||||||
|  | };       | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | #endif // CAMERA_H
 | ||||||
							
								
								
									
										108
									
								
								include/Lights.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								include/Lights.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,108 @@ | |||||||
|  | #ifndef LIGHTS_H | ||||||
|  | #define LIGHTS_H | ||||||
|  | 
 | ||||||
|  | #include <GLM/glm.hpp> | ||||||
|  | 
 | ||||||
|  | #include "Model.h" | ||||||
|  | #include "Camera.h" | ||||||
|  | 
 | ||||||
|  | // Максимальное число источников света
 | ||||||
|  | #define MAX_LIGHTS 64 | ||||||
|  | // Стандартное направление источника без поворота
 | ||||||
|  | #define DEFAULT_LIGHT_DIRECTION glm::vec4(0.0f, 0.0f, 1.0f, 0.0f) | ||||||
|  | // Максимальное число образцов для SSAO
 | ||||||
|  | #define MAX_SSAO 64 | ||||||
|  | 
 | ||||||
|  | // Точечный источник света
 | ||||||
|  | struct LightData  | ||||||
|  | { | ||||||
|  |     alignas(16) glm::vec3 position; // Позиция
 | ||||||
|  |     alignas(16) glm::vec3 color; // Цвет 
 | ||||||
|  |     alignas(16) glm::vec3 attenuation; // Радиус действия источника, линейный и квадратичный коэф. угасания   
 | ||||||
|  |     alignas(16) glm::vec4 direction_angle; // Направление и половинный угол освещенности
 | ||||||
|  |     alignas(16) glm::mat4 vp[6]; // Матрицы проекции и трансформации в пространство источника
 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | // Источник света
 | ||||||
|  | class Light : public Node | ||||||
|  | { | ||||||
|  |     public: | ||||||
|  |         static int getUBOsize(); // Возвращает размер буфера в байтах
 | ||||||
|  |         static void upload(UBO& lights_data); // Загрузка данных в буфер
 | ||||||
|  | 
 | ||||||
|  |         static Light& getNew(); // Возвращает ссылку на новый источник света
 | ||||||
|  |         void destroy(); // Уничтожает источник света
 | ||||||
|  | 
 | ||||||
|  |         static int getCount(); // Возвращает количество источников
 | ||||||
|  |         const glm::vec3& c_color() const; // Константный доступ к цвету
 | ||||||
|  |         glm::vec3& e_color(); // Неконстантная ссылка для изменений цвета
 | ||||||
|  | 
 | ||||||
|  |         const float& c_radius() const; // Константный доступ к радиусу
 | ||||||
|  |         float& e_radius(); // Неконстантная ссылка для изменений радиуса
 | ||||||
|  | 
 | ||||||
|  |         const float& c_angle() const; // Константный доступ к углу освещенности
 | ||||||
|  |         float& e_angle(); // Неконстантная ссылка для изменений угла освещенности
 | ||||||
|  | 
 | ||||||
|  |         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; // Радиус действия источника
 | ||||||
|  |         float angle; // Угол полный освещенности 
 | ||||||
|  | 
 | ||||||
|  |         int index; // Индекс в массиве отправки (может не совпадать с lights) для дефрагментированного доступа
 | ||||||
|  |         static Light& findByIndex(GLuint index); // Возвращает ссылку на источник с нужным индексом
 | ||||||
|  | 
 | ||||||
|  |         bool uploadReq; // Необходимость загрузки в следствии изменений
 | ||||||
|  |         void check_id(); // Проверка что не взаимодествуем с пустым источником
 | ||||||
|  |         void toData(); // Преобразует информацию об источнике в структуру LightData
 | ||||||
|  | 
 | ||||||
|  |         virtual void recalcMatrices(); // Метод пересчета матрицы трансформации по необходимости, должен сбрасывать флаг changed
 | ||||||
|  |         void recalcVP(); // Пересчитывает по необходимости матрицу вида-проекции
 | ||||||
|  | 
 | ||||||
|  |         static GLuint count; // количество используемых источников (должно быть <= MAX_LIGHTS)
 | ||||||
|  |         static LightData data[MAX_LIGHTS]; // Массив данных по источникам света
 | ||||||
|  |         static Light lights[MAX_LIGHTS]; // Массив источников-узлов сцены
 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | // Класс направленного источника освещения
 | ||||||
|  | class Sun | ||||||
|  | { | ||||||
|  |     public: | ||||||
|  |         static Sun& get(); // Доступ к синглтону
 | ||||||
|  |         static void upload(UBO& sun_data); // Загрузка данных об источнике в буфер
 | ||||||
|  |          | ||||||
|  |         const glm::vec3& c_direction() const; // Константный доступ к направлению лучей источника
 | ||||||
|  |         glm::vec3& e_direction(); // Неконстантная ссылка для изменений направления лучей источника
 | ||||||
|  | 
 | ||||||
|  |         const glm::vec3& c_color() const; // Константный доступ к цвету
 | ||||||
|  |         glm::vec3& e_color(); // Неконстантная ссылка для изменений цвета
 | ||||||
|  | 
 | ||||||
|  |     private: | ||||||
|  |         Sun(const glm::vec3 &direction = glm::vec3(0.0f, 1.0f, 0.0f), const glm::vec3 &color = glm::vec3(0.4f, 0.4f, 0.4f)); | ||||||
|  |          | ||||||
|  |         alignas(16) glm::vec3 direction; // Направление лучей источника
 | ||||||
|  |         alignas(16) glm::vec3 color; // Цвет
 | ||||||
|  |         alignas(16) glm::mat4 vp[CAMERA_CASCADE_COUNT]; // Матрица вида-проекции источника
 | ||||||
|  | 
 | ||||||
|  |         void recalcVP(); // Пересчитывает по необходимости матрицу вида-проекции
 | ||||||
|  |          | ||||||
|  |         static Sun instance; // Экземпляр синглтона
 | ||||||
|  |         static bool uploadReq; // Необходимость загрузки в следствии изменений
 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | // Данные для SSAO
 | ||||||
|  | struct SSAO_data | ||||||
|  | { | ||||||
|  |     float radius = 0.05f; | ||||||
|  |     float bias = 0.025f; | ||||||
|  |     int size = MAX_SSAO; | ||||||
|  |     alignas(16) glm::vec2 scale; | ||||||
|  |     glm::vec3 samples[MAX_SSAO]; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | #endif // LIGHTS_H
 | ||||||
							
								
								
									
										118
									
								
								include/Model.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								include/Model.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,118 @@ | |||||||
|  | #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); // Генерирует сферу заданного радиуса с определенным количеством сегментов
 | ||||||
|  | 
 | ||||||
|  | void calc_tb(const GLuint* indices, const int indices_count, const glm::vec3* verteces, const glm::vec2* texCords, glm::vec3* tangent, glm::vec3* bitangent); // Расчет касательных и бикасательных векторов
 | ||||||
|  | 
 | ||||||
|  | // Класс узла сцены
 | ||||||
|  | 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; // показатель глянцевости
 | ||||||
|  |     int normalmapped; // Использование карт нормалей
 | ||||||
|  |     int parallaxmapped; // Использование параллакса
 | ||||||
|  |     int displacementmapped; // Использование карт высот для сдвига вершин
 | ||||||
|  |     // Значения по умолчанию
 | ||||||
|  |     Material() : ka(0.2f), kd(0.2f), ks(0.2f), p(1), normalmapped(false), parallaxmapped(false), displacementmapped(false) { }; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | // Идентификатор модели
 | ||||||
|  | struct ID | ||||||
|  | { | ||||||
|  |     GLuint64 value = 0; // Идентификатор
 | ||||||
|  |     GLuint etc = 0; // Дополнительная информация
 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | // Класс модели
 | ||||||
|  | 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 load_tangent(glm::vec3* tangent, GLuint count); // Загрузка касательных векторов в буфер
 | ||||||
|  |         void load_bitangent(glm::vec3* bitangent, GLuint count); // Загрузка бикасательных векторов в буфер
 | ||||||
|  |         void set_index_range(size_t first_byteOffset, size_t count); // Ограничение диапазона из буфера индексов
 | ||||||
|  |         void set_texture(Texture& texture); // Привязка текстуры к модели
 | ||||||
|  |          | ||||||
|  |         Material material; // Материал модели
 | ||||||
|  | 
 | ||||||
|  |         ID id; // ID модели
 | ||||||
|  |     private: | ||||||
|  |         VAO vao; | ||||||
|  |         BO vertex_vbo, index_vbo; // вершинный и индексный буферы
 | ||||||
|  |         BO normals_vbo, texCoords_vbo; // буферы с нормалями и текстурными координатами
 | ||||||
|  |         BO tangent_vbo, bitangent_vbo; // буферы с касательными и бикасательными векторами
 | ||||||
|  |         GLuint verteces_count; // Количество вершин
 | ||||||
|  |         size_t first_index_byteOffset, indices_count; // Сдвиг в байтах для первого и количество индексов
 | ||||||
|  |         Texture texture_diffuse; // Диффузная текстура
 | ||||||
|  |         Texture texture_ambient; // Текстура фонового освщения
 | ||||||
|  |         Texture texture_specular; // Текстура зеркального отражения
 | ||||||
|  |         Texture texture_heights; // Текстура высот
 | ||||||
|  |         Texture texture_normals; // Текстура нормалей
 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | #endif // MODEL_H
 | ||||||
							
								
								
									
										39
									
								
								include/Scene.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								include/Scene.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,39 @@ | |||||||
|  | #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); // Рендер сцены
 | ||||||
|  | 
 | ||||||
|  |         void set_group_id(GLuint64 id, GLuint etc = 0); // Изменение флага записи идентификатора для всех моделей
 | ||||||
|  | 
 | ||||||
|  |         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
 | ||||||
							
								
								
									
										45
									
								
								include/TRS.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								include/TRS.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,45 @@ | |||||||
|  | #ifndef TRS_H | ||||||
|  | #define TRS_H | ||||||
|  | 
 | ||||||
|  | #define T_SENSITIVITY 0.001f | ||||||
|  | #define R_SENSITIVITY 0.01f | ||||||
|  | #define S_SENSITIVITY 0.00001f | ||||||
|  | 
 | ||||||
|  | #include "Scene.h" | ||||||
|  | 
 | ||||||
|  | // Интерфейс инструмента
 | ||||||
|  | class TRS  | ||||||
|  | { | ||||||
|  |     public: | ||||||
|  |         void render(GLuint64 selectedID, ShaderProgram &shaderProgram, UBO &material_buffer); // Рендер инструмента нужного типа для выбранного объекта
 | ||||||
|  |         virtual void process(GLuint64 selectedID, GLuint etc, const glm::vec4& dpos) = 0; // Взаимодействие с инструментом
 | ||||||
|  |     protected: | ||||||
|  |         void init_etc(); // Инициализирует дополнительную информацию модели
 | ||||||
|  |         Scene tool; // Модель
 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | // Инструмент трансформации
 | ||||||
|  | class Transform : public TRS | ||||||
|  | { | ||||||
|  |     public:  | ||||||
|  |         Transform(); | ||||||
|  |         virtual void process(GLuint64 selectedID, GLuint etc, const glm::vec4& dpos); // Взаимодействие с инструментом
 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | // Инструмент поворота
 | ||||||
|  | class Rotate : public TRS | ||||||
|  | { | ||||||
|  |     public:  | ||||||
|  |         Rotate(); | ||||||
|  |         virtual void process(GLuint64 selectedID, GLuint etc, const glm::vec4& drot); // Взаимодействие с инструментом
 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | // Инструмент масштабирования
 | ||||||
|  | class Scale : public TRS | ||||||
|  | { | ||||||
|  |     public:  | ||||||
|  |         Scale(); | ||||||
|  |         virtual void process(GLuint64 selectedID, GLuint etc, const glm::vec4& dscale); // Взаимодействие с инструментом
 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | #endif // TRS_H
 | ||||||
							
								
								
									
										85
									
								
								include/Texture.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								include/Texture.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,85 @@ | |||||||
|  | #ifndef TEXTURE_H | ||||||
|  | #define TEXTURE_H | ||||||
|  | 
 | ||||||
|  | #include <glad/glad.h> | ||||||
|  | 
 | ||||||
|  | #include <map> | ||||||
|  | #include <string> | ||||||
|  | 
 | ||||||
|  | enum TexType { | ||||||
|  |     TEX_DIFFUSE, | ||||||
|  |     TEX_AMBIENT, | ||||||
|  |     TEX_SPECULAR, | ||||||
|  |     TEX_HEIGHTS, | ||||||
|  |     TEX_NORMAL, | ||||||
|  |     TEX_AVAILABLE_COUNT | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | // Абстрактный класс базовой текстуры
 | ||||||
|  | class BaseTexture | ||||||
|  | { | ||||||
|  |     public: | ||||||
|  |         ~BaseTexture(); | ||||||
|  |         virtual void use() = 0; // Привязка текстуры
 | ||||||
|  |         static void disable(GLuint type); // Отвязка текстуры по типу
 | ||||||
|  |         GLuint getType(); // Возвращает тип текстуры
 | ||||||
|  |         void setType(GLuint type); // Задает тип текстуры
 | ||||||
|  |     protected: | ||||||
|  |         GLuint handler; // Дескриптор текстуры
 | ||||||
|  |         GLuint type; // Тип текстуры, соответствует её слоту
 | ||||||
|  |         static std::map<std::string, int> filename_handler; // Получение дескриптора текстуры по её имени
 | ||||||
|  |         static std::map<int, int> handler_count; // Получение количества использований по дескриптору текстуры (Shared pointer)
 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | // Класс 2D текстуры
 | ||||||
|  | class Texture : public BaseTexture | ||||||
|  | { | ||||||
|  |     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(GLuint width, GLuint height, void* data, GLuint texType = TEX_DIFFUSE, GLint internalformat = GL_RGBA, GLint format = GL_RGBA, GLenum dataType = GL_FLOAT); // Конструктор текстуры заданного размера без привязки к буферу с загрузкой пикселей по указателю
 | ||||||
|  |         Texture(const Texture& other); // Конструктор копирования
 | ||||||
|  | 
 | ||||||
|  |         Texture& operator=(const Texture& other); // Оператор присваивания
 | ||||||
|  | 
 | ||||||
|  |         virtual void use(); // Привязка текстуры       
 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | // Класс 3D текстуры
 | ||||||
|  | class TextureArray : public BaseTexture | ||||||
|  | { | ||||||
|  |     public: | ||||||
|  |         TextureArray(GLuint levels, GLuint width, GLuint height, GLuint attachment, GLuint texType = TEX_DIFFUSE, GLint internalformat = GL_RGBA, GLint format = GL_RGBA, GLenum dataType = GL_FLOAT); // Конструктор текстуры заданного размера для использования в буфере
 | ||||||
|  |         TextureArray(const TextureArray& other); // Конструктор копирования
 | ||||||
|  | 
 | ||||||
|  |         TextureArray& operator=(const TextureArray& other); // Оператор присваивания
 | ||||||
|  | 
 | ||||||
|  |         virtual void use(); // Привязка текстуры       
 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | // Класс кубической текстуры
 | ||||||
|  | class TextureCube : public BaseTexture | ||||||
|  | { | ||||||
|  |     public: | ||||||
|  |         TextureCube(GLuint type = TEX_AVAILABLE_COUNT, const std::string (&filename)[6] = {""}); // Загрузка текстуры с диска или использование "пустой"
 | ||||||
|  |         TextureCube(GLuint width, GLuint height, GLuint attachment, GLuint texType = TEX_DIFFUSE, GLint internalformat = GL_RGBA, GLint format = GL_RGBA, GLenum dataType = GL_FLOAT); // Конструктор текстуры заданного размера для использования в буфере
 | ||||||
|  |         TextureCube(const TextureCube& other); // Конструктор копирования
 | ||||||
|  | 
 | ||||||
|  |         TextureCube& operator=(const TextureCube& other); // Оператор присваивания
 | ||||||
|  | 
 | ||||||
|  |         virtual void use(); // Привязка текстуры       
 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | // Класс 3D кубической текстуры
 | ||||||
|  | class TextureCubeArray : public BaseTexture | ||||||
|  | { | ||||||
|  |     public: | ||||||
|  |         TextureCubeArray(GLuint levels, GLuint width, GLuint height, GLuint attachment, GLuint texType = TEX_DIFFUSE, GLint internalformat = GL_RGBA, GLint format = GL_RGBA, GLenum dataType = GL_FLOAT); // Конструктор текстуры заданного размера для использования в буфере
 | ||||||
|  |         TextureCubeArray(const TextureCubeArray& other); // Конструктор копирования
 | ||||||
|  | 
 | ||||||
|  |         TextureCubeArray& operator=(const TextureCubeArray& other); // Оператор присваивания
 | ||||||
|  | 
 | ||||||
|  |         virtual void use(); // Привязка текстуры       
 | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | #endif // TEXTURE_H
 | ||||||
							
								
								
									
										42
									
								
								shaders/bulb.frag
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								shaders/bulb.frag
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,42 @@ | |||||||
|  | #version 420 core  | ||||||
|  | 
 | ||||||
|  | layout(std140, binding = 1) uniform Material | ||||||
|  | { | ||||||
|  |     vec3 ka; | ||||||
|  |     vec3 kd; | ||||||
|  |     vec3 ks; | ||||||
|  |     float p; | ||||||
|  |     bool normalmapped; | ||||||
|  |     bool parallaxmapped; | ||||||
|  |     bool displacementmapped; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | in vec3 pos_local; | ||||||
|  | 
 | ||||||
|  | layout(std140, binding = 4) uniform gamma | ||||||
|  | { | ||||||
|  |     float inv_gamma; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | layout (location = 1) out vec3 gNormal; | ||||||
|  | layout (location = 3) out vec4 gAmbientSpecular; | ||||||
|  | layout (location = 4) out uvec3 gID; | ||||||
|  | 
 | ||||||
|  | uniform float angle; | ||||||
|  | uniform vec3 direction; | ||||||
|  | 
 | ||||||
|  | uniform uvec3 ID = uvec3(0); | ||||||
|  | 
 | ||||||
|  | void main() | ||||||
|  | {    | ||||||
|  |     float cosA = dot(normalize(pos_local), normalize(direction)); | ||||||
|  |     if (degrees(acos(cosA)) <= angle) | ||||||
|  |         gAmbientSpecular.rgb = pow(ka, vec3(inv_gamma)); | ||||||
|  |     else | ||||||
|  |         discard; | ||||||
|  | 
 | ||||||
|  |     gNormal = vec3(0); | ||||||
|  |      | ||||||
|  |     // Сохранение идентификатора объекта | ||||||
|  |     gID = ID; | ||||||
|  | } | ||||||
							
								
								
									
										20
									
								
								shaders/bulb.vert
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								shaders/bulb.vert
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | |||||||
|  | #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; | ||||||
|  | 
 | ||||||
|  | out vec3 pos_local; | ||||||
|  | 
 | ||||||
|  | void main()  | ||||||
|  | {  | ||||||
|  |     pos_local = pos; | ||||||
|  |     gl_Position = camera.projection * camera.view * model * vec4(pos, 1.0); | ||||||
|  | }  | ||||||
							
								
								
									
										6
									
								
								shaders/empty.frag
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								shaders/empty.frag
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | |||||||
|  | #version 330 core | ||||||
|  | 
 | ||||||
|  | void main() | ||||||
|  | { | ||||||
|  |      | ||||||
|  | } | ||||||
							
								
								
									
										111
									
								
								shaders/gshader.frag
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								shaders/gshader.frag
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,111 @@ | |||||||
|  | #version 420 core  | ||||||
|  | 
 | ||||||
|  | layout(std140, binding = 1) uniform Material | ||||||
|  | { | ||||||
|  |     vec3 ka; | ||||||
|  |     vec3 kd; | ||||||
|  |     vec3 ks; | ||||||
|  |     float p; | ||||||
|  |     bool normalmapped; | ||||||
|  |     bool parallaxmapped; | ||||||
|  |     bool displacementmapped; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | layout (location = 0) out vec3 gPosition; | ||||||
|  | layout (location = 1) out vec3 gNormal; | ||||||
|  | layout (location = 2) out vec4 gDiffuseP; | ||||||
|  | layout (location = 3) out vec4 gAmbientSpecular; | ||||||
|  | layout (location = 4) out uvec3 gID; | ||||||
|  | 
 | ||||||
|  | in vec3 vertex; // Позиция вершины в пространстве | ||||||
|  | in vec3 N; // Нормаль трансформированноая | ||||||
|  | in vec2 texCoord; // Текстурные координаты | ||||||
|  | in vec3 T; // Касательный вектор | ||||||
|  | in vec3 B; // Бикасательный вектор | ||||||
|  | in vec3 view; // Вектор от поверхности к камере | ||||||
|  | 
 | ||||||
|  | uniform sampler2D tex_diffuse; | ||||||
|  | uniform sampler2D tex_ambient; | ||||||
|  | uniform sampler2D tex_specular; | ||||||
|  | uniform sampler2D tex_heights; | ||||||
|  | uniform sampler2D tex_normal; | ||||||
|  | 
 | ||||||
|  | uniform float parallax_heightScale = 0.1; | ||||||
|  | 
 | ||||||
|  | uniform uvec3 ID = uvec3(0); | ||||||
|  | 
 | ||||||
|  | void main() | ||||||
|  | {     | ||||||
|  |     // Сформируем TBN матрицу | ||||||
|  |     mat3 TBN = mat3(T, B, N); | ||||||
|  |     // Перевод вектора в касательное пространство | ||||||
|  |     vec3 viewTBN = normalize(transpose(TBN) * view); | ||||||
|  |     // Измененные текстурные координаты | ||||||
|  |     vec2 new_texCoord = texCoord; | ||||||
|  | 
 | ||||||
|  |     // Сохранение позиции фрагмента в G-буфере | ||||||
|  |     gPosition = vertex; | ||||||
|  | 
 | ||||||
|  |     if (parallaxmapped) | ||||||
|  |     { | ||||||
|  |         // Число слоев | ||||||
|  |         float layersCount = 32;   | ||||||
|  |         // Вычислим размер каждого слоя | ||||||
|  |         float layerDepth = 1.0 / layersCount; | ||||||
|  |         // Глубина текущего слоя | ||||||
|  |         float currentLayerDepth = 0.0; | ||||||
|  |         // Величина сдвига между слоями | ||||||
|  |         vec2 deltaTexCoords = (parallax_heightScale * viewTBN.xy / viewTBN.z) / layersCount; | ||||||
|  |      | ||||||
|  |         // Переменные для вычислений | ||||||
|  |         vec2  currentTexCoords     = texCoord; | ||||||
|  |         float currentDepthMapValue = 1.0 - texture(tex_heights, currentTexCoords).r; | ||||||
|  |          | ||||||
|  |         // Пока глубина текущего слоя меньше текущего значения глубины из текстуры  | ||||||
|  |         while(currentLayerDepth < currentDepthMapValue) | ||||||
|  |         { | ||||||
|  |             // Сдвигаем координаты | ||||||
|  |             currentTexCoords -= deltaTexCoords; | ||||||
|  |             // Обновляем значение глубины из текстуры | ||||||
|  |             currentDepthMapValue = 1.0 - texture(tex_heights, currentTexCoords).r;   | ||||||
|  |             // Сдвигаем глубину на следующий слой | ||||||
|  |             currentLayerDepth += layerDepth;   | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         // Получим значение текстурных координат с предыдущего шага | ||||||
|  |         vec2 prevTexCoords = currentTexCoords + deltaTexCoords; | ||||||
|  | 
 | ||||||
|  |         // Значения глубины до и после пересечения | ||||||
|  |         float afterDepth  = currentDepthMapValue - currentLayerDepth; | ||||||
|  |         float beforeDepth = 1.0 - texture(tex_heights, prevTexCoords).r - currentLayerDepth + layerDepth; | ||||||
|  |      | ||||||
|  |         // Интерполяция текстурных координат | ||||||
|  |         float weight = afterDepth / (afterDepth - beforeDepth); | ||||||
|  |         new_texCoord = prevTexCoords * weight + currentTexCoords * (1.0 - weight); | ||||||
|  | 
 | ||||||
|  |         // Проверка диапазона [0;1] | ||||||
|  |         if(new_texCoord.x > 1.0 || new_texCoord.y > 1.0 || new_texCoord.x < 0.0 || new_texCoord.y < 0.0) | ||||||
|  |             discard; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Сохранение нормали в G-буфере | ||||||
|  |     gNormal = N; | ||||||
|  |     // Если используется карта нормалей | ||||||
|  |     if (normalmapped) | ||||||
|  |     { | ||||||
|  |         // Получим значение из карты нормалей и приведем их к диапазону [-1;1] | ||||||
|  |         gNormal = texture(tex_normal, new_texCoord).rgb * 2 - 1.0f;   | ||||||
|  |         gNormal = normalize(TBN * gNormal); // Из касательного пространства в мировые координаты | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Сохранение диффузного цвета | ||||||
|  |     gDiffuseP.rgb = texture(tex_diffuse, new_texCoord).rgb * kd; | ||||||
|  |     // Сохранение глянцевости | ||||||
|  |     gDiffuseP.a = p; | ||||||
|  |     // Сохранение фоновой составляющей | ||||||
|  |     gAmbientSpecular.rgb = texture(tex_ambient, new_texCoord).rgb * ka; | ||||||
|  |     // Сохранение зеркальной составляющей | ||||||
|  |     gAmbientSpecular.a = texture(tex_specular, new_texCoord).r * ks.r; | ||||||
|  |     // Сохранение идентификатора объекта | ||||||
|  |     gID = ID; | ||||||
|  | } | ||||||
							
								
								
									
										60
									
								
								shaders/gshader.vert
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								shaders/gshader.vert
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,60 @@ | |||||||
|  | #version 420 core  | ||||||
|  | 
 | ||||||
|  | layout(location = 0) in vec3 pos;  | ||||||
|  | layout(location = 1) in vec2 inTexCoord; | ||||||
|  | layout(location = 2) in vec3 normals;  | ||||||
|  | layout(location = 3) in vec3 tangent;  | ||||||
|  | layout(location = 4) in vec3 bitangent;  | ||||||
|  | 
 | ||||||
|  | layout(std140, binding = 0) uniform Camera | ||||||
|  | { | ||||||
|  |     mat4 projection; | ||||||
|  |     mat4 view; | ||||||
|  |     vec3 position; | ||||||
|  | } camera; | ||||||
|  | 
 | ||||||
|  | layout(std140, binding = 1) uniform Material | ||||||
|  | { | ||||||
|  |     vec3 ka; | ||||||
|  |     vec3 kd; | ||||||
|  |     vec3 ks; | ||||||
|  |     float p; | ||||||
|  |     bool normalmapped; | ||||||
|  |     bool parallaxmapped; | ||||||
|  |     bool displacementmapped; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | uniform sampler2D tex_heights; | ||||||
|  | uniform float displacement_heightScale = 0.1; | ||||||
|  | 
 | ||||||
|  | uniform mat4 model; | ||||||
|  | 
 | ||||||
|  | out vec3 vertex; // Позиция вершины в пространстве | ||||||
|  | out vec3 N; // Нормаль трансформированноая | ||||||
|  | out vec2 texCoord; // Текстурные координаты | ||||||
|  | out vec3 T; // Касательный вектор | ||||||
|  | out vec3 B; // Бикасательный вектор | ||||||
|  | out vec3 view; // Вектор от поверхности к камере | ||||||
|  | 
 | ||||||
|  | void main()  | ||||||
|  | {  | ||||||
|  |     vec4 P = model * vec4(pos, 1.0); // трансформация вершины | ||||||
|  |     vertex = P.xyz; | ||||||
|  | 
 | ||||||
|  |     N = normalize(mat3(model) * normals); // трансформация нормали | ||||||
|  | 
 | ||||||
|  |     texCoord = inTexCoord; // Текстурные координаты | ||||||
|  | 
 | ||||||
|  |     T = normalize(mat3(model) * tangent); | ||||||
|  |     B = normalize(mat3(model) * bitangent); | ||||||
|  | 
 | ||||||
|  |     view = camera.position - vertex; | ||||||
|  | 
 | ||||||
|  |     if (displacementmapped) | ||||||
|  |     { | ||||||
|  |         float height = texture(tex_heights, texCoord).r * displacement_heightScale; | ||||||
|  |         P.xyz += mat3(T, B, N) * vec3(0, 0, height); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     gl_Position = camera.projection * camera.view * P; | ||||||
|  | }  | ||||||
							
								
								
									
										221
									
								
								shaders/lighting.frag
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										221
									
								
								shaders/lighting.frag
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,221 @@ | |||||||
|  | #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; | ||||||
|  |     vec4 direction_angle; | ||||||
|  |     mat4 vp[6]; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | layout(std140, binding = 2) uniform Light | ||||||
|  | { | ||||||
|  |     LightData data[64]; | ||||||
|  |     int count; | ||||||
|  | } light_f; | ||||||
|  | 
 | ||||||
|  | layout(std140, binding = 3) uniform Sun | ||||||
|  | { | ||||||
|  |     vec3 direction; | ||||||
|  |     vec3 color; | ||||||
|  |     mat4 vp[4]; | ||||||
|  | } sun; | ||||||
|  | 
 | ||||||
|  | uniform float camera_cascade_distances[4]; // Размер массива должен соответствовать количеству каскадов | ||||||
|  | 
 | ||||||
|  | uniform sampler2D gPosition; | ||||||
|  | uniform sampler2D gNormal; | ||||||
|  | uniform sampler2D gDiffuseP; | ||||||
|  | uniform sampler2D gAmbientSpecular; | ||||||
|  | uniform sampler2DArray sunShadowDepth; | ||||||
|  | uniform samplerCubeArray pointShadowDepth; | ||||||
|  | uniform sampler2D ssao; | ||||||
|  | uniform usampler2D gID; | ||||||
|  | 
 | ||||||
|  | uniform uvec3 selectedID; | ||||||
|  | 
 | ||||||
|  | layout(std140, binding = 4) uniform gamma | ||||||
|  | { | ||||||
|  |     float inv_gamma; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | 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; | ||||||
|  |     float ssao_value = texture(ssao, texCoord).r; | ||||||
|  |      | ||||||
|  |     // Переменные используемые в цикле: | ||||||
|  |     vec3 L_vertex; // Данные об источнике относительно фрагмента | ||||||
|  |     vec3 Cam_vertex = normalize(camera.position - fragPos); // Данные о камере относительно фрагмента | ||||||
|  |     float diffuse; // Диффузная составляющая | ||||||
|  |     vec3 H; // Вектор половины пути | ||||||
|  |     float specular; // Зеркальная составляющая | ||||||
|  |     float L_distance; // Расстояние от поверхности до источника | ||||||
|  |     float attenuation; // Коэф. угасания | ||||||
|  |     float acosA; // Косинус между вектором от поверхности к источнику и обратным направлением источника | ||||||
|  |     float intensity; // Интенсивность для прожектора | ||||||
|  |     vec3 fragPosLightSpace; // Фрагмент в пространстве источника | ||||||
|  |     float shadowValue; // Значение затененности | ||||||
|  |     vec2 texelSize = 1.0 / textureSize(sunShadowDepth, 0).xy; // Размер текселя текстуры теней | ||||||
|  |     int x, y, z; // Счетчик для PCF | ||||||
|  |     float pcfDepth; // Глубина PCF | ||||||
|  |     float cubemap_offset = 0.05f; // Отступ в текстурных координатах для PCF | ||||||
|  |     float cubemap_depth; // Дистанция между фрагментом и источником в диапазоне [0;1] | ||||||
|  | 
 | ||||||
|  |     vec4 fragPosCamSpace = camera.view * vec4(fragPos, 1); // Фрагмент в пространстве камеры | ||||||
|  |     int cascade_index; // Индекс текущего каскада для вычисления теней | ||||||
|  | 
 | ||||||
|  |     // Определение индекса каскада в который попадает фрагмент (цикл на 1 меньше чем кол-во каскадов) | ||||||
|  |     for (cascade_index = 0; cascade_index < 3; cascade_index++) | ||||||
|  |         if (abs(fragPosCamSpace.z) < camera_cascade_distances[cascade_index]) | ||||||
|  |             break; | ||||||
|  | 
 | ||||||
|  |     // Фоновая освещенность | ||||||
|  |     color = vec4(ka, 1) * ssao_value; | ||||||
|  |     | ||||||
|  |     // Расчет солнца, если его цвет не черный | ||||||
|  |     if (length(sun.color) > 0) | ||||||
|  |     { | ||||||
|  |         // Расположение фрагмента в координатах теневой карты | ||||||
|  |         fragPosLightSpace = (sun.vp[cascade_index] * vec4(fragPos, 1.0)).xyz; | ||||||
|  |         // Переход от [-1;1] к [0;1] | ||||||
|  |         fragPosLightSpace = (fragPosLightSpace + vec3(1.0)) / 2; | ||||||
|  |         // Сдвиг для решения проблемы акне | ||||||
|  |         fragPosLightSpace.z -= max(0.05 * (1.0 - dot(N, sun.direction)), 0.005); | ||||||
|  |         // Проверка PCF | ||||||
|  |         shadowValue = 0.0; | ||||||
|  |         for(x = -1; x <= 1; ++x) | ||||||
|  |         { | ||||||
|  |             for(y = -1; y <= 1; ++y) | ||||||
|  |             { | ||||||
|  |                 pcfDepth = texture(sunShadowDepth, vec3(fragPosLightSpace.xy + vec2(x, y) * texelSize, cascade_index)).r; | ||||||
|  |                 shadowValue += fragPosLightSpace.z > pcfDepth  ? 1.0 : 0.0;         | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         shadowValue /= 9; | ||||||
|  |         // Рассчитываем освещенность, если значение тени меньше 1 | ||||||
|  |         if (shadowValue < 1.0) | ||||||
|  |         { | ||||||
|  |             // Данные об источнике относительно фрагмента | ||||||
|  |             L_vertex = normalize(sun.direction); | ||||||
|  |             // Диффузная составляющая | ||||||
|  |             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 | ||||||
|  |             // Результирующий цвет с учетом солнца | ||||||
|  |             color += (  vec4(sun.color*kd*diffuse,  1)   | ||||||
|  |                       + vec4(sun.color*ks*specular, 1) ) * (1.0 - shadowValue); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Цикл по источникам света | ||||||
|  |     int i; | ||||||
|  |     for (i = 0; i < light_f.count; i++) | ||||||
|  |     { | ||||||
|  |         // Обнулим значение тени | ||||||
|  |         shadowValue = 0; | ||||||
|  |         // Позиция фрагмента относительно источника | ||||||
|  |         fragPosLightSpace = fragPos - light_f.data[i].position; | ||||||
|  |         // Дистанция между фрагментом и источником в диапазоне [0;1] | ||||||
|  |         cubemap_depth = length(fragPosLightSpace) / light_f.data[i].attenuation.r; | ||||||
|  |         // Сдвиг для решения проблемы акне | ||||||
|  |         cubemap_depth -= max(0.05 * (1.0 - dot(N, light_f.data[i].direction_angle.xyz)), 0.005); | ||||||
|  |         for(x = -1; x <= 1; ++x) | ||||||
|  |         { | ||||||
|  |             for(y = -1; y <= 1; ++y) | ||||||
|  |             { | ||||||
|  |                 for(z = -1; z <= 1; ++z) | ||||||
|  |                 { | ||||||
|  |                     // Значение из кубической текстуры с учетом источника (i) | ||||||
|  |                     pcfDepth = texture(pointShadowDepth, vec4(fragPosLightSpace + vec3(x, y, z)*cubemap_offset, i)).r;  | ||||||
|  |                     if(cubemap_depth > pcfDepth) | ||||||
|  |                         shadowValue += 1.0; | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         shadowValue /= (27); | ||||||
|  |         if (shadowValue < 1.0) | ||||||
|  |         { | ||||||
|  |             // Данные об источнике относительно фрагмента | ||||||
|  |             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); | ||||||
|  |                 // арккосинус между вектором от поверхности к источнику и обратным направлением источника | ||||||
|  |                 acosA = degrees(acos(dot(-L_vertex, normalize(light_f.data[i].direction_angle.xyz)))); | ||||||
|  |                 // Если угол меньше угла источника или угол источника минимален, то считаем освещенность | ||||||
|  |                 if(acosA <= light_f.data[i].direction_angle.a)  | ||||||
|  |                 { | ||||||
|  |                     // Диффузная составляющая | ||||||
|  |                     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); | ||||||
|  | 
 | ||||||
|  |                     // Если источник - прожектор, то добавим смягчение | ||||||
|  |                     if (light_f.data[i].direction_angle.a < 180) | ||||||
|  |                     { | ||||||
|  |                         intensity = clamp((light_f.data[i].direction_angle.a - acosA) / 5, 0.0, 1.0);   | ||||||
|  |                         diffuse  *= intensity; | ||||||
|  |                         specular *= intensity; | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|  |                     color += ( vec4(light_f.data[i].color*kd*diffuse  * attenuation, 1)  | ||||||
|  |                               + vec4(light_f.data[i].color*ks*specular * attenuation, 1) )  * (1.0 - shadowValue); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Применение гамма-коррекции | ||||||
|  |     color.rgb = pow(color.rgb, vec3(inv_gamma)); | ||||||
|  | 
 | ||||||
|  |     vec3 ID = texture(gID, texCoord).rgb; | ||||||
|  |     // Обводка выбранного объекта | ||||||
|  |     if (length(selectedID.rg) > 0 && selectedID.rg == ID.rg && ID.b == 0) | ||||||
|  |     { | ||||||
|  |         int border_width = 3; | ||||||
|  |         vec2 size = 1.0f / textureSize(gID, 0); | ||||||
|  |         for (int i = -border_width; i <= +border_width; i++) | ||||||
|  |             for (int j = -border_width; j <= +border_width; j++) | ||||||
|  |             { | ||||||
|  |                 if (i == 0 && j == 0) | ||||||
|  |                     continue; | ||||||
|  | 
 | ||||||
|  |                 if (texture(gID, texCoord + vec2(i, j) * size).rg != selectedID.rg) | ||||||
|  |                     color.rgb = vec3(1.0); | ||||||
|  |             } | ||||||
|  |     } | ||||||
|  | }  | ||||||
							
								
								
									
										17
									
								
								shaders/point_shadow.frag
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								shaders/point_shadow.frag
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,17 @@ | |||||||
|  | #version 330 core | ||||||
|  | 
 | ||||||
|  | in vec4 FragPos; | ||||||
|  | in vec3 lightPos; | ||||||
|  | in float radius; | ||||||
|  | 
 | ||||||
|  | void main() | ||||||
|  | { | ||||||
|  |     // Расстояние между источником и фрагментом | ||||||
|  |     float lightDistance = length(FragPos.xyz - lightPos); | ||||||
|  |      | ||||||
|  |     // Приведение к диапазону [0;1] | ||||||
|  |     lightDistance = lightDistance / radius; | ||||||
|  |      | ||||||
|  |     // Замена значения глубины | ||||||
|  |     gl_FragDepth = lightDistance; | ||||||
|  | } | ||||||
							
								
								
									
										38
									
								
								shaders/point_shadow.geom
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								shaders/point_shadow.geom
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,38 @@ | |||||||
|  | #version 420 core | ||||||
|  | layout (triangles, invocations = 6) in; // здесь invocations соответствует числу сторон кубической карты теней | ||||||
|  | layout (triangle_strip, max_vertices=18) out; // здесь max_vertices = 3 вершины * 6 вызовов на стороны куба | ||||||
|  | 
 | ||||||
|  | struct LightData | ||||||
|  | { | ||||||
|  |     vec3 position; | ||||||
|  |     vec3 color; | ||||||
|  |     vec3 attenuation; | ||||||
|  |     vec4 direction_angle; | ||||||
|  |     mat4 vp[6]; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | layout(std140, binding = 2) uniform Light | ||||||
|  | { | ||||||
|  |     LightData data[64]; | ||||||
|  |     int count; | ||||||
|  | } light_g; | ||||||
|  | 
 | ||||||
|  | uniform int light_i; | ||||||
|  | 
 | ||||||
|  | out vec4 FragPos;  | ||||||
|  | out vec3 lightPos; | ||||||
|  | out float radius; | ||||||
|  | 
 | ||||||
|  | void main() | ||||||
|  | { | ||||||
|  |     for(int i = 0; i < 3; ++i) | ||||||
|  |     { | ||||||
|  |         FragPos = gl_in[i].gl_Position; | ||||||
|  |         lightPos = light_g.data[light_i].position; | ||||||
|  |         radius = light_g.data[light_i].attenuation.r; | ||||||
|  |         gl_Position = light_g.data[light_i].vp[gl_InvocationID] * gl_in[i].gl_Position; | ||||||
|  |         gl_Layer = gl_InvocationID + light_i*6;  | ||||||
|  |         EmitVertex(); | ||||||
|  |     }     | ||||||
|  |     EndPrimitive(); | ||||||
|  | }  | ||||||
							
								
								
									
										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] | ||||||
|  | } | ||||||
							
								
								
									
										17
									
								
								shaders/skybox.frag
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								shaders/skybox.frag
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,17 @@ | |||||||
|  | #version 420 core | ||||||
|  | out vec4 FragColor; | ||||||
|  | 
 | ||||||
|  | in vec3 TexCoords; | ||||||
|  | 
 | ||||||
|  | uniform samplerCube skybox; | ||||||
|  | 
 | ||||||
|  | layout(std140, binding = 4) uniform gamma | ||||||
|  | { | ||||||
|  |     float inv_gamma; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | void main() | ||||||
|  | {     | ||||||
|  |     FragColor.rgb = pow(texture(skybox, TexCoords).rgb, vec3(inv_gamma)); | ||||||
|  |     gl_FragDepth = 0.9999f; | ||||||
|  | } | ||||||
							
								
								
									
										17
									
								
								shaders/skybox.vert
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								shaders/skybox.vert
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,17 @@ | |||||||
|  | #version 420 core | ||||||
|  | layout (location = 0) in vec3 pos; | ||||||
|  | 
 | ||||||
|  | out vec3 TexCoords; | ||||||
|  | 
 | ||||||
|  | layout(std140, binding = 0) uniform Camera | ||||||
|  | { | ||||||
|  |     mat4 projection; | ||||||
|  |     mat4 view; | ||||||
|  |     vec3 position; | ||||||
|  | } camera; | ||||||
|  | 
 | ||||||
|  | void main() | ||||||
|  | { | ||||||
|  |     TexCoords = pos; | ||||||
|  |     gl_Position = camera.projection * mat4(mat3(camera.view)) * vec4(pos, 1.0); | ||||||
|  | }   | ||||||
							
								
								
									
										62
									
								
								shaders/ssao.frag
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								shaders/ssao.frag
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,62 @@ | |||||||
|  | #version 420 core | ||||||
|  | 
 | ||||||
|  | in vec2 texCoord; | ||||||
|  | 
 | ||||||
|  | out float occlusion; | ||||||
|  | 
 | ||||||
|  | uniform sampler2D gPosition; | ||||||
|  | uniform sampler2D gNormal; | ||||||
|  | uniform sampler2D noise; | ||||||
|  | 
 | ||||||
|  | layout(std140, binding = 0) uniform Camera | ||||||
|  | { | ||||||
|  |     mat4 projection; | ||||||
|  |     mat4 view; | ||||||
|  |     vec3 position; | ||||||
|  | } camera; | ||||||
|  | 
 | ||||||
|  | layout(std140, binding = 3) uniform SSAO | ||||||
|  | { | ||||||
|  |     float radius; | ||||||
|  |     float bias; | ||||||
|  |     int size; | ||||||
|  |     vec2 scale; | ||||||
|  |     vec3 samples[64]; | ||||||
|  | } ssao; | ||||||
|  | 
 | ||||||
|  | void main() | ||||||
|  | { | ||||||
|  |     // Получим информацию из текстур для данного фрагмента по текстурным координатам | ||||||
|  |     vec3 fragPos = (camera.view * vec4(texture(gPosition, texCoord).xyz, 1)).xyz; | ||||||
|  |     vec3 normal = normalize(texture(gNormal, texCoord).rgb); | ||||||
|  |     vec3 randomVec = normalize(texture(noise, texCoord * ssao.scale).xyz); | ||||||
|  |     // Расчет TBN матрицы | ||||||
|  |     vec3 tangent = normalize(randomVec - normal * dot(randomVec, normal)); | ||||||
|  |     vec3 bitangent = cross(normal, tangent); | ||||||
|  |     mat3 TBN = mat3(tangent, bitangent, normal); | ||||||
|  |      | ||||||
|  |     float sampleDepth; // Значение глубины образца выборки | ||||||
|  |     vec3 samplePos; // Выборка, ориентированная в пространстве вида камеры | ||||||
|  |     vec4 sampleCoord; // Выборка, преобразованная к текстурным координатам | ||||||
|  |     float rangeCheck; // Проверка диапазона | ||||||
|  |      | ||||||
|  |     // Проинициализируем значение счетчика и запустим цикл по выборкам | ||||||
|  |     occlusion = 0; | ||||||
|  |     for(int i = 0; i < ssao.size; i++) | ||||||
|  |     { | ||||||
|  |         samplePos = TBN * ssao.samples[i]; // в TBN-пространстве | ||||||
|  |         samplePos = fragPos + samplePos * ssao.radius; // в пространстве вида камеры | ||||||
|  |          | ||||||
|  |         sampleCoord = camera.projection * vec4(samplePos, 1.0);  | ||||||
|  |         sampleCoord.xyz /= sampleCoord.w; // Деление на значение перспективы | ||||||
|  |         sampleCoord.xyz = sampleCoord.xyz * 0.5 + 0.5; // Трансформация в диапазон [0.0; 1.0] | ||||||
|  |          | ||||||
|  |         // Получаем значение глубины по образцу выборки | ||||||
|  |         sampleDepth = (camera.view * vec4(texture(gPosition, sampleCoord.xy).rgb, 1)).z;  | ||||||
|  | 
 | ||||||
|  |         rangeCheck = smoothstep(0.0, 1.0, ssao.radius / abs(fragPos.z - sampleDepth)); | ||||||
|  |         occlusion += (sampleDepth >= samplePos.z + ssao.bias ? 1.0 : 0.0) * rangeCheck; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     occlusion = 1 - (occlusion / ssao.size); | ||||||
|  | } | ||||||
							
								
								
									
										23
									
								
								shaders/ssaoBlur.frag
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								shaders/ssaoBlur.frag
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,23 @@ | |||||||
|  | #version 330 core | ||||||
|  | 
 | ||||||
|  | in vec2 texCoord; | ||||||
|  | 
 | ||||||
|  | out float occlusion; | ||||||
|  | 
 | ||||||
|  | uniform sampler2D ssao; | ||||||
|  | 
 | ||||||
|  | void main()  | ||||||
|  | { | ||||||
|  |     vec2 texelSize = 1.0 / vec2(textureSize(ssao, 0)); | ||||||
|  |     vec2 offset; | ||||||
|  |     occlusion = 0.0; | ||||||
|  |     for (int x = -2; x < 2; x++)  | ||||||
|  |     { | ||||||
|  |         for (int y = -2; y < 2; y++)  | ||||||
|  |         { | ||||||
|  |             offset = vec2(x, y) * texelSize; | ||||||
|  |             occlusion += texture(ssao, texCoord + offset).r; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     occlusion = occlusion / (4.0 * 4.0); | ||||||
|  | }   | ||||||
							
								
								
									
										22
									
								
								shaders/sun_shadow.geom
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								shaders/sun_shadow.geom
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | |||||||
|  | #version 420 core | ||||||
|  | 
 | ||||||
|  | layout(triangles, invocations = 4) in; // здесь invocations должно соответствовать количеству каскадов | ||||||
|  | layout(triangle_strip, max_vertices = 3) out; | ||||||
|  | 
 | ||||||
|  | layout(std140, binding = 3) uniform Sun | ||||||
|  | { | ||||||
|  |     vec3 direction; | ||||||
|  |     vec3 color; | ||||||
|  |     mat4 vp[4]; | ||||||
|  | } sun; | ||||||
|  | 
 | ||||||
|  | void main() | ||||||
|  | {  | ||||||
|  | 	for (int i = 0; i < 3; ++i) | ||||||
|  | 	{ | ||||||
|  | 		gl_Position = sun.vp[gl_InvocationID] * gl_in[i].gl_Position; | ||||||
|  | 		gl_Layer = gl_InvocationID; | ||||||
|  | 		EmitVertex(); | ||||||
|  | 	} | ||||||
|  | 	EndPrimitive(); | ||||||
|  | }   | ||||||
							
								
								
									
										10
									
								
								shaders/sun_shadow.vert
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								shaders/sun_shadow.vert
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,10 @@ | |||||||
|  | #version 420 core | ||||||
|  | 
 | ||||||
|  | layout (location = 0) in vec3 pos; | ||||||
|  | 
 | ||||||
|  | uniform mat4 model; | ||||||
|  | 
 | ||||||
|  | void main() | ||||||
|  | { | ||||||
|  |     gl_Position = model * vec4(pos, 1.0); | ||||||
|  | } | ||||||
							
								
								
									
										38
									
								
								shaders/tools.frag
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								shaders/tools.frag
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,38 @@ | |||||||
|  | #version 420 core  | ||||||
|  | 
 | ||||||
|  | layout(std140, binding = 1) uniform Material | ||||||
|  | { | ||||||
|  |     vec3 ka; | ||||||
|  |     vec3 kd; | ||||||
|  |     vec3 ks; | ||||||
|  |     float p; | ||||||
|  |     bool normalmapped; | ||||||
|  |     bool parallaxmapped; | ||||||
|  |     bool displacementmapped; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | layout (location = 1) out vec3 gNormal; | ||||||
|  | layout (location = 3) out vec4 gAmbientSpecular; | ||||||
|  | layout (location = 4) out uvec3 gID; | ||||||
|  | 
 | ||||||
|  | in vec3 vertex; // Позиция вершины в пространстве | ||||||
|  | in vec3 N; // Нормаль трансформированная | ||||||
|  | in vec2 texCoord; // Текстурные координаты | ||||||
|  | in vec3 T; // Касательный вектор | ||||||
|  | in vec3 B; // Бикасательный вектор | ||||||
|  | in vec3 view; // Вектор от поверхности к камере | ||||||
|  | 
 | ||||||
|  | uniform float parallax_heightScale = 0.1; | ||||||
|  | 
 | ||||||
|  | uniform uvec3 ID = uvec3(0); | ||||||
|  | 
 | ||||||
|  | void main() | ||||||
|  | {     | ||||||
|  |     gNormal = vec3(0); | ||||||
|  |     // Сохранение фоновой составляющей | ||||||
|  |     gAmbientSpecular.rgb = ka; | ||||||
|  |     // Сохранение идентификатора объекта | ||||||
|  |     gID = ID; | ||||||
|  |      | ||||||
|  |     gl_FragDepth = 0.01 * gl_FragCoord.z; | ||||||
|  | } | ||||||
							
								
								
									
										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; | ||||||
|  | } | ||||||
							
								
								
									
										239
									
								
								src/Camera.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										239
									
								
								src/Camera.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,239 @@ | |||||||
|  | #include "Camera.h" | ||||||
|  | 
 | ||||||
|  | // Указатель на текущую используемую камеру
 | ||||||
|  | Camera* Camera::p_current = NULL;  | ||||||
|  | 
 | ||||||
|  | // Границы каскадов
 | ||||||
|  | const float camera_cascade_distances[] = {CAMERA_NEAR, CAMERA_FAR / 50.0f, CAMERA_FAR / 10.0f,  CAMERA_FAR / 3.0f, CAMERA_FAR}; | ||||||
|  | 
 | ||||||
|  | // Защищенный (protected) конструктор камеры без перспективы 
 | ||||||
|  | Camera::Camera(const glm::vec3 &pos, const glm::vec3 &initialRotation) : Node(NULL) // Пусть по умолчанию камера не относится к сцене
 | ||||||
|  | { | ||||||
|  |     sensitivity = CAMERA_DEFAULT_SENSIVITY; | ||||||
|  |     position = pos; // задаем позицию
 | ||||||
|  |     // Определяем начальный поворот
 | ||||||
|  |     glm::quat rotationAroundX = glm::angleAxis( glm::radians(initialRotation.x), glm::vec3(1.0f, 0.0f, 0.0f)); | ||||||
|  |     glm::quat rotationAroundY = glm::angleAxis(-glm::radians(initialRotation.y), glm::vec3(0.0f, 1.0f, 0.0f)); | ||||||
|  |     glm::quat rotationAroundZ = glm::angleAxis( glm::radians(initialRotation.z), glm::vec3(0.0f, 0.0f, 1.0f)); | ||||||
|  |     rotation = rotationAroundX * rotationAroundY * rotationAroundZ; | ||||||
|  |     // Признак изменения
 | ||||||
|  |     changed = true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Конструктор камеры с проекцией перспективы
 | ||||||
|  | Camera::Camera(float aspect, const glm::vec3 &position, const glm::vec3 &initialRotation, float fovy) | ||||||
|  | : Camera(position, initialRotation) | ||||||
|  | { | ||||||
|  |     setPerspective(fovy, aspect); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Конструктор ортографической камеры
 | ||||||
|  | Camera::Camera(float width, float height, const glm::vec3 &position, const glm::vec3 &initialRotation) | ||||||
|  | : Camera(position, initialRotation) | ||||||
|  | { | ||||||
|  |     setOrtho(width, height); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Конструктор копирования камеры
 | ||||||
|  | Camera::Camera(const Camera& copy)  | ||||||
|  | : Node(copy), projection(copy.projection), requiredRecalcVP(copy.requiredRecalcVP), sensitivity(copy.sensitivity), | ||||||
|  | requiredRecalcCoords(true) | ||||||
|  | { | ||||||
|  |     // Если у оригинала не было изменений - перепишем матрицу вида-проекции
 | ||||||
|  |     if (!requiredRecalcVP) | ||||||
|  |         vp = copy.vp; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Оператор присваивания
 | ||||||
|  | Camera& Camera::operator=(const Camera& other) | ||||||
|  | { | ||||||
|  |     Node::operator=(other); // Вызов родительского оператора= для переноса узла
 | ||||||
|  |      | ||||||
|  |     projection = other.projection; | ||||||
|  |     requiredRecalcVP = other.requiredRecalcVP; | ||||||
|  |     sensitivity = other.sensitivity; | ||||||
|  | 
 | ||||||
|  |     // Если у оригинала не было изменений - перепишем матрицу вида-проекции
 | ||||||
|  |     if (!requiredRecalcVP) | ||||||
|  |         vp = other.vp; | ||||||
|  | 
 | ||||||
|  |     return *this; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Деструктор
 | ||||||
|  | Camera::~Camera()  | ||||||
|  | {  | ||||||
|  |     if (p_current == this) | ||||||
|  |         p_current = NULL; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Возвращает ссылку на константную матрицу проекции
 | ||||||
|  | const glm::mat4& Camera::getProjection() | ||||||
|  | { | ||||||
|  |     return projection; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Возвращает ссылку на константную матрицу вида
 | ||||||
|  | const glm::mat4& Camera::getView() | ||||||
|  | { | ||||||
|  |     recalcMatrices(); | ||||||
|  | 
 | ||||||
|  |     return view; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Возвращает ссылку на константную матрицу вида
 | ||||||
|  | const glm::mat4& Camera::getVP() | ||||||
|  | { | ||||||
|  |     recalcMatrices(); | ||||||
|  | 
 | ||||||
|  |     return vp; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Устанавливает заданную матрицу перспективы
 | ||||||
|  | void Camera::setPerspective(float fovy, float aspect) | ||||||
|  | { | ||||||
|  |     projection = glm::perspective(glm::radians(fovy), aspect, CAMERA_NEAR, CAMERA_FAR); | ||||||
|  |     requiredRecalcVP = true; | ||||||
|  |     for (int cascade = 0; cascade < CAMERA_CASCADE_COUNT; cascade++) | ||||||
|  |         cascade_proj[cascade] = glm::perspective(glm::radians(fovy), aspect, camera_cascade_distances[cascade], camera_cascade_distances[cascade+1]); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Устанавливает заданную ортографическую матрицу
 | ||||||
|  | void Camera::setOrtho(float width, float height) | ||||||
|  | { | ||||||
|  |     const float aspect = width / height; | ||||||
|  |     projection = glm::ortho(-1.0f, 1.0f, -1.0f/aspect, 1.0f/aspect, CAMERA_NEAR, CAMERA_FAR); | ||||||
|  |     requiredRecalcVP = true; | ||||||
|  |     for (int cascade = 0; cascade < CAMERA_CASCADE_COUNT; cascade++) | ||||||
|  |         cascade_proj[cascade] = glm::ortho(-1.0f, 1.0f, -1.0f/aspect, 1.0f/aspect, camera_cascade_distances[cascade], camera_cascade_distances[cascade+1]); | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Изменяет чувствительность мыши
 | ||||||
|  | void Camera::setSensitivity(float sens) | ||||||
|  | { | ||||||
|  |     sensitivity = sens; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Возвращает чувствительность мыши
 | ||||||
|  | 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; | ||||||
|  |         requiredRecalcCoords = true; // Требуется пересчитать точки пространства камеры
 | ||||||
|  |         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; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Доступ к координатам с флагом изменения, описывающим пространство вида с пересчетом, если это требуется
 | ||||||
|  | std::pair<bool, const glm::vec4(*)[8]> Camera::getProjCoords()  | ||||||
|  | { | ||||||
|  |     const glm::mat4& cam_vp = getVP(); // Получение ссылки на матрицу вида-проекции с пересчетом, если требуется и активацией флага requiredRecalcCoords
 | ||||||
|  |     bool changes = false; // Возвращаемое значение
 | ||||||
|  | 
 | ||||||
|  |     if (requiredRecalcCoords) | ||||||
|  |     {  | ||||||
|  |         // Инверсия матрицы вида/проекции камеры
 | ||||||
|  |         glm::mat4 inv = glm::inverse(cam_vp); | ||||||
|  |         // Типовые точки, описывающие пространство 
 | ||||||
|  |         glm::vec4 typical_points[8] = {  { 1, 1, 1,1} | ||||||
|  |                                        , { 1, 1,-1,1} | ||||||
|  |                                        , { 1,-1, 1,1} | ||||||
|  |                                        , { 1,-1,-1,1} | ||||||
|  |                                        , {-1, 1, 1,1} | ||||||
|  |                                        , {-1, 1,-1,1} | ||||||
|  |                                        , {-1,-1, 1,1} | ||||||
|  |                                        , {-1,-1,-1,1}}; | ||||||
|  |          | ||||||
|  |         for (int cascade = 0; cascade < CAMERA_CASCADE_COUNT; cascade++) | ||||||
|  |         { | ||||||
|  |             glm::mat4 inv = glm::inverse(cascade_proj[cascade] * getView()); | ||||||
|  |             // Цикл по типовым точкам
 | ||||||
|  |             for (int i = 0; i < 8; i++) | ||||||
|  |             { | ||||||
|  |                 coords[cascade][i] = inv * typical_points[i]; | ||||||
|  |                 coords[cascade][i] /= coords[cascade][i].w; | ||||||
|  |             }  | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         requiredRecalcCoords = false; // Сбрасываем флаг
 | ||||||
|  |         changes = true; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return std::make_pair(changes, coords);  | ||||||
|  | } | ||||||
							
								
								
									
										379
									
								
								src/Lights.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										379
									
								
								src/Lights.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,379 @@ | |||||||
|  | #include "Lights.h" | ||||||
|  | 
 | ||||||
|  | #include "Scene.h" // Для отладочного вывода лампочек
 | ||||||
|  | 
 | ||||||
|  | #include <stdexcept> | ||||||
|  | 
 | ||||||
|  | GLuint Light::count = 0; // количество используемых источников (должно быть <= MAX_LIGHTS)
 | ||||||
|  | LightData Light::data[MAX_LIGHTS]; // Массив данных по источникам света
 | ||||||
|  | Light Light::lights[MAX_LIGHTS]; // Массив источников-узлов сцены
 | ||||||
|  | 
 | ||||||
|  | Sun Sun::instance; // Экземпляр синглтона
 | ||||||
|  | bool Sun::uploadReq = true; // Необходимость загрузки в следствии изменений
 | ||||||
|  | 
 | ||||||
|  | // возвращает размер буфера в байтах
 | ||||||
|  | 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(); // Проверка на работу с корректным индексом
 | ||||||
|  | 
 | ||||||
|  |     // Если позиция изменилась
 | ||||||
|  |     if (data[index].position.x != result_transform[3].x | ||||||
|  |     ||  data[index].position.y != result_transform[3].y | ||||||
|  |     ||  data[index].position.z != result_transform[3].z | ||||||
|  |     ) | ||||||
|  |     { | ||||||
|  |         data[index].position = glm::vec3(result_transform[3]); // Позиция из матрицы трансформации
 | ||||||
|  |         recalcVP(); // Пересчет матрицы вида-проекции для расчета теней
 | ||||||
|  |     } | ||||||
|  |     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]; // Квадратичный коэф. угасания
 | ||||||
|  |     } | ||||||
|  |     // Направление и угол источника
 | ||||||
|  |     data[index].direction_angle = glm::vec4( glm::normalize(glm::vec3(result_transform * DEFAULT_LIGHT_DIRECTION)) | ||||||
|  |                                            , angle / 2 // Половинный угол для вычислений на шейдере
 | ||||||
|  |                                            ); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Возвращает ссылку на новый источник света
 | ||||||
|  | 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), angle(360.0f) | ||||||
|  | { | ||||||
|  |      | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Оператор  присваивания
 | ||||||
|  | Light& Light::operator=(const Light& other) | ||||||
|  | { | ||||||
|  |     // Проверка на самоприсваивание
 | ||||||
|  |     if (this != &other)  | ||||||
|  |     { | ||||||
|  |         index = other.index; // Переносим индекс
 | ||||||
|  |         uploadReq = other.uploadReq; // Необходимость загрузки 
 | ||||||
|  |         color = other.color; | ||||||
|  |         radius = other.radius; | ||||||
|  |         angle = other.angle; | ||||||
|  | 
 | ||||||
|  |         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); | ||||||
|  | 
 | ||||||
|  |     GLuint angle_uniform = shaderProgram.getUniformLoc("angle"); | ||||||
|  |     GLuint direction_uniform = shaderProgram.getUniformLoc("direction"); | ||||||
|  | 
 | ||||||
|  |     // Цикл по источникам света
 | ||||||
|  |     for (int i = 0; i < count; i++) | ||||||
|  |     { | ||||||
|  |         // Идентификатор источника как узла сцены для всей модели лампочки
 | ||||||
|  |         bulb.set_group_id((GLuint64) &lights[i]); | ||||||
|  |         sphere.id.value = (GLuint64) &lights[i]; | ||||||
|  | 
 | ||||||
|  |         // Загрузим направление
 | ||||||
|  |         glUniform3fv(direction_uniform, 1, &data[i].direction_angle.x); | ||||||
|  |         // Угол для лампочки = 180 (рисуем целую модель)
 | ||||||
|  |         glUniform1f(angle_uniform, 180); // Зададим параметры материала сфере действия
 | ||||||
|  |          | ||||||
|  |         // Сдвиг на позицию источника
 | ||||||
|  |         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);     | ||||||
|  | 
 | ||||||
|  |         // Угол для сферы (рисуем направленный конус)
 | ||||||
|  |         glUniform1f(angle_uniform, data[i].direction_angle.a);  | ||||||
|  | 
 | ||||||
|  |         // Рисование сферы покрытия источника в режиме линий
 | ||||||
|  |         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; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Константный доступ к углу освещенности
 | ||||||
|  | const float& Light::c_angle() const | ||||||
|  | { | ||||||
|  |     return angle; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Неконстантная ссылка для изменений угла освещенности
 | ||||||
|  | float& Light::e_angle() | ||||||
|  | { | ||||||
|  |     uploadReq = true; | ||||||
|  | 
 | ||||||
|  |     return angle; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Конструктор направленного источника с параметрами направления и цвета
 | ||||||
|  | Sun::Sun(const glm::vec3 &dir, const glm::vec3 &c) : direction(dir), color(c) | ||||||
|  | { | ||||||
|  |      | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Доступ к синглтону
 | ||||||
|  | Sun& Sun::get() | ||||||
|  | { | ||||||
|  |     return instance; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Загрузка данных об источнике на шейдер
 | ||||||
|  | void Sun::upload(UBO& sun_data) | ||||||
|  | { | ||||||
|  |     instance.recalcVP(); // Пересчет матрицы вида-проекции источника по необходимости (влияет на флаг uploadReq)
 | ||||||
|  | 
 | ||||||
|  |     if (uploadReq) | ||||||
|  |     { | ||||||
|  |         sun_data.loadSub(&instance, sizeof(instance)); | ||||||
|  | 
 | ||||||
|  |         uploadReq = false; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Константный доступ к направлению лучей источника
 | ||||||
|  | const glm::vec3& Sun::c_direction() const | ||||||
|  | { | ||||||
|  |     return instance.direction;     | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Неконстантная ссылка для изменений направления лучей источника
 | ||||||
|  | glm::vec3& Sun::e_direction() | ||||||
|  | { | ||||||
|  |     uploadReq = true; | ||||||
|  | 
 | ||||||
|  |     return instance.direction; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Константный доступ к цвету
 | ||||||
|  | const glm::vec3& Sun::c_color() const | ||||||
|  | { | ||||||
|  |     return instance.color; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Неконстантная ссылка для изменений цвета
 | ||||||
|  | glm::vec3& Sun::e_color()  | ||||||
|  | { | ||||||
|  |     uploadReq = true; | ||||||
|  | 
 | ||||||
|  |     return instance.color; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Пересчитывает по необходимости матрицу вида-проекции
 | ||||||
|  | void Sun::recalcVP() | ||||||
|  | { | ||||||
|  |     // Точки по краям проекции камеры
 | ||||||
|  |    std::pair <bool, const glm::vec4(*)[8]> camProjCoords = Camera::current().getProjCoords(); | ||||||
|  | 
 | ||||||
|  |     // Есть изменения по источнику или камере
 | ||||||
|  |     if (uploadReq || camProjCoords.first) | ||||||
|  |     { | ||||||
|  |         uploadReq = true; // Требуется загрузка в следствии пересчета матрицы
 | ||||||
|  | 
 | ||||||
|  |         glm::vec3 mean; // Среднее арифметическое
 | ||||||
|  |         glm::vec4 max, min; // макс и мин координаты
 | ||||||
|  |         glm::vec4 point; // Точка приведенная в пространство источника света
 | ||||||
|  | 
 | ||||||
|  |      | ||||||
|  |         for (int cascade = 0; cascade < CAMERA_CASCADE_COUNT; cascade++) | ||||||
|  |         { | ||||||
|  |             mean = glm::vec3(0); | ||||||
|  |             // Найдем среднее арифметическое от точек для нахождения центра прямоугольника
 | ||||||
|  |             for (int i = 0; i < 8; i++) | ||||||
|  |                 mean += glm::vec3(camProjCoords.second[cascade][i]); | ||||||
|  |             mean /= 8; | ||||||
|  |             // Используем среднее арифметическое для получения матрицы вида параллельного источника
 | ||||||
|  |             glm::mat4 lightView = glm::lookAt(mean + glm::normalize(direction), mean, CAMERA_UP_VECTOR); | ||||||
|  |              | ||||||
|  |             // Примем первую точку как минимальную и максимальную (приведя в пространство вида источника)
 | ||||||
|  |             min = max = lightView * camProjCoords.second[cascade][0]; | ||||||
|  |             // Для оставшихся точек
 | ||||||
|  |             for (int i = 1; i < 8; i++) | ||||||
|  |             { | ||||||
|  |                 // Приведем в пространство вида источника
 | ||||||
|  |                 point = lightView * camProjCoords.second[cascade][i]; | ||||||
|  |                 max = glm::max(max, point); | ||||||
|  |                 min = glm::min(min, point); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             // Максимальное значение глубины
 | ||||||
|  |             max.z = std::max(fabs(max.z), fabs(min.z)); | ||||||
|  |             // На основании максимальных и минимальных координат создадим матрицу проекции источника
 | ||||||
|  |             vp[cascade] = glm::ortho(min.x, max.x, min.y, max.y, min.z, max.z) * lightView; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Пересчитывает по необходимости матрицу вида-проекции
 | ||||||
|  | void Light::recalcVP() | ||||||
|  | {     | ||||||
|  |     float near_plane = 0.1f; | ||||||
|  |     glm::mat4 shadowProj = glm::perspective(glm::radians(90.0f), 1.0f, near_plane, radius); | ||||||
|  |     data[index].vp[0] = shadowProj * glm::lookAt(position, position + glm::vec3( 1.0f,  0.0f,  0.0f), glm::vec3(0.0f, -1.0f,  0.0f)); | ||||||
|  |     data[index].vp[1] = shadowProj * glm::lookAt(position, position + glm::vec3(-1.0f,  0.0f,  0.0f), glm::vec3(0.0f, -1.0f,  0.0f)); | ||||||
|  |     data[index].vp[2] = shadowProj * glm::lookAt(position, position + glm::vec3( 0.0f,  1.0f,  0.0f), glm::vec3(0.0f,  0.0f,  1.0f)); | ||||||
|  |     data[index].vp[3] = shadowProj * glm::lookAt(position, position + glm::vec3( 0.0f, -1.0f,  0.0f), glm::vec3(0.0f,  0.0f, -1.0f)); | ||||||
|  |     data[index].vp[4] = shadowProj * glm::lookAt(position, position + glm::vec3( 0.0f,  0.0f,  1.0f), glm::vec3(0.0f, -1.0f,  0.0f)); | ||||||
|  |     data[index].vp[5] = shadowProj * glm::lookAt(position, position + glm::vec3( 0.0f,  0.0f, -1.0f), glm::vec3(0.0f, -1.0f,  0.0f)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Возвращает количество источников
 | ||||||
|  | int Light::getCount() | ||||||
|  | { | ||||||
|  |     return count; | ||||||
|  | } | ||||||
							
								
								
									
										598
									
								
								src/Model.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										598
									
								
								src/Model.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,598 @@ | |||||||
|  | #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.rotation), scale(copy.scale), | ||||||
|  | parent(copy.parent), changed(copy.changed), 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), | ||||||
|  | tangent_vbo(VERTEX), bitangent_vbo(VERTEX) | ||||||
|  | { | ||||||
|  |     // Приведение указателя к целому 8байт
 | ||||||
|  |     id.value = (GLuint64) this; | ||||||
|  |     id.etc = 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Конструктор копирования
 | ||||||
|  | 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), | ||||||
|  | tangent_vbo(copy.tangent_vbo), bitangent_vbo(copy.bitangent_vbo), | ||||||
|  | texture_diffuse(copy.texture_diffuse), texture_ambient(copy.texture_ambient), texture_specular(copy.texture_specular),  | ||||||
|  | texture_heights(copy.texture_heights), texture_normals(copy.texture_normals), | ||||||
|  | material(copy.material) | ||||||
|  | { | ||||||
|  |     // Приведение указателя к целому 8байт
 | ||||||
|  |     id.value = (GLuint64) this; | ||||||
|  |     id.etc = copy.id.etc; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Оператор присваивания
 | ||||||
|  | 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; | ||||||
|  | 
 | ||||||
|  |     tangent_vbo = other.tangent_vbo; | ||||||
|  |     bitangent_vbo = other.bitangent_vbo; | ||||||
|  |      | ||||||
|  |     texture_diffuse = other.texture_diffuse; | ||||||
|  |     texture_ambient = other.texture_ambient; | ||||||
|  |     texture_specular = other.texture_specular; | ||||||
|  |      | ||||||
|  |     texture_heights = other.texture_heights; | ||||||
|  |     texture_normals = other.texture_normals; | ||||||
|  |      | ||||||
|  |     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)  | ||||||
|  | { | ||||||
|  |     // Загрузка идентификатора объекта
 | ||||||
|  |     glUniform3uiv(shaderProgram.getUniformLoc("ID"), 1, (GLuint*) &id); | ||||||
|  | 
 | ||||||
|  |     // Расчитаем матрицу трансформации
 | ||||||
|  |     glUniformMatrix4fv(shaderProgram.getUniformLoc("model"), 1, GL_FALSE, &this->getTransformMatrix()[0][0]); | ||||||
|  | 
 | ||||||
|  |     // Подключаем текстуры
 | ||||||
|  |     texture_diffuse.use(); | ||||||
|  |     texture_ambient.use(); | ||||||
|  |     texture_specular.use(); | ||||||
|  |     texture_heights.use(); | ||||||
|  |     texture_normals.use();     | ||||||
|  | 
 | ||||||
|  |     // Загружаем данные о материале
 | ||||||
|  |     material_buffer.load(&material, sizeof(material)); | ||||||
|  | 
 | ||||||
|  |     render(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Функция для конфигурации атрибута вершинного буфера
 | ||||||
|  | void vertex_attrib_config() | ||||||
|  | { | ||||||
|  |     // Определим спецификацию атрибута
 | ||||||
|  |     glVertexAttribPointer(  0         // индекс атрибута, должен совпадать с Layout шейдера
 | ||||||
|  |                           , 3         // количество компонент одного элемента
 | ||||||
|  |                           , GL_FLOAT  // тип
 | ||||||
|  |                           , GL_FALSE  // необходимость нормировать значения
 | ||||||
|  |                           , 0         // шаг
 | ||||||
|  |                           , (void *)0 // отступ с начала массива
 | ||||||
|  |                          ); | ||||||
|  |     // Включаем необходимый атрибут у выбранного VAO
 | ||||||
|  |     glEnableVertexAttribArray(0); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Загрузка вершин в буфер
 | ||||||
|  | void Model::load_verteces(glm::vec3* verteces, GLuint count) | ||||||
|  | { | ||||||
|  |     // Подключаем VAO и вершинный буфер
 | ||||||
|  |     vao.use(); | ||||||
|  |     vertex_vbo.use(); | ||||||
|  | 
 | ||||||
|  |     // Загрузка вершин в память буфера
 | ||||||
|  |     vertex_vbo.load(verteces, sizeof(glm::vec3)*count); | ||||||
|  |     vertex_attrib_config(); | ||||||
|  |     // Запоминаем количество вершин для отрисовки
 | ||||||
|  |     verteces_count = count; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Загрузка индексов в буфер
 | ||||||
|  | void Model::load_indices(GLuint* indices, GLuint count)  | ||||||
|  | { | ||||||
|  |     // Подключаем VAO и индексный буфер
 | ||||||
|  |     vao.use(); | ||||||
|  |     index_vbo.use(); | ||||||
|  | 
 | ||||||
|  |     // Загрузка вершин в память буфера
 | ||||||
|  |     index_vbo.load(indices, sizeof(GLuint)*count); | ||||||
|  |     // Запоминаем количество вершин для отрисовки
 | ||||||
|  |     indices_count = count; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Функция для конфигурации атрибута вершинного буфера
 | ||||||
|  | void texCoords_attrib_config() | ||||||
|  | { | ||||||
|  |     // Определим спецификацию атрибута
 | ||||||
|  |     glVertexAttribPointer(  1         // индекс атрибута, должен совпадать с Layout шейдера
 | ||||||
|  |                           , 2         // количество компонент одного элемента
 | ||||||
|  |                           , GL_FLOAT  // тип
 | ||||||
|  |                           , GL_FALSE  // необходимость нормировать значения
 | ||||||
|  |                           , 0         // шаг
 | ||||||
|  |                           , (void *)0 // отступ с начала массива
 | ||||||
|  |                          ); | ||||||
|  |     // Включаем необходимый атрибут у выбранного VAO
 | ||||||
|  |     glEnableVertexAttribArray(1); | ||||||
|  | }  | ||||||
|  | 
 | ||||||
|  | // Загрузка текстурных координат в буфер
 | ||||||
|  | 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 и привязанным VBO
 | ||||||
|  |     glVertexAttribPointer(  2         // индекс атрибута, должен совпадать с Layout шейдера
 | ||||||
|  |                           , 3         // количество компонент одного элемента
 | ||||||
|  |                           , GL_FLOAT  // тип
 | ||||||
|  |                           , GL_FALSE  // необходимость нормировать значения
 | ||||||
|  |                           , 0         // шаг
 | ||||||
|  |                           , (void *)0 // отступ с начала массива
 | ||||||
|  |                          ); | ||||||
|  |     // Включаем необходимый атрибут у выбранного VAO
 | ||||||
|  |     glEnableVertexAttribArray(2); | ||||||
|  | }  | ||||||
|  | 
 | ||||||
|  | // Загрузка нормалей в буфер
 | ||||||
|  | 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; | ||||||
|  |         case TEX_HEIGHTS: | ||||||
|  |             texture_heights = texture; | ||||||
|  |             break; | ||||||
|  |         case TEX_NORMAL: | ||||||
|  |             texture_normals = texture; | ||||||
|  |             break; | ||||||
|  |     }; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Функция для конфигурации атрибута вершинного буфера
 | ||||||
|  | void tangent_attrib_config() | ||||||
|  | { | ||||||
|  |     // Определим спецификацию атрибута
 | ||||||
|  |     glVertexAttribPointer(  3         // индекс атрибута, должен совпадать с Layout шейдера
 | ||||||
|  |                           , 3         // количество компонент одного элемента
 | ||||||
|  |                           , GL_FLOAT  // тип
 | ||||||
|  |                           , GL_FALSE  // необходимость нормировать значения
 | ||||||
|  |                           , 0         // шаг
 | ||||||
|  |                           , (void *)0 // отступ с начала массива
 | ||||||
|  |                          ); | ||||||
|  |     // Включаем необходимый атрибут у выбранного VAO
 | ||||||
|  |     glEnableVertexAttribArray(3); | ||||||
|  | }  | ||||||
|  | 
 | ||||||
|  | // Функция для конфигурации атрибута вершинного буфера
 | ||||||
|  | void bitangent_attrib_config() | ||||||
|  | { | ||||||
|  |     // Определим спецификацию атрибута
 | ||||||
|  |     glVertexAttribPointer(  4         // индекс атрибута, должен совпадать с Layout шейдера
 | ||||||
|  |                           , 3         // количество компонент одного элемента
 | ||||||
|  |                           , GL_FLOAT  // тип
 | ||||||
|  |                           , GL_FALSE  // необходимость нормировать значения
 | ||||||
|  |                           , 0         // шаг
 | ||||||
|  |                           , (void *)0 // отступ с начала массива
 | ||||||
|  |                          ); | ||||||
|  |     // Включаем необходимый атрибут у выбранного VAO
 | ||||||
|  |     glEnableVertexAttribArray(4); | ||||||
|  | }  | ||||||
|  | 
 | ||||||
|  | // Загрузка касательных векторов в буфер
 | ||||||
|  | void Model::load_tangent(glm::vec3* tangent, GLuint count)  | ||||||
|  | { | ||||||
|  |     // Подключаем VAO
 | ||||||
|  |     vao.use(); | ||||||
|  | 
 | ||||||
|  |     tangent_vbo.use(); | ||||||
|  | 
 | ||||||
|  |     // Загрузка вершин в память буфера
 | ||||||
|  |     tangent_vbo.load(tangent, sizeof(glm::vec3)*count); | ||||||
|  |     tangent_attrib_config(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Загрузка бикасательных векторов в буфер
 | ||||||
|  | void Model::load_bitangent(glm::vec3* bitangent, GLuint count)  | ||||||
|  | { | ||||||
|  |     // Подключаем VAO
 | ||||||
|  |     vao.use(); | ||||||
|  | 
 | ||||||
|  |     bitangent_vbo.use(); | ||||||
|  | 
 | ||||||
|  |     // Загрузка вершин в память буфера
 | ||||||
|  |     bitangent_vbo.load(bitangent, sizeof(glm::vec3)*count); | ||||||
|  |     bitangent_attrib_config(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Генерирует сферу заданного радиуса с определенным количеством сегментов
 | ||||||
|  | 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; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Расчет касательных и бикасательных векторов
 | ||||||
|  | void calc_tb(const GLuint* indices, const int indices_count, const glm::vec3* verteces, const glm::vec2* texCords, glm::vec3* tangent, glm::vec3* bitangent) | ||||||
|  | { | ||||||
|  |     glm::vec2 dTex1, dTex2; // Разница по текстурным координатам
 | ||||||
|  |     glm::vec3 dPos1, dPos2; // Разница по координатам вершин
 | ||||||
|  |     float f; // Разность произведений
 | ||||||
|  |     glm::vec3 tmp; // Для вычислений вектора
 | ||||||
|  | 
 | ||||||
|  |     for (int i = 0; i < indices_count; i+=3) | ||||||
|  |     { | ||||||
|  |         // Разности векторов
 | ||||||
|  |         dTex1 = texCords[indices[i+1]] - texCords[indices[i]]; | ||||||
|  |         dTex2 = texCords[indices[i+2]] - texCords[indices[i]]; | ||||||
|  |         dPos1 = verteces[indices[i+1]] - verteces[indices[i]]; | ||||||
|  |         dPos2 = verteces[indices[i+2]] - verteces[indices[i]]; | ||||||
|  |         f = dTex1.x * dTex2.y - dTex2.x * dTex1.y; | ||||||
|  |          | ||||||
|  |         // Покомпонентное вычисление касательного вектора
 | ||||||
|  |         tmp.x = (dTex2.y * dPos1.x - dTex1.y * dPos2.x) / f; | ||||||
|  |         tmp.y = (dTex2.y * dPos1.y - dTex1.y * dPos2.y) / f; | ||||||
|  |         tmp.z = (dTex2.y * dPos1.z - dTex1.y * dPos2.z) / f; | ||||||
|  |         // Нормируем значение
 | ||||||
|  |         tmp = glm::normalize(tmp); | ||||||
|  |         // Добавим вектор в контейнер        
 | ||||||
|  |         tangent[indices[i  ]] = tmp; // Для каждого индекса полигона
 | ||||||
|  |         tangent[indices[i+1]] = tmp; // значение вектора
 | ||||||
|  |         tangent[indices[i+2]] = tmp; // одинаковое
 | ||||||
|  | 
 | ||||||
|  |         // Покомпонентное вычисление бикасательного вектора
 | ||||||
|  |         tmp.x = (-dTex2.x * dPos1.x + dTex1.x * dPos2.x) / f; | ||||||
|  |         tmp.y = (-dTex2.x * dPos1.y + dTex1.x * dPos2.y) / f; | ||||||
|  |         tmp.z = (-dTex2.x * dPos1.z + dTex1.x * dPos2.z) / f; | ||||||
|  |         // Нормируем значение
 | ||||||
|  |         tmp = glm::normalize(tmp); | ||||||
|  |         // Добавим вектор в контейнер        
 | ||||||
|  |         bitangent[indices[i  ]] = tmp; // Для каждого индекса полигона
 | ||||||
|  |         bitangent[indices[i+1]] = tmp; // значение вектора
 | ||||||
|  |         bitangent[indices[i+2]] = tmp; // одинаковое
 | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										249
									
								
								src/Scene.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										249
									
								
								src/Scene.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,249 @@ | |||||||
|  | #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; | ||||||
|  | 
 | ||||||
|  |     // Значение гамма-коррекции
 | ||||||
|  |     extern float inv_gamma; | ||||||
|  | 
 | ||||||
|  |     // Если в процессе загрузки возникли ошибки - выдадим исключение
 | ||||||
|  |     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; // текстурные координаты
 | ||||||
|  |     std::vector<glm::vec3> tangent, bitangent; // касательный и бикасательный веткоры
 | ||||||
|  |     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) 
 | ||||||
|  | 
 | ||||||
|  |     // Изменим размер массивов
 | ||||||
|  |     tangent.resize(verteces.size()); | ||||||
|  |     bitangent.resize(verteces.size()); | ||||||
|  |     // Расчет касательных и бикасательных векторов
 | ||||||
|  |     calc_tb(indices.data(), indices.size(), verteces.data(), texCords.data(), tangent.data(), bitangent.data()); | ||||||
|  | 
 | ||||||
|  |     // Загрузка в буферы
 | ||||||
|  |     model.load_verteces (&verteces[0], verteces.size()); | ||||||
|  |     model.load_normals  (&normals[0],  normals.size()); | ||||||
|  |     model.load_texCoords(&texCords[0], texCords.size()); | ||||||
|  |     model.load_tangent(&tangent[0], tangent.size()); | ||||||
|  |     model.load_bitangent(&bitangent[0], bitangent.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); | ||||||
|  |         Texture normal(TEX_NORMAL, texture_directory + materials[materials_ids[i]].normal_texname); | ||||||
|  |         s->set_texture(normal); | ||||||
|  |         Texture heights(TEX_HEIGHTS, texture_directory + materials[materials_ids[i]].bump_texname); | ||||||
|  |         s->set_texture(heights); | ||||||
|  | 
 | ||||||
|  |         // Материал
 | ||||||
|  |         s->material.ka = pow(glm::vec3(materials[materials_ids[i]].ambient[0],  materials[materials_ids[i]].ambient[1],  materials[materials_ids[i]].ambient[2]), glm::vec3(1/inv_gamma)); | ||||||
|  |         s->material.kd = pow(glm::vec3(materials[materials_ids[i]].diffuse[0],  materials[materials_ids[i]].diffuse[1],  materials[materials_ids[i]].diffuse[2]), glm::vec3(1/inv_gamma)); | ||||||
|  |         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; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Изменение флага записи идентификатора для всех моделей
 | ||||||
|  | void Scene::set_group_id(GLuint64 id, GLuint etc) | ||||||
|  | { | ||||||
|  |     for (auto& model : models)  | ||||||
|  |     { | ||||||
|  |         model.id.value = id; | ||||||
|  |         if (etc) | ||||||
|  |             model.id.etc = etc; | ||||||
|  |     } | ||||||
|  | } | ||||||
							
								
								
									
										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); | ||||||
|  | } | ||||||
							
								
								
									
										187
									
								
								src/TRS.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										187
									
								
								src/TRS.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,187 @@ | |||||||
|  | #include "TRS.h" | ||||||
|  | #include <GLM/gtx/matrix_decompose.hpp> | ||||||
|  | 
 | ||||||
|  | // Инициализирует дополнительную информацию модели
 | ||||||
|  | void TRS::init_etc() | ||||||
|  | { | ||||||
|  |     int value = 1; | ||||||
|  |     for (auto it = tool.models.begin(); it != tool.models.end(); ++it) | ||||||
|  |         it->id.etc = value++; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Рендер инструмента нужного типа для выбранного объекта
 | ||||||
|  | void TRS::render(GLuint64 selectedID, ShaderProgram &shaderProgram, UBO &material_buffer) | ||||||
|  | { | ||||||
|  |     // Если есть выбранная модель - рендерим инструмент для неё
 | ||||||
|  |     if (selectedID) | ||||||
|  |     { | ||||||
|  |         // Указатель на объект
 | ||||||
|  |         Node* selectedObject = (Node*) selectedID; | ||||||
|  | 
 | ||||||
|  |         // Смещение выбранного объекта в глобальных координатах из его матрицы трансформации (включая родительские)
 | ||||||
|  |         tool.root.e_position() = glm::vec3(selectedObject->getTransformMatrix()[3]); | ||||||
|  | 
 | ||||||
|  |         // Замена идентификатора инструмента идентификатором выбранного объекта
 | ||||||
|  |         tool.set_group_id(selectedID); // без замены доп. информации
 | ||||||
|  | 
 | ||||||
|  |         // Рендер инструмента
 | ||||||
|  |         tool.render(shaderProgram, material_buffer); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Transform::Transform()  | ||||||
|  | { | ||||||
|  |     tool = loadOBJtoScene("../resources/models/tools/transform.obj", "../resources/models/tools/", "../resources/textures/"); | ||||||
|  |      | ||||||
|  |     // Масштабирование
 | ||||||
|  |     tool.root.e_scale() = glm::vec3(0.3); | ||||||
|  |      | ||||||
|  |     // Инициализация дополнительной информации
 | ||||||
|  |     init_etc(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Взаимодействие с инструментом
 | ||||||
|  | void Transform::process(GLuint64 selectedID, GLuint etc, const glm::vec4& dpos) | ||||||
|  | { | ||||||
|  |     // Если взаимодействие с осями инструмента
 | ||||||
|  |     if (etc > 0) | ||||||
|  |         // Если есть выбранная модель - рендерим инструмент для неё
 | ||||||
|  |         if (selectedID) | ||||||
|  |         { | ||||||
|  |             // Указатель на объект
 | ||||||
|  |             Node* selectedObject = (Node*) selectedID; | ||||||
|  | 
 | ||||||
|  |             glm::vec3 dVec(0.0f, 0.0f, 0.0f); | ||||||
|  | 
 | ||||||
|  |             // Сдвиг с учетом чувствительности для соответствующих осей
 | ||||||
|  |             if (etc & 01) | ||||||
|  |                 dVec.x = dpos.x * T_SENSITIVITY; | ||||||
|  |             if (etc & 02) | ||||||
|  |                 dVec.y = dpos.y * T_SENSITIVITY; | ||||||
|  |             if (etc & 04) | ||||||
|  |                 dVec.z = dpos.z * T_SENSITIVITY;       | ||||||
|  |              | ||||||
|  |             // Если есть родитель - требуется учесть его поворот
 | ||||||
|  |             Node* parent = selectedObject->getParent(); | ||||||
|  |             if (parent) | ||||||
|  |             { | ||||||
|  |                 // Извлекаем 3x3 подматрицу, отвечающую за вращение и масштаб
 | ||||||
|  |                 glm::mat3 rotationMatrix = glm::mat3(parent->getTransformMatrix()); | ||||||
|  | 
 | ||||||
|  |                 // Нормализуем столбцы подматрицы, чтобы исключить масштабирование
 | ||||||
|  |                 for (int i = 0; i < 3; i++)  | ||||||
|  |                     rotationMatrix[i] = glm::normalize(rotationMatrix[i]); | ||||||
|  | 
 | ||||||
|  |                 // Применим поворот родителя к вектору сдвига
 | ||||||
|  |                 dVec = glm::inverse(rotationMatrix) * dVec; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             // Добавим сдвиг от инструмента к позиции выбранного объекта
 | ||||||
|  |             selectedObject->e_position() += dVec; | ||||||
|  |         } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Rotate::Rotate()  | ||||||
|  | { | ||||||
|  |     tool = loadOBJtoScene("../resources/models/tools/rotate.obj", "../resources/models/tools/", "../resources/textures/"); | ||||||
|  |          | ||||||
|  |     // Масштабирование
 | ||||||
|  |     tool.root.e_scale() = glm::vec3(0.3); | ||||||
|  | 
 | ||||||
|  |     int value = 1; | ||||||
|  |     for (auto it = tool.models.begin(); it != tool.models.end(); ++it) | ||||||
|  |     { | ||||||
|  |         it->id.etc = value; | ||||||
|  |         value *= 2; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Взаимодействие с инструментом
 | ||||||
|  | void Rotate::process(GLuint64 selectedID, GLuint etc, const glm::vec4& drot) | ||||||
|  | { | ||||||
|  |     // Если взаимодействие с осями инструмента
 | ||||||
|  |     if (etc > 0) | ||||||
|  |         // Если есть выбранная модель - рендерим инструмент для неё
 | ||||||
|  |         if (selectedID) | ||||||
|  |         { | ||||||
|  |             // Указатель на объект
 | ||||||
|  |             Node* selectedObject = (Node*) selectedID; | ||||||
|  |             glm::quat &selectedRot = selectedObject->e_rotation(); | ||||||
|  | 
 | ||||||
|  |             // Матрица родительского поворота            
 | ||||||
|  |             glm::mat3 parentRotation(1); | ||||||
|  | 
 | ||||||
|  |             // Учет родительского поворота для вращения
 | ||||||
|  |             Node* parent = selectedObject->getParent(); | ||||||
|  |             if (parent) | ||||||
|  |             { | ||||||
|  |                 // Извлекаем 3x3 подматрицу, отвечающую за вращение и масштаб
 | ||||||
|  |                 parentRotation = glm::mat3(parent->getTransformMatrix()); | ||||||
|  | 
 | ||||||
|  |                 // Нормализуем столбцы подматрицы, чтобы исключить масштабирование
 | ||||||
|  |                 for (int i = 0; i < 3; i++)  | ||||||
|  |                     parentRotation[i] = glm::normalize(parentRotation[i]); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             // Поворот по осям
 | ||||||
|  |             if (etc & 01) | ||||||
|  |                 selectedRot = glm::angleAxis(drot.y * R_SENSITIVITY, parentRotation * glm::vec3(1.0f, 0.0f, 0.0f)) * selectedRot; | ||||||
|  |             if (etc & 02) | ||||||
|  |                 selectedRot = glm::angleAxis(drot.x * R_SENSITIVITY, parentRotation * glm::vec3(0.0f, 1.0f, 0.0f)) * selectedRot; | ||||||
|  |             if (etc & 04) | ||||||
|  |                 selectedRot = glm::angleAxis(drot.z * R_SENSITIVITY, parentRotation * glm::vec3(0.0f, 0.0f, 1.0f)) * selectedRot; | ||||||
|  |         } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Scale::Scale()  | ||||||
|  | { | ||||||
|  |     tool = loadOBJtoScene("../resources/models/tools/scale.obj", "../resources/models/tools/", "../resources/textures/"); | ||||||
|  |      | ||||||
|  |     // Масштабирование
 | ||||||
|  |     tool.root.e_scale() = glm::vec3(0.3); | ||||||
|  | 
 | ||||||
|  |     // Инициализация дополнительной информации
 | ||||||
|  |     init_etc(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Взаимодействие с инструментом
 | ||||||
|  | void Scale::process(GLuint64 selectedID, GLuint etc, const glm::vec4& dscale) | ||||||
|  | { | ||||||
|  |     // Если взаимодействие с осями инструмента
 | ||||||
|  |     if (etc > 0) | ||||||
|  |         // Если есть выбранная модель - рендерим инструмент для неё
 | ||||||
|  |         if (selectedID) | ||||||
|  |         { | ||||||
|  |             // Указатель на объект
 | ||||||
|  |             Node* selectedObject = (Node*) selectedID; | ||||||
|  | 
 | ||||||
|  |             // Для хранения результата
 | ||||||
|  |             glm::vec3 dVec(0); | ||||||
|  | 
 | ||||||
|  |             // Масштабирование с учетом чувствительности для соответствующих осей
 | ||||||
|  |             if (etc & 01) | ||||||
|  |                 dVec.x = dscale.x * S_SENSITIVITY; | ||||||
|  |             if (etc & 02) | ||||||
|  |                 dVec.y = dscale.y * S_SENSITIVITY; | ||||||
|  |             if (etc & 04) | ||||||
|  |                 dVec.z = dscale.z * S_SENSITIVITY;     | ||||||
|  | 
 | ||||||
|  |             // Если есть родитель - требуется учесть его поворот
 | ||||||
|  |             Node* parent = selectedObject->getParent(); | ||||||
|  |             if (parent) | ||||||
|  |             { | ||||||
|  |                 // Извлекаем 3x3 подматрицу, отвечающую за вращение и масштаб
 | ||||||
|  |                 glm::mat3 rotationMatrix = glm::mat3(parent->getTransformMatrix()); | ||||||
|  | 
 | ||||||
|  |                 // Нормализуем столбцы подматрицы, чтобы исключить масштабирование
 | ||||||
|  |                 for (int i = 0; i < 3; i++)  | ||||||
|  |                     rotationMatrix[i] = glm::normalize(rotationMatrix[i]); | ||||||
|  | 
 | ||||||
|  |                 // Применим поворот родителя к вектору сдвига
 | ||||||
|  |                 dVec = glm::inverse(rotationMatrix) * dVec; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             // Прибавим вектор масштабирования к объекту
 | ||||||
|  |             selectedObject->e_scale() += dVec;    | ||||||
|  |         } | ||||||
|  | } | ||||||
							
								
								
									
										420
									
								
								src/Texture.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										420
									
								
								src/Texture.cpp
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,420 @@ | |||||||
|  | #include "Texture.h" | ||||||
|  | 
 | ||||||
|  | #define STB_IMAGE_IMPLEMENTATION | ||||||
|  | #include <stb_image.h> | ||||||
|  | 
 | ||||||
|  | std::map<std::string, int> BaseTexture::filename_handler; // Получение дескриптора текстуры по её имени
 | ||||||
|  | std::map<int, int> BaseTexture::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) | ||||||
|  |             { | ||||||
|  |                 // Выбор формата с учетом типа текстуры (нормали не sRGB) и числа каналов
 | ||||||
|  |                 GLuint internalformat = GL_RGB, format = GL_RGB;  | ||||||
|  |                 switch (channels) | ||||||
|  |                 { | ||||||
|  |                     case 1: | ||||||
|  |                         internalformat = format = GL_RED; | ||||||
|  |                         break; | ||||||
|  |                     case 2: | ||||||
|  |                         internalformat = format = GL_RG; | ||||||
|  |                         break; | ||||||
|  |                     case 3: | ||||||
|  |                         format = GL_RGB; | ||||||
|  |                         if (type == TEX_NORMAL || type == TEX_HEIGHTS) | ||||||
|  |                             internalformat = GL_RGB; | ||||||
|  |                         else | ||||||
|  |                             internalformat = GL_SRGB; | ||||||
|  |                         break; | ||||||
|  |                     case 4: | ||||||
|  |                         format = GL_RGBA; | ||||||
|  |                         if (type == TEX_NORMAL || type == TEX_HEIGHTS) | ||||||
|  |                             internalformat = GL_RGBA; | ||||||
|  |                         else | ||||||
|  |                             internalformat = GL_SRGB_ALPHA; | ||||||
|  |                         break; | ||||||
|  | 
 | ||||||
|  |                 } | ||||||
|  |                 // Загрузка данных с учетом формата
 | ||||||
|  |                 glTexImage2D(GL_TEXTURE_2D, 0, internalformat, width, height, 0, format, 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(GLuint width, GLuint height, void* data, 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, data); | ||||||
|  |     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | ||||||
|  |     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | ||||||
|  | 
 | ||||||
|  |     // Создаем счетчик использований дескриптора
 | ||||||
|  |     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; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | BaseTexture::~BaseTexture() | ||||||
|  | { | ||||||
|  |     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 BaseTexture::disable(GLuint type) | ||||||
|  | { | ||||||
|  |     glActiveTexture(type + GL_TEXTURE0); | ||||||
|  |     glBindTexture(GL_TEXTURE_2D, 0); // Отвязка текстуры
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Возвращает тип текстуры
 | ||||||
|  | GLuint BaseTexture::getType() | ||||||
|  | { | ||||||
|  |     return type; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Задает тип текстуры
 | ||||||
|  | void BaseTexture::setType(GLuint type) | ||||||
|  | { | ||||||
|  |     this->type = type; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Конструктор текстуры заданного размера для использования в буфере
 | ||||||
|  | TextureArray::TextureArray(GLuint levels, GLuint width, GLuint height, GLuint attachment, GLuint texType, GLint internalformat, GLint format, GLenum dataType) | ||||||
|  | { | ||||||
|  |     type = texType; | ||||||
|  |     // Генерация текстуры заданного размера
 | ||||||
|  |     glGenTextures(1, &handler); | ||||||
|  |     glBindTexture(GL_TEXTURE_2D_ARRAY, handler); | ||||||
|  |     glTexImage3D( | ||||||
|  |         GL_TEXTURE_2D_ARRAY, 0, internalformat, width, height, levels, 0, format, dataType, 0); | ||||||
|  | 
 | ||||||
|  |     glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | ||||||
|  |     glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | ||||||
|  | 
 | ||||||
|  |     // Привязка к буферу кадра
 | ||||||
|  |     glFramebufferTexture(GL_FRAMEBUFFER, attachment, handler, 0); | ||||||
|  | 
 | ||||||
|  |     // Создаем счетчик использований дескриптора
 | ||||||
|  |     handler_count[handler] = 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Конструктор копирования
 | ||||||
|  | TextureArray::TextureArray(const TextureArray& other) | ||||||
|  | { | ||||||
|  |     handler = other.handler;  | ||||||
|  |     type = other.type; | ||||||
|  |     // Делаем копию и увеличиваем счетчик
 | ||||||
|  |     handler_count[handler]++; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Оператор присваивания
 | ||||||
|  | TextureArray& TextureArray::operator=(const TextureArray& other) | ||||||
|  | { | ||||||
|  |     // Если это разные текстуры
 | ||||||
|  |     if (handler != other.handler) | ||||||
|  |     { | ||||||
|  |         this->~TextureArray(); // Уничтожаем имеющуюся
 | ||||||
|  |         // Заменяем новой
 | ||||||
|  |         handler = other.handler; | ||||||
|  |         handler_count[handler]++; | ||||||
|  |     } | ||||||
|  |     type = other.type; | ||||||
|  | 
 | ||||||
|  |     return *this; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Привязка текстуры
 | ||||||
|  | void TextureArray::use() | ||||||
|  | { | ||||||
|  |     glActiveTexture(type + GL_TEXTURE0); | ||||||
|  |     glBindTexture(GL_TEXTURE_2D_ARRAY, handler); // Привязка текстуры как активной
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Загрузка текстуры с диска или использование "пустой"
 | ||||||
|  | TextureCube::TextureCube(GLuint t, const std::string (&filename)[6]) | ||||||
|  | { | ||||||
|  |     type = t; | ||||||
|  |     std::string complex_name; | ||||||
|  |     for (int i = 0; i < 6; i++) | ||||||
|  |         complex_name += filename[i]; | ||||||
|  |     if (!filename_handler.count(complex_name)) | ||||||
|  |     { | ||||||
|  |         std::string empty = ""; | ||||||
|  |         int width, height, channels; // Ширина, высота и цветовые каналы текстуры
 | ||||||
|  |         unsigned char* image; | ||||||
|  | 
 | ||||||
|  |         glActiveTexture(type + GL_TEXTURE0); | ||||||
|  |         glGenTextures(1, &handler); // Генерация одной текстуры
 | ||||||
|  |         glBindTexture(GL_TEXTURE_CUBE_MAP, handler); // Привязка текстуры как активной
 | ||||||
|  | 
 | ||||||
|  |         filename_handler[complex_name] = handler; // Запомним её дескриптор для этого имени файла
 | ||||||
|  |         handler_count[handler] = 0; // Создадим счетчик использований дескриптора, который будет изменен в конце
 | ||||||
|  | 
 | ||||||
|  |         for (int i = 0; i < 6; i++)  | ||||||
|  |         { | ||||||
|  |             image = stbi_load(filename[i].c_str(), &width, &height, &channels, STBI_default); // Загрузка в оперативную память изображения
 | ||||||
|  | 
 | ||||||
|  |             // Если изображение успешно считано
 | ||||||
|  |             if (image) | ||||||
|  |             { | ||||||
|  |                 // Выбор формата с учетом типа текстуры (нормали не sRGB) и числа каналов
 | ||||||
|  |                 GLuint internalformat = GL_RGB, format = GL_RGB;  | ||||||
|  |                 switch (channels) | ||||||
|  |                 { | ||||||
|  |                     case 1: | ||||||
|  |                         internalformat = format = GL_RED; | ||||||
|  |                         break; | ||||||
|  |                     case 2: | ||||||
|  |                         internalformat = format = GL_RG; | ||||||
|  |                         break; | ||||||
|  |                     case 3: | ||||||
|  |                         format = GL_RGB; | ||||||
|  |                         if (type == TEX_NORMAL || type == TEX_HEIGHTS) | ||||||
|  |                             internalformat = GL_RGB; | ||||||
|  |                         else | ||||||
|  |                             internalformat = GL_SRGB; | ||||||
|  |                         break; | ||||||
|  |                     case 4: | ||||||
|  |                         format = GL_RGBA; | ||||||
|  |                         if (type == TEX_NORMAL || type == TEX_HEIGHTS) | ||||||
|  |                             internalformat = GL_RGBA; | ||||||
|  |                         else | ||||||
|  |                             internalformat = GL_SRGB_ALPHA; | ||||||
|  |                         break; | ||||||
|  | 
 | ||||||
|  |                 } | ||||||
|  |                 // Загрузка данных с учетом формата
 | ||||||
|  |                 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, internalformat, width, height, 0, format, GL_UNSIGNED_BYTE, image); | ||||||
|  | 
 | ||||||
|  |                 stbi_image_free(image); // Освобождение оперативной памяти
 | ||||||
|  |             } | ||||||
|  |             // Иначе изображение не считано и надо создать пустую текстуру
 | ||||||
|  |             else | ||||||
|  |             { | ||||||
|  |                 image = new unsigned char[3] {255,255,255}; // RGB по 1 байту на 
 | ||||||
|  |                 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, image); // Загрузка данных на видеокарту
 | ||||||
|  |                 delete[] image; // Освобождение оперативной памяти
 | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     // Иначе используем уже существующую по имени файла
 | ||||||
|  |     else | ||||||
|  |         handler = filename_handler[complex_name]; | ||||||
|  | 
 | ||||||
|  |     glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | ||||||
|  |     glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | ||||||
|  |     glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | ||||||
|  |     glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | ||||||
|  |     glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); | ||||||
|  | 
 | ||||||
|  |     handler_count[handler]++; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Конструктор текстуры заданного размера для использования в буфере
 | ||||||
|  | TextureCube::TextureCube(GLuint width, GLuint height, GLuint attachment, GLuint texType, GLint internalformat, GLint format, GLenum dataType) | ||||||
|  | { | ||||||
|  |     type = texType; | ||||||
|  |     // Генерация текстуры заданного размера
 | ||||||
|  |     glGenTextures(1, &handler); | ||||||
|  |     glBindTexture(GL_TEXTURE_CUBE_MAP, handler); | ||||||
|  |     for (int i = 0; i < 6; ++i) | ||||||
|  |         glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, internalformat, width, height, 0, format, dataType, 0);   | ||||||
|  | 
 | ||||||
|  |     glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | ||||||
|  |     glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | ||||||
|  | 
 | ||||||
|  |     // Привязка к буферу кадра
 | ||||||
|  |     glFramebufferTexture(GL_FRAMEBUFFER, attachment, handler, 0); | ||||||
|  | 
 | ||||||
|  |     // Создаем счетчик использований дескриптора
 | ||||||
|  |     handler_count[handler] = 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Конструктор копирования
 | ||||||
|  | TextureCube::TextureCube(const TextureCube& other) | ||||||
|  | { | ||||||
|  |     handler = other.handler;  | ||||||
|  |     type = other.type; | ||||||
|  |     // Делаем копию и увеличиваем счетчик
 | ||||||
|  |     handler_count[handler]++; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Оператор присваивания
 | ||||||
|  | TextureCube& TextureCube::operator=(const TextureCube& other) | ||||||
|  | { | ||||||
|  |     // Если это разные текстуры
 | ||||||
|  |     if (handler != other.handler) | ||||||
|  |     { | ||||||
|  |         this->~TextureCube(); // Уничтожаем имеющуюся
 | ||||||
|  |         // Заменяем новой
 | ||||||
|  |         handler = other.handler; | ||||||
|  |         handler_count[handler]++; | ||||||
|  |     } | ||||||
|  |     type = other.type; | ||||||
|  | 
 | ||||||
|  |     return *this; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Привязка текстуры
 | ||||||
|  | void TextureCube::use() | ||||||
|  | { | ||||||
|  |     glActiveTexture(type + GL_TEXTURE0); | ||||||
|  |     glBindTexture(GL_TEXTURE_CUBE_MAP, handler); // Привязка текстуры как активной
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Конструктор текстуры заданного размера для использования в буфере
 | ||||||
|  | TextureCubeArray::TextureCubeArray(GLuint levels, GLuint width, GLuint height, GLuint attachment, GLuint texType, GLint internalformat, GLint format, GLenum dataType) | ||||||
|  | { | ||||||
|  |     type = texType; | ||||||
|  |     // Генерация текстуры заданного размера
 | ||||||
|  |     glGenTextures(1, &handler); | ||||||
|  |     glBindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, handler); | ||||||
|  |     glTexImage3D( | ||||||
|  |         GL_TEXTURE_CUBE_MAP_ARRAY, 0, internalformat, width, height, 6*levels, 0, format, dataType, 0); | ||||||
|  | 
 | ||||||
|  |     glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | ||||||
|  |     glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | ||||||
|  | 
 | ||||||
|  |     // Привязка к буферу кадра
 | ||||||
|  |     glFramebufferTexture(GL_FRAMEBUFFER, attachment, handler, 0); | ||||||
|  | 
 | ||||||
|  |     // Создаем счетчик использований дескриптора
 | ||||||
|  |     handler_count[handler] = 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Конструктор копирования
 | ||||||
|  | TextureCubeArray::TextureCubeArray(const TextureCubeArray& other) | ||||||
|  | { | ||||||
|  |     handler = other.handler;  | ||||||
|  |     type = other.type; | ||||||
|  |     // Делаем копию и увеличиваем счетчик
 | ||||||
|  |     handler_count[handler]++; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Оператор присваивания
 | ||||||
|  | TextureCubeArray& TextureCubeArray::operator=(const TextureCubeArray& other) | ||||||
|  | { | ||||||
|  |     // Если это разные текстуры
 | ||||||
|  |     if (handler != other.handler) | ||||||
|  |     { | ||||||
|  |         this->~TextureCubeArray(); // Уничтожаем имеющуюся
 | ||||||
|  |         // Заменяем новой
 | ||||||
|  |         handler = other.handler; | ||||||
|  |         handler_count[handler]++; | ||||||
|  |     } | ||||||
|  |     type = other.type; | ||||||
|  | 
 | ||||||
|  |     return *this; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Привязка текстуры
 | ||||||
|  | void TextureCubeArray::use() | ||||||
|  | { | ||||||
|  |     glActiveTexture(type + GL_TEXTURE0); | ||||||
|  |     glBindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, handler); // Привязка текстуры как активной
 | ||||||
|  | } | ||||||
							
								
								
									
										561
									
								
								src/main.cpp
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										561
									
								
								src/main.cpp
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,561 @@ | |||||||
|  | 
 | ||||||
|  | #include <glad/glad.h> | ||||||
|  | #include <GLFW/glfw3.h> | ||||||
|  | #include <GLM/glm.hpp> | ||||||
|  | 
 | ||||||
|  | #include <iostream> | ||||||
|  | #include <random> | ||||||
|  | 
 | ||||||
|  | #include "Scene.h" | ||||||
|  | #include "Shader.h" | ||||||
|  | #include "Lights.h" | ||||||
|  | #include "TRS.h" | ||||||
|  | 
 | ||||||
|  | #define WINDOW_WIDTH 800 | ||||||
|  | #define WINDOW_HEIGHT 600 | ||||||
|  | #define WINDOW_CAPTION "OPENGL notes on rekovalev.site" | ||||||
|  | 
 | ||||||
|  | // Значение гамма-коррекции
 | ||||||
|  | float inv_gamma = 1/2.2; | ||||||
|  | 
 | ||||||
|  | // Функция-callback для изменения размеров буфера кадра в случае изменения размеров поверхности окна
 | ||||||
|  | void framebuffer_size_callback(GLFWwindow* window, int width, int height) | ||||||
|  | { | ||||||
|  |     glViewport(0, 0, width, height); | ||||||
|  | } | ||||||
|  |   | ||||||
|  | // Данные о мыши
 | ||||||
|  | struct Mouse | ||||||
|  | { | ||||||
|  |     float x = 0, y = 0; // Координаты курсора
 | ||||||
|  |     float prev_x = 0, prev_y = 0; // Координаты курсора на предыдущем кадре
 | ||||||
|  |     uint16_t left = 040100, right = 040100; // Состояние кнопок
 | ||||||
|  | } mouse;  | ||||||
|  | 
 | ||||||
|  | void process_mouse_button(uint16_t& button) | ||||||
|  | { | ||||||
|  |     if ((++button & 037777) == 037777) | ||||||
|  |         button &= 0140100; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void mouse_callback(GLFWwindow* window, double xpos, double ypos) | ||||||
|  | {  | ||||||
|  |     mouse.x = xpos; | ||||||
|  |     mouse.y = ypos; | ||||||
|  | }   | ||||||
|  | 
 | ||||||
|  | void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) | ||||||
|  | { | ||||||
|  |     uint16_t& mouse_button = (button == GLFW_MOUSE_BUTTON_LEFT)?mouse.left:mouse.right; | ||||||
|  |      | ||||||
|  |     if (action == GLFW_PRESS && !(mouse_button & 0100000)) | ||||||
|  |         mouse_button = 0100000; | ||||||
|  |     else if (action == GLFW_RELEASE) | ||||||
|  |         mouse_button = 040000; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 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); | ||||||
|  |     glfwSetMouseButtonCallback(window, mouse_button_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", "tex_heights", "tex_normal"}; | ||||||
|  |     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.05,0.05,0.05}; | ||||||
|  |     scene.set_group_id((GLuint64) &scene); | ||||||
|  |      | ||||||
|  |     // Установка цвета очистки буфера цвета
 | ||||||
|  |     glClearColor(0.0f, 0.0f, 0.0f, 1.0f); | ||||||
|  | 
 | ||||||
|  |     // Сдвинем направленный источник света и камеру
 | ||||||
|  |     Sun::get().e_direction().z = -1.0; | ||||||
|  |     Camera::current().e_position().x = 0.3f; | ||||||
|  | 
 | ||||||
|  |     // Источники света
 | ||||||
|  |     Light& first = Light::getNew(); | ||||||
|  |     first.e_color() = {1.0f, 0.0f, 0.0f}; // цвет
 | ||||||
|  |     first.e_position() = {0.3f, 0.0f, 0.6f}; // Позиция
 | ||||||
|  |     first.e_angle() = 100.0f; | ||||||
|  |     Light& second = Light::getNew(); | ||||||
|  |     second.e_color() = {0.0f, 0.0f, 1.0f}; // цвет
 | ||||||
|  |     second.e_position() = {-0.3f, 0.3f, 0.5f}; // Позиция
 | ||||||
|  | 
 | ||||||
|  |     // Uniform-буферы
 | ||||||
|  |     UBO cameraUB(sizeof(CameraData), 0); | ||||||
|  |     UBO material_data(sizeof(Material), 1); | ||||||
|  |     UBO light_data(Light::getUBOsize(), 2); | ||||||
|  |     UBO sun_data(sizeof(Sun), 3); | ||||||
|  | 
 | ||||||
|  |     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, GL_COLOR_ATTACHMENT4 }; | ||||||
|  |     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); // Фоновая составляющая и один канал зеркальной
 | ||||||
|  |     Texture gID(WINDOW_WIDTH, WINDOW_HEIGHT, GL_COLOR_ATTACHMENT4, 7, GL_RGB32UI, GL_RGB_INTEGER, GL_UNSIGNED_INT); // Идентификатор объекта
 | ||||||
|  |     // Создадим буфер рендера под буфер глубины и привяжем его
 | ||||||
|  |     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", "sunShadowDepth", "pointShadowDepth", "ssao", "gID"}; | ||||||
|  |     lightShader.bindTextures(gtextures_shader_names, sizeof(gtextures_shader_names)/sizeof(const char*)); | ||||||
|  |     // Загрузка данных о границах каскадов
 | ||||||
|  |     glUniform1fv(lightShader.getUniformLoc("camera_cascade_distances"), CAMERA_CASCADE_COUNT, &camera_cascade_distances[1]); | ||||||
|  | 
 | ||||||
|  |     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); | ||||||
|  | 
 | ||||||
|  |     // Размер текстуры тени от солнца
 | ||||||
|  |     const GLuint sunShadow_resolution = 1024; | ||||||
|  |     // Создадим буфер кадра для рендера теней
 | ||||||
|  |     FBO sunShadowBuffer; | ||||||
|  |     // Создадим текстуры для буфера кадра
 | ||||||
|  |     TextureArray sunShadowDepth(CAMERA_CASCADE_COUNT, sunShadow_resolution, sunShadow_resolution, GL_DEPTH_ATTACHMENT, 4, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT); | ||||||
|  |     // Правка фантомных теней
 | ||||||
|  |     glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); | ||||||
|  |     glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); | ||||||
|  |     float shadowBorderColor[] = { 1.0, 1.0, 1.0, 1.0 }; | ||||||
|  |     glTexParameterfv(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_BORDER_COLOR, shadowBorderColor); | ||||||
|  |     // Отключим работу с цветом
 | ||||||
|  |     glDrawBuffer(GL_NONE); | ||||||
|  |     glReadBuffer(GL_NONE); | ||||||
|  |     // Активируем базовый буфер кадра
 | ||||||
|  |     FBO::useDefault(); | ||||||
|  | 
 | ||||||
|  |     // Шейдер для расчета теней
 | ||||||
|  |     ShaderProgram sunShadowShader; | ||||||
|  |     // Загрузим шейдер
 | ||||||
|  |     sunShadowShader.load(GL_VERTEX_SHADER, "shaders/sun_shadow.vert"); | ||||||
|  |     sunShadowShader.load(GL_GEOMETRY_SHADER, "shaders/sun_shadow.geom"); | ||||||
|  |     sunShadowShader.load(GL_FRAGMENT_SHADER, "shaders/empty.frag"); | ||||||
|  |     sunShadowShader.link(); | ||||||
|  |      | ||||||
|  |     // Размер одной стороны кубической карты
 | ||||||
|  |     const GLuint pointShadow_resolution = 500; | ||||||
|  |     // Создадим буфер кадра для рендера теней от источников света
 | ||||||
|  |     FBO pointShadowBuffer; | ||||||
|  |     // Создадим текстуры для буфера кадра
 | ||||||
|  |     TextureCubeArray pointShadowDepth(MAX_LIGHTS, pointShadow_resolution, pointShadow_resolution, GL_DEPTH_ATTACHMENT, 5, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT); | ||||||
|  |     // Отключим работу с цветом
 | ||||||
|  |     glDrawBuffer(GL_NONE); | ||||||
|  |     glReadBuffer(GL_NONE); | ||||||
|  |     // Активируем базовый буфер кадра
 | ||||||
|  |     FBO::useDefault(); | ||||||
|  | 
 | ||||||
|  |     // Шейдер для расчета теней от точечных источников
 | ||||||
|  |     ShaderProgram pointShadowShader; | ||||||
|  |     // Загрузим шейдер
 | ||||||
|  |     pointShadowShader.load(GL_VERTEX_SHADER, "shaders/sun_shadow.vert"); | ||||||
|  |     pointShadowShader.load(GL_GEOMETRY_SHADER, "shaders/point_shadow.geom"); | ||||||
|  |     pointShadowShader.load(GL_FRAGMENT_SHADER, "shaders/point_shadow.frag"); | ||||||
|  |     pointShadowShader.link(); | ||||||
|  | 
 | ||||||
|  |     // Создадим буфер для вычисления SSAO
 | ||||||
|  |     GLuint attachments_ssao[] = { GL_COLOR_ATTACHMENT0 }; | ||||||
|  |     FBO ssaoBuffer(attachments_ssao, sizeof(attachments_ssao) / sizeof(GLuint)); | ||||||
|  |     // Создадим текстуры для буфера кадра
 | ||||||
|  |     Texture ssaoTexture_raw(WINDOW_WIDTH, WINDOW_HEIGHT, GL_COLOR_ATTACHMENT0, 0, GL_RED, GL_RED); | ||||||
|  |     // Активируем базовый буфер кадра
 | ||||||
|  |     FBO::useDefault(); | ||||||
|  | 
 | ||||||
|  |     // Стандартные параметры SSAO
 | ||||||
|  |     SSAO_data ssao_data; | ||||||
|  |     // Расчет масштабирования текстуры шума
 | ||||||
|  |     ssao_data.scale = {WINDOW_WIDTH/4,WINDOW_HEIGHT/4}; | ||||||
|  |     // Генерируем случайные векторы
 | ||||||
|  |     std::uniform_real_distribution<GLfloat> randomFloats(0.0, 1.0); // Генерирует случайные вещественные числа в заданном диапазоне
 | ||||||
|  |     std::default_random_engine generator; | ||||||
|  |     glm::vec3 sample; // Выборка
 | ||||||
|  |     for (int i = 0; i < ssao_data.size; i++) | ||||||
|  |     { | ||||||
|  |         sample = {  randomFloats(generator) * 2.0 - 1.0 | ||||||
|  |                   , randomFloats(generator) * 2.0 - 1.0 | ||||||
|  |                   , randomFloats(generator) | ||||||
|  |                  }; | ||||||
|  |         sample = glm::normalize(sample); | ||||||
|  |         sample *= randomFloats(generator); | ||||||
|  |          | ||||||
|  |         // Отмасштабируем выборку
 | ||||||
|  |         sample *= 0.1 + 0.9 * (i / (float)ssao_data.size) * (i / (float)ssao_data.size); | ||||||
|  |         ssao_data.samples[i] = sample; | ||||||
|  |     } | ||||||
|  |     // Загрузка данных в uniform-буфер
 | ||||||
|  |     UBO ssaoUB(&ssao_data, sizeof(SSAO_data), 4); | ||||||
|  | 
 | ||||||
|  |     // Текстура шума
 | ||||||
|  |     glm::vec3 noise_vecs[16]; | ||||||
|  |     for (int i = 0; i < 16; i++) | ||||||
|  |         noise_vecs[i] = { randomFloats(generator) * 2.0 - 1.0 | ||||||
|  |                         , randomFloats(generator) * 2.0 - 1.0 | ||||||
|  |                         , 0.0f | ||||||
|  |                         }; | ||||||
|  |     Texture noiseTexture(4,4, noise_vecs, 2, GL_RGBA32F, GL_RGB); | ||||||
|  | 
 | ||||||
|  |     // Шейдер для расчета SSAO
 | ||||||
|  |     ShaderProgram ssaoShader; | ||||||
|  |     // Загрузим шейдер
 | ||||||
|  |     ssaoShader.load(GL_VERTEX_SHADER, "shaders/quad.vert"); | ||||||
|  |     ssaoShader.load(GL_FRAGMENT_SHADER, "shaders/ssao.frag"); | ||||||
|  |     ssaoShader.link(); | ||||||
|  |     // Текстуры, используемые в шейдере
 | ||||||
|  |     const char* ssaoShader_names[]  = {"gPosition", "gNormal", "noise"}; | ||||||
|  |     ssaoShader.bindTextures(ssaoShader_names, sizeof(ssaoShader_names)/sizeof(const char*)); | ||||||
|  | 
 | ||||||
|  |     // Создадим буфер для размытия SSAO
 | ||||||
|  |     FBO ssaoBlurBuffer(attachments_ssao, sizeof(attachments_ssao) / sizeof(GLuint));   | ||||||
|  |     // Создадим текстуры для буфера кадра
 | ||||||
|  |     Texture ssaoTexture(WINDOW_WIDTH, WINDOW_HEIGHT, GL_COLOR_ATTACHMENT0, 6, GL_RED, GL_RED);  | ||||||
|  |     // Активируем базовый буфер кадра
 | ||||||
|  |     FBO::useDefault(); | ||||||
|  | 
 | ||||||
|  |     // Шейдер для размытия SSAO
 | ||||||
|  |     ShaderProgram ssaoBlurShader; | ||||||
|  |     // Загрузим шейдер
 | ||||||
|  |     ssaoBlurShader.load(GL_VERTEX_SHADER, "shaders/quad.vert"); | ||||||
|  |     ssaoBlurShader.load(GL_FRAGMENT_SHADER, "shaders/ssaoBlur.frag"); | ||||||
|  |     ssaoBlurShader.link(); | ||||||
|  | 
 | ||||||
|  |     // Модель прямоугольника
 | ||||||
|  |     Scene rectangle = loadOBJtoScene("../resources/models/plane2.obj", "../resources/models/", "../resources/textures/");  | ||||||
|  |      | ||||||
|  |     // Зададим горизонтальное положение перед камерой
 | ||||||
|  |     rectangle.root.e_position().y = -1; | ||||||
|  |     rectangle.root.e_position().z = 2; | ||||||
|  |     rectangle.root.e_rotation() = glm::quat(0.707f, 0.707f, 0.0f, 0.0f); | ||||||
|  |     rectangle.root.e_scale() = glm::vec3(4); | ||||||
|  | 
 | ||||||
|  |     // Текстуры для прямоугольника
 | ||||||
|  |     Texture rectangle_diffuse(TEX_DIFFUSE, "../resources/textures/rekovalev_diffusemap.png"); | ||||||
|  |     rectangle.models.begin()->set_texture(rectangle_diffuse); | ||||||
|  |     Texture rectangle_normal(TEX_NORMAL, "../resources/textures/rekovalev_normalmap.png"); | ||||||
|  |     rectangle.models.begin()->set_texture(rectangle_normal); | ||||||
|  |     Texture rectangle_heights(TEX_HEIGHTS, "../resources/textures/rekovalev_bumpmap.png"); | ||||||
|  |     rectangle.models.begin()->set_texture(rectangle_heights); | ||||||
|  | 
 | ||||||
|  |     // Шейдер для рисования отладочных лампочек
 | ||||||
|  |     ShaderProgram bulbShader; | ||||||
|  |     // Загрузка и компиляция шейдеров
 | ||||||
|  |     bulbShader.load(GL_VERTEX_SHADER, "shaders/bulb.vert"); | ||||||
|  |     bulbShader.load(GL_FRAGMENT_SHADER, "shaders/bulb.frag"); | ||||||
|  |     bulbShader.link(); | ||||||
|  | 
 | ||||||
|  |     // Вершины для скайбокса
 | ||||||
|  |     glm::vec3 skybox_verticies[] = {         | ||||||
|  |         {-1.0f,  1.0f, -1.0f}, | ||||||
|  |         {-1.0f, -1.0f, -1.0f}, | ||||||
|  |         { 1.0f, -1.0f, -1.0f}, | ||||||
|  |         { 1.0f, -1.0f, -1.0f}, | ||||||
|  |         { 1.0f,  1.0f, -1.0f}, | ||||||
|  |         {-1.0f,  1.0f, -1.0f}, | ||||||
|  | 
 | ||||||
|  |         {-1.0f, -1.0f,  1.0f}, | ||||||
|  |         {-1.0f, -1.0f, -1.0f}, | ||||||
|  |         {-1.0f,  1.0f, -1.0f}, | ||||||
|  |         {-1.0f,  1.0f, -1.0f}, | ||||||
|  |         {-1.0f,  1.0f,  1.0f}, | ||||||
|  |         {-1.0f, -1.0f,  1.0f}, | ||||||
|  | 
 | ||||||
|  |         { 1.0f, -1.0f, -1.0f}, | ||||||
|  |         { 1.0f, -1.0f,  1.0f}, | ||||||
|  |         { 1.0f,  1.0f,  1.0f}, | ||||||
|  |         { 1.0f,  1.0f,  1.0f}, | ||||||
|  |         { 1.0f,  1.0f, -1.0f}, | ||||||
|  |         { 1.0f, -1.0f, -1.0f}, | ||||||
|  | 
 | ||||||
|  |         {-1.0f, -1.0f,  1.0f}, | ||||||
|  |         {-1.0f,  1.0f,  1.0f}, | ||||||
|  |         { 1.0f,  1.0f,  1.0f}, | ||||||
|  |         { 1.0f,  1.0f,  1.0f}, | ||||||
|  |         { 1.0f, -1.0f,  1.0f}, | ||||||
|  |         {-1.0f, -1.0f,  1.0f}, | ||||||
|  | 
 | ||||||
|  |         {-1.0f,  1.0f, -1.0f}, | ||||||
|  |         { 1.0f,  1.0f, -1.0f}, | ||||||
|  |         { 1.0f,  1.0f,  1.0f}, | ||||||
|  |         { 1.0f,  1.0f,  1.0f}, | ||||||
|  |         {-1.0f,  1.0f,  1.0f}, | ||||||
|  |         {-1.0f,  1.0f, -1.0f}, | ||||||
|  | 
 | ||||||
|  |         {-1.0f, -1.0f, -1.0f}, | ||||||
|  |         {-1.0f, -1.0f,  1.0f}, | ||||||
|  |         { 1.0f, -1.0f, -1.0f}, | ||||||
|  |         { 1.0f, -1.0f, -1.0f}, | ||||||
|  |         {-1.0f, -1.0f,  1.0f}, | ||||||
|  |         { 1.0f, -1.0f,  1.0f} | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     // Модель скайбокса
 | ||||||
|  |     Model skybox; | ||||||
|  |     skybox.load_verteces(skybox_verticies, sizeof(skybox_verticies)/sizeof(glm::vec3)); | ||||||
|  |     TextureCube skybox_texture(TEX_DIFFUSE, {  "../resources/textures/skybox/px.jpg" | ||||||
|  |                                              , "../resources/textures/skybox/nx.jpg" | ||||||
|  |                                              , "../resources/textures/skybox/py.jpg" | ||||||
|  |                                              , "../resources/textures/skybox/ny.jpg" | ||||||
|  |                                              , "../resources/textures/skybox/pz.jpg" | ||||||
|  |                                              , "../resources/textures/skybox/nz.jpg" | ||||||
|  |                                             }); | ||||||
|  | 
 | ||||||
|  |     // Шейдер для скайбокса
 | ||||||
|  |     ShaderProgram skyboxShader; | ||||||
|  |     // Загрузим шейдеры
 | ||||||
|  |     skyboxShader.load(GL_VERTEX_SHADER, "shaders/skybox.vert"); | ||||||
|  |     skyboxShader.load(GL_FRAGMENT_SHADER, "shaders/skybox.frag"); | ||||||
|  |     skyboxShader.link(); | ||||||
|  |     // Привязка текстуры скайбокса
 | ||||||
|  |     const char* skybox_shader_names[]  = {"skybox"}; | ||||||
|  |     skyboxShader.bindTextures(skybox_shader_names, sizeof(skybox_shader_names)/sizeof(const char*)); | ||||||
|  |      | ||||||
|  |     // Значение гамма-коррекции
 | ||||||
|  |     UBO gamma(&inv_gamma, sizeof(inv_gamma), 4); | ||||||
|  | 
 | ||||||
|  |     ID selected; // Выбранная модель
 | ||||||
|  | 
 | ||||||
|  |     // Шейдер для инструментов
 | ||||||
|  |     ShaderProgram toolsShader; | ||||||
|  |     // Загрузим шейдеры
 | ||||||
|  |     toolsShader.load(GL_VERTEX_SHADER, "shaders/gshader.vert"); | ||||||
|  |     toolsShader.load(GL_FRAGMENT_SHADER, "shaders/tools.frag"); | ||||||
|  |     toolsShader.link(); | ||||||
|  | 
 | ||||||
|  |     // Инструменты
 | ||||||
|  |     Transform transform; | ||||||
|  |     Rotate rotate; | ||||||
|  |     Scale scale; | ||||||
|  |     TRS& currentTool = transform;  | ||||||
|  | 
 | ||||||
|  |     // Пока не произойдет событие запроса закрытия окна
 | ||||||
|  |     while(!glfwWindowShouldClose(window)) | ||||||
|  |     { | ||||||
|  |         // Загрузка данных о камере
 | ||||||
|  |         cameraUB.loadSub(&Camera::current().getData(), sizeof(CameraData)); | ||||||
|  |         // Загрузим информацию об источниках света
 | ||||||
|  |         Light::upload(light_data); | ||||||
|  |         // Загружаем информацию о направленном источнике
 | ||||||
|  |         Sun::upload(sun_data); | ||||||
|  | 
 | ||||||
|  |         // Активируем G-кадра
 | ||||||
|  |         gbuffer.use(); | ||||||
|  |         // Используем шейдер с освещением
 | ||||||
|  |         gShader.use(); | ||||||
|  |         // Очистка буфера цвета и глубины
 | ||||||
|  |         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | ||||||
|  | 
 | ||||||
|  |         // Тут производится рендер
 | ||||||
|  |         scene.render(gShader, material_data); | ||||||
|  |         rectangle.render(gShader, material_data); | ||||||
|  | 
 | ||||||
|  |         // Отрисовка отладочных лампочек со специальным шейдером
 | ||||||
|  |         bulbShader.use(); | ||||||
|  |         Light::render(bulbShader, material_data); | ||||||
|  |          | ||||||
|  |         // Используем шейдер для инструментов
 | ||||||
|  |         toolsShader.use(); | ||||||
|  |         // Рендерим инструменты для выбранного объекта
 | ||||||
|  |         currentTool.render(selected.value, toolsShader, material_data); | ||||||
|  | 
 | ||||||
|  |         // Выбор объекта
 | ||||||
|  |         if (mouse.left == 0100000) | ||||||
|  |         { | ||||||
|  |             glReadBuffer(GL_COLOR_ATTACHMENT4); | ||||||
|  |             glReadPixels(mouse.x, WINDOW_HEIGHT-mouse.y, 1, 1, GL_RGB_INTEGER, GL_UNSIGNED_INT, &selected); | ||||||
|  |             std::cout << (void*) selected.value << ' ' << selected.etc << '\n'; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // Активируем буфер SSAO
 | ||||||
|  |         ssaoBuffer.use(); | ||||||
|  |         // Используем шейдер для расчета SSAO
 | ||||||
|  |         ssaoShader.use(); | ||||||
|  |         // Очистка буфера цвета
 | ||||||
|  |         glClear(GL_COLOR_BUFFER_BIT); | ||||||
|  |         // Подключаем текстуры G-буфера
 | ||||||
|  |         gPosition.use(); | ||||||
|  |         gNormal.use(); | ||||||
|  |         // Подключаем текстуру шума для SSAO
 | ||||||
|  |         noiseTexture.use(); | ||||||
|  |         // Рендерим прямоугольник
 | ||||||
|  |         quadModel.render(); | ||||||
|  | 
 | ||||||
|  |         // Активируем буфер размытия SSAO
 | ||||||
|  |         ssaoBlurBuffer.use(); | ||||||
|  |         // Используем шейдер для размытия SSAO
 | ||||||
|  |         ssaoBlurShader.use(); | ||||||
|  |         // Очистка буфера цвета
 | ||||||
|  |         glClear(GL_COLOR_BUFFER_BIT); | ||||||
|  |         // Подключаем текстуру сырого SSAO
 | ||||||
|  |         ssaoTexture_raw.use(); | ||||||
|  |         // Рендерим прямоугольник
 | ||||||
|  |         quadModel.render(); | ||||||
|  | 
 | ||||||
|  |         // Изменим размер вывода для тени
 | ||||||
|  |         glViewport(0, 0, sunShadow_resolution, sunShadow_resolution); | ||||||
|  |         // Активируем буфер кадра для теней от солнца
 | ||||||
|  |         sunShadowBuffer.use(); | ||||||
|  |         // Подключим шейдер для расчета теней
 | ||||||
|  |         sunShadowShader.use(); | ||||||
|  |         // Очистка буфера глубины
 | ||||||
|  |         glClear(GL_DEPTH_BUFFER_BIT); | ||||||
|  |         // Рендерим геометрию в буфер глубины
 | ||||||
|  |         scene.render(sunShadowShader, material_data); | ||||||
|  |         rectangle.render(sunShadowShader, material_data); | ||||||
|  | 
 | ||||||
|  |         // Изменим размер вывода для стороны кубической карты точечного источника
 | ||||||
|  |         glViewport(0, 0, pointShadow_resolution, pointShadow_resolution); | ||||||
|  |         // Активируем буфер кадра для теней от солнца
 | ||||||
|  |         pointShadowBuffer.use(); | ||||||
|  |         // Подключим шейдер для расчета теней
 | ||||||
|  |         pointShadowShader.use(); | ||||||
|  |         // Очистка буфера глубины
 | ||||||
|  |         glClear(GL_DEPTH_BUFFER_BIT); | ||||||
|  |         // Для каждого источника вызывается рендер сцены
 | ||||||
|  |         for (int i = 0; i < Light::getCount(); i++) | ||||||
|  |         { | ||||||
|  |             glUniform1i(pointShadowShader.getUniformLoc("light_i"), i); | ||||||
|  |             // Рендерим геометрию в буфер глубины
 | ||||||
|  |             scene.render(pointShadowShader, material_data);   | ||||||
|  |             rectangle.render(pointShadowShader, material_data); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // Изменим размер вывода для окна
 | ||||||
|  |         glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT); | ||||||
|  |         // Активируем базовый буфер кадра
 | ||||||
|  |         FBO::useDefault(); | ||||||
|  |         // Подключаем шейдер для прямоугольника
 | ||||||
|  |         lightShader.use(); | ||||||
|  |         // Очистка буфера цвета и глубины
 | ||||||
|  |         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | ||||||
|  |         // Подключаем текстуры G-буфера
 | ||||||
|  |         gPosition.use(); | ||||||
|  |         gNormal.use(); | ||||||
|  |         gDiffuseP.use(); | ||||||
|  |         gAmbientSpecular.use(); | ||||||
|  |         gID.use(); | ||||||
|  |         // Идентификатор выбранного объекта для обводки
 | ||||||
|  |         glUniform3uiv(lightShader.getUniformLoc("selectedID"), 1, (GLuint*) &selected); | ||||||
|  |         // Подключаем текстуры теней
 | ||||||
|  |         sunShadowDepth.use(); | ||||||
|  |         pointShadowDepth.use(); | ||||||
|  |         // Подключим текстуру SSAO
 | ||||||
|  |         ssaoTexture.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(); // Использование базового буфера для дальнейших работ
 | ||||||
|  | 
 | ||||||
|  |         // Отрисовка скайбокса без записи глубины
 | ||||||
|  |         glDepthMask(GL_FALSE); | ||||||
|  |         // Используем шейдер для скайбокса
 | ||||||
|  |         skyboxShader.use(); | ||||||
|  |         // Подключаем текстуру скайбокса
 | ||||||
|  |         skybox_texture.use(); | ||||||
|  |         // Рендерим куб
 | ||||||
|  |         skybox.render(); | ||||||
|  |         // Возвращаем запись глубины
 | ||||||
|  |         glDepthMask(GL_TRUE); | ||||||
|  |          | ||||||
|  |         // Дополнительная обработка мыши
 | ||||||
|  |         process_mouse_button(mouse.left); | ||||||
|  |         process_mouse_button(mouse.right); | ||||||
|  |         mouse.prev_x = mouse.x; | ||||||
|  |         mouse.prev_y = mouse.y; | ||||||
|  | 
 | ||||||
|  |         // Представление содержимого буфера цепочки показа на окно
 | ||||||
|  |         glfwSwapBuffers(window); | ||||||
|  |         // Обработка системных событий
 | ||||||
|  |         glfwPollEvents(); | ||||||
|  | 
 | ||||||
|  |         // Поворот камеры
 | ||||||
|  |         if (mouse.right & 0100000 | ||||||
|  |         &&  mouse.x != mouse.prev_x  | ||||||
|  |         &&  mouse.y != mouse.prev_y) | ||||||
|  |             Camera::current().rotate(glm::vec2(mouse.x - mouse.prev_x, mouse.prev_y - mouse.y)); | ||||||
|  |              | ||||||
|  |         // Взаимодействие с инструментом при зажатой левой кнопке
 | ||||||
|  |         if (mouse.left > 0100000) | ||||||
|  |             if (selected.etc) | ||||||
|  |                 currentTool.process(selected.value, selected.etc, glm::transpose(Camera::current().getVP()) * glm::vec4(mouse.x - mouse.prev_x, mouse.prev_y - mouse.y, 0, 1)); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user