#include #include #include #include #include #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 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; }