Копия проекта с 13
This commit is contained in:
		
							parent
							
								
									369c6f1865
								
							
						
					
					
						commit
						319de834ef
					
				
							
								
								
									
										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
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										48
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								.vscode/settings.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,48 @@
 | 
			
		||||
{
 | 
			
		||||
    "files.associations": {
 | 
			
		||||
        "fstream": "cpp",
 | 
			
		||||
        "iosfwd": "cpp",
 | 
			
		||||
        "map": "cpp",
 | 
			
		||||
        "atomic": "cpp",
 | 
			
		||||
        "new": "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"
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										79
									
								
								.vscode/tasks.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								.vscode/tasks.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@ -0,0 +1,79 @@
 | 
			
		||||
{
 | 
			
		||||
    "tasks": [
 | 
			
		||||
        {
 | 
			
		||||
            "type": "cppbuild",
 | 
			
		||||
            "label": "C/C++: g++.exe сборка активного файла",
 | 
			
		||||
            "command": "C:/MinGW/bin/g++.exe",
 | 
			
		||||
            "args": [
 | 
			
		||||
                "-fdiagnostics-color=always",
 | 
			
		||||
                "${workspaceRoot}/src/*.cpp",
 | 
			
		||||
                "${workspaceRoot}/../dependencies/glad/src/glad.c",
 | 
			
		||||
 | 
			
		||||
                "-I${workspaceRoot}/include",
 | 
			
		||||
 | 
			
		||||
                "--std=c++11",
 | 
			
		||||
 | 
			
		||||
                "-I${workspaceRoot}/../dependencies/GLFW/include",
 | 
			
		||||
                "-L${workspaceRoot}/../dependencies/GLFW/lib-mingw",
 | 
			
		||||
                "-I${workspaceFolder}/../dependencies/glad/include",
 | 
			
		||||
                "-I${workspaceFolder}/../dependencies/glm",
 | 
			
		||||
                "-I${workspaceFolder}/../dependencies/stb",
 | 
			
		||||
                "-I${workspaceFolder}/../dependencies/tinyobjloader",
 | 
			
		||||
                "-static",
 | 
			
		||||
                "-lopengl32",
 | 
			
		||||
                "-lglfw3dll",
 | 
			
		||||
                "-o",
 | 
			
		||||
                "${workspaceRoot}/${workspaceFolderBasename}.exe"
 | 
			
		||||
            ],
 | 
			
		||||
            "options": {
 | 
			
		||||
                "cwd": "${fileDirname}"
 | 
			
		||||
            },
 | 
			
		||||
            "problemMatcher": [
 | 
			
		||||
                "$gcc"
 | 
			
		||||
            ],
 | 
			
		||||
            "group": {
 | 
			
		||||
                "kind": "build",
 | 
			
		||||
                "isDefault": true
 | 
			
		||||
            },
 | 
			
		||||
            "detail": "Задача создана отладчиком."
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "type": "cppbuild",
 | 
			
		||||
            "label": "C/C++ x64: g++.exe сборка активного файла",
 | 
			
		||||
            "command": "C:/MinGW64/bin/g++.exe",
 | 
			
		||||
            "args": [
 | 
			
		||||
                "-fdiagnostics-color=always",
 | 
			
		||||
                "${workspaceRoot}/src/*.cpp",
 | 
			
		||||
                "${workspaceRoot}/../dependencies/glad/src/glad.c",
 | 
			
		||||
 | 
			
		||||
                "-I${workspaceRoot}/include",
 | 
			
		||||
 | 
			
		||||
                "--std=c++11",
 | 
			
		||||
 | 
			
		||||
                "-I${workspaceRoot}/../dependencies/GLFW/include",
 | 
			
		||||
                "-L${workspaceRoot}/../dependencies/GLFW/lib-mingw-w64",
 | 
			
		||||
                "-I${workspaceFolder}/../dependencies/glad/include",
 | 
			
		||||
                "-I${workspaceFolder}/../dependencies/glm",
 | 
			
		||||
                "-I${workspaceFolder}/../dependencies/stb",
 | 
			
		||||
                "-I${workspaceFolder}/../dependencies/tinyobjloader",
 | 
			
		||||
                "-static",
 | 
			
		||||
                "-lopengl32",
 | 
			
		||||
                "-lglfw3dll",
 | 
			
		||||
                "-o",
 | 
			
		||||
                "${workspaceRoot}/${workspaceFolderBasename}.exe"
 | 
			
		||||
            ],
 | 
			
		||||
            "options": {
 | 
			
		||||
                "cwd": "${fileDirname}"
 | 
			
		||||
            },
 | 
			
		||||
            "problemMatcher": [
 | 
			
		||||
                "$gcc"
 | 
			
		||||
            ],
 | 
			
		||||
            "group": {
 | 
			
		||||
                "kind": "build",
 | 
			
		||||
                "isDefault": true
 | 
			
		||||
            },
 | 
			
		||||
            "detail": "Задача создана отладчиком."
 | 
			
		||||
        }
 | 
			
		||||
    ],
 | 
			
		||||
    "version": "2.0.0"
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										88
									
								
								include/Buffers.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								include/Buffers.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,88 @@
 | 
			
		||||
#ifndef BUFFERS_H
 | 
			
		||||
#define BUFFERS_H
 | 
			
		||||
 | 
			
		||||
#include <glad/glad.h>
 | 
			
		||||
 | 
			
		||||
#include <map>
 | 
			
		||||
 | 
			
		||||
// Объект массива вершин
 | 
			
		||||
class VAO
 | 
			
		||||
{
 | 
			
		||||
    public:
 | 
			
		||||
        VAO(); // Создает VAO и активирует его
 | 
			
		||||
        ~VAO(); // Уничтожает VAO
 | 
			
		||||
        VAO(const VAO & copy); // Конструктор копирования
 | 
			
		||||
        VAO& operator=(const VAO & other); // Оператор присваивания
 | 
			
		||||
 | 
			
		||||
        void use(); // Активация VAO
 | 
			
		||||
        static void disable(); // Деактивация активного VAO
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        GLuint handler; // Дескриптор
 | 
			
		||||
        static std::map<GLuint, GLuint> handler_count; // Счетчик использований дескриптора
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Тип буфера
 | 
			
		||||
enum BUFFER_TYPE {  VERTEX = GL_ARRAY_BUFFER
 | 
			
		||||
                  , ELEMENT = GL_ELEMENT_ARRAY_BUFFER
 | 
			
		||||
                  , UNIFORM = GL_UNIFORM_BUFFER
 | 
			
		||||
                 };
 | 
			
		||||
 | 
			
		||||
// Объект вершинного буфера
 | 
			
		||||
class BO
 | 
			
		||||
{
 | 
			
		||||
    public:
 | 
			
		||||
        BO(BUFFER_TYPE type); // Создает пустой буфер заданного типа
 | 
			
		||||
        BO(BUFFER_TYPE type, const void *data, int size); // Создает и загружает туда данные
 | 
			
		||||
        ~BO(); // Уничтожает буфер
 | 
			
		||||
        BO(const BO & copy); // Конструктор копирования
 | 
			
		||||
        BO& operator=(const BO & other); // Оператор присваивания
 | 
			
		||||
 | 
			
		||||
        void load(const void *data, int size, GLuint mode = GL_STATIC_DRAW); // Загрузка данных в буфер
 | 
			
		||||
        void use(); 
 | 
			
		||||
 | 
			
		||||
    protected:
 | 
			
		||||
        GLuint handler; // Дескриптор
 | 
			
		||||
        BUFFER_TYPE type; // Тип буфера
 | 
			
		||||
    private:
 | 
			
		||||
        static std::map<GLuint, GLuint> handler_count; // Счетчик использований дескриптора
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Объект uniform-буфера
 | 
			
		||||
class UBO : public BO
 | 
			
		||||
{
 | 
			
		||||
    public:
 | 
			
		||||
        UBO(int size, int binding); // Создает пустой uniform-буфер заданного размера с автоматической привязкой
 | 
			
		||||
        UBO(const void *data, int size, int binding); // Создает пустой uniform-буфер заданного размера с автоматической привязкой
 | 
			
		||||
 | 
			
		||||
        void rebind(int binding); // Перепривязка
 | 
			
		||||
        void loadSub(const void *data, int size, int offset = 0); // Загрузка с отступом
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Объект буфера кадра
 | 
			
		||||
class FBO
 | 
			
		||||
{
 | 
			
		||||
    public:
 | 
			
		||||
        FBO(GLuint *attachments = 0, int count = 0); // Создает буфер кадра с нужным числом прикреплений текстур
 | 
			
		||||
        ~FBO(); // Уничтожение буфера
 | 
			
		||||
 | 
			
		||||
        void use(GLuint mode = GL_FRAMEBUFFER); // Активирует буфер кадра в заданном режиме
 | 
			
		||||
        static void useDefault(GLuint mode = GL_FRAMEBUFFER); // Активирует базовый буфер в заданном режиме
 | 
			
		||||
        void assignRenderBuffer(GLuint hander, GLuint attachment = GL_DEPTH_ATTACHMENT); // Привязка рендер буфера
 | 
			
		||||
    protected:
 | 
			
		||||
        GLuint handler; // Дескриптор
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Объект буфера рендера
 | 
			
		||||
class RBO
 | 
			
		||||
{
 | 
			
		||||
    public:
 | 
			
		||||
        RBO(int w, int h, GLuint component = GL_DEPTH_COMPONENT); // Создает буфер рендера с заданными параметрами размеров и используемых компонент
 | 
			
		||||
        ~RBO(); // Уничтожение буфера
 | 
			
		||||
 | 
			
		||||
        GLuint getHandler(); // Возвращает дескриптор буфера рендера
 | 
			
		||||
    protected:
 | 
			
		||||
        GLuint handler; // Дескриптор
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // BUFFERS_H
 | 
			
		||||
							
								
								
									
										66
									
								
								include/Camera.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								include/Camera.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,66 @@
 | 
			
		||||
#ifndef CAMERA_H
 | 
			
		||||
#define CAMERA_H
 | 
			
		||||
 | 
			
		||||
#include <GLM/glm.hpp>
 | 
			
		||||
 | 
			
		||||
// Ближняя граница области отсечения
 | 
			
		||||
#define CAMERA_NEAR 0.1f
 | 
			
		||||
// Дальняя граница области отсечения
 | 
			
		||||
#define CAMERA_FAR 100.0f
 | 
			
		||||
// Вектор, задающий верх для камеры
 | 
			
		||||
#define CAMERA_UP_VECTOR glm::vec3(0.0f, 1.0f, 0.0f)
 | 
			
		||||
// Стандартный угол обзора 
 | 
			
		||||
#define CAMERA_FOVy 60.0f
 | 
			
		||||
// Количество каскадов для карт теней
 | 
			
		||||
#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:
 | 
			
		||||
        Camera(float aspect, const glm::vec3 &position = glm::vec3(0.0f, 0.0f, 0.0f), const glm::vec2 &xyOffset = glm::vec2(90.0f, 0.0f), float fovy = CAMERA_FOVy); // Конструктор камеры с проекцией перспективы
 | 
			
		||||
        Camera(float width, float height, const glm::vec3 &position = glm::vec3(0.0f, 0.0f, 0.0f), const glm::vec2 &xyOffset = glm::vec2(90.0f, 0.0f)); // Конструктор ортографической камеры
 | 
			
		||||
        virtual ~Camera(); // Деструктор
 | 
			
		||||
        const glm::mat4& getVP(); // Возвращает ссылку на константную матрицу произведения матриц вида и проекции
 | 
			
		||||
        const glm::mat4& getProjection(); // Возвращает ссылку на константную матрицу проекции 
 | 
			
		||||
        const glm::mat4& getView(); // Возвращает ссылку на константную матрицу вида
 | 
			
		||||
        void rotate(const glm::vec2 &xyOffset); // Поворачивает камеру на dx и dy пикселей
 | 
			
		||||
        void move(const glm::vec3 &posOffset); // Сдвигает камеру на указанный вектор (dx,dy,dz)
 | 
			
		||||
        void setPosition(const glm::vec3 &position); // Устанавливает местоположение
 | 
			
		||||
        void setRotation(const glm::vec2 &xyOffset); // Устанавливает угол поворота камеры
 | 
			
		||||
        void setPerspective(float fov, float aspect); // Устанавливает заданную матрицу перспективы
 | 
			
		||||
        void setOrtho(float width, float height); // Устанавливает заданную ортографическую матрицу
 | 
			
		||||
        void setSensitivity(float sensitivity); // Изменяет чувствительность мыши
 | 
			
		||||
        CameraData& getData(); // Данные о камере для шейдера
 | 
			
		||||
        const glm::vec4 (*getProjCoords())[8];
 | 
			
		||||
    protected:
 | 
			
		||||
        Camera(const glm::vec3 &position, const glm::vec2 &xyOffset); // Защищенный (protected) констуктор камеры без перспективы 
 | 
			
		||||
        void recalcTarget(); // Пересчет цели, на которую смотрит камера
 | 
			
		||||
        void recalcView(); // Пересчет матрицы вида
 | 
			
		||||
        void recalcVP(); // Пересчет произведения матриц
 | 
			
		||||
 | 
			
		||||
        glm::vec3 position; // Местоположение камеры
 | 
			
		||||
        glm::vec3 target; // Цель, на которую смотрит камера
 | 
			
		||||
        glm::vec2 currentRotation; // Текущий поворот камеры
 | 
			
		||||
        glm::mat4 projection; // Матрица проекции
 | 
			
		||||
        glm::mat4 view; // Матрица вида
 | 
			
		||||
        glm::mat4 vp; // Матрица произведения вида и проекции
 | 
			
		||||
        bool requiredRecalcVP; // Необходимость пересчета матрицы вида и проекции камеры
 | 
			
		||||
        bool requiredRecalcView; // Необходимость пересчета матрицы вида камеры
 | 
			
		||||
        bool requiredRecalcCoords; // Необходимость пересчета точек, описывающих трансф. объем проекции
 | 
			
		||||
        float sensitivity; // Чувствительность мыши
 | 
			
		||||
        glm::vec4 coords[CAMERA_CASCADE_COUNT][8]; // Координаты в проекции 
 | 
			
		||||
        glm::mat4 cascade_proj[CAMERA_CASCADE_COUNT]; // Матрицы проекций каскадов
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#endif // CAMERA_H
 | 
			
		||||
							
								
								
									
										45
									
								
								include/Lights.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								include/Lights.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,45 @@
 | 
			
		||||
#ifndef LIGHTS_H
 | 
			
		||||
#define LIGHTS_H
 | 
			
		||||
 | 
			
		||||
#include <GLM/glm.hpp>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#include "Model.h"
 | 
			
		||||
#include "Camera.h"
 | 
			
		||||
 | 
			
		||||
// Максимальное число источников света
 | 
			
		||||
#define MAX_LIGHTS 64
 | 
			
		||||
 | 
			
		||||
// Класс лампочки (точечный источник с возможностью отладочного вывода)
 | 
			
		||||
class Bulb
 | 
			
		||||
{
 | 
			
		||||
    public:
 | 
			
		||||
        Bulb(const glm::vec3 &pos = glm::vec3(0.0f, 0.0f, 0.0f), const glm::vec3 &color = glm::vec3(0.0f, 0.0f, 0.0f), float radius = 10.0f, float angle = 180, const glm::vec3 &direction = glm::vec3(0,0,1)); // Конструктор с координатами, цветом, радиусом и направлением
 | 
			
		||||
        
 | 
			
		||||
        void render(ShaderProgram &shaderProgram, UBO &material_buffer); // Отрисовка отладочной лампы и сферы
 | 
			
		||||
        
 | 
			
		||||
        alignas(16) glm::vec3 position; // Позиция
 | 
			
		||||
        alignas(16) glm::vec3 color; // Цвет 
 | 
			
		||||
        void setRadius(float radius); // Задание радиуса и расчет коэф. угасания   
 | 
			
		||||
        float angle; // Угол освещенности
 | 
			
		||||
        alignas(16) glm::vec3 direction; // Направление для прожектора
 | 
			
		||||
        void recalc_pov(); // Пересчитывает матрицы проекции и трансформации в пространство источника
 | 
			
		||||
    private:
 | 
			
		||||
        float radius; // Радиус действия источника
 | 
			
		||||
        alignas(16) glm::vec2 K; // линейный и квадратичный компоненты затухания 
 | 
			
		||||
        alignas(16) glm::mat4 vp[6]; // Матрицы проекции и трансформации в пространство источника
 | 
			
		||||
        static GrouptedModel bulb_model;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Класс направленного источника освещения
 | 
			
		||||
class Sun
 | 
			
		||||
{
 | 
			
		||||
    public:
 | 
			
		||||
        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; // Цвет
 | 
			
		||||
        void upload(ShaderProgram &shaderProgram); // Загрузка данных об источнике на шейдер
 | 
			
		||||
        void pov(ShaderProgram &shaderProgram, Camera camera); // Загружает матрицу проекции и трансформации в пространство источника
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // LIGHTS_H
 | 
			
		||||
							
								
								
									
										74
									
								
								include/Model.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								include/Model.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,74 @@
 | 
			
		||||
#ifndef MODEL_H
 | 
			
		||||
#define MODEL_H
 | 
			
		||||
 | 
			
		||||
#include "Buffers.h"
 | 
			
		||||
#include "Texture.h"
 | 
			
		||||
#include "Shader.h"
 | 
			
		||||
 | 
			
		||||
#include <GLM/glm.hpp>
 | 
			
		||||
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#define DEFAULT_MTL_DIR "./"
 | 
			
		||||
class GrouptedModel loadOBJtoGroupted(const char* filename, const char* mtl_directory = DEFAULT_MTL_DIR, const char* texture_directory = DEFAULT_MTL_DIR);
 | 
			
		||||
 | 
			
		||||
struct Material
 | 
			
		||||
{
 | 
			
		||||
    alignas(16) glm::vec3 ka; // коэф. фонового отражения (цвет фонового освещения)
 | 
			
		||||
    alignas(16) glm::vec3 kd; // коэф. диффузного отражения (цвет объекта)
 | 
			
		||||
    alignas(16) glm::vec3 ks; // коэф. зеркального блика
 | 
			
		||||
    float p; // показатель глянцевости
 | 
			
		||||
    // Значения по умолчанию
 | 
			
		||||
    Material() : ka(0.2f), kd(0.2f), ks(0.2f), p(1) { };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Класс определяющий положение, вращение и размер объекта
 | 
			
		||||
class Movable
 | 
			
		||||
{
 | 
			
		||||
    public:
 | 
			
		||||
        Movable(); // Конструктор без параметров
 | 
			
		||||
        Movable(const Movable& copy); // Конструктор копирования
 | 
			
		||||
 | 
			
		||||
        glm::vec3 position; // позиция модели
 | 
			
		||||
        glm::vec3 rotation; // поворот модели
 | 
			
		||||
        glm::vec3 scale;    // масштабирование модели
 | 
			
		||||
        glm::mat4 getTransformMatrix(); // Матрица трансформации модели
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Класс модели с примененным материалом
 | 
			
		||||
class Model : public Movable
 | 
			
		||||
{
 | 
			
		||||
    public:
 | 
			
		||||
        Model(); // Конструктор без параметров
 | 
			
		||||
        Model(const Model& copy); // Конструктор копирования
 | 
			
		||||
        ~Model();
 | 
			
		||||
        void render(); // Вызов отрисовки без uniform-даных
 | 
			
		||||
        void render(ShaderProgram &shaderProgram, UBO &material_buffer, const glm::mat4& global_tranform = glm::mat4(1)); // Вызов отрисовки
 | 
			
		||||
        void load_verteces(glm::vec3* verteces, GLuint count); // Загрузка вершин в буфер
 | 
			
		||||
        void load_indices(GLuint* indices, GLuint count); // Загрузка индексов в буфер
 | 
			
		||||
        void load_texCoords(glm::vec2* texCoords, GLuint count); // Загрузка текстурных координат в буфер
 | 
			
		||||
        void load_normals(glm::vec3* normals, GLuint count); // Загрузка нормалей в буфер
 | 
			
		||||
        void set_texture(Texture& texture); // Привязка текстуры к модели
 | 
			
		||||
        void set_index_range(GLuint beg, GLuint count); // Ограничение диапазона из буфера индексов
 | 
			
		||||
 | 
			
		||||
        Material material; // Материал модели
 | 
			
		||||
    private:
 | 
			
		||||
        VAO vao;
 | 
			
		||||
        BO vertex_vbo, index_vbo; // вершинный и индексный буферы
 | 
			
		||||
        BO normals_vbo, texCoords_vbo; // буферы с нормалями и текстурными координатами
 | 
			
		||||
        GLuint verteces_count; // Количество вершин
 | 
			
		||||
        GLuint first_index, indices_count; // Первый и количество индексов
 | 
			
		||||
        Texture texture_diffuse; // Диффузная текстура
 | 
			
		||||
        Texture texture_ambient; // Текстура фонового освщения
 | 
			
		||||
        Texture texture_specular; // Текстура зеркального отражения
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Класс сгруппированной модели
 | 
			
		||||
class GrouptedModel: public Movable
 | 
			
		||||
{
 | 
			
		||||
    public:
 | 
			
		||||
        void render(ShaderProgram &shaderProgram, UBO &material_buffer); // Вызов отрисовки
 | 
			
		||||
        std::vector<Model> parts;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // MODEL_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
 | 
			
		||||
							
								
								
									
										82
									
								
								include/Texture.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								include/Texture.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,82 @@
 | 
			
		||||
#ifndef TEXTURE_H
 | 
			
		||||
#define TEXTURE_H
 | 
			
		||||
 | 
			
		||||
#include <glad/glad.h>
 | 
			
		||||
 | 
			
		||||
#include <map>
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
enum TexType {
 | 
			
		||||
    TEX_DIFFUSE,
 | 
			
		||||
    TEX_AMBIENT,
 | 
			
		||||
    TEX_SPECULAR,
 | 
			
		||||
    TEX_AVAILABLE_COUNT
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Абстрактный класс базовой текстуры
 | 
			
		||||
class 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(const Texture& other); // Конструктор копирования
 | 
			
		||||
        
 | 
			
		||||
        Texture& operator=(const Texture& other); // Оператор присваивания
 | 
			
		||||
 | 
			
		||||
        virtual void use(); // Привязка текстуры       
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Класс 3D текстуры
 | 
			
		||||
class TextureArray : public BaseTexture
 | 
			
		||||
{
 | 
			
		||||
    public:
 | 
			
		||||
        TextureArray(GLuint levels, GLuint width, GLuint height, GLuint attachment, GLuint texType = TEX_DIFFUSE, GLint internalformat = GL_RGBA, GLint format = GL_RGBA, GLenum dataType = GL_FLOAT); // Конструктор текстуры заданного размера для использования в буфере
 | 
			
		||||
        TextureArray(const TextureArray& other); // Конструктор копирования
 | 
			
		||||
 | 
			
		||||
        TextureArray& operator=(const TextureArray& other); // Оператор присваивания
 | 
			
		||||
 | 
			
		||||
        virtual void use(); // Привязка текстуры       
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Класс кубической текстуры
 | 
			
		||||
class TextureCube : public BaseTexture
 | 
			
		||||
{
 | 
			
		||||
    public:
 | 
			
		||||
        TextureCube(GLuint type = TEX_AVAILABLE_COUNT, const std::string (&filename)[6] = {""}); // Загрузка текстуры с диска или использование "пустой"
 | 
			
		||||
        TextureCube(GLuint width, GLuint height, GLuint attachment, GLuint texType = TEX_DIFFUSE, GLint internalformat = GL_RGBA, GLint format = GL_RGBA, GLenum dataType = GL_FLOAT); // Конструктор текстуры заданного размера для использования в буфере
 | 
			
		||||
        TextureCube(const TextureCube& other); // Конструктор копирования
 | 
			
		||||
 | 
			
		||||
        TextureCube& operator=(const TextureCube& other); // Оператор присваивания
 | 
			
		||||
 | 
			
		||||
        virtual void use(); // Привязка текстуры       
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// Класс 3D кубической текстуры
 | 
			
		||||
class TextureCubeArray : public BaseTexture
 | 
			
		||||
{
 | 
			
		||||
    public:
 | 
			
		||||
        TextureCubeArray(GLuint levels, GLuint width, GLuint height, GLuint attachment, GLuint texType = TEX_DIFFUSE, GLint internalformat = GL_RGBA, GLint format = GL_RGBA, GLenum dataType = GL_FLOAT); // Конструктор текстуры заданного размера для использования в буфере
 | 
			
		||||
        TextureCubeArray(const TextureCubeArray& other); // Конструктор копирования
 | 
			
		||||
 | 
			
		||||
        TextureCubeArray& operator=(const TextureCubeArray& other); // Оператор присваивания
 | 
			
		||||
 | 
			
		||||
        virtual void use(); // Привязка текстуры       
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif // TEXTURE_H
 | 
			
		||||
							
								
								
									
										25
									
								
								shaders/bulb.frag
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								shaders/bulb.frag
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,25 @@
 | 
			
		||||
#version 420 core 
 | 
			
		||||
 | 
			
		||||
layout(std140, binding = 1) uniform Material
 | 
			
		||||
{
 | 
			
		||||
    vec3 ka;
 | 
			
		||||
    vec3 kd;
 | 
			
		||||
    vec3 ks;
 | 
			
		||||
    float p;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
in vec3 pos_local;
 | 
			
		||||
 | 
			
		||||
out vec4 color;
 | 
			
		||||
 | 
			
		||||
uniform float angle;
 | 
			
		||||
uniform vec3 direction;
 | 
			
		||||
 | 
			
		||||
void main()
 | 
			
		||||
{   
 | 
			
		||||
    float cosA = dot(normalize(pos_local), normalize(direction));
 | 
			
		||||
    if (degrees(acos(cosA)) <= angle)
 | 
			
		||||
        color = vec4(ka, 1);
 | 
			
		||||
    else
 | 
			
		||||
        discard;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										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()
 | 
			
		||||
{
 | 
			
		||||
    
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										38
									
								
								shaders/gshader.frag
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								shaders/gshader.frag
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,38 @@
 | 
			
		||||
#version 420 core 
 | 
			
		||||
 | 
			
		||||
layout(std140, binding = 1) uniform Material
 | 
			
		||||
{
 | 
			
		||||
    vec3 ka;
 | 
			
		||||
    vec3 kd;
 | 
			
		||||
    vec3 ks;
 | 
			
		||||
    float p;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
layout (location = 0) out vec3 gPosition;
 | 
			
		||||
layout (location = 1) out vec3 gNormal;
 | 
			
		||||
layout (location = 2) out vec4 gDiffuseP;
 | 
			
		||||
layout (location = 3) out vec4 gAmbientSpecular;
 | 
			
		||||
 | 
			
		||||
in vec3 vertex; // Позиция вершины в пространстве
 | 
			
		||||
in vec3 N; // Нормаль трансформированноая
 | 
			
		||||
in vec2 texCoord; // Текстурные координаты
 | 
			
		||||
 | 
			
		||||
uniform sampler2D tex_diffuse;
 | 
			
		||||
uniform sampler2D tex_ambient;
 | 
			
		||||
uniform sampler2D tex_specular;
 | 
			
		||||
 | 
			
		||||
void main()
 | 
			
		||||
{    
 | 
			
		||||
    // Сохранение позиции фрагмента в G-буфере
 | 
			
		||||
    gPosition = vertex;
 | 
			
		||||
    // Сохранение нормали в G-буфере
 | 
			
		||||
    gNormal = N;
 | 
			
		||||
    // Сохранение диффузного цвета
 | 
			
		||||
    gDiffuseP.rgb = texture(tex_diffuse, texCoord).rgb * kd;
 | 
			
		||||
    // Сохранение глянцевости
 | 
			
		||||
    gDiffuseP.a = p;
 | 
			
		||||
    // Сохранение фоновой составляющей
 | 
			
		||||
    gAmbientSpecular.rgb = texture(tex_ambient, texCoord).rgb * ka;
 | 
			
		||||
    // Сохранение зеркальной составляющей
 | 
			
		||||
    gAmbientSpecular.a = texture(tex_specular, texCoord).r * ks.r;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										30
									
								
								shaders/gshader.vert
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								shaders/gshader.vert
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,30 @@
 | 
			
		||||
#version 420 core 
 | 
			
		||||
 | 
			
		||||
layout(location = 0) in vec3 pos; 
 | 
			
		||||
layout(location = 1) in vec2 inTexCoord;
 | 
			
		||||
layout(location = 2) in vec3 normals; 
 | 
			
		||||
 | 
			
		||||
layout(std140, binding = 0) uniform Camera
 | 
			
		||||
{
 | 
			
		||||
    mat4 projection;
 | 
			
		||||
    mat4 view;
 | 
			
		||||
    vec3 position;
 | 
			
		||||
} camera;
 | 
			
		||||
 | 
			
		||||
uniform mat4 model;
 | 
			
		||||
 | 
			
		||||
out vec3 vertex; // Позиция вершины в пространстве
 | 
			
		||||
out vec3 N; // Нормаль трансформированноая
 | 
			
		||||
out vec2 texCoord; // Текстурные координаты
 | 
			
		||||
 | 
			
		||||
void main() 
 | 
			
		||||
{ 
 | 
			
		||||
    vec4 P = model * vec4(pos, 1.0); // трансформация вершины
 | 
			
		||||
    vertex = P.xyz;
 | 
			
		||||
 | 
			
		||||
    N = normalize(mat3(model) * normals); // трансформация нормали
 | 
			
		||||
 | 
			
		||||
    texCoord = inTexCoord; // Текстурные координаты
 | 
			
		||||
 | 
			
		||||
    gl_Position = camera.projection * camera.view * P;
 | 
			
		||||
} 
 | 
			
		||||
							
								
								
									
										189
									
								
								shaders/lighting.frag
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										189
									
								
								shaders/lighting.frag
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,189 @@
 | 
			
		||||
#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;
 | 
			
		||||
    float angle;
 | 
			
		||||
    vec3 direction;
 | 
			
		||||
    float radius;
 | 
			
		||||
    vec2 K;
 | 
			
		||||
    mat4 vp[6];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
layout(std140, binding = 2) uniform Light
 | 
			
		||||
{
 | 
			
		||||
    LightData data[64];
 | 
			
		||||
    int count;
 | 
			
		||||
} light_f;
 | 
			
		||||
 | 
			
		||||
uniform vec3 Sun_direction;
 | 
			
		||||
uniform vec3 Sun_color;
 | 
			
		||||
uniform mat4 Sun_VP[4]; // Размер массива должен соответствовать количеству каскадов
 | 
			
		||||
 | 
			
		||||
uniform float camera_cascade_distances[4]; // Размер массива должен соответствовать количеству каскадов
 | 
			
		||||
 | 
			
		||||
uniform sampler2D gPosition;
 | 
			
		||||
uniform sampler2D gNormal;
 | 
			
		||||
uniform sampler2D gDiffuseP;
 | 
			
		||||
uniform sampler2D gAmbientSpecular;
 | 
			
		||||
uniform sampler2DArray sunShadowDepth;
 | 
			
		||||
uniform samplerCubeArray pointShadowDepth;
 | 
			
		||||
 | 
			
		||||
out vec4 color; 
 | 
			
		||||
 | 
			
		||||
void main() 
 | 
			
		||||
{ 
 | 
			
		||||
    // Получим данные из текстур буфера
 | 
			
		||||
    vec3 fragPos = texture(gPosition, texCoord).rgb;
 | 
			
		||||
    vec3 N = texture(gNormal, texCoord).rgb;
 | 
			
		||||
    vec3 kd = texture(gDiffuseP, texCoord).rgb;
 | 
			
		||||
    vec3 ka = texture(gAmbientSpecular, texCoord).rgb;
 | 
			
		||||
    float ks = texture(gAmbientSpecular, texCoord).a;
 | 
			
		||||
    float p = texture(gDiffuseP, texCoord).a;
 | 
			
		||||
    
 | 
			
		||||
    // Переменные используемые в цикле:
 | 
			
		||||
    vec3 L_vertex; // Расположение источника относительно фрагмента
 | 
			
		||||
    float L_distance; // Расстояние от поверхности до источника
 | 
			
		||||
    vec3 Cam_vertex = normalize(camera.position - fragPos); // Расположение камеры относительно фрагмента
 | 
			
		||||
    float diffuse; // Диффузная составляющая
 | 
			
		||||
    vec3 H; // Вектор половины пути
 | 
			
		||||
    float specular; // Зеркальная составляющая
 | 
			
		||||
    float attenuation; // Угасание с учетом расстояния
 | 
			
		||||
    float acosA; // Косинус между вектором от поверхности к источнику и обратным направлением источника
 | 
			
		||||
    float intensity; // Интенсивность для прожектора
 | 
			
		||||
    vec3 fragPosLightSpace; // Фрагмент в пространстве источника
 | 
			
		||||
    vec4 fragPosCamSpace = camera.view * vec4(fragPos, 1); // Фрагмент в пространстве камеры
 | 
			
		||||
    float shadowValue; // Значение затененности
 | 
			
		||||
    vec2 texelSize; // Размер текселя текстуры теней
 | 
			
		||||
    int x, y, z; // Счетчик для PCF
 | 
			
		||||
    float pcfDepth; // Глубина PCF
 | 
			
		||||
    int cascade_index; // Индекс текущего каскада для вычисления теней
 | 
			
		||||
    float cubemap_offset = 0.05f; // Отступ в текстурных координатах для PCF
 | 
			
		||||
    float cubemap_depth; // Дистанция между фрагментом и источником в диапазоне [0;1]
 | 
			
		||||
 | 
			
		||||
    // Определение индекса каскада в который попадает фрагмент (цикл на 1 меньше чем кол-во каскадов)
 | 
			
		||||
    for (cascade_index = 0; cascade_index < 3; cascade_index++)
 | 
			
		||||
        if (abs(fragPosCamSpace.z) < camera_cascade_distances[cascade_index])
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
    // Фоновая освещенность
 | 
			
		||||
    color = vec4(ka, 1);
 | 
			
		||||
   
 | 
			
		||||
    // Расчет солнца, если его цвет не черный
 | 
			
		||||
    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;
 | 
			
		||||
        texelSize = 1.0 / textureSize(sunShadowDepth, 0).xy; // Размер текселя текстуры теней
 | 
			
		||||
        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.0;
 | 
			
		||||
        // Рассчитываем освещенность, если значение тени меньше 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].radius;
 | 
			
		||||
        // Сдвиг для решения проблемы акне
 | 
			
		||||
        cubemap_depth -= max(0.05 * (1.0 - dot(N, Sun_direction)), 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].radius)
 | 
			
		||||
            {
 | 
			
		||||
                // Нормирование вектора
 | 
			
		||||
                L_vertex = normalize(L_vertex);
 | 
			
		||||
                // арккосинус между вектором от поверхности к источнику и обратным направлением источника
 | 
			
		||||
                acosA = degrees(acos(dot(-L_vertex, normalize(light_f.data[i].direction))));
 | 
			
		||||
                // Если угол меньше угла источника или угол источника минимален, то считаем освещенность
 | 
			
		||||
                if(acosA <= light_f.data[i].angle) 
 | 
			
		||||
                {
 | 
			
		||||
                    // Диффузная составляющая
 | 
			
		||||
                    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].K[0] * L_distance + light_f.data[i].K[1] * L_distance * L_distance);
 | 
			
		||||
 | 
			
		||||
                    // Если источник - прожектор, то добавим смягчение
 | 
			
		||||
                    if (light_f.data[i].angle < 180)
 | 
			
		||||
                    {
 | 
			
		||||
                        intensity = clamp((light_f.data[i].angle - 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);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
} 
 | 
			
		||||
							
								
								
									
										16
									
								
								shaders/point_shadow.frag
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								shaders/point_shadow.frag
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,16 @@
 | 
			
		||||
#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;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										40
									
								
								shaders/point_shadow.geom
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								shaders/point_shadow.geom
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,40 @@
 | 
			
		||||
#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;
 | 
			
		||||
    float angle;
 | 
			
		||||
    vec3 direction;
 | 
			
		||||
    float radius;
 | 
			
		||||
    vec2 K;
 | 
			
		||||
    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].radius;
 | 
			
		||||
        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]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										12
									
								
								shaders/skybox.frag
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								shaders/skybox.frag
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,12 @@
 | 
			
		||||
#version 330 core
 | 
			
		||||
out vec4 FragColor;
 | 
			
		||||
 | 
			
		||||
in vec3 TexCoords;
 | 
			
		||||
 | 
			
		||||
uniform samplerCube skybox;
 | 
			
		||||
 | 
			
		||||
void main()
 | 
			
		||||
{    
 | 
			
		||||
    FragColor = texture(skybox, TexCoords);
 | 
			
		||||
    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);
 | 
			
		||||
}  
 | 
			
		||||
							
								
								
									
										17
									
								
								shaders/sun_shadow.geom
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								shaders/sun_shadow.geom
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,17 @@
 | 
			
		||||
#version 420 core
 | 
			
		||||
 | 
			
		||||
layout(triangles, invocations = 4) in; // здесь invocations должно соответствовать количеству каскадов
 | 
			
		||||
layout(triangle_strip, max_vertices = 3) out;
 | 
			
		||||
 | 
			
		||||
uniform mat4 Sun_VP[4]; // Матрицы вида и проекции каскадов
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										196
									
								
								src/Buffers.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										196
									
								
								src/Buffers.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,196 @@
 | 
			
		||||
#include "Buffers.h"
 | 
			
		||||
 | 
			
		||||
// Счетчики использований дескрипторов
 | 
			
		||||
std::map<GLuint, GLuint> VAO::handler_count; 
 | 
			
		||||
std::map<GLuint, GLuint> BO::handler_count; 
 | 
			
		||||
 | 
			
		||||
// Создает VAO и активирует его
 | 
			
		||||
VAO::VAO()
 | 
			
		||||
{ 
 | 
			
		||||
    glGenVertexArrays(1, &handler); // Генерация одного объекта массива вершин
 | 
			
		||||
    glBindVertexArray(handler);     // Привязка для использования
 | 
			
		||||
    handler_count[handler] = 1;     // Инициализация счетчика для дескриптора 
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Уничтожает VAO
 | 
			
		||||
VAO::~VAO()
 | 
			
		||||
{
 | 
			
		||||
    // Если дескриптор никем не используется - освободим его
 | 
			
		||||
    if (!--handler_count[handler])
 | 
			
		||||
    {
 | 
			
		||||
        glDeleteVertexArrays(1, &handler);
 | 
			
		||||
        handler_count.erase(handler); // Удаление из словаря
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Конструктор копирования
 | 
			
		||||
VAO::VAO(const VAO & copy) : handler(copy.handler)
 | 
			
		||||
{
 | 
			
		||||
    handler_count[handler]++;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Оператор присваивания
 | 
			
		||||
VAO& VAO::operator=(const VAO & other) 
 | 
			
		||||
{
 | 
			
		||||
    // Если это разные дескрипторы
 | 
			
		||||
    if (handler != other.handler)
 | 
			
		||||
    { // то следуюет удалить текущий перед заменой
 | 
			
		||||
        this->~VAO(); 
 | 
			
		||||
        handler = other.handler;
 | 
			
		||||
        handler_count[handler]++;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Активация VAO
 | 
			
		||||
void VAO::use()
 | 
			
		||||
{
 | 
			
		||||
    glBindVertexArray(handler); // Привязка VAO для использования
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Деактивация активного VAO
 | 
			
		||||
void VAO::disable()
 | 
			
		||||
{
 | 
			
		||||
    glBindVertexArray(0);       // Отключение VAO
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Создает пустой буфер заданного типа
 | 
			
		||||
BO::BO(BUFFER_TYPE t) : type(t)
 | 
			
		||||
{
 | 
			
		||||
    glGenBuffers(1, &handler); // Генерация одного объекта буфера
 | 
			
		||||
    handler_count[handler] = 1;
 | 
			
		||||
    use(); // Привязка буфера
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Создает и загружает туда данные
 | 
			
		||||
BO::BO(BUFFER_TYPE t, const void *data, int size) : BO(t)
 | 
			
		||||
{
 | 
			
		||||
    load(data, size);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Уничтожает буфер
 | 
			
		||||
BO::~BO()
 | 
			
		||||
{
 | 
			
		||||
    if (handler) // Если буфер был создан
 | 
			
		||||
    {
 | 
			
		||||
        // Если дескриптор никем не используется - освободим его
 | 
			
		||||
        if (!--handler_count[handler])
 | 
			
		||||
        {
 | 
			
		||||
            glDeleteBuffers(1, &handler);
 | 
			
		||||
            handler_count.erase(handler); // Удаление из словаря
 | 
			
		||||
        }
 | 
			
		||||
        handler = 0;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Конструктор копирования
 | 
			
		||||
BO::BO(const BO & copy) : handler(copy.handler), type(copy.type)
 | 
			
		||||
{
 | 
			
		||||
    handler_count[handler]++;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Оператор присваивания
 | 
			
		||||
BO& BO::operator=(const BO & other)
 | 
			
		||||
{
 | 
			
		||||
    // Если это разные дескрипторы
 | 
			
		||||
    if (handler != other.handler)
 | 
			
		||||
    { // то следуюет удалить текущий перед заменой
 | 
			
		||||
        this->~BO(); 
 | 
			
		||||
        handler = other.handler;
 | 
			
		||||
        handler_count[handler]++;
 | 
			
		||||
    }
 | 
			
		||||
    // Изменим тип
 | 
			
		||||
    type = other.type;
 | 
			
		||||
 | 
			
		||||
    return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Загрузка вершин в буфер
 | 
			
		||||
void BO::load(const void *data, int size, GLuint mode)
 | 
			
		||||
{
 | 
			
		||||
    use(); // Привязка буфера
 | 
			
		||||
    glBufferData(type, size, data, mode);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void BO::use()
 | 
			
		||||
{
 | 
			
		||||
    glBindBuffer(type, handler); // Привязка элементного буфера
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Создает пустой uniform-буфер заданного размера с автоматической привязкой
 | 
			
		||||
UBO::UBO(int size, int binding) : BO(UNIFORM, 0, size)
 | 
			
		||||
{
 | 
			
		||||
    rebind(binding);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Создает пустой uniform-буфер заданного размера с автоматической привязкой
 | 
			
		||||
UBO::UBO(const void *data, int size, int binding) : BO(UNIFORM, data, size)
 | 
			
		||||
{
 | 
			
		||||
    rebind(binding);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// перепривязка
 | 
			
		||||
void UBO::rebind(int binding)
 | 
			
		||||
{
 | 
			
		||||
    glBindBufferBase(type, binding, handler); 
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Загрузка с отступом
 | 
			
		||||
void UBO::loadSub(const void *data, int size, int offset)
 | 
			
		||||
{
 | 
			
		||||
    use();
 | 
			
		||||
    glBufferSubData(type, offset, size, data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Создает буфер кадра с нужным числом прикреплений текстур
 | 
			
		||||
FBO::FBO(GLuint *attachments, int count)
 | 
			
		||||
{
 | 
			
		||||
    glGenFramebuffers(1, &handler);
 | 
			
		||||
    use();
 | 
			
		||||
    glDrawBuffers(count, attachments);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Уничтожение буфера
 | 
			
		||||
FBO::~FBO()
 | 
			
		||||
{
 | 
			
		||||
    glDeleteFramebuffers(1, &handler);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Активирует буфер кадра в заданном режиме
 | 
			
		||||
void FBO::use(GLuint mode) 
 | 
			
		||||
{
 | 
			
		||||
    glBindFramebuffer(mode, handler);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Активирует базовый буфер в заданном режиме
 | 
			
		||||
void FBO::useDefault(GLuint mode)
 | 
			
		||||
{
 | 
			
		||||
    glBindFramebuffer(mode, 0);
 | 
			
		||||
} 
 | 
			
		||||
 | 
			
		||||
// Привязка рендер буфера
 | 
			
		||||
void FBO::assignRenderBuffer(GLuint hander, GLuint attachment)
 | 
			
		||||
{
 | 
			
		||||
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, hander);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Создает буфер рендера с заданными параметрами размеров и используемых компонент
 | 
			
		||||
RBO::RBO(int w, int h, GLuint component)
 | 
			
		||||
{
 | 
			
		||||
    glGenRenderbuffers(1, &handler);
 | 
			
		||||
    glBindRenderbuffer(GL_RENDERBUFFER, handler);
 | 
			
		||||
    glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, w, h);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Уничтожение буфера
 | 
			
		||||
RBO::~RBO()
 | 
			
		||||
{
 | 
			
		||||
    glDeleteRenderbuffers(1, &handler);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Возвращает дескриптор буфера рендера
 | 
			
		||||
GLuint RBO::getHandler()
 | 
			
		||||
{
 | 
			
		||||
    return handler;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										190
									
								
								src/Camera.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										190
									
								
								src/Camera.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,190 @@
 | 
			
		||||
#include "Camera.h"
 | 
			
		||||
 | 
			
		||||
#include <GLM/gtc/matrix_transform.hpp>
 | 
			
		||||
#include <GLM/ext/matrix_transform.hpp>
 | 
			
		||||
 | 
			
		||||
// Границы каскадов
 | 
			
		||||
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::vec2 &xyOffset) 
 | 
			
		||||
: position(pos), currentRotation(xyOffset)
 | 
			
		||||
{
 | 
			
		||||
    sensitivity = 0.05;
 | 
			
		||||
    recalcTarget();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Конструктор камеры с проекцией перспективы
 | 
			
		||||
Camera::Camera(float aspect, const glm::vec3 &position, const glm::vec2 &xyOffset, float fovy)
 | 
			
		||||
: Camera(position, xyOffset)
 | 
			
		||||
{
 | 
			
		||||
    setPerspective(fovy, aspect);
 | 
			
		||||
}
 | 
			
		||||
  
 | 
			
		||||
// Конструктор ортографической камеры
 | 
			
		||||
Camera::Camera(float width, float height, const glm::vec3 &position, const glm::vec2 &xyOffset)
 | 
			
		||||
: Camera(position, xyOffset)
 | 
			
		||||
{
 | 
			
		||||
    setOrtho(width, height);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Деструктор
 | 
			
		||||
Camera::~Camera() { }
 | 
			
		||||
 | 
			
		||||
// Пересчет цели, на которую смотрит камера
 | 
			
		||||
void Camera::recalcTarget()
 | 
			
		||||
{
 | 
			
		||||
    if(currentRotation.y > 89.0f)
 | 
			
		||||
        currentRotation.y = 89.0f;
 | 
			
		||||
    if(currentRotation.y < -89.0f)
 | 
			
		||||
        currentRotation.y = -89.0f;
 | 
			
		||||
 | 
			
		||||
    target.x = cos(glm::radians(currentRotation.x)) * cos(glm::radians(currentRotation.y));
 | 
			
		||||
    target.y = sin(glm::radians(currentRotation.y));
 | 
			
		||||
    target.z = sin(glm::radians(currentRotation.x)) * cos(glm::radians(currentRotation.y));
 | 
			
		||||
    
 | 
			
		||||
    requiredRecalcView = true;
 | 
			
		||||
    requiredRecalcVP = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Пересчет матрицы вида
 | 
			
		||||
void Camera::recalcView()
 | 
			
		||||
{
 | 
			
		||||
    view = glm::lookAt(position, position + target, CAMERA_UP_VECTOR);
 | 
			
		||||
    requiredRecalcView = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Пересчет произведения матриц
 | 
			
		||||
void Camera::recalcVP()
 | 
			
		||||
{
 | 
			
		||||
    vp = projection * view;
 | 
			
		||||
    requiredRecalcVP = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Возвращает ссылку на константную матрицу проекции
 | 
			
		||||
const glm::mat4& Camera::getProjection()
 | 
			
		||||
{
 | 
			
		||||
    return projection;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Возвращает ссылку на константную матрицу вида
 | 
			
		||||
const glm::mat4& Camera::getView()
 | 
			
		||||
{
 | 
			
		||||
    if (requiredRecalcView)
 | 
			
		||||
        recalcView();
 | 
			
		||||
    return view;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Возвращает ссылку на константную матрицу вида
 | 
			
		||||
const glm::mat4& Camera::getVP()
 | 
			
		||||
{
 | 
			
		||||
    if (requiredRecalcVP)
 | 
			
		||||
    {
 | 
			
		||||
        if (requiredRecalcView)
 | 
			
		||||
            recalcView();
 | 
			
		||||
        recalcVP();
 | 
			
		||||
    }
 | 
			
		||||
    return vp;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Поворачивает камеру на dx и dy пикселей
 | 
			
		||||
void Camera::rotate(const glm::vec2 &xyOffset)
 | 
			
		||||
{
 | 
			
		||||
    currentRotation += xyOffset * sensitivity;
 | 
			
		||||
 | 
			
		||||
    recalcTarget();
 | 
			
		||||
    requiredRecalcView = true;
 | 
			
		||||
    requiredRecalcVP = true;
 | 
			
		||||
    requiredRecalcCoords = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Сдвигает камеру на указанный вектор (dx,dy,dz)
 | 
			
		||||
void Camera::move(const glm::vec3 &posOffset)
 | 
			
		||||
{
 | 
			
		||||
    position += posOffset;
 | 
			
		||||
 | 
			
		||||
    requiredRecalcView = true;
 | 
			
		||||
    requiredRecalcVP = true;
 | 
			
		||||
    requiredRecalcCoords = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Устанавливает местоположение
 | 
			
		||||
void Camera::setPosition(const glm::vec3 &pos)
 | 
			
		||||
{
 | 
			
		||||
    position = pos;
 | 
			
		||||
    
 | 
			
		||||
    requiredRecalcView = true;
 | 
			
		||||
    requiredRecalcVP = true;
 | 
			
		||||
    requiredRecalcCoords = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Устанавливает угол поворота камеры
 | 
			
		||||
void Camera::setRotation(const glm::vec2 &xyOffset)
 | 
			
		||||
{
 | 
			
		||||
    currentRotation = xyOffset;
 | 
			
		||||
    recalcTarget();
 | 
			
		||||
    requiredRecalcCoords = true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Устанавливает заданную матрицу перспективы
 | 
			
		||||
void Camera::setPerspective(float fovy, float aspect)
 | 
			
		||||
{
 | 
			
		||||
    projection = glm::perspective(glm::radians(fovy), aspect, CAMERA_NEAR, CAMERA_FAR);
 | 
			
		||||
    requiredRecalcVP = true;
 | 
			
		||||
    requiredRecalcCoords = 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;
 | 
			
		||||
    requiredRecalcCoords = 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;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Данные о камере для шейдера
 | 
			
		||||
CameraData& Camera::getData()
 | 
			
		||||
{
 | 
			
		||||
    static CameraData data;
 | 
			
		||||
    data = {getProjection(), getView(), position};
 | 
			
		||||
    return data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Доступ к координатам проекции
 | 
			
		||||
const glm::vec4 (*Camera::getProjCoords())[8]
 | 
			
		||||
{
 | 
			
		||||
    if (requiredRecalcCoords)
 | 
			
		||||
    {
 | 
			
		||||
        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;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return coords;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										153
									
								
								src/Lights.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										153
									
								
								src/Lights.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,153 @@
 | 
			
		||||
#include "Lights.h"
 | 
			
		||||
 | 
			
		||||
#include <GLM/gtc/matrix_transform.hpp>
 | 
			
		||||
#include <GLM/ext/matrix_transform.hpp>
 | 
			
		||||
 | 
			
		||||
void genShpere(Model& model, float radius, int sectorsCount); // Model.cpp
 | 
			
		||||
 | 
			
		||||
// Статическое поле для модели лампочки
 | 
			
		||||
GrouptedModel Bulb::bulb_model;
 | 
			
		||||
 | 
			
		||||
// Конструктор с координатами, цветом и радиусом
 | 
			
		||||
Bulb::Bulb(const glm::vec3 &pos, const glm::vec3 &c, float r, float a, const glm::vec3 &dir)
 | 
			
		||||
{
 | 
			
		||||
    // Если отладочная модель не загружена - загрузим
 | 
			
		||||
    if (!bulb_model.parts.size())
 | 
			
		||||
    {
 | 
			
		||||
        bulb_model = loadOBJtoGroupted("../resources/models/bulb.obj", "../resources/models/", "../resources/textures/"); 
 | 
			
		||||
        
 | 
			
		||||
        Model radius_sphere;
 | 
			
		||||
        // Сгенерируем и загрузим меш сферы
 | 
			
		||||
        genShpere(radius_sphere, 1, 16);
 | 
			
		||||
        bulb_model.parts.insert(bulb_model.parts.begin(), radius_sphere);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Сохраним данные о параметрах источника:
 | 
			
		||||
    position = pos;
 | 
			
		||||
    color = c;
 | 
			
		||||
    radius = r;
 | 
			
		||||
    K[0] = 4.5/radius;
 | 
			
		||||
    K[1] = 4 * K[0] * K[0];
 | 
			
		||||
    angle = a;
 | 
			
		||||
    direction = dir;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Отрисовка отладочной лампы и сферы
 | 
			
		||||
void Bulb::render(ShaderProgram &shaderProgram, UBO &material_buffer)
 | 
			
		||||
{
 | 
			
		||||
    // Расположение uniform-переменных
 | 
			
		||||
    GLuint model_uniform = shaderProgram.getUniformLoc("model");
 | 
			
		||||
    GLuint angle_uniform = shaderProgram.getUniformLoc("angle");
 | 
			
		||||
    GLuint direction_uniform = shaderProgram.getUniformLoc("direction");
 | 
			
		||||
    
 | 
			
		||||
    // Загрузим направление
 | 
			
		||||
    glUniform3fv(direction_uniform, 1, &direction[0]);
 | 
			
		||||
 | 
			
		||||
    // Зададим параметры материала сфере действия
 | 
			
		||||
    bulb_model.parts[0].material.ka = color;
 | 
			
		||||
    bulb_model.parts[0].position = position;
 | 
			
		||||
    bulb_model.parts[0].scale = {radius, radius, radius};
 | 
			
		||||
    
 | 
			
		||||
    // Угол для сферы (рисуем направленный конус)
 | 
			
		||||
    glUniform1f(angle_uniform, angle); 
 | 
			
		||||
 | 
			
		||||
    // Рисование сферы покрытия источника в режиме линий
 | 
			
		||||
    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
 | 
			
		||||
    bulb_model.parts[0].render(shaderProgram, material_buffer);
 | 
			
		||||
    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
 | 
			
		||||
    
 | 
			
		||||
    // Угол для лампочки = 180 (рисуем целую модель)
 | 
			
		||||
    glUniform1f(angle_uniform, 180); // Зададим параметры материала сфере действия
 | 
			
		||||
    
 | 
			
		||||
    // Зададим цвет для колбы (первая в составе модели)
 | 
			
		||||
    bulb_model.parts[1].material.ka = color;
 | 
			
		||||
 | 
			
		||||
    bulb_model.position = position;
 | 
			
		||||
    glm::mat4 transform = bulb_model.getTransformMatrix();
 | 
			
		||||
    for (int i = 1; i < bulb_model.parts.size(); i++)
 | 
			
		||||
    {
 | 
			
		||||
        bulb_model.parts[i].render(shaderProgram, material_buffer, transform);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Задание радиуса и расчет коэф. угасания
 | 
			
		||||
void Bulb::setRadius(float r)
 | 
			
		||||
{
 | 
			
		||||
    radius = r;
 | 
			
		||||
    K[0] = 4.5/radius;
 | 
			
		||||
    K[1] = 4 * K[0] * K[0];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Конструктор направленного источника с параметрами направления и цвета
 | 
			
		||||
Sun::Sun(const glm::vec3 &dir, const glm::vec3 &c) : direction(dir), color(c)
 | 
			
		||||
{
 | 
			
		||||
    
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Загрузка данных об источнике на шейдер
 | 
			
		||||
void Sun::upload(ShaderProgram &shaderProgram)
 | 
			
		||||
{
 | 
			
		||||
    GLuint direction_uniform = shaderProgram.getUniformLoc("Sun_direction");
 | 
			
		||||
    GLuint color_uniform = shaderProgram.getUniformLoc("Sun_color");
 | 
			
		||||
 | 
			
		||||
    // Загрузим данные
 | 
			
		||||
    glUniform3fv(direction_uniform, 1, &direction[0]);
 | 
			
		||||
    glUniform3fv(color_uniform, 1, &color[0]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Загружает матрицу проекции и трансформации в пространство источника
 | 
			
		||||
void Sun::pov(ShaderProgram &shaderProgram, Camera camera)
 | 
			
		||||
{
 | 
			
		||||
    // Точки по краям проекции камеры
 | 
			
		||||
    const glm::vec4 (*projCoords)[8] = camera.getProjCoords();
 | 
			
		||||
 | 
			
		||||
    glm::vec3 mean; // Среднее арифметическое
 | 
			
		||||
    glm::vec4 max, min; // макс и мин координаты
 | 
			
		||||
    glm::vec4 point; // Точка приведенная в пространство источника света
 | 
			
		||||
    
 | 
			
		||||
    glm::mat4 lightView; // Матрица вида для вычисляемого каскада
 | 
			
		||||
    glm::mat4 results[CAMERA_CASCADE_COUNT]; // Результат вычисления каждого каскада
 | 
			
		||||
    
 | 
			
		||||
    for (int cascade = 0; cascade < CAMERA_CASCADE_COUNT; cascade++)
 | 
			
		||||
    {
 | 
			
		||||
        mean = glm::vec3(0);
 | 
			
		||||
        // Найдем среднее арифметическое от точек для нахождения центра прямоугольника
 | 
			
		||||
        for (int i = 0; i < 8; i++)
 | 
			
		||||
            mean += glm::vec3(projCoords[cascade][i]);
 | 
			
		||||
        mean /= 8;
 | 
			
		||||
        // Используем среднее арифметическое для получения матрицы вида параллельного источника
 | 
			
		||||
        lightView = glm::lookAt(mean + glm::normalize(direction), mean, CAMERA_UP_VECTOR);
 | 
			
		||||
        
 | 
			
		||||
        // Примем первую точку как минимальную и максимальную (приведя в пространство вида источника)
 | 
			
		||||
        min = max = lightView * projCoords[cascade][0];
 | 
			
		||||
        // Для оставшихся точек
 | 
			
		||||
        for (int i = 1; i < 8; i++)
 | 
			
		||||
        {
 | 
			
		||||
            // Приведем в пространство вида источника
 | 
			
		||||
            point = lightView * projCoords[cascade][i];
 | 
			
		||||
            max = glm::max(max, point);
 | 
			
		||||
            min = glm::min(min, point);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Максимальное значение глубины
 | 
			
		||||
        max.z = std::max(fabs(max.z), fabs(min.z));
 | 
			
		||||
        // На основании максимальных и минимальных координат создадим матрицу проекции источника
 | 
			
		||||
        results[cascade] = glm::ortho(min.x, max.x, min.y, max.y, min.z, max.z) * lightView;
 | 
			
		||||
    }
 | 
			
		||||
    // Загрузим данные о матрице проекции на выбранный шейдер
 | 
			
		||||
    GLuint lightVP_uniform = shaderProgram.getUniformLoc("Sun_VP");
 | 
			
		||||
    glUniformMatrix4fv(lightVP_uniform, CAMERA_CASCADE_COUNT, GL_FALSE, &results[0][0][0]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Пересчитывает матрицы проекции и трансформации в пространство источника
 | 
			
		||||
void Bulb::recalc_pov()
 | 
			
		||||
{
 | 
			
		||||
    float near_plane = 0.1f;
 | 
			
		||||
    glm::mat4 shadowProj = glm::perspective(glm::radians(90.0f), 1.0f, near_plane, radius);
 | 
			
		||||
    vp[0] = shadowProj * glm::lookAt(position, position + glm::vec3( 1.0f,  0.0f,  0.0f), glm::vec3(0.0f, -1.0f,  0.0f));
 | 
			
		||||
    vp[1] = shadowProj * glm::lookAt(position, position + glm::vec3(-1.0f,  0.0f,  0.0f), glm::vec3(0.0f, -1.0f,  0.0f));
 | 
			
		||||
    vp[2] = shadowProj * glm::lookAt(position, position + glm::vec3( 0.0f,  1.0f,  0.0f), glm::vec3(0.0f,  0.0f,  1.0f));
 | 
			
		||||
    vp[3] = shadowProj * glm::lookAt(position, position + glm::vec3( 0.0f, -1.0f,  0.0f), glm::vec3(0.0f,  0.0f, -1.0f));
 | 
			
		||||
    vp[4] = shadowProj * glm::lookAt(position, position + glm::vec3( 0.0f,  0.0f,  1.0f), glm::vec3(0.0f, -1.0f,  0.0f));
 | 
			
		||||
    vp[5] = shadowProj * glm::lookAt(position, position + glm::vec3( 0.0f,  0.0f, -1.0f), glm::vec3(0.0f, -1.0f,  0.0f));
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										414
									
								
								src/Model.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										414
									
								
								src/Model.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,414 @@
 | 
			
		||||
#include "Model.h"
 | 
			
		||||
#include "Camera.h"
 | 
			
		||||
extern Camera camera;
 | 
			
		||||
 | 
			
		||||
Movable::Movable() : position(0), rotation(0), scale(1) {}
 | 
			
		||||
// Конструктор копирования
 | 
			
		||||
Movable::Movable(const Movable& copy) : position(copy.position), rotation(copy.rotation), scale(copy.scale) {}
 | 
			
		||||
 | 
			
		||||
// Конструктор без параметров
 | 
			
		||||
Model::Model() : verteces_count(0), first_index(0), indices_count(0), 
 | 
			
		||||
vertex_vbo(VERTEX), index_vbo(ELEMENT), normals_vbo(VERTEX), texCoords_vbo(VERTEX)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Конструктор копирования
 | 
			
		||||
Model::Model(const Model& copy) : 
 | 
			
		||||
vao(copy.vao), 
 | 
			
		||||
verteces_count(copy.verteces_count), first_index(copy.first_index), indices_count(copy.indices_count), 
 | 
			
		||||
vertex_vbo(copy.vertex_vbo), index_vbo(copy.index_vbo), normals_vbo(copy.normals_vbo), texCoords_vbo(copy.texCoords_vbo), 
 | 
			
		||||
texture_diffuse(copy.texture_diffuse), texture_ambient(copy.texture_ambient), texture_specular(copy.texture_specular), material(copy.material)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Model::~Model()
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Вызов отрисовки без uniform-даных
 | 
			
		||||
void Model::render()
 | 
			
		||||
{
 | 
			
		||||
    // Подключаем VAO
 | 
			
		||||
    vao.use();
 | 
			
		||||
    // Если есть индексы - рисуем с их использованием
 | 
			
		||||
    if (indices_count)
 | 
			
		||||
        glDrawElements(GL_TRIANGLES, indices_count, GL_UNSIGNED_INT, (void*)(first_index*sizeof(GLuint)));
 | 
			
		||||
    // Если есть вершины - рисуем на основании массива вершин
 | 
			
		||||
    else if (verteces_count)
 | 
			
		||||
        glDrawArrays(GL_TRIANGLES, 0, verteces_count);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Вызов отрисовки
 | 
			
		||||
void Model::render(ShaderProgram &shaderProgram, UBO &material_buffer, const glm::mat4& global_tranform) 
 | 
			
		||||
{
 | 
			
		||||
    // Расчитаем матрицу трансформации
 | 
			
		||||
    glm::mat4 model = global_tranform * this->getTransformMatrix();
 | 
			
		||||
    GLuint model_uniform = shaderProgram.getUniformLoc("model");
 | 
			
		||||
    glUniformMatrix4fv(model_uniform, 1, GL_FALSE, &model[0][0]);
 | 
			
		||||
 | 
			
		||||
    // Подключаем текстуры
 | 
			
		||||
    texture_diffuse.use();
 | 
			
		||||
    texture_ambient.use();
 | 
			
		||||
    texture_specular.use();
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    // Загружаем данные о материале
 | 
			
		||||
    material_buffer.load(&material, sizeof(material));
 | 
			
		||||
 | 
			
		||||
    render();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Функция для конфигурации атрибута вершинного буфера
 | 
			
		||||
void vertex_attrib_config()
 | 
			
		||||
{
 | 
			
		||||
    // Включаем необходимый атрибут у выбранного VAO
 | 
			
		||||
    glEnableVertexAttribArray(0);
 | 
			
		||||
    // Устанавливаем связь между VAO и привязанным VBO
 | 
			
		||||
    glVertexAttribPointer(  0         // индекс атрибута, должен совпадать с Layout шейдера
 | 
			
		||||
                          , 3         // количество компонент одного элемента
 | 
			
		||||
                          , GL_FLOAT  // тип
 | 
			
		||||
                          , GL_FALSE  // нормализованность значений
 | 
			
		||||
                          , 0         // шаг
 | 
			
		||||
                          , (void *)0 // отступ с начала массива
 | 
			
		||||
                         );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Загрузка вершин в буфер
 | 
			
		||||
void Model::load_verteces(glm::vec3* verteces, GLuint count)
 | 
			
		||||
{
 | 
			
		||||
    // Подключаем VAO и вершинный буфер
 | 
			
		||||
    vao.use();
 | 
			
		||||
    vertex_vbo.use();
 | 
			
		||||
 | 
			
		||||
    // Загрузка вершин в память буфера
 | 
			
		||||
    vertex_vbo.load(verteces, sizeof(glm::vec3)*count);
 | 
			
		||||
    vertex_attrib_config();
 | 
			
		||||
    // Запоминаем количество вершин для отрисовки
 | 
			
		||||
    verteces_count = count;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Загрузка индексов в буфер
 | 
			
		||||
void Model::load_indices(GLuint* indices, GLuint count) 
 | 
			
		||||
{
 | 
			
		||||
    // Подключаем VAO и индексный буфер
 | 
			
		||||
    vao.use();
 | 
			
		||||
    index_vbo.use();
 | 
			
		||||
 | 
			
		||||
    // Загрузка вершин в память буфера
 | 
			
		||||
    index_vbo.load(indices, sizeof(GLuint)*count);
 | 
			
		||||
    // Запоминаем количество вершин для отрисовки
 | 
			
		||||
    indices_count = count;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Функция для конфигурации атрибута вершинного буфера
 | 
			
		||||
void texCoords_attrib_config()
 | 
			
		||||
{
 | 
			
		||||
    // Включаем необходимый атрибут у выбранного VAO
 | 
			
		||||
    glEnableVertexAttribArray(1);
 | 
			
		||||
    // Устанавливаем связь между VAO и привязанным VBO
 | 
			
		||||
    glVertexAttribPointer(  1         // индекс атрибута, должен совпадать с Layout шейдера
 | 
			
		||||
                          , 2         // количество компонент одного элемента
 | 
			
		||||
                          , GL_FLOAT  // тип
 | 
			
		||||
                          , GL_FALSE  // нормализованность значений
 | 
			
		||||
                          , 0         // шаг
 | 
			
		||||
                          , (void *)0 // отступ с начала массива
 | 
			
		||||
                         );
 | 
			
		||||
} 
 | 
			
		||||
 | 
			
		||||
// Загрузка текстурных координат в буфер
 | 
			
		||||
void Model::load_texCoords(glm::vec2* texCoords, GLuint count)
 | 
			
		||||
{
 | 
			
		||||
    // Подключаем VAO
 | 
			
		||||
    vao.use();
 | 
			
		||||
 | 
			
		||||
    texCoords_vbo.use();
 | 
			
		||||
 | 
			
		||||
    // Загрузка вершин в память буфера
 | 
			
		||||
    texCoords_vbo.load(texCoords, sizeof(glm::vec2)*count);
 | 
			
		||||
    texCoords_attrib_config();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Функция для конфигурации атрибута вершинного буфера
 | 
			
		||||
void normals_attrib_config()
 | 
			
		||||
{
 | 
			
		||||
    // Включаем необходимый атрибут у выбранного VAO
 | 
			
		||||
    glEnableVertexAttribArray(2);
 | 
			
		||||
    // Устанавливаем связь между VAO и привязанным VBO
 | 
			
		||||
    glVertexAttribPointer(  2         // индекс атрибута, должен совпадать с Layout шейдера
 | 
			
		||||
                          , 3         // количество компонент одного элемента
 | 
			
		||||
                          , GL_FLOAT  // тип
 | 
			
		||||
                          , GL_FALSE  // нормализованность значений
 | 
			
		||||
                          , 0         // шаг
 | 
			
		||||
                          , (void *)0 // отступ с начала массива
 | 
			
		||||
                         );
 | 
			
		||||
} 
 | 
			
		||||
 | 
			
		||||
// Загрузка нормалей в буфер
 | 
			
		||||
void Model::load_normals(glm::vec3* normals, GLuint count) 
 | 
			
		||||
{
 | 
			
		||||
    // Подключаем VAO
 | 
			
		||||
    vao.use();
 | 
			
		||||
 | 
			
		||||
    normals_vbo.use();
 | 
			
		||||
 | 
			
		||||
    // Загрузка вершин в память буфера
 | 
			
		||||
    normals_vbo.load(normals, sizeof(glm::vec3)*count);
 | 
			
		||||
    normals_attrib_config();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#include <glm/gtc/matrix_transform.hpp>
 | 
			
		||||
 | 
			
		||||
// Матрица трансформации модели
 | 
			
		||||
glm::mat4 Movable::getTransformMatrix()
 | 
			
		||||
{
 | 
			
		||||
    glm::mat4 transformMatrix = glm::mat4(1.0f);
 | 
			
		||||
    // Перемещение модели
 | 
			
		||||
    transformMatrix = glm::translate(transformMatrix, position);
 | 
			
		||||
    // Поворот модели
 | 
			
		||||
    transformMatrix = glm::rotate(transformMatrix, glm::radians(rotation.x), glm::vec3(1.0, 0.0, 0.0));
 | 
			
		||||
    transformMatrix = glm::rotate(transformMatrix, glm::radians(rotation.y), glm::vec3(0.0, 1.0, 0.0));
 | 
			
		||||
    transformMatrix = glm::rotate(transformMatrix, glm::radians(rotation.z), glm::vec3(0.0, 0.0, 1.0));
 | 
			
		||||
    // Масштабирование
 | 
			
		||||
    transformMatrix = glm::scale(transformMatrix, scale);  
 | 
			
		||||
 | 
			
		||||
    return transformMatrix;
 | 
			
		||||
} 
 | 
			
		||||
 | 
			
		||||
// Привязка текстуры к модели
 | 
			
		||||
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;
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Ограничение диапазона из буфера индексов
 | 
			
		||||
void Model::set_index_range(GLuint beg, GLuint count)
 | 
			
		||||
{
 | 
			
		||||
    first_index = beg;
 | 
			
		||||
    indices_count = count;
 | 
			
		||||
} 
 | 
			
		||||
 | 
			
		||||
#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...);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GrouptedModel loadOBJtoGroupted(const char* filename, const char* mtl_directory, const char* texture_directory)
 | 
			
		||||
{
 | 
			
		||||
    GrouptedModel result;
 | 
			
		||||
    Model model;
 | 
			
		||||
 | 
			
		||||
    tinyobj::attrib_t attrib;
 | 
			
		||||
    std::vector<tinyobj::shape_t> shapes;
 | 
			
		||||
    std::vector<tinyobj::material_t> materials;
 | 
			
		||||
 | 
			
		||||
    std::string err;
 | 
			
		||||
 | 
			
		||||
    // Если в процессе загрузки возникли ошибки - выдадим исключение
 | 
			
		||||
    if (!tinyobj::LoadObj(&attrib, &shapes, &materials, &err, filename, mtl_directory))
 | 
			
		||||
        throw std::runtime_error(err);
 | 
			
		||||
 
 | 
			
		||||
    std::vector<GLuint>    indices;  // индексы модели
 | 
			
		||||
    std::vector<glm::vec3> verteces; // вершины
 | 
			
		||||
    std::vector<glm::vec3> normals; // нормали
 | 
			
		||||
    std::vector<glm::vec2> texCords; // текстурные координаты
 | 
			
		||||
    size_t hash; // Для уникальных вершин
 | 
			
		||||
    std::map <int, int> uniqueVerteces; // словарь для уникальных вершин: ключ - хеш, значение - индекс вершины
 | 
			
		||||
    
 | 
			
		||||
    int last_material_index = 0; // индекс последнего материала (для группировки моделей)
 | 
			
		||||
    int count = 0, offset; // для индексов начала и конца в индексном буфере
 | 
			
		||||
    std::vector<int> materials_range; // хранилище индексов
 | 
			
		||||
    std::vector<int> materials_ids; // индексы материалов
 | 
			
		||||
 | 
			
		||||
    materials_range.push_back(count); // Закидываем начало отрезка в индексном буфере
 | 
			
		||||
    // Цикл по считанным моделям
 | 
			
		||||
    for (const auto& shape : shapes) 
 | 
			
		||||
    {
 | 
			
		||||
        offset = count;  // Переменная для 
 | 
			
		||||
        last_material_index = shape.mesh.material_ids[(count - offset)/3]; // Запоминаем индекс материала
 | 
			
		||||
 | 
			
		||||
        // Цикл по индексам модели
 | 
			
		||||
        for (const auto& index : shape.mesh.indices) 
 | 
			
		||||
        {
 | 
			
		||||
            hash = 0;
 | 
			
		||||
            hash_combine( hash
 | 
			
		||||
                        , attrib.vertices[3 * index.vertex_index + 0], attrib.vertices[3 * index.vertex_index + 1], attrib.vertices[3 * index.vertex_index + 2]
 | 
			
		||||
                        , attrib.normals[3 * index.normal_index + 0], attrib.normals[3 * index.normal_index + 1], attrib.normals[3 * index.normal_index + 2]
 | 
			
		||||
                        , attrib.texcoords[2 * index.texcoord_index + 0], attrib.texcoords[2 * index.texcoord_index + 1]);
 | 
			
		||||
        
 | 
			
		||||
            if (!uniqueVerteces.count(hash))
 | 
			
		||||
            {
 | 
			
		||||
                uniqueVerteces[hash] = verteces.size();
 | 
			
		||||
                
 | 
			
		||||
                // группируем вершины в массив на основании индексов
 | 
			
		||||
                verteces.push_back({  attrib.vertices[3 * index.vertex_index + 0]
 | 
			
		||||
                                                , attrib.vertices[3 * index.vertex_index + 1]
 | 
			
		||||
                                                , attrib.vertices[3 * index.vertex_index + 2]
 | 
			
		||||
                                            });
 | 
			
		||||
                // группируем нормали в массив на основании индексов
 | 
			
		||||
                normals.push_back({  attrib.normals[3 * index.normal_index + 0]
 | 
			
		||||
                                                , attrib.normals[3 * index.normal_index + 1]
 | 
			
		||||
                                                , attrib.normals[3 * index.normal_index + 2]
 | 
			
		||||
                                            });
 | 
			
		||||
                // группируем текстурные координаты в массив на основании индексов
 | 
			
		||||
                texCords.push_back({  attrib.texcoords[2 * index.texcoord_index + 0]
 | 
			
		||||
                                                , 1-attrib.texcoords[2 * index.texcoord_index + 1]
 | 
			
		||||
                                            });
 | 
			
		||||
            }
 | 
			
		||||
            // Сохраняем индекс в массив
 | 
			
		||||
            indices.push_back(uniqueVerteces[hash]);
 | 
			
		||||
            
 | 
			
		||||
            // Если индекс последнего материала изменился, то необходимо сохранить его
 | 
			
		||||
            if (last_material_index != shape.mesh.material_ids[(count - offset)/3])
 | 
			
		||||
            {
 | 
			
		||||
                materials_range.push_back(count); // как конец отрезка
 | 
			
		||||
                materials_ids.push_back(last_material_index); // как используемый материал
 | 
			
		||||
                last_material_index = shape.mesh.material_ids[(count - offset)/3];
 | 
			
		||||
            }
 | 
			
		||||
            count++; 
 | 
			
		||||
        } // for (const auto& index : shape.mesh.indices) 
 | 
			
		||||
        
 | 
			
		||||
        // Если последний материал не загружен - загружаем его
 | 
			
		||||
        if (materials_range[materials_range.size()-1] != count-1)
 | 
			
		||||
        {
 | 
			
		||||
            materials_range.push_back(count); // последний конец отрезка
 | 
			
		||||
            materials_ids.push_back(last_material_index); // последний используемый материал
 | 
			
		||||
        }
 | 
			
		||||
    } // for (const auto& shape : shapes) 
 | 
			
		||||
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    // Загрузка в буферы
 | 
			
		||||
    model.load_verteces (&verteces[0], verteces.size());
 | 
			
		||||
    model.load_normals  (&normals[0],  normals.size());
 | 
			
		||||
    model.load_texCoords(&texCords[0], texCords.size());
 | 
			
		||||
    // Загрузка индексного буфера
 | 
			
		||||
    model.load_indices  (&indices[0],  indices.size());
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // Создаем копии модели, которые будут рендериться в заданном диапазоне
 | 
			
		||||
    // И присваиваем текстуры копиям на основании материала
 | 
			
		||||
    for (int i = 0; i < materials_range.size()-1; i++)
 | 
			
		||||
    {
 | 
			
		||||
        result.parts.push_back(model); // Создание копии с общим VAO
 | 
			
		||||
        auto s = --result.parts.end();
 | 
			
		||||
        s->set_index_range(materials_range[i], materials_range[i+1]-materials_range[i]);
 | 
			
		||||
 | 
			
		||||
        // Текстуры
 | 
			
		||||
        Texture diffuse(TEX_DIFFUSE, texture_directory + materials[materials_ids[i]].diffuse_texname);
 | 
			
		||||
        s->set_texture(diffuse);
 | 
			
		||||
        Texture ambient(TEX_AMBIENT, texture_directory + materials[materials_ids[i]].ambient_texname);
 | 
			
		||||
        s->set_texture(ambient);
 | 
			
		||||
        Texture specular(TEX_SPECULAR, texture_directory + materials[materials_ids[i]].specular_texname);
 | 
			
		||||
        s->set_texture(specular);
 | 
			
		||||
 | 
			
		||||
        // Материал
 | 
			
		||||
        s->material.ka = glm::vec3(materials[materials_ids[i]].ambient[0],  materials[materials_ids[i]].ambient[1],  materials[materials_ids[i]].ambient[2]);
 | 
			
		||||
        s->material.kd = glm::vec3(materials[materials_ids[i]].diffuse[0],  materials[materials_ids[i]].diffuse[1],  materials[materials_ids[i]].diffuse[2]);
 | 
			
		||||
        s->material.ks = glm::vec3(materials[materials_ids[i]].specular[0], materials[materials_ids[i]].specular[1], materials[materials_ids[i]].specular[2]);
 | 
			
		||||
        s->material.p  = (materials[materials_ids[i]].shininess > 0.0f) ? 1000.0f / materials[materials_ids[i]].shininess : 1000.0f;
 | 
			
		||||
    }    
 | 
			
		||||
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Вызов отрисовки групповой модели
 | 
			
		||||
void GrouptedModel::render(ShaderProgram &shaderProgram, UBO &material_buffer)
 | 
			
		||||
{
 | 
			
		||||
    glm::mat4 transform = this->getTransformMatrix();
 | 
			
		||||
    for (auto& model : parts)
 | 
			
		||||
        model.render(shaderProgram, material_buffer, transform);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Генерирует сферу заданного радиуса с определенным количеством сегментов
 | 
			
		||||
void genShpere(Model& model, float radius, int sectorsCount)
 | 
			
		||||
{
 | 
			
		||||
    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);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    // Загрузка в модель
 | 
			
		||||
    model.load_verteces(&vertices[0], vertices.size());
 | 
			
		||||
    model.load_normals(&normals[0], normals.size());
 | 
			
		||||
    model.load_indices(&indices[0], indices.size());
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										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);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										359
									
								
								src/Texture.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										359
									
								
								src/Texture.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,359 @@
 | 
			
		||||
#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)
 | 
			
		||||
            {
 | 
			
		||||
                // Загрузка данных с учетом прозрачности
 | 
			
		||||
                if (channels == 3) // RGB
 | 
			
		||||
                    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
 | 
			
		||||
                else if (channels == 4) // RGBA
 | 
			
		||||
                    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);
 | 
			
		||||
 | 
			
		||||
                glGenerateMipmap(GL_TEXTURE_2D); // Генерация мипмапа для активной текстуры
 | 
			
		||||
                glBindTexture(GL_TEXTURE_2D, 0); // Отвязка активной текстуры
 | 
			
		||||
                
 | 
			
		||||
                stbi_image_free(image); // Освобождение оперативной памяти
 | 
			
		||||
            }
 | 
			
		||||
            // Иначе изображение не считано и надо создать пустую текстуру
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                image = new unsigned char[3] {255,255,255}; // RGB по 1 байту на 
 | 
			
		||||
                glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, image); // Загрузка данных на видеокарту
 | 
			
		||||
                delete image; // Освобождение оперативной памяти
 | 
			
		||||
                
 | 
			
		||||
                filename_handler[empty] = handler; // Запоминим дополнительно её дескриптор для NULL-строки
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        // Иначе используем существующую пустую текстуру (текстура не загружена, пустую создавать не нужно)
 | 
			
		||||
        else
 | 
			
		||||
            handler = filename_handler[empty];
 | 
			
		||||
    }
 | 
			
		||||
    // Иначе используем уже существующую по имени файла
 | 
			
		||||
    else
 | 
			
		||||
        handler = filename_handler[filename];
 | 
			
		||||
        
 | 
			
		||||
    handler_count[handler]++;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Конструктор текстуры заданного размера для использования в буфере
 | 
			
		||||
Texture::Texture(GLuint width, GLuint height, GLuint attachment, GLuint texType, GLint internalformat, GLint format, GLenum dataType)
 | 
			
		||||
{
 | 
			
		||||
    type = texType;
 | 
			
		||||
    // Генерация текстуры заданного размера
 | 
			
		||||
    glGenTextures(1, &handler);
 | 
			
		||||
    glBindTexture(GL_TEXTURE_2D, handler);
 | 
			
		||||
    glTexImage2D(GL_TEXTURE_2D, 0, internalformat, width, height, 0, format, dataType, NULL);
 | 
			
		||||
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 | 
			
		||||
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 | 
			
		||||
 | 
			
		||||
    // Привязка к буферу кадра
 | 
			
		||||
    glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GL_TEXTURE_2D, handler, 0);
 | 
			
		||||
 | 
			
		||||
    // Создаем счетчик использований дескриптора
 | 
			
		||||
    handler_count[handler] = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Конструктор копирования
 | 
			
		||||
Texture::Texture(const Texture& other)
 | 
			
		||||
{
 | 
			
		||||
    handler = other.handler; 
 | 
			
		||||
    type = other.type;
 | 
			
		||||
    // Делаем копию и увеличиваем счетчик
 | 
			
		||||
    handler_count[handler]++;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Оператор присваивания
 | 
			
		||||
Texture& Texture::operator=(const Texture& other)
 | 
			
		||||
{
 | 
			
		||||
    // Если это разные текстуры
 | 
			
		||||
    if (handler != other.handler)
 | 
			
		||||
    {
 | 
			
		||||
        this->~Texture(); // Уничтожаем имеющуюся
 | 
			
		||||
        // Заменяем новой
 | 
			
		||||
        handler = other.handler;
 | 
			
		||||
        handler_count[handler]++;
 | 
			
		||||
    }
 | 
			
		||||
    type = other.type;
 | 
			
		||||
 | 
			
		||||
    return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BaseTexture::~BaseTexture()
 | 
			
		||||
{
 | 
			
		||||
    if (!--handler_count[handler]) // Если количество ссылок = 0
 | 
			
		||||
    {
 | 
			
		||||
        glDeleteTextures(1, &handler); // Удаление текстуры
 | 
			
		||||
        // Удаление из словаря имен файлов и дескрипторов
 | 
			
		||||
        for (auto it = filename_handler.begin(); it != filename_handler.end();)
 | 
			
		||||
        {
 | 
			
		||||
            if (it->second == handler) 
 | 
			
		||||
                it = filename_handler.erase(it);
 | 
			
		||||
            else
 | 
			
		||||
                it++;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Привязка текстуры
 | 
			
		||||
void Texture::use()
 | 
			
		||||
{
 | 
			
		||||
    glActiveTexture(type + GL_TEXTURE0);
 | 
			
		||||
    glBindTexture(GL_TEXTURE_2D, handler); // Привязка текстуры как активной
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Отвязка текстуры по типу
 | 
			
		||||
void BaseTexture::disable(GLuint type)
 | 
			
		||||
{
 | 
			
		||||
    glActiveTexture(type + GL_TEXTURE0);
 | 
			
		||||
    glBindTexture(GL_TEXTURE_2D, 0); // Отвязка текстуры
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Возвращает тип текстуры
 | 
			
		||||
GLuint BaseTexture::getType()
 | 
			
		||||
{
 | 
			
		||||
    return type;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Задает тип текстуры
 | 
			
		||||
void BaseTexture::setType(GLuint type)
 | 
			
		||||
{
 | 
			
		||||
    this->type = type;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Конструктор текстуры заданного размера для использования в буфере
 | 
			
		||||
TextureArray::TextureArray(GLuint levels, GLuint width, GLuint height, GLuint attachment, GLuint texType, GLint internalformat, GLint format, GLenum dataType)
 | 
			
		||||
{
 | 
			
		||||
    type = texType;
 | 
			
		||||
    // Генерация текстуры заданного размера
 | 
			
		||||
    glGenTextures(1, &handler);
 | 
			
		||||
    glBindTexture(GL_TEXTURE_2D_ARRAY, handler);
 | 
			
		||||
    glTexImage3D(
 | 
			
		||||
        GL_TEXTURE_2D_ARRAY, 0, internalformat, width, height, levels, 0, format, dataType, 0);
 | 
			
		||||
 | 
			
		||||
    glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 | 
			
		||||
    glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 | 
			
		||||
 | 
			
		||||
    // Привязка к буферу кадра
 | 
			
		||||
    glFramebufferTexture(GL_FRAMEBUFFER, attachment, handler, 0);
 | 
			
		||||
 | 
			
		||||
    // Создаем счетчик использований дескриптора
 | 
			
		||||
    handler_count[handler] = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Конструктор копирования
 | 
			
		||||
TextureArray::TextureArray(const TextureArray& other)
 | 
			
		||||
{
 | 
			
		||||
    handler = other.handler; 
 | 
			
		||||
    type = other.type;
 | 
			
		||||
    // Делаем копию и увеличиваем счетчик
 | 
			
		||||
    handler_count[handler]++;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Оператор присваивания
 | 
			
		||||
TextureArray& TextureArray::operator=(const TextureArray& other)
 | 
			
		||||
{
 | 
			
		||||
    // Если это разные текстуры
 | 
			
		||||
    if (handler != other.handler)
 | 
			
		||||
    {
 | 
			
		||||
        this->~TextureArray(); // Уничтожаем имеющуюся
 | 
			
		||||
        // Заменяем новой
 | 
			
		||||
        handler = other.handler;
 | 
			
		||||
        handler_count[handler]++;
 | 
			
		||||
    }
 | 
			
		||||
    type = other.type;
 | 
			
		||||
 | 
			
		||||
    return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Привязка текстуры
 | 
			
		||||
void TextureArray::use()
 | 
			
		||||
{
 | 
			
		||||
    glActiveTexture(type + GL_TEXTURE0);
 | 
			
		||||
    glBindTexture(GL_TEXTURE_2D_ARRAY, handler); // Привязка текстуры как активной
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Загрузка текстуры с диска или использование "пустой"
 | 
			
		||||
TextureCube::TextureCube(GLuint t, const std::string (&filename)[6])
 | 
			
		||||
{
 | 
			
		||||
    type = t;
 | 
			
		||||
    std::string complex_name;
 | 
			
		||||
    for (int i = 0; i < 6; i++)
 | 
			
		||||
        complex_name += filename[i];
 | 
			
		||||
    if (!filename_handler.count(complex_name))
 | 
			
		||||
    {
 | 
			
		||||
        std::string empty = "";
 | 
			
		||||
        int width, height, channels; // Ширина, высота и цветовые каналы текстуры
 | 
			
		||||
        unsigned char* image;
 | 
			
		||||
 | 
			
		||||
        glActiveTexture(type + GL_TEXTURE0);
 | 
			
		||||
        glGenTextures(1, &handler); // Генерация одной текстуры
 | 
			
		||||
        glBindTexture(GL_TEXTURE_CUBE_MAP, handler); // Привязка текстуры как активной
 | 
			
		||||
 | 
			
		||||
        filename_handler[complex_name] = handler; // Запомним её дескриптор для этого имени файла
 | 
			
		||||
        handler_count[handler] = 0; // Создадим счетчик использований дескриптора, который будет изменен в конце
 | 
			
		||||
 | 
			
		||||
        for (int i = 0; i < 6; i++) 
 | 
			
		||||
        {
 | 
			
		||||
            image = stbi_load(filename[i].c_str(), &width, &height, &channels, STBI_default); // Загрузка в оперативную память изображения
 | 
			
		||||
 | 
			
		||||
            // Если изображение успешно считано
 | 
			
		||||
            if (image)
 | 
			
		||||
            {
 | 
			
		||||
                // Загрузка данных с учетом прозрачности
 | 
			
		||||
                if (channels == 3) // RGB
 | 
			
		||||
                    glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
 | 
			
		||||
                else if (channels == 4) // RGBA
 | 
			
		||||
                    glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);
 | 
			
		||||
 | 
			
		||||
                stbi_image_free(image); // Освобождение оперативной памяти
 | 
			
		||||
            }
 | 
			
		||||
            // Иначе изображение не считано и надо создать пустую текстуру
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                image = new unsigned char[3] {255,255,255}; // RGB по 1 байту на 
 | 
			
		||||
                glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, image); // Загрузка данных на видеокарту
 | 
			
		||||
                delete image; // Освобождение оперативной памяти
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    // Иначе используем уже существующую по имени файла
 | 
			
		||||
    else
 | 
			
		||||
        handler = filename_handler[complex_name];
 | 
			
		||||
 | 
			
		||||
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 | 
			
		||||
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 | 
			
		||||
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
 | 
			
		||||
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 | 
			
		||||
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
 | 
			
		||||
 | 
			
		||||
    handler_count[handler]++;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Конструктор текстуры заданного размера для использования в буфере
 | 
			
		||||
TextureCube::TextureCube(GLuint width, GLuint height, GLuint attachment, GLuint texType, GLint internalformat, GLint format, GLenum dataType)
 | 
			
		||||
{
 | 
			
		||||
    type = texType;
 | 
			
		||||
    // Генерация текстуры заданного размера
 | 
			
		||||
    glGenTextures(1, &handler);
 | 
			
		||||
    glBindTexture(GL_TEXTURE_CUBE_MAP, handler);
 | 
			
		||||
    for (int i = 0; i < 6; ++i)
 | 
			
		||||
        glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, internalformat, width, height, 0, format, dataType, 0);  
 | 
			
		||||
 | 
			
		||||
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 | 
			
		||||
    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 | 
			
		||||
 | 
			
		||||
    // Привязка к буферу кадра
 | 
			
		||||
    glFramebufferTexture(GL_FRAMEBUFFER, attachment, handler, 0);
 | 
			
		||||
 | 
			
		||||
    // Создаем счетчик использований дескриптора
 | 
			
		||||
    handler_count[handler] = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Конструктор копирования
 | 
			
		||||
TextureCube::TextureCube(const TextureCube& other)
 | 
			
		||||
{
 | 
			
		||||
    handler = other.handler; 
 | 
			
		||||
    type = other.type;
 | 
			
		||||
    // Делаем копию и увеличиваем счетчик
 | 
			
		||||
    handler_count[handler]++;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Оператор присваивания
 | 
			
		||||
TextureCube& TextureCube::operator=(const TextureCube& other)
 | 
			
		||||
{
 | 
			
		||||
    // Если это разные текстуры
 | 
			
		||||
    if (handler != other.handler)
 | 
			
		||||
    {
 | 
			
		||||
        this->~TextureCube(); // Уничтожаем имеющуюся
 | 
			
		||||
        // Заменяем новой
 | 
			
		||||
        handler = other.handler;
 | 
			
		||||
        handler_count[handler]++;
 | 
			
		||||
    }
 | 
			
		||||
    type = other.type;
 | 
			
		||||
 | 
			
		||||
    return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Привязка текстуры
 | 
			
		||||
void TextureCube::use()
 | 
			
		||||
{
 | 
			
		||||
    glActiveTexture(type + GL_TEXTURE0);
 | 
			
		||||
    glBindTexture(GL_TEXTURE_CUBE_MAP, handler); // Привязка текстуры как активной
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Конструктор текстуры заданного размера для использования в буфере
 | 
			
		||||
TextureCubeArray::TextureCubeArray(GLuint levels, GLuint width, GLuint height, GLuint attachment, GLuint texType, GLint internalformat, GLint format, GLenum dataType)
 | 
			
		||||
{
 | 
			
		||||
    type = texType;
 | 
			
		||||
    // Генерация текстуры заданного размера
 | 
			
		||||
    glGenTextures(1, &handler);
 | 
			
		||||
    glBindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, handler);
 | 
			
		||||
    glTexImage3D(
 | 
			
		||||
        GL_TEXTURE_CUBE_MAP_ARRAY, 0, internalformat, width, height, 6*levels, 0, format, dataType, 0);
 | 
			
		||||
 | 
			
		||||
    glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 | 
			
		||||
    glTexParameteri(GL_TEXTURE_CUBE_MAP_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
 | 
			
		||||
 | 
			
		||||
    // Привязка к буферу кадра
 | 
			
		||||
    glFramebufferTexture(GL_FRAMEBUFFER, attachment, handler, 0);
 | 
			
		||||
 | 
			
		||||
    // Создаем счетчик использований дескриптора
 | 
			
		||||
    handler_count[handler] = 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Конструктор копирования
 | 
			
		||||
TextureCubeArray::TextureCubeArray(const TextureCubeArray& other)
 | 
			
		||||
{
 | 
			
		||||
    handler = other.handler; 
 | 
			
		||||
    type = other.type;
 | 
			
		||||
    // Делаем копию и увеличиваем счетчик
 | 
			
		||||
    handler_count[handler]++;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Оператор присваивания
 | 
			
		||||
TextureCubeArray& TextureCubeArray::operator=(const TextureCubeArray& other)
 | 
			
		||||
{
 | 
			
		||||
    // Если это разные текстуры
 | 
			
		||||
    if (handler != other.handler)
 | 
			
		||||
    {
 | 
			
		||||
        this->~TextureCubeArray(); // Уничтожаем имеющуюся
 | 
			
		||||
        // Заменяем новой
 | 
			
		||||
        handler = other.handler;
 | 
			
		||||
        handler_count[handler]++;
 | 
			
		||||
    }
 | 
			
		||||
    type = other.type;
 | 
			
		||||
 | 
			
		||||
    return *this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Привязка текстуры
 | 
			
		||||
void TextureCubeArray::use()
 | 
			
		||||
{
 | 
			
		||||
    glActiveTexture(type + GL_TEXTURE0);
 | 
			
		||||
    glBindTexture(GL_TEXTURE_CUBE_MAP_ARRAY, handler); // Привязка текстуры как активной
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										439
									
								
								src/main.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										439
									
								
								src/main.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,439 @@
 | 
			
		||||
 | 
			
		||||
#include <glad/glad.h>
 | 
			
		||||
#include <GLFW/glfw3.h>
 | 
			
		||||
#include <GLM/glm.hpp>
 | 
			
		||||
 | 
			
		||||
#include <iostream>
 | 
			
		||||
 | 
			
		||||
#include "Camera.h"
 | 
			
		||||
#include "Model.h"
 | 
			
		||||
#include "Texture.h"
 | 
			
		||||
#include "Shader.h"
 | 
			
		||||
#include "Lights.h"
 | 
			
		||||
 | 
			
		||||
#define WINDOW_WIDTH 800
 | 
			
		||||
#define WINDOW_HEIGHT 600
 | 
			
		||||
#define WINDOW_CAPTION "OPENGL notes on rekovalev.site"
 | 
			
		||||
 | 
			
		||||
// Функция-callback для изменения размеров буфера кадра в случае изменения размеров поверхности окна
 | 
			
		||||
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
 | 
			
		||||
{
 | 
			
		||||
    glViewport(0, 0, width, height);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Camera camera(800.0f/600.0f);
 | 
			
		||||
 
 | 
			
		||||
bool firstMouse = true;
 | 
			
		||||
float lastX, lastY;
 | 
			
		||||
 | 
			
		||||
void mouse_callback(GLFWwindow* window, double xpos, double ypos)
 | 
			
		||||
{
 | 
			
		||||
    if (firstMouse)
 | 
			
		||||
    {
 | 
			
		||||
        lastX = xpos;
 | 
			
		||||
        lastY = ypos;
 | 
			
		||||
        firstMouse = false;
 | 
			
		||||
    }
 | 
			
		||||
  
 | 
			
		||||
    glm::vec2 offset(xpos - lastX, lastY - ypos); 
 | 
			
		||||
    lastX = xpos;
 | 
			
		||||
    lastY = ypos;
 | 
			
		||||
 | 
			
		||||
    camera.rotate(offset);
 | 
			
		||||
}  
 | 
			
		||||
 | 
			
		||||
int main(void)
 | 
			
		||||
{
 | 
			
		||||
    GLFWwindow* window; // Указатель на окно GLFW3
 | 
			
		||||
 | 
			
		||||
    // Инициализация GLFW3
 | 
			
		||||
    if (!glfwInit())
 | 
			
		||||
    {
 | 
			
		||||
        std::cout << "GLFW init error\n";
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); // Мажорная версия спецификаций OpenGL
 | 
			
		||||
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5); // Минорная версия спецификаций 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";
 | 
			
		||||
        glfwTerminate(); // Завершение работы с GLFW3 в случае ошибки
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Установка основного контекста окна
 | 
			
		||||
    glfwMakeContextCurrent(window);
 | 
			
		||||
    // Установка callback-функции для изменения размеров окна и буфера кадра
 | 
			
		||||
    glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
 | 
			
		||||
 | 
			
		||||
    glfwSwapInterval(1); // Вертикальная синхронизация
 | 
			
		||||
 | 
			
		||||
    // Установка callback-функции для мыши и камеры
 | 
			
		||||
    glfwSetCursorPosCallback(window, mouse_callback);
 | 
			
		||||
 | 
			
		||||
    // Загрузка функций OpenGL с помощью GLAD
 | 
			
		||||
    if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
 | 
			
		||||
    {
 | 
			
		||||
        std::cout << "GLAD load GL error\n";
 | 
			
		||||
        glfwTerminate(); // Завершение работы с GLFW3 в случае ошибки
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Включаем проверку по буферу глубины
 | 
			
		||||
    glEnable(GL_DEPTH_TEST);
 | 
			
		||||
 | 
			
		||||
    // Шейдер для G-буфера
 | 
			
		||||
    ShaderProgram gShader;
 | 
			
		||||
    // Загрузка и компиляция шейдеров
 | 
			
		||||
    gShader.load(GL_VERTEX_SHADER, "shaders/gshader.vert");
 | 
			
		||||
    gShader.load(GL_FRAGMENT_SHADER, "shaders/gshader.frag");
 | 
			
		||||
    gShader.link();
 | 
			
		||||
    // Установим значения текстур
 | 
			
		||||
    const char* textures_base_shader_names[] = {"tex_diffuse", "tex_ambient", "tex_specular"};
 | 
			
		||||
    gShader.bindTextures(textures_base_shader_names, sizeof(textures_base_shader_names)/sizeof(const char*));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // Загрузка сцены из obj файла
 | 
			
		||||
    GrouptedModel scene = loadOBJtoGroupted("../resources/models/blob.obj", "../resources/models/", "../resources/textures/"); 
 | 
			
		||||
    scene.scale = glm::vec3(0.01);
 | 
			
		||||
    scene.position.z = 1;
 | 
			
		||||
    scene.parts[0].material.kd = {0.5,0.5,0.5};
 | 
			
		||||
    scene.parts[0].material.ka = {0.2,0.2,0.2};
 | 
			
		||||
    
 | 
			
		||||
    // Установка цвета очистки буфера цвета
 | 
			
		||||
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
 | 
			
		||||
 | 
			
		||||
    // Шейдер для рисования лампочки
 | 
			
		||||
    ShaderProgram bulbShader;
 | 
			
		||||
    // Загрузка и компиляция шейдеров
 | 
			
		||||
    bulbShader.load(GL_VERTEX_SHADER, "shaders/bulb.vert");
 | 
			
		||||
    bulbShader.load(GL_FRAGMENT_SHADER, "shaders/bulb.frag");
 | 
			
		||||
    bulbShader.link();
 | 
			
		||||
 | 
			
		||||
    // Направленный источник света
 | 
			
		||||
    Sun sun;
 | 
			
		||||
    sun.direction.z = -1.0;
 | 
			
		||||
 | 
			
		||||
    camera.move({0.3,0,0});
 | 
			
		||||
 | 
			
		||||
    // Источники света
 | 
			
		||||
    Bulb lights[MAX_LIGHTS];
 | 
			
		||||
    // Количество используемых источников
 | 
			
		||||
    GLint lights_count = 0;
 | 
			
		||||
 | 
			
		||||
    lights[lights_count].position = {0.3f, 0.0f, 0.6f}; // позиция
 | 
			
		||||
    lights[lights_count].color = {1.0f, 0.0f, 0.0f}; // цвет
 | 
			
		||||
    lights[lights_count++].angle = 50; 
 | 
			
		||||
    lights[lights_count].position = {-0.3f, 0.3f, 0.5f}; // позиция
 | 
			
		||||
    lights[lights_count++].color = {0.0f, 0.0f, 1.0f}; // цвет
 | 
			
		||||
 | 
			
		||||
    // Uniform-буферы
 | 
			
		||||
    UBO cameraUB(sizeof(CameraData), 0);
 | 
			
		||||
    UBO material_data(sizeof(Material), 1);
 | 
			
		||||
    UBO light_data(sizeof(lights_count) + sizeof(lights), 2);
 | 
			
		||||
 | 
			
		||||
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); // Использование уменьшенных версий mipmap  
 | 
			
		||||
 | 
			
		||||
    // Создадим G-буфер с данными о используемых привязках
 | 
			
		||||
    GLuint attachments[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3 };
 | 
			
		||||
    FBO gbuffer(attachments, sizeof(attachments) / sizeof(GLuint));
 | 
			
		||||
    // Создадим текстуры для буфера кадра
 | 
			
		||||
    Texture gPosition(WINDOW_WIDTH, WINDOW_HEIGHT, GL_COLOR_ATTACHMENT0, 0, GL_RGB16F, GL_RGB); // Позиция вершины
 | 
			
		||||
    Texture gNormal(WINDOW_WIDTH, WINDOW_HEIGHT, GL_COLOR_ATTACHMENT1, 1, GL_RGB16F, GL_RGB); // Нормали
 | 
			
		||||
    Texture gDiffuseP(WINDOW_WIDTH, WINDOW_HEIGHT, GL_COLOR_ATTACHMENT2, 2, GL_RGBA16F); // Диффузная составляющая и коэф. глянцевости
 | 
			
		||||
    Texture gAmbientSpecular(WINDOW_WIDTH, WINDOW_HEIGHT, GL_COLOR_ATTACHMENT3, 3); // Фоновая составляющая и один канал зеркальной
 | 
			
		||||
    // Создадим буфер рендера под буфер глубины и привяжем его
 | 
			
		||||
    RBO grbo(WINDOW_WIDTH, WINDOW_HEIGHT);
 | 
			
		||||
    gbuffer.assignRenderBuffer(grbo.getHandler());
 | 
			
		||||
    // Активируем базовый буфер кадра
 | 
			
		||||
    FBO::useDefault();
 | 
			
		||||
 | 
			
		||||
    // Шейдер для расчета освещенности
 | 
			
		||||
    ShaderProgram lightShader;
 | 
			
		||||
    // Загрузка и компиляция шейдеров
 | 
			
		||||
    lightShader.load(GL_VERTEX_SHADER, "shaders/quad.vert");
 | 
			
		||||
    lightShader.load(GL_FRAGMENT_SHADER, "shaders/lighting.frag");
 | 
			
		||||
    lightShader.link();
 | 
			
		||||
    // Привязка текстур
 | 
			
		||||
    const char* gtextures_shader_names[]  = {"gPosition", "gNormal", "gDiffuseP", "gAmbientSpecular", "sunShadowDepth", "pointShadowDepth"};
 | 
			
		||||
    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();
 | 
			
		||||
 | 
			
		||||
    // Модель прямоугольника
 | 
			
		||||
    Model rectangle; 
 | 
			
		||||
 | 
			
		||||
    // Вершины прямоугольника
 | 
			
		||||
    glm::vec3 rectangle_verticies[] = {  {-0.5f, -0.5f, 0.0f}
 | 
			
		||||
                                       , { 0.5f, -0.5f, 0.0f}
 | 
			
		||||
                                       , { 0.5f,  0.5f, 0.0f}
 | 
			
		||||
                                       , {-0.5f,  0.5f, 0.0f}
 | 
			
		||||
                                    };
 | 
			
		||||
    // Загрузка вершин модели
 | 
			
		||||
    rectangle.load_verteces(rectangle_verticies, sizeof(rectangle_verticies)/sizeof(glm::vec3));
 | 
			
		||||
 | 
			
		||||
    // индексы вершин
 | 
			
		||||
    GLuint rectangle_indices[] = {0, 1, 2, 2, 3, 0}; 
 | 
			
		||||
    // Загрузка индексов модели
 | 
			
		||||
    rectangle.load_indices(rectangle_indices, sizeof(rectangle_indices)/sizeof(GLuint));
 | 
			
		||||
 | 
			
		||||
    // Нормали
 | 
			
		||||
    glm::vec3 rectangle_normals[] = {  {0.0f, 0.0f, -1.0f}
 | 
			
		||||
                                     , {0.0f, 0.0f, -1.0f}
 | 
			
		||||
                                     , {0.0f, 0.0f, -1.0f}
 | 
			
		||||
                                     , {0.0f, 0.0f, -1.0f}
 | 
			
		||||
                                    };
 | 
			
		||||
    // Загрузка нормалей модели
 | 
			
		||||
    rectangle.load_normals(rectangle_normals, sizeof(rectangle_normals)/sizeof(glm::vec3));
 | 
			
		||||
 | 
			
		||||
    // Зададим горизонтальное положение перед камерой
 | 
			
		||||
    rectangle.position.y = -1;
 | 
			
		||||
    rectangle.position.z = 2;
 | 
			
		||||
    rectangle.rotation.x = 90;
 | 
			
		||||
    rectangle.scale = glm::vec3(4);
 | 
			
		||||
 | 
			
		||||
    // Параметры материала
 | 
			
		||||
    rectangle.material.ka = {0.2, 0.2, 0.2};
 | 
			
		||||
    rectangle.material.kd = {0.9, 0.9, 0.9};
 | 
			
		||||
 | 
			
		||||
    // Вершины для скайбокса
 | 
			
		||||
    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*));
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    // Пока не произойдет событие запроса закрытия окна
 | 
			
		||||
    while(!glfwWindowShouldClose(window))
 | 
			
		||||
    {
 | 
			
		||||
        // Активируем G-кадра
 | 
			
		||||
        gbuffer.use();
 | 
			
		||||
        // Используем шейдер с освещением
 | 
			
		||||
        gShader.use();
 | 
			
		||||
        // Очистка буфера цвета и глубины
 | 
			
		||||
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 | 
			
		||||
 | 
			
		||||
        // Загрузка данных о камере
 | 
			
		||||
        cameraUB.loadSub(&camera.getData(), sizeof(CameraData));
 | 
			
		||||
        // Пересчет матриц проекции и вида точечных источников
 | 
			
		||||
        for (int i = 0; i < lights_count; i++)
 | 
			
		||||
            lights[i].recalc_pov();
 | 
			
		||||
        // Загружаем информацию об источниках света и их количестве
 | 
			
		||||
        light_data.loadSub(lights, sizeof(Bulb) * lights_count);
 | 
			
		||||
        light_data.loadSub(&lights_count, sizeof(GLint), sizeof(lights));
 | 
			
		||||
 | 
			
		||||
        // Тут производится рендер
 | 
			
		||||
        scene.render(gShader, material_data);
 | 
			
		||||
        rectangle.render(gShader, material_data);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        // Изменим размер вывода для тени
 | 
			
		||||
        glViewport(0, 0, sunShadow_resolution, sunShadow_resolution);
 | 
			
		||||
        // Активируем буфер кадра для теней от солнца
 | 
			
		||||
        sunShadowBuffer.use();
 | 
			
		||||
        // Подключим шейдер для расчета теней
 | 
			
		||||
        sunShadowShader.use();
 | 
			
		||||
        // Очистка буфера глубины
 | 
			
		||||
        glClear(GL_DEPTH_BUFFER_BIT);
 | 
			
		||||
        // Загружаем матрицу проекции и трансформации в пространство источника
 | 
			
		||||
        sun.pov(sunShadowShader, camera);
 | 
			
		||||
        // Рендерим геометрию в буфер глубины
 | 
			
		||||
        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 < lights_count; 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();
 | 
			
		||||
        // Подключаем текстуры теней
 | 
			
		||||
        sunShadowDepth.use();
 | 
			
		||||
        pointShadowDepth.use();
 | 
			
		||||
        // Загружаем информацию о направленном источнике
 | 
			
		||||
        sun.upload(lightShader);
 | 
			
		||||
        // Загружаем матрицу проекции и трансформации в пространство источника
 | 
			
		||||
        sun.pov(lightShader, camera);
 | 
			
		||||
        // Рендерим прямоугольник с расчетом освещения
 | 
			
		||||
        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);
 | 
			
		||||
        
 | 
			
		||||
        // Отрисовка отладочных лампочек со специальным шейдером
 | 
			
		||||
        bulbShader.use();
 | 
			
		||||
        for (int i = 0; i < lights_count; i++)
 | 
			
		||||
            lights[i].render(bulbShader, material_data);
 | 
			
		||||
 | 
			
		||||
        // Представление содержимого буфера цепочки показа на окно
 | 
			
		||||
        glfwSwapBuffers(window);
 | 
			
		||||
        // Обработка системных событий
 | 
			
		||||
        glfwPollEvents();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Отключение атрибутов
 | 
			
		||||
    glDisableVertexAttribArray(0);
 | 
			
		||||
 | 
			
		||||
    // Завершение работы с GLFW3 перед выходом
 | 
			
		||||
    glfwTerminate();
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user