619 lines
27 KiB
C++
Executable File
619 lines
27 KiB
C++
Executable File
|
||
#include <glad/glad.h>
|
||
#include <GLFW/glfw3.h>
|
||
#include <GLM/glm.hpp>
|
||
|
||
#include <iostream>
|
||
#include <random>
|
||
|
||
#include "Scene.h"
|
||
#include "Shader.h"
|
||
#include "Lights.h"
|
||
#include "TRS.h"
|
||
|
||
#define WINDOW_CAPTION "OPENGL notes on rekovalev.site"
|
||
|
||
// Указатели на текстуры для изменения размеров окна
|
||
Texture* pgPosition = NULL;
|
||
Texture* pgNormal = NULL;
|
||
Texture* pgBaseColor = NULL;
|
||
Texture* pgRMS = NULL;
|
||
Texture* pgEmittedColor = NULL;
|
||
Texture* pgID = NULL;
|
||
RBO* pgrbo = NULL;
|
||
Texture* pssaoTexture = NULL;
|
||
Texture* pssaoTexture_raw = NULL;
|
||
// Размеры окна
|
||
int WINDOW_WIDTH = 800;
|
||
int WINDOW_HEIGHT = 600;
|
||
|
||
// Значение гамма-коррекции
|
||
float inv_gamma = 1/2.2;
|
||
|
||
// Функция-callback для изменения размеров буфера кадра в случае изменения размеров поверхности окна
|
||
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
|
||
{
|
||
glViewport(0, 0, width, height);
|
||
|
||
// Изменение размеров текстур для G-буфера
|
||
if (pgPosition)
|
||
pgPosition->reallocate(width, height, 0, GL_RGB32F, GL_RGB);
|
||
if (pgNormal)
|
||
pgNormal->reallocate(width, height, 1, GL_RGB16F, GL_RGB);
|
||
if (pgBaseColor)
|
||
pgBaseColor->reallocate(width, height, 2, GL_RGB);
|
||
if (pgRMS)
|
||
pgRMS->reallocate(width, height, 3, GL_RGB, GL_RGB);
|
||
if (pgEmittedColor)
|
||
pgEmittedColor->reallocate(width, height, 8, GL_RGB, GL_RGB);
|
||
if (pgID)
|
||
pgID->reallocate(width, height, 7, GL_RGB32UI, GL_RGB_INTEGER, GL_UNSIGNED_INT);
|
||
// И буфера глубины
|
||
if (pgrbo)
|
||
pgrbo->reallocate(width, height);
|
||
// SSAO
|
||
if (pssaoTexture)
|
||
pssaoTexture->reallocate(width, height, 6, GL_RED, GL_RED);
|
||
if (pssaoTexture_raw)
|
||
pssaoTexture_raw->reallocate(width, height, 0, GL_RED, GL_RED);
|
||
|
||
// Запомним новые размеры окна
|
||
WINDOW_WIDTH = width;
|
||
WINDOW_HEIGHT = height;
|
||
|
||
// Изменим параметры перспективной матрицы проекции для камеры
|
||
Camera::current().setPerspective(CAMERA_FOVy, (float)width/height);
|
||
}
|
||
|
||
// Данные о мыши
|
||
struct Mouse
|
||
{
|
||
float x = 0, y = 0; // Координаты курсора
|
||
float prev_x = 0, prev_y = 0; // Координаты курсора на предыдущем кадре
|
||
uint16_t left = 040100, right = 040100; // Состояние кнопок
|
||
} mouse;
|
||
|
||
void process_mouse_button(uint16_t& button)
|
||
{
|
||
if ((++button & 037777) == 037777)
|
||
button &= 0140100;
|
||
}
|
||
|
||
void mouse_callback(GLFWwindow* window, double xpos, double ypos)
|
||
{
|
||
mouse.x = xpos;
|
||
mouse.y = ypos;
|
||
}
|
||
|
||
void mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
|
||
{
|
||
uint16_t& mouse_button = (button == GLFW_MOUSE_BUTTON_LEFT)?mouse.left:mouse.right;
|
||
|
||
if (action == GLFW_PRESS && !(mouse_button & 0100000))
|
||
mouse_button = 0100000;
|
||
else if (action == GLFW_RELEASE)
|
||
mouse_button = 040000;
|
||
}
|
||
|
||
int main(void)
|
||
{
|
||
GLFWwindow* window; // Указатель на окно GLFW3
|
||
|
||
// Инициализация GLFW3
|
||
if (!glfwInit())
|
||
{
|
||
std::cout << "GLFW init error\n";
|
||
return -1;
|
||
}
|
||
|
||
// Завершение работы с GLFW3 перед выходом
|
||
atexit(glfwTerminate);
|
||
|
||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); // Мажорная версия спецификаций OpenGL
|
||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6); // Минорная версия спецификаций OpenGL
|
||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // Контекст OpenGL, который поддерживает только основные функции
|
||
|
||
// Создание окна GLFW3 с заданными шириной, высотой и заголовком окна
|
||
window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_CAPTION, NULL, NULL);
|
||
if (!window)
|
||
{
|
||
std::cout << "GLFW create window error\n";
|
||
return -1;
|
||
}
|
||
|
||
// Установка основного контекста окна
|
||
glfwMakeContextCurrent(window);
|
||
// Установка callback-функции для изменения размеров окна и буфера кадра
|
||
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
|
||
|
||
glfwSwapInterval(1); // Вертикальная синхронизация
|
||
|
||
// Установка callback-функции для мыши и камеры
|
||
glfwSetCursorPosCallback(window, mouse_callback);
|
||
glfwSetMouseButtonCallback(window, mouse_button_callback);
|
||
|
||
// Загрузка функций OpenGL с помощью GLAD
|
||
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
|
||
{
|
||
std::cout << "GLAD load GL error\n";
|
||
return -1;
|
||
}
|
||
|
||
// Включаем проверку по буферу глубины
|
||
glEnable(GL_DEPTH_TEST);
|
||
|
||
// Шейдер для G-буфера
|
||
ShaderProgram gShader;
|
||
// Загрузка и компиляция шейдеров
|
||
gShader.load(GL_VERTEX_SHADER, "shaders/gshader.vert");
|
||
gShader.load(GL_FRAGMENT_SHADER, "shaders/gshader.frag");
|
||
gShader.link();
|
||
// Установим значения текстур
|
||
const char* textures_base_shader_names[] = {"tex_albedo", "tex_roughness", "tex_metallic", "tex_specular", "tex_emitted", "tex_heights", "tex_normal"};
|
||
gShader.bindTextures(textures_base_shader_names, sizeof(textures_base_shader_names)/sizeof(const char*));
|
||
|
||
// Загрузка сцены из obj файла
|
||
Scene scene = loadOBJtoScene("../resources/models/blob.obj", "../resources/models/", "../resources/textures/");
|
||
scene.root.e_scale() = glm::vec3(0.01);
|
||
scene.root.e_position().z = 1;
|
||
scene.set_group_id((GLuint64) &scene.root);
|
||
|
||
// Установка цвета очистки буфера цвета
|
||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||
|
||
// Сдвинем направленный источник света и камеру
|
||
Sun::get().e_direction().z = -1.0;
|
||
Camera::current().e_position().x = 0.3f;
|
||
|
||
// Источники света
|
||
Light& first = Light::getNew();
|
||
first.e_color() = {1.0f, 0.0f, 0.0f}; // цвет
|
||
first.e_position() = {0.3f, 0.0f, 0.6f}; // Позиция
|
||
first.e_angle() = 100.0f;
|
||
Light& second = Light::getNew();
|
||
second.e_color() = {0.0f, 0.0f, 1.0f}; // цвет
|
||
second.e_position() = {-0.3f, 0.3f, 0.5f}; // Позиция
|
||
|
||
// Uniform-буферы
|
||
UBO cameraUB(sizeof(CameraData), 0);
|
||
UBO material_data(sizeof(Material), 1);
|
||
UBO light_data(Light::getUBOsize(), 2);
|
||
UBO sun_data(sizeof(Sun), 3);
|
||
|
||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); // Использование уменьшенных версий mipmap
|
||
|
||
// Создадим G-буфер с данными о используемых привязках
|
||
GLuint attachments[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3, GL_COLOR_ATTACHMENT4, GL_COLOR_ATTACHMENT5 };
|
||
FBO gbuffer(attachments, sizeof(attachments) / sizeof(GLuint));
|
||
// Создадим текстуры для буфера кадра
|
||
Texture gPosition(WINDOW_WIDTH, WINDOW_HEIGHT, GL_COLOR_ATTACHMENT0, 0, GL_RGB32F, GL_RGB); // Позиция вершины
|
||
Texture gNormal(WINDOW_WIDTH, WINDOW_HEIGHT, GL_COLOR_ATTACHMENT1, 1, GL_RGB16F, GL_RGB); // Нормали
|
||
Texture gBaseColor(WINDOW_WIDTH, WINDOW_HEIGHT, GL_COLOR_ATTACHMENT2, 2, GL_RGB, GL_RGB); // Базовый цвет материала
|
||
Texture gRMS(WINDOW_WIDTH, WINDOW_HEIGHT, GL_COLOR_ATTACHMENT3, 3, GL_RGB, GL_RGB); // Шероховатость, металличность, интенсивность блика
|
||
Texture gID(WINDOW_WIDTH, WINDOW_HEIGHT, GL_COLOR_ATTACHMENT4, 7, GL_RGB32UI, GL_RGB_INTEGER, GL_UNSIGNED_INT); // Идентификатор объекта
|
||
Texture gEmittedColor(WINDOW_WIDTH, WINDOW_HEIGHT, GL_COLOR_ATTACHMENT5, 8, GL_RGB, GL_RGB); // Излучаемый свет
|
||
// Создадим буфер рендера под буфер глубины и привяжем его
|
||
RBO grbo(WINDOW_WIDTH, WINDOW_HEIGHT);
|
||
gbuffer.assignRenderBuffer(grbo.getHandler());
|
||
// Активируем базовый буфер кадра
|
||
FBO::useDefault();
|
||
|
||
// Сохраним указатели на текстуры для изменения размеров окна
|
||
pgPosition = &gPosition;
|
||
pgNormal = &gNormal;
|
||
pgBaseColor = &gBaseColor;
|
||
pgRMS = &gRMS;
|
||
pgrbo = &grbo;
|
||
pgID = &gID;
|
||
pgEmittedColor = &gEmittedColor;
|
||
|
||
// Шейдер для расчета освещенности
|
||
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", "gBaseColor", "gRMS", "sunShadowDepth", "pointShadowDepth", "ssao", "gID", "gEmittedColor", "reflections"};
|
||
lightShader.bindTextures(gtextures_shader_names, sizeof(gtextures_shader_names)/sizeof(const char*));
|
||
// Загрузка данных о границах каскадов
|
||
glUniform1fv(lightShader.getUniformLoc("camera_cascade_distances"), CAMERA_CASCADE_COUNT, &camera_cascade_distances[1]);
|
||
|
||
glm::vec3 quadVertices[] = { {-1.0f, 1.0f, 0.0f}
|
||
, {-1.0f, -1.0f, 0.0f}
|
||
, { 1.0f, 1.0f, 0.0f}
|
||
, { 1.0f, -1.0f, 0.0f}
|
||
};
|
||
|
||
GLuint quadIndices[] = {0,1,2,2,1,3};
|
||
|
||
Model quadModel;
|
||
quadModel.load_verteces(quadVertices, 4);
|
||
quadModel.load_indices(quadIndices, 6);
|
||
|
||
// Размер текстуры тени от солнца
|
||
const GLuint sunShadow_resolution = 1024;
|
||
// Создадим буфер кадра для рендера теней
|
||
FBO sunShadowBuffer;
|
||
// Создадим текстуры для буфера кадра
|
||
TextureArray sunShadowDepth(CAMERA_CASCADE_COUNT, sunShadow_resolution, sunShadow_resolution, GL_DEPTH_ATTACHMENT, 4, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT);
|
||
// Правка фантомных теней
|
||
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
|
||
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
|
||
float shadowBorderColor[] = { 1.0, 1.0, 1.0, 1.0 };
|
||
glTexParameterfv(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_BORDER_COLOR, shadowBorderColor);
|
||
// Отключим работу с цветом
|
||
glDrawBuffer(GL_NONE);
|
||
glReadBuffer(GL_NONE);
|
||
// Активируем базовый буфер кадра
|
||
FBO::useDefault();
|
||
|
||
// Шейдер для расчета теней
|
||
ShaderProgram sunShadowShader;
|
||
// Загрузим шейдер
|
||
sunShadowShader.load(GL_VERTEX_SHADER, "shaders/sun_shadow.vert");
|
||
sunShadowShader.load(GL_GEOMETRY_SHADER, "shaders/sun_shadow.geom");
|
||
sunShadowShader.load(GL_FRAGMENT_SHADER, "shaders/empty.frag");
|
||
sunShadowShader.link();
|
||
|
||
// Размер одной стороны кубической карты
|
||
const GLuint pointShadow_resolution = 500;
|
||
// Создадим буфер кадра для рендера теней от источников света
|
||
FBO pointShadowBuffer;
|
||
// Создадим текстуры для буфера кадра
|
||
TextureCubeArray pointShadowDepth(MAX_LIGHTS, pointShadow_resolution, pointShadow_resolution, GL_DEPTH_ATTACHMENT, 5, GL_DEPTH_COMPONENT, GL_DEPTH_COMPONENT);
|
||
// Отключим работу с цветом
|
||
glDrawBuffer(GL_NONE);
|
||
glReadBuffer(GL_NONE);
|
||
// Активируем базовый буфер кадра
|
||
FBO::useDefault();
|
||
|
||
// Шейдер для расчета теней от точечных источников
|
||
ShaderProgram pointShadowShader;
|
||
// Загрузим шейдер
|
||
pointShadowShader.load(GL_VERTEX_SHADER, "shaders/sun_shadow.vert");
|
||
pointShadowShader.load(GL_GEOMETRY_SHADER, "shaders/point_shadow.geom");
|
||
pointShadowShader.load(GL_FRAGMENT_SHADER, "shaders/point_shadow.frag");
|
||
pointShadowShader.link();
|
||
|
||
// Создадим буфер для вычисления SSAO
|
||
GLuint attachments_ssao[] = { GL_COLOR_ATTACHMENT0 };
|
||
FBO ssaoBuffer(attachments_ssao, sizeof(attachments_ssao) / sizeof(GLuint));
|
||
// Создадим текстуры для буфера кадра
|
||
Texture ssaoTexture_raw(WINDOW_WIDTH, WINDOW_HEIGHT, GL_COLOR_ATTACHMENT0, 0, GL_RED, GL_RED);
|
||
pssaoTexture_raw = &ssaoTexture_raw;
|
||
// Активируем базовый буфер кадра
|
||
FBO::useDefault();
|
||
|
||
// Стандартные параметры SSAO
|
||
SSAO_data ssao_data;
|
||
// Расчет масштабирования текстуры шума
|
||
ssao_data.scale = {WINDOW_WIDTH/4,WINDOW_HEIGHT/4};
|
||
// Генерируем случайные векторы
|
||
std::uniform_real_distribution<GLfloat> randomFloats(0.0, 1.0); // Генерирует случайные вещественные числа в заданном диапазоне
|
||
std::default_random_engine generator;
|
||
glm::vec3 sample; // Выборка
|
||
for (int i = 0; i < ssao_data.size; i++)
|
||
{
|
||
sample = { randomFloats(generator) * 2.0 - 1.0
|
||
, randomFloats(generator) * 2.0 - 1.0
|
||
, randomFloats(generator)
|
||
};
|
||
sample = glm::normalize(sample);
|
||
sample *= randomFloats(generator);
|
||
|
||
// Отмасштабируем выборку
|
||
sample *= 0.1 + 0.9 * (i / (float)ssao_data.size) * (i / (float)ssao_data.size);
|
||
ssao_data.samples[i] = sample;
|
||
}
|
||
// Загрузка данных в uniform-буфер
|
||
UBO ssaoUB(&ssao_data, sizeof(SSAO_data), 4);
|
||
|
||
// Текстура шума
|
||
glm::vec3 noise_vecs[16];
|
||
for (int i = 0; i < 16; i++)
|
||
noise_vecs[i] = { randomFloats(generator) * 2.0 - 1.0
|
||
, randomFloats(generator) * 2.0 - 1.0
|
||
, 0.0f
|
||
};
|
||
Texture noiseTexture(4,4, noise_vecs, 2, GL_RGBA32F, GL_RGB);
|
||
|
||
// Шейдер для расчета SSAO
|
||
ShaderProgram ssaoShader;
|
||
// Загрузим шейдер
|
||
ssaoShader.load(GL_VERTEX_SHADER, "shaders/quad.vert");
|
||
ssaoShader.load(GL_FRAGMENT_SHADER, "shaders/ssao.frag");
|
||
ssaoShader.link();
|
||
// Текстуры, используемые в шейдере
|
||
const char* ssaoShader_names[] = {"gPosition", "gNormal", "noise"};
|
||
ssaoShader.bindTextures(ssaoShader_names, sizeof(ssaoShader_names)/sizeof(const char*));
|
||
|
||
// Создадим буфер для размытия SSAO
|
||
FBO ssaoBlurBuffer(attachments_ssao, sizeof(attachments_ssao) / sizeof(GLuint));
|
||
// Создадим текстуры для буфера кадра
|
||
Texture ssaoTexture(WINDOW_WIDTH, WINDOW_HEIGHT, GL_COLOR_ATTACHMENT0, 6, GL_RED, GL_RED);
|
||
pssaoTexture = &ssaoTexture;
|
||
// Активируем базовый буфер кадра
|
||
FBO::useDefault();
|
||
|
||
// Шейдер для размытия SSAO
|
||
ShaderProgram ssaoBlurShader;
|
||
// Загрузим шейдер
|
||
ssaoBlurShader.load(GL_VERTEX_SHADER, "shaders/quad.vert");
|
||
ssaoBlurShader.load(GL_FRAGMENT_SHADER, "shaders/ssaoBlur.frag");
|
||
ssaoBlurShader.link();
|
||
|
||
// Модель прямоугольника
|
||
Scene rectangle = loadOBJtoScene("../resources/models/plane2.obj", "../resources/models/", "../resources/textures/");
|
||
|
||
// Зададим горизонтальное положение перед камерой
|
||
rectangle.root.e_position().y = -1;
|
||
rectangle.root.e_position().z = 2;
|
||
rectangle.root.e_rotation() = glm::quat(0.707f, 0.707f, 0.0f, 0.0f);
|
||
rectangle.root.e_scale() = glm::vec3(4);
|
||
|
||
// Текстуры для прямоугольника
|
||
Texture rectangle_diffuse(TEX_ALBEDO, "../resources/textures/rekovalev_diffusemap.png");
|
||
rectangle.models.begin()->set_texture(rectangle_diffuse);
|
||
Texture rectangle_normal(TEX_NORMAL, "../resources/textures/rekovalev_normalmap.png");
|
||
rectangle.models.begin()->set_texture(rectangle_normal);
|
||
Texture rectangle_heights(TEX_HEIGHTS, "../resources/textures/rekovalev_bumpmap.png");
|
||
rectangle.models.begin()->set_texture(rectangle_heights);
|
||
|
||
// Шейдер для рисования отладочных лампочек
|
||
ShaderProgram bulbShader;
|
||
// Загрузка и компиляция шейдеров
|
||
bulbShader.load(GL_VERTEX_SHADER, "shaders/bulb.vert");
|
||
bulbShader.load(GL_FRAGMENT_SHADER, "shaders/bulb.frag");
|
||
bulbShader.link();
|
||
|
||
// Вершины для скайбокса
|
||
glm::vec3 skybox_verticies[] = {
|
||
{-1.0f, 1.0f, -1.0f},
|
||
{-1.0f, -1.0f, -1.0f},
|
||
{ 1.0f, -1.0f, -1.0f},
|
||
{ 1.0f, -1.0f, -1.0f},
|
||
{ 1.0f, 1.0f, -1.0f},
|
||
{-1.0f, 1.0f, -1.0f},
|
||
|
||
{-1.0f, -1.0f, 1.0f},
|
||
{-1.0f, -1.0f, -1.0f},
|
||
{-1.0f, 1.0f, -1.0f},
|
||
{-1.0f, 1.0f, -1.0f},
|
||
{-1.0f, 1.0f, 1.0f},
|
||
{-1.0f, -1.0f, 1.0f},
|
||
|
||
{ 1.0f, -1.0f, -1.0f},
|
||
{ 1.0f, -1.0f, 1.0f},
|
||
{ 1.0f, 1.0f, 1.0f},
|
||
{ 1.0f, 1.0f, 1.0f},
|
||
{ 1.0f, 1.0f, -1.0f},
|
||
{ 1.0f, -1.0f, -1.0f},
|
||
|
||
{-1.0f, -1.0f, 1.0f},
|
||
{-1.0f, 1.0f, 1.0f},
|
||
{ 1.0f, 1.0f, 1.0f},
|
||
{ 1.0f, 1.0f, 1.0f},
|
||
{ 1.0f, -1.0f, 1.0f},
|
||
{-1.0f, -1.0f, 1.0f},
|
||
|
||
{-1.0f, 1.0f, -1.0f},
|
||
{ 1.0f, 1.0f, -1.0f},
|
||
{ 1.0f, 1.0f, 1.0f},
|
||
{ 1.0f, 1.0f, 1.0f},
|
||
{-1.0f, 1.0f, 1.0f},
|
||
{-1.0f, 1.0f, -1.0f},
|
||
|
||
{-1.0f, -1.0f, -1.0f},
|
||
{-1.0f, -1.0f, 1.0f},
|
||
{ 1.0f, -1.0f, -1.0f},
|
||
{ 1.0f, -1.0f, -1.0f},
|
||
{-1.0f, -1.0f, 1.0f},
|
||
{ 1.0f, -1.0f, 1.0f}
|
||
};
|
||
|
||
// Модель скайбокса
|
||
Model skybox;
|
||
skybox.load_verteces(skybox_verticies, sizeof(skybox_verticies)/sizeof(glm::vec3));
|
||
TextureCube skybox_texture(TEX_ALBEDO, { "../resources/textures/skybox/px.jpg"
|
||
, "../resources/textures/skybox/nx.jpg"
|
||
, "../resources/textures/skybox/py.jpg"
|
||
, "../resources/textures/skybox/ny.jpg"
|
||
, "../resources/textures/skybox/pz.jpg"
|
||
, "../resources/textures/skybox/nz.jpg"
|
||
});
|
||
|
||
// Шейдер для скайбокса
|
||
ShaderProgram skyboxShader;
|
||
// Загрузим шейдеры
|
||
skyboxShader.load(GL_VERTEX_SHADER, "shaders/skybox.vert");
|
||
skyboxShader.load(GL_FRAGMENT_SHADER, "shaders/skybox.frag");
|
||
skyboxShader.link();
|
||
// Привязка текстуры скайбокса
|
||
const char* skybox_shader_names[] = {"skybox"};
|
||
skyboxShader.bindTextures(skybox_shader_names, sizeof(skybox_shader_names)/sizeof(const char*));
|
||
|
||
// Значение гамма-коррекции
|
||
UBO gamma(&inv_gamma, sizeof(inv_gamma), 4);
|
||
|
||
ID selected; // Выбранная модель
|
||
|
||
// Шейдер для инструментов
|
||
ShaderProgram toolsShader;
|
||
// Загрузим шейдеры
|
||
toolsShader.load(GL_VERTEX_SHADER, "shaders/gshader.vert");
|
||
toolsShader.load(GL_FRAGMENT_SHADER, "shaders/tools.frag");
|
||
toolsShader.link();
|
||
|
||
// Инструменты
|
||
Transform transform;
|
||
Rotate rotate;
|
||
Scale scale;
|
||
TRS& currentTool = transform;
|
||
|
||
// Текстура для отражений скайбокса
|
||
TextureCube reflections_texture(skybox_texture);
|
||
reflections_texture.setType(9);
|
||
|
||
// Пока не произойдет событие запроса закрытия окна
|
||
while(!glfwWindowShouldClose(window))
|
||
{
|
||
// Загрузка данных о камере
|
||
cameraUB.loadSub(&Camera::current().getData(), sizeof(CameraData));
|
||
// Загрузим информацию об источниках света
|
||
Light::upload(light_data);
|
||
// Загружаем информацию о направленном источнике
|
||
Sun::upload(sun_data);
|
||
|
||
// Активируем G-кадра
|
||
gbuffer.use();
|
||
// Используем шейдер с освещением
|
||
gShader.use();
|
||
// Очистка буфера цвета и глубины
|
||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||
|
||
// Тут производится рендер
|
||
scene.render(gShader, material_data);
|
||
rectangle.render(gShader, material_data);
|
||
|
||
// Отрисовка отладочных лампочек со специальным шейдером
|
||
bulbShader.use();
|
||
Light::render(bulbShader, material_data);
|
||
|
||
// Используем шейдер для инструментов
|
||
toolsShader.use();
|
||
// Рендерим инструменты для выбранного объекта
|
||
currentTool.render(selected.value, toolsShader, material_data);
|
||
|
||
// Выбор объекта
|
||
if (mouse.left == 0100000)
|
||
{
|
||
glReadBuffer(GL_COLOR_ATTACHMENT4);
|
||
glReadPixels(mouse.x, WINDOW_HEIGHT-mouse.y, 1, 1, GL_RGB_INTEGER, GL_UNSIGNED_INT, &selected);
|
||
std::cout << (void*) selected.value << ' ' << selected.etc << '\n';
|
||
}
|
||
|
||
// Активируем буфер SSAO
|
||
ssaoBuffer.use();
|
||
// Используем шейдер для расчета SSAO
|
||
ssaoShader.use();
|
||
// Очистка буфера цвета
|
||
glClear(GL_COLOR_BUFFER_BIT);
|
||
// Подключаем текстуры G-буфера
|
||
gPosition.use();
|
||
gNormal.use();
|
||
// Подключаем текстуру шума для SSAO
|
||
noiseTexture.use();
|
||
// Рендерим прямоугольник
|
||
quadModel.render();
|
||
|
||
// Активируем буфер размытия SSAO
|
||
ssaoBlurBuffer.use();
|
||
// Используем шейдер для размытия SSAO
|
||
ssaoBlurShader.use();
|
||
// Очистка буфера цвета
|
||
glClear(GL_COLOR_BUFFER_BIT);
|
||
// Подключаем текстуру сырого SSAO
|
||
ssaoTexture_raw.use();
|
||
// Рендерим прямоугольник
|
||
quadModel.render();
|
||
|
||
// Изменим размер вывода для тени
|
||
glViewport(0, 0, sunShadow_resolution, sunShadow_resolution);
|
||
// Активируем буфер кадра для теней от солнца
|
||
sunShadowBuffer.use();
|
||
// Подключим шейдер для расчета теней
|
||
sunShadowShader.use();
|
||
// Очистка буфера глубины
|
||
glClear(GL_DEPTH_BUFFER_BIT);
|
||
// Рендерим геометрию в буфер глубины
|
||
scene.render(sunShadowShader, material_data);
|
||
rectangle.render(sunShadowShader, material_data);
|
||
|
||
// Изменим размер вывода для стороны кубической карты точечного источника
|
||
glViewport(0, 0, pointShadow_resolution, pointShadow_resolution);
|
||
// Активируем буфер кадра для теней от солнца
|
||
pointShadowBuffer.use();
|
||
// Подключим шейдер для расчета теней
|
||
pointShadowShader.use();
|
||
// Очистка буфера глубины
|
||
glClear(GL_DEPTH_BUFFER_BIT);
|
||
// Для каждого источника вызывается рендер сцены
|
||
for (int i = 0; i < Light::getCount(); i++)
|
||
{
|
||
glUniform1i(pointShadowShader.getUniformLoc("light_i"), i);
|
||
// Рендерим геометрию в буфер глубины
|
||
scene.render(pointShadowShader, material_data);
|
||
rectangle.render(pointShadowShader, material_data);
|
||
}
|
||
|
||
// Изменим размер вывода для окна
|
||
glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
|
||
// Активируем базовый буфер кадра
|
||
FBO::useDefault();
|
||
// Подключаем шейдер для прямоугольника
|
||
lightShader.use();
|
||
// Очистка буфера цвета и глубины
|
||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||
// Подключаем текстуры G-буфера
|
||
gPosition.use();
|
||
gNormal.use();
|
||
gBaseColor.use();
|
||
gRMS.use();
|
||
gID.use();
|
||
gEmittedColor.use();
|
||
reflections_texture.use();
|
||
// Идентификатор выбранного объекта для обводки
|
||
glUniform3uiv(lightShader.getUniformLoc("selectedID"), 1, (GLuint*) &selected);
|
||
// Подключаем текстуры теней
|
||
sunShadowDepth.use();
|
||
pointShadowDepth.use();
|
||
// Подключим текстуру SSAO
|
||
ssaoTexture.use();
|
||
// Рендерим прямоугольник с расчетом освещения
|
||
quadModel.render();
|
||
|
||
// Перенос буфера глубины
|
||
FBO::useDefault(GL_DRAW_FRAMEBUFFER); // Базовый в режиме записи
|
||
gbuffer.use(GL_READ_FRAMEBUFFER); // Буфер геометрии в режиме чтения
|
||
// Копирование значений глубины
|
||
glBlitFramebuffer(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, GL_DEPTH_BUFFER_BIT, GL_NEAREST);
|
||
FBO::useDefault(); // Использование базового буфера для дальнейших работ
|
||
|
||
// Отрисовка скайбокса без записи глубины
|
||
glDepthMask(GL_FALSE);
|
||
// Используем шейдер для скайбокса
|
||
skyboxShader.use();
|
||
// Подключаем текстуру скайбокса
|
||
skybox_texture.use();
|
||
// Рендерим куб
|
||
skybox.render();
|
||
// Возвращаем запись глубины
|
||
glDepthMask(GL_TRUE);
|
||
|
||
// Дополнительная обработка мыши
|
||
process_mouse_button(mouse.left);
|
||
process_mouse_button(mouse.right);
|
||
mouse.prev_x = mouse.x;
|
||
mouse.prev_y = mouse.y;
|
||
|
||
// Представление содержимого буфера цепочки показа на окно
|
||
glfwSwapBuffers(window);
|
||
// Обработка системных событий
|
||
glfwPollEvents();
|
||
|
||
// Поворот камеры
|
||
if (mouse.right & 0100000
|
||
&& mouse.x != mouse.prev_x
|
||
&& mouse.y != mouse.prev_y)
|
||
Camera::current().rotate(glm::vec2(mouse.x - mouse.prev_x, mouse.prev_y - mouse.y));
|
||
|
||
// Взаимодействие с инструментом при зажатой левой кнопке
|
||
if (mouse.left > 0100000)
|
||
if (selected.etc)
|
||
currentTool.process(selected.value, selected.etc, glm::transpose(Camera::current().getVP()) * glm::vec4(mouse.x - mouse.prev_x, mouse.prev_y - mouse.y, 0, 1));
|
||
}
|
||
|
||
return 0;
|
||
}
|