From 1c73e79c65eca5fdb55adbc7228f29c0a7b09e13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9F=D0=B5=D0=BB=D0=B8=D0=BF=D0=B5=D0=BD=D0=BA=D0=BE=20?= =?UTF-8?q?=D0=98=D0=B2=D0=B0=D0=BD?= Date: Fri, 6 Dec 2019 22:26:37 +0000 Subject: [PATCH] git-svn-id: svn://db.shs.com.ru/libs@661 a8b55f48-bf90-11e4-a774-851b48703e85 --- qglengine/core/glframebuffer.cpp | 27 +++- qglengine/core/glframebuffer.h | 6 +- qglengine/core/glframebuffer_mipmap.h | 1 + qglengine/qglview.h | 1 + qglengine/qglview_test/qglview_window.h | 1 - qglengine/renderer.cpp | 79 +--------- qglengine/renderer.h | 16 +- qglengine/renderer_selection.cpp | 2 +- qglengine/shaders/ds_tonemap.glsl | 16 +- qglengine/tonemapping_proc.cpp | 185 ++++++++++++++++++++++++ qglengine/tonemapping_proc.h | 65 +++++++++ 11 files changed, 295 insertions(+), 104 deletions(-) create mode 100644 qglengine/tonemapping_proc.cpp create mode 100644 qglengine/tonemapping_proc.h diff --git a/qglengine/core/glframebuffer.cpp b/qglengine/core/glframebuffer.cpp index 8d8cfbc..786ccf2 100644 --- a/qglengine/core/glframebuffer.cpp +++ b/qglengine/core/glframebuffer.cpp @@ -93,9 +93,7 @@ void Framebuffer::resize(int width, int height, bool force) { } f->glBindFramebuffer(GL_FRAMEBUFFER, 0); if (pbo.isInit()) { - pbo.bind(f); - pbo.resize(f, width*height*4); - pbo.release(f); + enablePixelBuffer(); } is_changed = false; } @@ -119,7 +117,7 @@ void Framebuffer::queryPoint(int index, QPoint p) { } -void Framebuffer::queryPoints(int index, QRect rect_) { +void Framebuffer::queryPoints(int index, QRect rect_, GLenum pixel_format) { pbo_queried = 0; if (index < 0 || index >= colors.size()) return; rect_ &= rect(); @@ -127,7 +125,7 @@ void Framebuffer::queryPoints(int index, QRect rect_) { f->glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo); f->glReadBuffer(GL_COLOR_ATTACHMENT0 + index); pbo.bind(f); - f->glReadPixels(rect_.x(), height() - rect_.bottom(), rect_.width(), rect_.height(), GL_RGBA, GL_UNSIGNED_BYTE, 0); + f->glReadPixels(rect_.x(), height() - rect_.bottom(), rect_.width(), rect_.height(), GL_RGBA, pixel_format, 0); pbo_queried = rect_.width() * rect_.height(); pbo.release(f); } @@ -151,7 +149,7 @@ uint Framebuffer::getPoint() const { } -QVector Framebuffer::getPoints() const { +QVector Framebuffer::getPointsByte() const { QVector ret; if (!pbo.isInit() || (pbo_queried == 0)) return ret; ret.resize(pbo_queried); @@ -165,6 +163,20 @@ QVector Framebuffer::getPoints() const { } +QVector Framebuffer::getPointsFloat() const { + QVector ret; + if (!pbo.isInit() || (pbo_queried == 0)) return ret; + ret.resize(pbo_queried); + pbo.bind(f); + void * map = pbo.map(f, GL_MAP_READ_BIT, pbo_queried * sizeof(QVector4D)); + if (map) + memcpy(ret.data(), map, pbo_queried * sizeof(QVector4D)); + pbo.unmap(f); + pbo.release(f); + return ret; +} + + QImage Framebuffer::getImage() const { QImage ret; if (!pbo.isInit() || (pbo_queried == 0)) return ret; @@ -258,6 +270,9 @@ void Framebuffer::unsetWriteBuffers() { void Framebuffer::enablePixelBuffer() { pbo.init(f); + pbo.bind(f); + pbo.resize(f, width()*height()*4*4); + pbo.release(f); } diff --git a/qglengine/core/glframebuffer.h b/qglengine/core/glframebuffer.h index b544da7..4a1a4a7 100644 --- a/qglengine/core/glframebuffer.h +++ b/qglengine/core/glframebuffer.h @@ -35,6 +35,7 @@ public: //GLenum colorFormat() const {return color_format;} GLuint depthTexture() const {return tex_d;} GLenum target() const {return target_;} + bool isInit() const {return fbo != 0;} int width() const {return wid;} int height() const {return hei;} QSize size() const {return QSize(wid, hei);} @@ -42,10 +43,11 @@ public: QImage grab() const; QVector grabF(int index) const; void queryPoint(int index, QPoint p); - void queryPoints(int index, QRect rect); + void queryPoints(int index, QRect rect, GLenum pixel_format = GL_UNSIGNED_BYTE); void queryImage(int index); uint getPoint() const; - QVector getPoints() const; + QVector getPointsByte() const; + QVector getPointsFloat() const; QImage getImage() const; int queriedPoints() const {return pbo_queried;} void blit(int index_from, GLuint fb_to, int index_to, QRect from, QRect to, GLbitfield mask = GL_COLOR_BUFFER_BIT, GLenum filter = GL_NEAREST) const; diff --git a/qglengine/core/glframebuffer_mipmap.h b/qglengine/core/glframebuffer_mipmap.h index 5320d21..59c3b27 100644 --- a/qglengine/core/glframebuffer_mipmap.h +++ b/qglengine/core/glframebuffer_mipmap.h @@ -31,6 +31,7 @@ public: int levelsCount() const {return fbo.size();} int lastLevel() const {return fbo.size() - 1;} Framebuffer & plane(int level) {return *fbo[level];} + Framebuffer & lastPlane() {return *fbo[lastLevel()];} int width (int level) const {return fbo[level]->wid;} int height(int level) const {return fbo[level]->hei;} QSize size(int level) const {return fbo[level]->size();} diff --git a/qglengine/qglview.h b/qglengine/qglview.h index fecde87..f217947 100644 --- a/qglengine/qglview.h +++ b/qglengine/qglview.h @@ -43,6 +43,7 @@ class QGLView: public OpenGLWindow friend class RendererMaterial; friend class RendererService; friend class RendererSelection; + friend class TonemappingProc; Q_OBJECT Q_PROPERTY (QColor backColor READ backColor WRITE setBackColor) Q_PROPERTY (float lineWidth READ lineWidth WRITE setLineWidth) diff --git a/qglengine/qglview_test/qglview_window.h b/qglengine/qglview_test/qglview_window.h index 39580e5..30e3d0f 100644 --- a/qglengine/qglview_test/qglview_window.h +++ b/qglengine/qglview_test/qglview_window.h @@ -76,7 +76,6 @@ private slots: void on_colorAmbient_colorChanged(QColor color) {view->view()->setAmbientColor(color);} void on_checkCameraOrbit_clicked(bool val) {view->view()->setCameraOrbit(val);} void on_checkCameraLight_clicked(bool val) {view->view()->setCameraLightOn(val);} - void on_spinViewLineWidth_valueChanged(double val) {view->view()->setLineWidth(val);} void on_groupShadows_clicked(bool val) {view->view()->setFeature(QGLView::qglShadowsEnabled, val);} void on_groupEyeAccomodation_clicked(bool val) {view->view()->setFeature(QGLView::qglEyeAccomodationEnabled, val);} diff --git a/qglengine/renderer.cpp b/qglengine/renderer.cpp index 8dd0359..96f8766 100644 --- a/qglengine/renderer.cpp +++ b/qglengine/renderer.cpp @@ -30,11 +30,7 @@ using namespace QGLEngineShaders; Renderer::Renderer(QGLView * view_): RendererBase(view_), fbo_ds (view_, QVector() << GL_RGBA16F << GL_RGBA32F << GL_RGBA16F << GL_RGBA16F << GL_RGBA16F), fbo_out (view_, 6, false, GL_RGBA16F), - fbo_1x1 (view_, 1, false, GL_RGB32F ), - fbomm(fbo_out, obrSum, 3), - buffer_vbo(GL_ARRAY_BUFFER, GL_DYNAMIC_DRAW), - rend_mat(this), rend_service(this), rend_selection(this) { - shader_sum = 0; + rend_mat(this), rend_service(this), rend_selection(this), tone_proc(this) { quad = Primitive::plane(2., 2.); cam_light = new Light(); cam_light->intensity = 0.75; @@ -80,17 +76,15 @@ Renderer::~Renderer() { delete quad; delete cam_light; qDeleteAll(shaders.values()); - if (shader_sum) delete shader_sum; } void Renderer::init(int width, int height) { - prepareSum(); - fbo_1x1.resize(1, 1); resize(width, height); rend_mat.init(width, height); rend_service.init(width, height); rend_selection.init(width, height); + tone_proc.init(); initQuad(quad); initTextureArrays(); need_init_shaders = true; @@ -103,8 +97,7 @@ void Renderer::resize(int width, int height) { rend_selection.resize(width, height); fbo_ds .resize(width, height); fbo_out .resize(width, height); - fbomm.resize(); - resizeSum(); + tone_proc.resize(); } @@ -115,7 +108,7 @@ void Renderer::reloadShaders() { it.next(); loadShadersMulti(shaders[it.key()], dir + it.value(), true, shader_defines.value(it.key())); } - loadShadersMulti(shader_sum, dir + "sum.glsl", false); + loadShadersMulti(tone_proc.shader_sum, dir + "sum.glsl", false); need_init_shaders = true; view->scene()->setLightsChanged(); view->scene()->setTreeStructChanged(); @@ -211,62 +204,6 @@ void Renderer::renderObjects(Scene & scene, RenderPass pass) { } -void Renderer::prepareSum() { - QOpenGLExtraFunctions * f = view; - buffer_vbo.init(f); - f->glGenVertexArrays(1, &vbo_vao); - f->glBindVertexArray(vbo_vao); - buffer_vbo.bind(f); - f->glEnableVertexAttribArray(1); - f->glVertexAttribIPointer(1, 2, GL_UNSIGNED_INT, 0, 0); - buffer_vbo.release(f); - f->glBindVertexArray(0); -} - - -void Renderer::resizeSum() { - QOpenGLExtraFunctions * f = view; - int pcnt = fbomm.width(fbomm.lastLevel()) * fbomm.height(fbomm.lastLevel()); - QVector _data; - _data.resize(pcnt); - pcnt = -1; - for (int x = 0; x < fbomm.width(fbomm.lastLevel()); ++x) - for (int y = 0; y < fbomm.height(fbomm.lastLevel()); ++y) - _data[++pcnt] = Vector2i(x,y); - buffer_vbo.bind(f); - buffer_vbo.resize(f, _data.size() * sizeof(Vector2i)); - buffer_vbo.load(f, _data.constData(), _data.size() * sizeof(Vector2i)); -} - - -void Renderer::renderSum(Framebuffer & fbo_src, int index) { - QOpenGLExtraFunctions * f = view; - int pcnt = fbo_src.width() * fbo_src.height(); - fbo_src.bindColorTexture(index); - fbo_1x1.bind(); - //glClearFramebuffer(Qt::white, false); - glClearFramebuffer(); - if (shader_sum) { - if (shader_sum->isLinked()) { - if (shader_sum->bind()) { - shader_sum->setUniformValue("tex", 0); - shader_sum->setUniformValue("pcnt", float(pcnt)); - f->glBindVertexArray(vbo_vao); - f->glEnable(GL_BLEND); - f->glBlendFunc(GL_ONE, GL_ONE); - f->glBlendEquation(GL_MAX); - f->glDrawArrays(GL_POINTS, 0, pcnt); - f->glBlendEquation(GL_FUNC_ADD); - f->glDisable(GL_BLEND); - f->glBindVertexArray(0); - } - } - } - fbo_1x1.release(); - //fbo_src.bind(); -} - - void Renderer::renderScene() { initShaders(); QOpenGLExtraFunctions * f = view; @@ -346,12 +283,12 @@ void Renderer::renderScene() { fbo_out.setWriteBuffer(obrSum); renderQuad(prog, quad); } - fbomm.create(); - renderSum(fbomm.plane(fbomm.lastLevel()), 0); - fbo_out.bind(); + if (tone_proc.process()) + fbo_out.bind(); if (bindShader(srTonemapPass, &prog)) { prog->setUniformValue("exposure", exposure_); - fbo_1x1.bindColorTexture(0, 1); + prog->setUniformValue("frame_max", tone_proc.frameMax()); + //fbo_1x1.bindColorTexture(0, 1); fbo_out.bindColorTexture(obrSum, 0); fbo_out.setWriteBuffer(obrTonemap); renderQuad(prog, quad); diff --git a/qglengine/renderer.h b/qglengine/renderer.h index d0f9b42..42a5e12 100644 --- a/qglengine/renderer.h +++ b/qglengine/renderer.h @@ -23,7 +23,7 @@ #include "renderer_material.h" #include "renderer_service.h" #include "renderer_selection.h" -#include "glframebuffer_mipmap.h" +#include "tonemapping_proc.h" #include @@ -33,6 +33,7 @@ class Renderer: public RendererBase { friend class RendererMaterial; friend class RendererService; friend class RendererSelection; + friend class TonemappingProc; enum RenderPass { rpSolid, rpTransparent, @@ -91,9 +92,6 @@ protected: void fillObjectsBuffer(const QList & ol, RenderPass pass); void reloadObjects(); void renderObjects(Scene & scene, RenderPass pass); - void prepareSum(); - void resizeSum(); - void renderSum(Framebuffer & fbo_src, int index); bool bindShader(ShaderRole role, QOpenGLShaderProgram ** ret = 0); void initShaders(); @@ -101,9 +99,8 @@ protected: private: float exposure_; - bool edit_mode, need_init_shaders, is_camera_light; - Framebuffer fbo_ds, fbo_out, fbo_1x1; - FramebufferMipmap fbomm; + bool edit_mode, need_init_shaders, is_camera_light, need_render_sum; + Framebuffer fbo_ds, fbo_out; /*QOpenGLShaderProgram * shader_fxaa, * shader_ds_0, * shader_ds_1, * shader_hdr, * shader_small; QOpenGLShaderProgram * shader_bloom_0, * shader_bloom_1, * shader_motion_blur, * shader_fbo_add; QOpenGLShaderProgram * shader_shadow, * shader_ssr, * shader_ssr_blur, * shader_ssr_merge; @@ -112,13 +109,10 @@ private: QMap shader_defines; QMap shaders; - QOpenGLShaderProgram * shader_sum; - Buffer buffer_vbo; - GLenum vbo_vao; - RendererMaterial rend_mat; RendererService rend_service; RendererSelection rend_selection; + TonemappingProc tone_proc; Mesh * quad; Light * cam_light; diff --git a/qglengine/renderer_selection.cpp b/qglengine/renderer_selection.cpp index 4562635..924bef4 100644 --- a/qglengine/renderer_selection.cpp +++ b/qglengine/renderer_selection.cpp @@ -101,7 +101,7 @@ void RendererSelection::renderSelection(Scene & scene) { } //qDebug() << id_hover; } else { - QVector points = fbo_selection.getPoints(); + QVector points = fbo_selection.getPointsByte(); QSet ids_hover; foreach (uint i, points) ids_hover << i; diff --git a/qglengine/shaders/ds_tonemap.glsl b/qglengine/shaders/ds_tonemap.glsl index db08167..623cc31 100644 --- a/qglengine/shaders/ds_tonemap.glsl +++ b/qglengine/shaders/ds_tonemap.glsl @@ -7,26 +7,18 @@ void main(void) { // frag // -uniform sampler2D tex_0, tex_sum; -uniform float exposure; +uniform sampler2D tex_0; +uniform float exposure, frame_max; const vec3 luma = vec3(0.299, 0.587, 0.114); void main(void) { ivec2 tc = ivec2(gl_FragCoord.xy); vec4 src = texelFetch(tex_0, tc, 0); - vec4 sum = texelFetch(tex_sum, ivec2(0,0), 0); vec3 res = src.rgb; - float l = dot(res, luma); - float g = exposure / dot(sum.rgb, luma); + float l = dot(res, luma) * 0.75; + float g = exposure / frame_max; res /= l; - //res = log(res + vec3(2.)) - log(vec3(2.)); - //res = pow(res,vec3(1/2.2)); - //l = pow(l,1/2.2); l = 1 - exp(-l*g); - //l /= 100; - //res = pow(res,vec3(2.2)); - //l = pow(l,2.2); qgl_FragColor.rgb = res * l; - //qgl_FragColor.rgb = sum.rgb*10; } diff --git a/qglengine/tonemapping_proc.cpp b/qglengine/tonemapping_proc.cpp new file mode 100644 index 0000000..8f4f45d --- /dev/null +++ b/qglengine/tonemapping_proc.cpp @@ -0,0 +1,185 @@ +/* + QGLView + Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#define GL_GLEXT_PROTOTYPES +#include +#include "tonemapping_proc.h" +#include "qglview.h" +#include + +using namespace QGLEngineShaders; + + +TonemappingProc::TonemappingProc(Renderer * rend): QThread(), r(rend), + fbo_1x1(r->view, 1, false, GL_RGB32F), + fbomm(r->fbo_out, Renderer::obrSum, 3), + buffer_vbo(GL_ARRAY_BUFFER, GL_DYNAMIC_DRAW) { + shader_sum = 0; + timer_delim = 0; + frame_max = cur_max = 1.; + need_render_sum = exit_ = false; + timer_tone = startTimer(10); +} + + +TonemappingProc::~TonemappingProc() { + exit_ = true; + if (!wait(1000)) + terminate(); + killTimer(timer_tone); + if (shader_sum) delete shader_sum; +} + + +void TonemappingProc::init() { + QOpenGLExtraFunctions * f = r->view; + buffer_vbo.init(f); + f->glGenVertexArrays(1, &vbo_vao); + f->glBindVertexArray(vbo_vao); + buffer_vbo.bind(f); + f->glEnableVertexAttribArray(1); + f->glVertexAttribIPointer(1, 2, GL_UNSIGNED_INT, 0, 0); + buffer_vbo.release(f); + f->glBindVertexArray(0); + fbomm.lastPlane().enablePixelBuffer(); + fbo_1x1.resize(1, 1); + resize(); + if (!isRunning()) start(); +} + + +void TonemappingProc::resize() { + QOpenGLExtraFunctions * f = r->view; + fbomm.resize(); + int pcnt = fbomm.width(fbomm.lastLevel()) * fbomm.height(fbomm.lastLevel()); + QVector _data; + _data.resize(pcnt); + pcnt = -1; + for (int x = 0; x < fbomm.width(fbomm.lastLevel()); ++x) + for (int y = 0; y < fbomm.height(fbomm.lastLevel()); ++y) + _data[++pcnt] = Vector2i(x,y); + buffer_vbo.bind(f); + buffer_vbo.resize(f, _data.size() * sizeof(Vector2i)); + buffer_vbo.load(f, _data.constData(), _data.size() * sizeof(Vector2i)); +} + + +void TonemappingProc::timerEvent(QTimerEvent * e) { + if (!fbo_1x1.isInit()) return; + if (timer_delim == 0) + need_render_sum = true; + timer_delim = (++timer_delim) % 10; + mutex.lock(); + float fmax = frame_max; + mutex.unlock(); + float dt = 0.01f, a = dt * 5.f, b = 1.f - a; + cur_max = fmax * a + cur_max * b; +} + + +void TonemappingProc::renderSum(Framebuffer & fbo_src, int index) { + QOpenGLExtraFunctions * f = r->view; + int pcnt = fbo_src.width() * fbo_src.height(); + fbo_src.bindColorTexture(index); + fbo_1x1.bind(); + //glClearFramebuffer(Qt::white, false); + glClearFramebuffer(); + if (shader_sum) { + if (shader_sum->isLinked()) { + if (shader_sum->bind()) { + shader_sum->setUniformValue("tex", 0); + shader_sum->setUniformValue("pcnt", float(pcnt)); + f->glBindVertexArray(vbo_vao); + f->glEnable(GL_BLEND); + f->glBlendFunc(GL_ONE, GL_ONE); + f->glBlendEquation(GL_MAX); + f->glDrawArrays(GL_POINTS, 0, pcnt); + f->glBlendEquation(GL_FUNC_ADD); + f->glDisable(GL_BLEND); + f->glBindVertexArray(0); + } + } + } + fbo_1x1.release(); + //fbo_src.bind(); +} + + +void TonemappingProc::run() { + while (!exit_) { + mutex.lock(); + if (last_data.isEmpty()) { + mutex.unlock(); + msleep(10); + continue; + } + QVector data = last_data; + last_data.clear(); + mutex.unlock(); + float max = calcHistogram(data); + last_max << max; + if (last_max.size() > 5) + last_max.removeAt(0); + float cm = last_max[0]; + for (int i = 1; i < last_max.size(); ++i) + cm += last_max[i]; + cm /= last_max.size(); + mutex.lock(); + frame_max = cm; + mutex.unlock(); + } +} + + +float TonemappingProc::calcHistogram(const QVector & data) { + if (data.isEmpty()) return 1.f; + float max = 0.; + QVector3D luma(0.299, 0.587, 0.114); + foreach (const QVector4D & p, data) { + float l = QVector3D::dotProduct(p.toVector3D(), luma); + max = qMax(max, l); + } + return max; +} + + +bool TonemappingProc::process() { + if (!need_render_sum) return false; + need_render_sum = false; + Framebuffer & fbo(fbomm.lastPlane()); + if (fbo.queriedPoints() > 0) { + QVector data = fbo.getPointsFloat(); + mutex.lock(); + last_data = data; + mutex.unlock(); + } + fbomm.create(); + fbo.queryPoints(0, fbo.rect(), GL_FLOAT); + //renderSum(fbomm.plane(fbomm.lastLevel()), 0); + return true; +} + + +float TonemappingProc::frameMax() { + return cur_max; + /*mutex.lock(); + float ret = frame_max; + mutex.unlock(); + return ret;*/ + +} diff --git a/qglengine/tonemapping_proc.h b/qglengine/tonemapping_proc.h new file mode 100644 index 0000000..0071948 --- /dev/null +++ b/qglengine/tonemapping_proc.h @@ -0,0 +1,65 @@ +/* + QGLView + Copyright (C) 2019 Ivan Pelipenko peri4ko@yandex.ru + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef TONEMAPPING_PROC_H +#define TONEMAPPING_PROC_H + +#include "glframebuffer_mipmap.h" +#include + + +class TonemappingProc: public QThread +{ + friend class Renderer; +public: + TonemappingProc(Renderer * rend); + virtual ~TonemappingProc(); + + void init(); + void resize(); + void prepareSum(); + void renderSum(Framebuffer & fbo_src, int index); + + bool process(); + float frameMax(); + +protected: + void timerEvent(QTimerEvent * e); + void run() override; + float calcHistogram(const QVector & data); + +private: + Renderer * r; + QMutex mutex; + QVector last_data; + QVector last_max; + + float frame_max, cur_max; + bool need_render_sum; + volatile bool exit_; + int timer_tone, timer_delim; + Framebuffer fbo_1x1; + FramebufferMipmap fbomm; + + QOpenGLShaderProgram * shader_sum; + Buffer buffer_vbo; + GLenum vbo_vao; + +}; + +#endif // RENDERER_H