Копия с 17
This commit is contained in:
		
							parent
							
								
									4d833f85d9
								
							
						
					
					
						commit
						cf9983bcc6
					
				
							
								
								
									
										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
 | 
				
			||||||
							
								
								
									
										90
									
								
								include/Buffers.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								include/Buffers.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,90 @@
 | 
				
			|||||||
 | 
					#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(); // Уничтожение буфера
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        void reallocate(int w, int h, GLuint component = GL_DEPTH_COMPONENT); // Изменяет размеры буфера рендера
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        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
 | 
				
			||||||
							
								
								
									
										93
									
								
								include/Texture.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								include/Texture.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,93 @@
 | 
				
			|||||||
 | 
					#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); // Оператор присваивания
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        void reallocate(GLuint width, GLuint height, GLuint texType = TEX_DIFFUSE, GLint internalformat = GL_RGBA, GLint format = GL_RGBA, GLenum dataType = GL_FLOAT); // Пересоздает текстуру для имеющегося дескриптора
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        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); // Оператор присваивания
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        void reallocate(GLuint levels, GLuint width, GLuint height, GLuint texType = TEX_DIFFUSE, GLint internalformat = GL_RGBA, GLint format = GL_RGBA, GLenum dataType = GL_FLOAT); // Пересоздает текстуру для имеющегося дескриптора
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        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); // Оператор присваивания
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        void reallocate(GLuint width, GLuint height, GLuint texType = TEX_DIFFUSE, GLint internalformat = GL_RGBA, GLint format = GL_RGBA, GLenum dataType = GL_FLOAT); // Пересоздает текстуру для имеющегося дескриптора
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        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); // Оператор присваивания
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        void reallocate(GLuint levels, GLuint width, GLuint height, GLuint texType = TEX_DIFFUSE, GLint internalformat = GL_RGBA, GLint format = GL_RGBA, GLenum dataType = GL_FLOAT); // Пересоздает текстуру для имеющегося дескриптора
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        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;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										203
									
								
								src/Buffers.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										203
									
								
								src/Buffers.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,203 @@
 | 
				
			|||||||
 | 
					#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);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Изменяет размеры буфера рендера
 | 
				
			||||||
 | 
					void RBO::reallocate(int w, int h, GLuint component)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    glBindRenderbuffer(GL_RENDERBUFFER, handler); // Привязка элементного буфера
 | 
				
			||||||
 | 
					    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, w, h);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Возвращает дескриптор буфера рендера
 | 
				
			||||||
 | 
					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;   
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										450
									
								
								src/Texture.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										450
									
								
								src/Texture.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,450 @@
 | 
				
			|||||||
 | 
					#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::reallocate(GLuint width, GLuint height, GLuint texType, GLint internalformat, GLint format, GLenum dataType)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    use();
 | 
				
			||||||
 | 
					    glTexImage2D(GL_TEXTURE_2D, 0, internalformat, width, height, 0, format, dataType, NULL);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Привязка текстуры
 | 
				
			||||||
 | 
					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::reallocate(GLuint levels, GLuint width, GLuint height, GLuint texType, GLint internalformat, GLint format, GLenum dataType)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    use();
 | 
				
			||||||
 | 
					    glTexImage2D(GL_TEXTURE_2D, 0, internalformat, width, height, 0, format, dataType, NULL);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Привязка текстуры
 | 
				
			||||||
 | 
					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::reallocate(GLuint width, GLuint height, GLuint texType, GLint internalformat, GLint format, GLenum dataType)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    use();
 | 
				
			||||||
 | 
					    for (int i = 0; i < 6; ++i)
 | 
				
			||||||
 | 
					        glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, internalformat, width, height, 0, format, dataType, 0);  
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Привязка текстуры
 | 
				
			||||||
 | 
					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::reallocate(GLuint levels, GLuint width, GLuint height, GLuint texType, GLint internalformat, GLint format, GLenum dataType)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    use();
 | 
				
			||||||
 | 
					    glTexImage3D(
 | 
				
			||||||
 | 
					        GL_TEXTURE_CUBE_MAP_ARRAY, 0, internalformat, width, height, 6*levels, 0, format, dataType, 0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Привязка текстуры
 | 
				
			||||||
 | 
					void TextureCubeArray::use()
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    glActiveTexture(type + GL_TEXTURE0);
 | 
				
			||||||
 | 
					    glBindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, handler); // Привязка текстуры как активной
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										609
									
								
								src/main.cpp
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										609
									
								
								src/main.cpp
									
									
									
									
									
										Executable file
									
								
							@ -0,0 +1,609 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					#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_CAPTION "OPENGL notes on rekovalev.site"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Указатели на текстуры для изменения размеров окна
 | 
				
			||||||
 | 
					Texture* pgPosition = NULL;
 | 
				
			||||||
 | 
					Texture* pgNormal = NULL;
 | 
				
			||||||
 | 
					Texture* pgDiffuseP = NULL;
 | 
				
			||||||
 | 
					Texture* pgAmbientSpecular = NULL;
 | 
				
			||||||
 | 
					Texture* pgID = NULL;
 | 
				
			||||||
 | 
					RBO*     pgrbo = NULL;
 | 
				
			||||||
 | 
					Texture* pssaoTexture = NULL;
 | 
				
			||||||
 | 
					Texture* pssaoTexture_raw = NULL;
 | 
				
			||||||
 | 
					// Размеры окна
 | 
				
			||||||
 | 
					int WINDOW_WIDTH = 800;
 | 
				
			||||||
 | 
					int WINDOW_HEIGHT = 600;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Значение гамма-коррекции
 | 
				
			||||||
 | 
					float inv_gamma = 1/2.2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Функция-callback для изменения размеров буфера кадра в случае изменения размеров поверхности окна
 | 
				
			||||||
 | 
					void framebuffer_size_callback(GLFWwindow* window, int width, int height)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    glViewport(0, 0, width, height);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    // Изменение размеров текстур для G-буфера
 | 
				
			||||||
 | 
					    if (pgPosition)
 | 
				
			||||||
 | 
					        pgPosition->reallocate(width, height, 0, GL_RGB32F, GL_RGB);
 | 
				
			||||||
 | 
					    if (pgNormal)
 | 
				
			||||||
 | 
					        pgNormal->reallocate(width, height, 1, GL_RGB16F, GL_RGB); 
 | 
				
			||||||
 | 
					    if (pgDiffuseP)
 | 
				
			||||||
 | 
					        pgDiffuseP->reallocate(width, height, 2, GL_RGBA16F); 
 | 
				
			||||||
 | 
					    if (pgAmbientSpecular)
 | 
				
			||||||
 | 
					        pgAmbientSpecular->reallocate(width, height, 3); 
 | 
				
			||||||
 | 
					    if (pgID)
 | 
				
			||||||
 | 
					        pgID->reallocate(width, height, 7, GL_RGB32UI, GL_RGB_INTEGER, GL_UNSIGNED_INT); 
 | 
				
			||||||
 | 
					    // И буфера глубины
 | 
				
			||||||
 | 
					    if (pgrbo)
 | 
				
			||||||
 | 
					        pgrbo->reallocate(width, height);
 | 
				
			||||||
 | 
					    // SSAO
 | 
				
			||||||
 | 
					    if (pssaoTexture)
 | 
				
			||||||
 | 
					        pssaoTexture->reallocate(width, height, 6, GL_RED, GL_RED);
 | 
				
			||||||
 | 
					    if (pssaoTexture_raw)
 | 
				
			||||||
 | 
					        pssaoTexture_raw->reallocate(width, height, 0, GL_RED, GL_RED);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Запомним новые размеры окна
 | 
				
			||||||
 | 
					    WINDOW_WIDTH = width;
 | 
				
			||||||
 | 
					    WINDOW_HEIGHT = height;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Изменим параметры перспективной матрицы проекции для камеры
 | 
				
			||||||
 | 
					    Camera::current().setPerspective(CAMERA_FOVy, (float)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();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Сохраним указатели на текстуры для изменения размеров окна
 | 
				
			||||||
 | 
					    pgPosition = &gPosition;
 | 
				
			||||||
 | 
					    pgNormal = &gNormal;
 | 
				
			||||||
 | 
					    pgDiffuseP = &gDiffuseP;
 | 
				
			||||||
 | 
					    pgAmbientSpecular = &gAmbientSpecular;
 | 
				
			||||||
 | 
					    pgrbo = &grbo;
 | 
				
			||||||
 | 
					    pgID = &gID;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Шейдер для расчета освещенности
 | 
				
			||||||
 | 
					    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);
 | 
				
			||||||
 | 
					    pssaoTexture_raw = &ssaoTexture_raw;
 | 
				
			||||||
 | 
					    // Активируем базовый буфер кадра
 | 
				
			||||||
 | 
					    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); 
 | 
				
			||||||
 | 
					    pssaoTexture = &ssaoTexture;
 | 
				
			||||||
 | 
					    // Активируем базовый буфер кадра
 | 
				
			||||||
 | 
					    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