/* 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(6, true, GL_RGBA16F) { shader_fxaa = shader_ds_0 = shader_ds_1 = 0; } void RendererDeferredShading::renderScene() { prepareUniform(); QMatrix4x4 view_matrix = getGLMatrix(GL_MODELVIEW_MATRIX); QMatrix4x4 proj_matrix = getGLMatrix(GL_PROJECTION_MATRIX); QMatrix4x4 viewprojinv = (proj_matrix * view_matrix).inverted(); corner_dirs[0] = (QVector4D(-1, -1, 1, 1) * viewprojinv).normalized(); corner_dirs[1] = (QVector4D( 1, -1, 1, 1) * viewprojinv).normalized(); corner_dirs[2] = (QVector4D( 1, 1, 1, 1) * viewprojinv).normalized(); corner_dirs[3] = (QVector4D(-1, 1, 1, 1) * viewprojinv).normalized(); //qDebug() << corner_dirs[0] << corner_dirs[1] << corner_dirs[2] << corner_dirs[3]; int passes = (view.lightsCount() - 1) / 8 + 1; if (passes < 1) passes = 1; fbo.bind(); int buffs[] = {0, 1, 2, 3}; fbo.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(); 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(); prepareUniform(); glSetLightEnabled(false); glDisable(GL_BLEND); //glBlendFunc(GL_ONE, GL_ONE); glDisableDepth(); shader_ds_1->bind(); setUniform(shader_ds_1); 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", proj_matrix.inverted()); shader_ds_1->setUniformValue("dt", QVector2D(1. / view.viewport()->width(), 1. / view.viewport()->height())); fbo.setWriteBuffer(4); fbo.bindColorTextures(); fbo.bindDepthTexture(4); glClearFramebuffer(Qt::black, false); //QVector lpos; //qDebug() << view_matrix; for (int l = 0; l < passes; ++l) { fbo.setWriteBuffer(5 - l % 2); shader_ds_1->setUniformValue("tb", 4 + l % 2); setupDSLights(l, 16, view_matrix); //shader_ds_1->setUniformValue("lightsCount", cplc); drawFB(shader_ds_1); //renderObjects(GLObjectBase::Solid, l, 0, true, true, view.isFogEnabled()); //renderObjects(GLObjectBase::Transparent, l, 0, true, true, view.isFogEnabled()); glFlush(); } fbo.release(); glReleaseShaders(); glActiveTextureChannel(0); glBindTexture(GL_TEXTURE_2D, fbo.colorTexture(4 + 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::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 + 8; 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; setUniformLights(shader_ds_1, lv, view_matrix, view.camera().pos()); } void RendererDeferredShading::setupAmbientLight(const QColor & a, bool first_pass) { } void RendererDeferredShading::prepareUniform() { pm = getGLMatrix(GL_PROJECTION_MATRIX); mvm = getGLMatrix(GL_MODELVIEW_MATRIX); mvpm = pm * mvm; pim = pm.inverted(); mvim = mvm.inverted(); mvpim = mvpm.inverted(); nm = mvm.normalMatrix(); } void RendererDeferredShading::setUniform(QGLShaderProgram * prog) { //qDebug() << mvm; prog->setUniformValue("qgl_ModelViewMatrix", mvm); prog->setUniformValue("qgl_ProjectionMatrix", pm); prog->setUniformValue("qgl_ModelViewProjectionMatrix", mvpm); prog->setUniformValue("qgl_NormalMatrix", nm); prog->setUniformValue("qgl_ModelViewMatrixInverse", mvim); prog->setUniformValue("qgl_ProjectionMatrixInverse", pim); prog->setUniformValue("qgl_ModelViewProjectionMatrixInverse", mvpim); prog->setUniformValue("qgl_ModelViewMatrixTranspose", mvm.transposed()); prog->setUniformValue("qgl_ProjectionMatrixTranspose", pm.transposed()); prog->setUniformValue("qgl_ModelViewProjectionMatrixTranspose", mvpm.transposed()); prog->setUniformValue("qgl_ModelViewMatrixInverseTranspose", mvim.transposed()); prog->setUniformValue("qgl_ProjectionMatrixInverseTranspose", pim.transposed()); prog->setUniformValue("qgl_ModelViewProjectionMatrixInverseTranspose", mvpim.transposed()); } void RendererDeferredShading::drawFB(QGLShaderProgram * prog) { glSetPolygonMode(GL_FILL); int loc = prog->attributeLocation("qgl_Color"); glVertexAttrib3f(loc, 1.f, 1.f, 1.f); int locv = prog->attributeLocation("qgl_Vertex"), loct = prog->attributeLocation("qgl_Texture"), locc = prog->attributeLocation("view_corner"); glBegin(GL_QUADS); glColor3f(1.f, 1.f, 1.f); prog->setAttributeValue(locc, corner_dirs[0]); glVertexAttrib2f(loct, 0.f, 0.f); glTexCoord2f(0.f, 0.f); glVertexAttrib2f(locv, -1.f, -1.f); glVertex2f(-1.f, -1.f); prog->setAttributeValue(locc, corner_dirs[1]); glVertexAttrib2f(loct, 1.f, 0.f); glTexCoord2f(1.f, 0.f); glVertexAttrib2f(locv, 1.f, -1.f); glVertex2f(1.f, -1.f); prog->setAttributeValue(locc, corner_dirs[2]); glVertexAttrib2f(loct, 1.f, 1.f); glTexCoord2f(1.f, 1.f); glVertexAttrib2f(locv, 1.f, 1.f); glVertex2f(1.f, 1.f); prog->setAttributeValue(locc, corner_dirs[3]); glVertexAttrib2f(loct, 0.f, 1.f); glTexCoord2f(0.f, 1.f); glVertexAttrib2f(locv, -1.f, 1.f); glVertex2f(-1.f, 1.f); glEnd(); }