#include #include #include #include #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}; // Позиция first.e_angle() = 70.0f; 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); 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 }; 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); // Загружаем информацию о направленном источнике Sun::upload(sun_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; }