/* QGLView Copyright (C) 2012 Ivan Pelipenko peri4ko@gmail.com 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 . */ #include "renderer_deferred_shading.h" RendererDeferredShading::RendererDeferredShading(QGLView * view_): GLRendererBase(view_), fbo_g(4, true, GL_RGBA16F), fbo_out(2, GL_RGBA16F) { shader_fxaa = shader_ds_0 = shader_ds_1 = 0; } void RendererDeferredShading::renderScene() { QMatrix4x4 mproji = rp.proj_matrix_i; QMatrix4x4 mview = rp.view_matrix; corner_dirs[0] = (QVector4D(-1, -1, 1, 1) * rp.viewproj_matrix).normalized(); corner_dirs[1] = (QVector4D( 1, -1, 1, 1) * rp.viewproj_matrix).normalized(); corner_dirs[2] = (QVector4D( 1, 1, 1, 1) * rp.viewproj_matrix).normalized(); corner_dirs[3] = (QVector4D(-1, 1, 1, 1) * rp.viewproj_matrix).normalized(); //qDebug() << corner_dirs[0] << corner_dirs[1] << corner_dirs[2] << corner_dirs[3]; fbo_g.bind(); int buffs[] = {0, 1, 2, 3}; fbo_g.setWriteBuffers(buffs); if (white_image_id == 0) { glActiveTextureChannel(6); white_image_id = ((GLTextureManagerBase*)currentGLTextureManager)->loadTexture(white_image, false); glBindTexture(GL_TEXTURE_2D, white_image_id); glActiveTextureChannel(0); } if (violent_image_id == 0) { glActiveTextureChannel(7); violent_image_id = ((GLTextureManagerBase*)currentGLTextureManager)->loadTexture(violent_image, false); glBindTexture(GL_TEXTURE_2D, violent_image_id); glActiveTextureChannel(0); } glClearFramebuffer(QColor(0, 0, 0, 0)); //glEnable(GL_TEXTURE_2D); glEnableDepth(); shader_ds_0->bind(); rp.setUniform(shader_ds_0); shader_ds_0->setUniformValue("z_far", GLfloat(view.depthEnd())); shader_ds_0->setUniformValue("z_near", GLfloat(view.depthStart())); shader_ds_0->setUniformValue("t0", 0); shader_ds_0->setUniformValue("t1", 1); shader_ds_0->setUniformValue("t2", 2); shader_ds_0->setUniformValue("t3", 3); shader_ds_0->setUniformValue("dt", QVector2D(1. / view.viewport()->width(), 1. / view.viewport()->height())); renderObjects(GLObjectBase::Solid, 0, shader_ds_0, true, false, false); //glReleaseShaders(); //fbo.release(); glResetAllTransforms(); rp.prepare(); glSetLightEnabled(false); glDisable(GL_BLEND); //glBlendFunc(GL_ONE, GL_ONE); glDisableDepth(); shader_ds_1->bind(); rp.setUniform(shader_ds_1); //qDebug() << rp.view_matrix; shader_ds_1->setUniformValue("z_far", GLfloat(view.depthEnd())); shader_ds_1->setUniformValue("z_near", GLfloat(view.depthStart())); shader_ds_1->setUniformValue("t0", 0); shader_ds_1->setUniformValue("t1", 1); shader_ds_1->setUniformValue("t2", 2); shader_ds_1->setUniformValue("t3", 3); shader_ds_1->setUniformValue("td", 4); shader_ds_1->setUniformValue("back_color", view.backColor()); shader_ds_1->setUniformValue("mat_proji", mproji); shader_ds_1->setUniformValue("dt", QVector2D(1. / view.viewport()->width(), 1. / view.viewport()->height())); fbo_g.bindColorTextures(); fbo_g.bindDepthTexture(4); fbo_out.bind(); fbo_out.setWriteBuffer(0); glClearFramebuffer(Qt::black, false); //QVector lpos; //qDebug() << view_matrix; int passes = (view.lightsCount() - 1) / 16 + 1; if (passes < 1) passes = 1; shader_ds_1->setUniformValue("t_pp", 5); //qDebug() << "render in" << passes << "passes"; for (int l = 0; l < passes; ++l) { int wi = 1 - l % 2, ri = l % 2; //qDebug() << " pass" << l << "read from" << ri << "write to" << wi; glActiveTextureChannel(5); glBindTexture(GL_TEXTURE_2D, fbo_out.colorTexture(ri)); fbo_out.setWriteBuffer(wi); setupDSLights(l, 16, mview); //shader_ds_1->setUniformValue("lightsCount", cplc); glDrawQuad(shader_ds_1); //renderObjects(GLObjectBase::Solid, l, 0, true, true, view.isFogEnabled()); //renderObjects(GLObjectBase::Transparent, l, 0, true, true, view.isFogEnabled()); glFinish(); //break; } fbo_out.release(); glReleaseShaders(); glActiveTextureChannel(0); glBindTexture(GL_TEXTURE_2D, fbo_out.colorTexture(passes % 2)); if (view.isFXAAEnabled()) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); shader_fxaa->bind(); shader_fxaa->setUniformValue("dt", QVector2D(1. / view.viewport()->width(), 1. / view.viewport()->height())); } else { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); } glDrawQuad(); if (view.isFXAAEnabled()) shader_fxaa->release(); } void RendererDeferredShading::init(int width, int height) { fbo_g.resize(width, height); fbo_out.resize(width, height); } void RendererDeferredShading::resize(int width, int height) { fbo_g.resize(width, height); fbo_out.resize(width, height); } void RendererDeferredShading::reloadShaders() { if (shader_fxaa == 0) shader_fxaa = new QGLShaderProgram(view.context()); if (shader_ds_0 == 0) shader_ds_0 = new QGLShaderProgram(view.context()); if (shader_ds_1 == 0) shader_ds_1 = new QGLShaderProgram(view.context()); //if (shader_ds_0 == 0) shader_ds_0 = new QGLShaderProgram(view.context()); loadShaders(shader_fxaa, "FXAA", "shaders"); loadShaders(shader_ds_0, "dsl_pass_0", "shaders"); loadShaders(shader_ds_1, "dsl_pass_1", "shaders"); } void RendererDeferredShading::setupShadersTextures(GLObjectBase & object, GLRendererBase::RenderingParameters & rp) { shader_ds_0->setUniformValue("has_diffuse", object.material().map_diffuse.bitmap_id != 0); shader_ds_0->setUniformValue("has_bump", object.material().map_normal.bitmap_id != 0); shader_ds_0->setUniformValue("has_height", object.material().map_relief.bitmap_id != 0); shader_ds_0->setUniformValue("bump_scale", object.material().map_normal.color_amount); shader_ds_0->setUniformValue("height_scale", object.material().map_relief.color_amount); glActiveTextureChannel(6); glBindTexture(GL_TEXTURE_2D, white_image_id); glActiveTextureChannel(7); glBindTexture(GL_TEXTURE_2D, violent_image_id); } void RendererDeferredShading::setupDSLights(int pass, int lights_per_pass, const QMatrix4x4 & view_matrix) { int light_start, light_end, lmax; light_start = pass * lights_per_pass; light_end = qMin((pass + 1) * lights_per_pass, view.lights().size()); lmax = light_start + lights_per_pass; amb_light.intensity = (pass == 0 ? 1. : 0.); amb_light.setColor(pass == 0 ? view.ambientColor() : Qt::black); amb_light.setName("ambient"); setUniformLight(shader_ds_1, &amb_light, "qgl_AmbientLight"); amb_light.intensity = 0.; QVector lv; for (int i = light_start; i < light_end; ++i) lv << view.lights()[i]; amb_light.setName("null"); for (int i = light_end; i < lmax; ++i) lv << &amb_light; //QStringList lnl; foreach (Light * l, lv) lnl << l->name(); //qDebug() << " lights" << light_start << "->" << light_end << ", inactive" << (lmax - light_end) << lnl; setUniformLights(shader_ds_1, lv, view_matrix, view.camera().pos()); } void RendererDeferredShading::setupAmbientLight(const QColor & a, bool first_pass) { }