2022-12-20 12:50:32 +00:00
|
|
|
|
|
|
|
|
|
#include <glad/glad.h>
|
|
|
|
|
#include <GLFW/glfw3.h>
|
|
|
|
|
#include <GLM/glm.hpp>
|
|
|
|
|
|
|
|
|
|
#include <iostream>
|
|
|
|
|
|
|
|
|
|
#include "Scene.h"
|
|
|
|
|
#include "Shader.h"
|
|
|
|
|
#include "Lights.h"
|
|
|
|
|
|
|
|
|
|
#define WINDOW_CAPTION "OPENGL notes on rekovalev.site"
|
|
|
|
|
|
|
|
|
|
// Указатели на текстуры для изменения размеров окна
|
|
|
|
|
Texture* pgPosition = NULL;
|
|
|
|
|
Texture* pgNormal = NULL;
|
|
|
|
|
Texture* pgDiffuseP = NULL;
|
|
|
|
|
Texture* pgAmbientSpecular = NULL;
|
|
|
|
|
RBO* pgrbo = NULL;
|
|
|
|
|
// Размеры окна
|
|
|
|
|
int WINDOW_WIDTH = 800;
|
|
|
|
|
int WINDOW_HEIGHT = 600;
|
|
|
|
|
|
|
|
|
|
// Функция-callback для изменения размеров буфера кадра в случае изменения размеров поверхности окна
|
|
|
|
|
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
|
|
|
|
|
{
|
|
|
|
|
glViewport(0, 0, width, height);
|
|
|
|
|
|
|
|
|
|
// Изменение размеров текстур для G-буфера
|
|
|
|
|
if (pgPosition)
|
|
|
|
|
pgPosition->reallocate(width, height, 0, GL_RGB32F, GL_RGB);
|
|
|
|
|
if (pgNormal)
|
|
|
|
|
pgNormal->reallocate(width, height, 1, GL_RGB16F, GL_RGB);
|
|
|
|
|
if (pgDiffuseP)
|
|
|
|
|
pgDiffuseP->reallocate(width, height, 2, GL_RGBA16F);
|
|
|
|
|
if (pgAmbientSpecular)
|
|
|
|
|
pgAmbientSpecular->reallocate(width, height, 3);
|
|
|
|
|
// И буфера глубины
|
|
|
|
|
if (pgrbo)
|
|
|
|
|
pgrbo->reallocate(width, height);
|
|
|
|
|
|
|
|
|
|
// Запомним новые размеры окна
|
|
|
|
|
WINDOW_WIDTH = width;
|
|
|
|
|
WINDOW_HEIGHT = height;
|
|
|
|
|
|
|
|
|
|
// Изменим параметры перспективной матрицы проекции для камеры
|
|
|
|
|
Camera::current().setPerspective(CAMERA_FOVy, (float)width/height);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool firstMouse = true;
|
|
|
|
|
float lastX, lastY;
|
|
|
|
|
|
|
|
|
|
void mouse_callback(GLFWwindow* window, double xpos, double ypos)
|
|
|
|
|
{
|
|
|
|
|
if (firstMouse)
|
|
|
|
|
{
|
|
|
|
|
lastX = xpos;
|
|
|
|
|
lastY = ypos;
|
|
|
|
|
firstMouse = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
glm::vec2 offset(xpos - lastX, lastY - ypos);
|
|
|
|
|
lastX = xpos;
|
|
|
|
|
lastY = ypos;
|
|
|
|
|
|
|
|
|
|
Camera::current().rotate(offset);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int main(void)
|
|
|
|
|
{
|
|
|
|
|
GLFWwindow* window; // Указатель на окно GLFW3
|
|
|
|
|
|
|
|
|
|
// Инициализация GLFW3
|
|
|
|
|
if (!glfwInit())
|
|
|
|
|
{
|
|
|
|
|
std::cout << "GLFW init error\n";
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Завершение работы с GLFW3 перед выходом
|
|
|
|
|
atexit(glfwTerminate);
|
|
|
|
|
|
|
|
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); // Мажорная версия спецификаций OpenGL
|
|
|
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6); // Минорная версия спецификаций OpenGL
|
|
|
|
|
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // Контекст OpenGL, который поддерживает только основные функции
|
|
|
|
|
|
|
|
|
|
// Создание окна GLFW3 с заданными шириной, высотой и заголовком окна
|
|
|
|
|
window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_CAPTION, NULL, NULL);
|
|
|
|
|
if (!window)
|
|
|
|
|
{
|
|
|
|
|
std::cout << "GLFW create window error\n";
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Установка основного контекста окна
|
|
|
|
|
glfwMakeContextCurrent(window);
|
|
|
|
|
// Установка callback-функции для изменения размеров окна и буфера кадра
|
|
|
|
|
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
|
|
|
|
|
|
|
|
|
|
glfwSwapInterval(1); // Вертикальная синхронизация
|
|
|
|
|
|
|
|
|
|
// Установка callback-функции для мыши и камеры
|
|
|
|
|
glfwSetCursorPosCallback(window, mouse_callback);
|
|
|
|
|
|
|
|
|
|
// Загрузка функций OpenGL с помощью GLAD
|
|
|
|
|
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
|
|
|
|
|
{
|
|
|
|
|
std::cout << "GLAD load GL error\n";
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Включаем проверку по буферу глубины
|
|
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
|
|
|
|
|
|
// Шейдер для G-буфера
|
|
|
|
|
ShaderProgram gShader;
|
|
|
|
|
// Загрузка и компиляция шейдеров
|
|
|
|
|
gShader.load(GL_VERTEX_SHADER, "shaders/gshader.vert");
|
|
|
|
|
gShader.load(GL_FRAGMENT_SHADER, "shaders/gshader.frag");
|
|
|
|
|
gShader.link();
|
|
|
|
|
// Установим значения текстур
|
|
|
|
|
const char* textures_base_shader_names[] = {"tex_diffuse", "tex_ambient", "tex_specular"};
|
|
|
|
|
gShader.bindTextures(textures_base_shader_names, sizeof(textures_base_shader_names)/sizeof(const char*));
|
|
|
|
|
|
|
|
|
|
// Загрузка сцены из obj файла
|
|
|
|
|
Scene scene = loadOBJtoScene("../resources/models/blob.obj", "../resources/models/", "../resources/textures/");
|
|
|
|
|
scene.root.e_scale() = glm::vec3(0.01);
|
|
|
|
|
scene.root.e_position().z = 1;
|
|
|
|
|
scene.models.begin()->material.kd = {0.5,0.5,0.5};
|
|
|
|
|
scene.models.begin()->material.ka = {0.2,0.2,0.2};
|
|
|
|
|
|
|
|
|
|
// Установка цвета очистки буфера цвета
|
|
|
|
|
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
|
|
|
|
|
|
|
|
|
// Источники света
|
|
|
|
|
Light& first = Light::getNew();
|
|
|
|
|
first.e_color() = {1.0f, 0.0f, 0.0f}; // цвет
|
|
|
|
|
first.e_position() = {0.3f, 0.1f, 0.5f}; // Позиция
|
2022-12-20 12:58:42 +00:00
|
|
|
|
first.e_angle() = 70.0f;
|
2022-12-20 12:50:32 +00:00
|
|
|
|
Light& second = Light::getNew();
|
|
|
|
|
second.e_color() = {0.0f, 0.0f, 1.0f}; // цвет
|
|
|
|
|
second.e_position() = {-0.3f, -0.1f, 0.5f}; // Позиция
|
|
|
|
|
|
|
|
|
|
// Uniform-буферы
|
|
|
|
|
UBO cameraUB(sizeof(CameraData), 0);
|
|
|
|
|
UBO material_data(sizeof(Material), 1);
|
|
|
|
|
UBO light_data(Light::getUBOsize(), 2);
|
|
|
|
|
|
|
|
|
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); // Использование уменьшенных версий mipmap
|
|
|
|
|
|
|
|
|
|
// Создадим G-буфер с данными о используемых привязках
|
|
|
|
|
GLuint attachments[] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3 };
|
|
|
|
|
FBO gbuffer(attachments, sizeof(attachments) / sizeof(GLuint));
|
|
|
|
|
// Создадим текстуры для буфера кадра
|
|
|
|
|
Texture gPosition(WINDOW_WIDTH, WINDOW_HEIGHT, GL_COLOR_ATTACHMENT0, 0, GL_RGB32F, GL_RGB); // Позиция вершины
|
|
|
|
|
Texture gNormal(WINDOW_WIDTH, WINDOW_HEIGHT, GL_COLOR_ATTACHMENT1, 1, GL_RGB16F, GL_RGB); // Нормали
|
|
|
|
|
Texture gDiffuseP(WINDOW_WIDTH, WINDOW_HEIGHT, GL_COLOR_ATTACHMENT2, 2, GL_RGBA16F); // Диффузная составляющая и коэф. глянцевости
|
|
|
|
|
Texture gAmbientSpecular(WINDOW_WIDTH, WINDOW_HEIGHT, GL_COLOR_ATTACHMENT3, 3); // Фоновая составляющая и один канал зеркальной
|
|
|
|
|
// Создадим буфер рендера под буфер глубины и привяжем его
|
|
|
|
|
RBO grbo(WINDOW_WIDTH, WINDOW_HEIGHT);
|
|
|
|
|
gbuffer.assignRenderBuffer(grbo.getHandler());
|
|
|
|
|
// Активируем базовый буфер кадра
|
|
|
|
|
FBO::useDefault();
|
|
|
|
|
|
|
|
|
|
// Сохраним указатели на текстуры для изменения размеров окна
|
|
|
|
|
pgPosition = &gPosition;
|
|
|
|
|
pgNormal = &gNormal;
|
|
|
|
|
pgDiffuseP = &gDiffuseP;
|
|
|
|
|
pgAmbientSpecular = &gAmbientSpecular;
|
|
|
|
|
pgrbo = &grbo;
|
|
|
|
|
|
|
|
|
|
// Шейдер для расчета освещенности
|
|
|
|
|
ShaderProgram lightShader;
|
|
|
|
|
// Загрузка и компиляция шейдеров
|
|
|
|
|
lightShader.load(GL_VERTEX_SHADER, "shaders/quad.vert");
|
|
|
|
|
lightShader.load(GL_FRAGMENT_SHADER, "shaders/lighting.frag");
|
|
|
|
|
lightShader.link();
|
|
|
|
|
const char* gtextures_shader_names[] = {"gPosition", "gNormal", "gDiffuseP", "gAmbientSpecular"};
|
|
|
|
|
lightShader.bindTextures(gtextures_shader_names, sizeof(gtextures_shader_names)/sizeof(const char*));
|
|
|
|
|
|
|
|
|
|
glm::vec3 quadVertices[] = { {-1.0f, 1.0f, 0.0f}
|
|
|
|
|
, {-1.0f, -1.0f, 0.0f}
|
|
|
|
|
, { 1.0f, 1.0f, 0.0f}
|
|
|
|
|
, { 1.0f, -1.0f, 0.0f}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
GLuint quadIndices[] = {0,1,2,2,1,3};
|
|
|
|
|
|
|
|
|
|
Model quadModel;
|
|
|
|
|
quadModel.load_verteces(quadVertices, 4);
|
|
|
|
|
quadModel.load_indices(quadIndices, 6);
|
|
|
|
|
|
|
|
|
|
// Шейдер для рисования отладочных лампочек
|
|
|
|
|
ShaderProgram bulbShader;
|
|
|
|
|
// Загрузка и компиляция шейдеров
|
|
|
|
|
bulbShader.load(GL_VERTEX_SHADER, "shaders/bulb.vert");
|
|
|
|
|
bulbShader.load(GL_FRAGMENT_SHADER, "shaders/bulb.frag");
|
|
|
|
|
bulbShader.link();
|
|
|
|
|
|
|
|
|
|
// Пока не произойдет событие запроса закрытия окна
|
|
|
|
|
while(!glfwWindowShouldClose(window))
|
|
|
|
|
{
|
|
|
|
|
// Загрузка данных о камере
|
|
|
|
|
cameraUB.loadSub(&Camera::current().getData(), sizeof(CameraData));
|
|
|
|
|
// Загрузим информацию об источниках света
|
|
|
|
|
Light::upload(light_data);
|
|
|
|
|
|
|
|
|
|
// Активируем G-кадра
|
|
|
|
|
gbuffer.use();
|
|
|
|
|
// Используем шейдер с освещением
|
|
|
|
|
gShader.use();
|
|
|
|
|
// Очистка буфера цвета и глубины
|
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
|
|
|
|
|
|
|
|
// Тут производится рендер
|
|
|
|
|
scene.render(gShader, material_data);
|
|
|
|
|
|
|
|
|
|
// Активируем базовый буфер кадра
|
|
|
|
|
FBO::useDefault();
|
|
|
|
|
// Подключаем шейдер для прямоугольника
|
|
|
|
|
lightShader.use();
|
|
|
|
|
// Очистка буфера цвета и глубины
|
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
|
|
|
// Подключаем текстуры G-буфера
|
|
|
|
|
gPosition.use();
|
|
|
|
|
gNormal.use();
|
|
|
|
|
gDiffuseP.use();
|
|
|
|
|
gAmbientSpecular.use();
|
|
|
|
|
// Рендерим прямоугольник с расчетом освещения
|
|
|
|
|
quadModel.render();
|
|
|
|
|
|
|
|
|
|
// Перенос буфера глубины
|
|
|
|
|
FBO::useDefault(GL_DRAW_FRAMEBUFFER); // Базовый в режиме записи
|
|
|
|
|
gbuffer.use(GL_READ_FRAMEBUFFER); // Буфер геометрии в режиме чтения
|
|
|
|
|
// Копирование значений глубины
|
|
|
|
|
glBlitFramebuffer(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, GL_DEPTH_BUFFER_BIT, GL_NEAREST);
|
|
|
|
|
FBO::useDefault(); // Использование базового буфера для дальнейших работ
|
|
|
|
|
|
|
|
|
|
// Отрисовка отладочных лампочек со специальным шейдером
|
|
|
|
|
bulbShader.use();
|
|
|
|
|
Light::render(bulbShader, material_data);
|
|
|
|
|
|
|
|
|
|
// Представление содержимого буфера цепочки показа на окно
|
|
|
|
|
glfwSwapBuffers(window);
|
|
|
|
|
// Обработка системных событий
|
|
|
|
|
glfwPollEvents();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|