/
ArtemNech
/
simpleOpenGL
Обзор
Документация
Войти
/
ArtemNech
/
simpleOpenGL
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
develop
backend/ogl_sys/drawing-sets/CLayerPostprocess.cpp
272 строки
9 KB
Artem Nechitaylenko
Необходимо поддерживать масштабирование KDE. Прокинул реальный размер QOpenGLWidget в backend, надо прикрутить к физике
28 июл 2026, 08:27
28 июл 2026, 08:27
e16a021
Код
Авторство
О чём код?
// // Created by artem on 20.05.26. // #include "CLayerPostprocess.h" #include "shaderprogram.h" #include "../../CBacking.h" #include <QDebug> #include "../CGlTransformator.h" CLayerPostprocess::CLayerPostprocess() : COglLayer(0.5f) // Самый верхний слой { m_timer.start(); } CLayerPostprocess::~CLayerPostprocess() { if (m_fbo) glDeleteFramebuffers(1, &m_fbo); if (m_fboTexture) glDeleteTextures(1, &m_fboTexture); if (m_fboDepth) glDeleteRenderbuffers(1, &m_fboDepth); } void CLayerPostprocess::init_shaders() { m_vertex_shader = R"( #version 330 core layout(location = 0) in vec3 a_position; layout(location = 1) in vec4 a_color; layout(location = 2) in vec2 a_texCoord; out vec4 v_color; out vec2 v_texCoord; uniform mat4 u_view_projection; void main() { v_color = a_color; v_texCoord = a_texCoord; gl_Position = u_view_projection * vec4(a_position, 1.0); } )"; m_frag_shader = R"( #version 330 core in vec2 v_texCoord; out vec4 fragColor; uniform sampler2D u_fboTexture; uniform float u_time; // Пузатость vec2 curve(vec2 uv) { uv = (uv - 0.5) * 2.0; uv.x *= 1.0 + pow((abs(uv.y) / 5.0), 2.0); uv.y *= 1.0 + pow((abs(uv.x) / 4.0), 2.0); uv = (uv / 2.0) + 0.5; return uv; } // Быстрый шум для "снега" float noise(vec2 uv) { return fract(sin(dot(uv, vec2(12.9898, 78.233) + u_time)) * 43758.5453); } void main() { // 1. Сначала считаем базовую геометрию пузатости vec2 uv = curve(v_texCoord); // Рамка ТВ if (uv.x < 0.0 || uv.x > 1.0 || uv.y < 0.0 || uv.y > 1.0) { fragColor = vec4(0.0, 0.0, 0.0, 1.0); return; } // 2. МИКРО-ДРОЖАНИЕ И СДВИГ СТРОК (Та самая "жизнь") // Строим микроскопический сдвиг по X, зависящий от времени и Y координаты (эффект VHS) float horiz_jitter = sin(uv.y * 100.0 + u_time * 20.0) * 0.0004; // Вертикальное чересстрочное дрожание (колебание всей картинки вверх-вниз на доли пикселя) float vert_jitter = sin(u_time * 60.0) * 0.0003; // Применяем искажения к текстурным координатам vec2 jitteredUv = vec2(uv.x + horiz_jitter, uv.y + vert_jitter); // 3. ХРОМАТИЧЕСКАЯ АБЕРРАЦИЯ (Разделение каналов по краям) // Из-за несведения лучей сдвигаем красный и синий каналы в разные стороны float chromAb = 0.0015; // Сила разделения цветов vec4 col; col.r = texture(u_fboTexture, vec2(jitteredUv.x + chromAb, jitteredUv.y)).r; col.g = texture(u_fboTexture, jitteredUv).g; col.b = texture(u_fboTexture, vec2(jitteredUv.x - chromAb, jitteredUv.y)).b; col.a = 1.0; // 4. ЖЕСТКИЕ СКАНИРУЮЩИЕ ЛИНИИ (Завязаны на исходный uv.y, чтобы не дрожали вместе со сдвигом) // Подкрутим контраст: сделаем полосы чуть глубже float scanline = sin(uv.y * 700.0) * 0.09; col.rgb -= scanline; // 5. ЕДВА ЗАМЕТНЫЙ ШУМ ЛЮМИНОФОРА ("Белый шум" кинескопа) float grain = (noise(uv) - 0.5) * 0.02; col.rgb += grain; // 6. МЯГКАЯ КАДРОВАЯ НАВОДКА (50 Гц от сети) float wave = sin(uv.y * 1.5 - u_time * 1.2) * 0.012; col.rgb += wave; // 7. Виньетка float vignette = uv.x * uv.y * (1.0 - uv.x) * (1.0 - uv.y); vignette = clamp(pow(16.0 * vignette, 0.25), 0.0, 1.0); col.rgb *= vignette; fragColor = col; } )"; } bool CLayerPostprocess::compile_shaders() { if (!m_shaderProgram->compile(m_vertex_shader, m_frag_shader)) { qDebug() << "Fragment shader compilation in 'CMeasureGrid' failed: ", m_shaderProgram->errors(); m_enabled = false; return false; } return true; } bool CLayerPostprocess::init() { m_vao->bind(); m_vbo->bind(); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (void*)nullptr); glEnableVertexAttribArray(1); glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (void*)(3 * sizeof(float))); glEnableVertexAttribArray(2); glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(vertex_t), (void*)(7 * sizeof(float))); m_vao->unbind(); m_vbo->unbind(); init_shaders(); return compile_shaders(); } void CLayerPostprocess::render(CBacking *backing, const glm::mat4 &projection, const glm::mat4 &view) { if (!backing) return; //auto size = backing->getViewportRect().size(); //m_fboHeight = size.height(); //m_fboWidth = size.width(); m_backing = backing; //auto base_projection = projection * view; m_batches.clear(); m_vertices.clear(); generateVertices(); if (m_batches.empty()) { qDebug() << "nothing to render"; } m_shaderProgram->bind(); m_shaderProgram->setUniform("u_view_projection", projection); m_shaderProgram->setUniform("u_fboTexture", 0); float elapsedSeconds = static_cast<float>(m_timer.elapsed()) / 1000.0f; m_shaderProgram->setUniform("u_time", static_cast<float>(elapsedSeconds)); m_vao->bind(); m_vbo->bind(); m_vbo->data(m_vertices.data(), m_vertices.size() * sizeof(vertex_t), BufferUsage::Static); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, m_fboTexture); glDrawArrays(GL_TRIANGLES, 0, 6); } bool CLayerPostprocess::createFBO(int width, int height) { if (m_fbo > 0 && width == m_fboWidth && height == m_fboHeight) { return true; } m_fboWidth = width; m_fboHeight = height; if (m_fbo) { glDeleteFramebuffers(1, &m_fbo); glDeleteTextures(1, &m_fboTexture); glDeleteRenderbuffers(1, &m_fboDepth); } glGenFramebuffers(1, &m_fbo); glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); glGenTextures(1, &m_fboTexture); glBindTexture(GL_TEXTURE_2D, m_fboTexture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_fboWidth, m_fboHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_fboTexture, 0); glGenRenderbuffers(1, &m_fboDepth); glBindRenderbuffer(GL_RENDERBUFFER, m_fboDepth); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, m_fboWidth, m_fboHeight); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_fboDepth); GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE) { qDebug() << "FBO Error status:" << status; glBindFramebuffer(GL_FRAMEBUFFER, 0); return false; } glBindFramebuffer(GL_FRAMEBUFFER, 0); return true; } void CLayerPostprocess::generateVertices() { ngraph::NColor dummyColor = {255, 255, 255, 255}; // или {1,1,1,1} смотря какие у тебя типы float x1 = 0.0f; float y1 = 0.0f; float x2 = static_cast<float>(m_fboWidth); float y2 = static_cast<float>(m_fboHeight); startBatch(GL_TRIANGLES); // Первый треугольник // TOP-LEFT теперь берет самую верхнюю строчку текстуры (1.0f) m_vertices.emplace_back(x1, y1, m_z, dummyColor, 0.0f, 1.0f); // Было 0.0f, 0.0f // TOP-RIGHT m_vertices.emplace_back(x2, y1, m_z, dummyColor, 1.0f, 1.0f); // Было 1.0f, 0.0f // BOTTOM-LEFT теперь берет самую нижнюю строчку текстуры (0.0f) m_vertices.emplace_back(x1, y2, m_z, dummyColor, 0.0f, 0.0f); // Было 0.0f, 1.0f // Второй треугольник // BOTTOM-LEFT m_vertices.emplace_back(x1, y2, m_z, dummyColor, 0.0f, 0.0f); // Было 0.0f, 1.0f // TOP-RIGHT m_vertices.emplace_back(x2, y1, m_z, dummyColor, 1.0f, 1.0f); // Было 1.0f, 0.0f // BOTTOM-RIGHT m_vertices.emplace_back(x2, y2, m_z, dummyColor, 1.0f, 0.0f); // Было 1.0f, 1.0f endBatch(); }