/** Render the post-processed scene */ FrameBuffer *PostProcessing::render(scene::ICameraSceneNode * const camnode) { IVideoDriver * const drv = irr_driver->getVideoDriver(); MotionBlurProvider * const mocb = (MotionBlurProvider *) irr_driver-> getCallback(ES_MOTIONBLUR); GaussianBlurProvider * const gacb = (GaussianBlurProvider *) irr_driver-> getCallback(ES_GAUSSIAN3H); FrameBuffer *in_fbo = &irr_driver->getFBO(FBO_COLORS); FrameBuffer *out_fbo = &irr_driver->getFBO(FBO_TMP1_WITH_DS); // Each effect uses these as named, and sets them up for the next effect. // This allows chaining effects where some may be disabled. // As the original color shouldn't be touched, the first effect can't be disabled. glDisable(GL_DEPTH_TEST); glDisable(GL_BLEND); if (UserConfigParams::m_dof) { PROFILER_PUSH_CPU_MARKER("- DoF", 0xFF, 0x00, 0x00); ScopedGPUTimer Timer(irr_driver->getGPUTimer(Q_DOF)); renderDoF(*out_fbo, in_fbo->getRTT()[0]); std::swap(in_fbo, out_fbo); PROFILER_POP_CPU_MARKER(); } { PROFILER_PUSH_CPU_MARKER("- Godrays", 0xFF, 0x00, 0x00); ScopedGPUTimer Timer(irr_driver->getGPUTimer(Q_GODRAYS)); bool hasgodrays = false; if (World::getWorld() != NULL) hasgodrays = World::getWorld()->getTrack()->hasGodRays(); if (UserConfigParams::m_light_shaft && m_sunpixels > 30 && hasgodrays) { glEnable(GL_DEPTH_TEST); // Grab the sky out_fbo->Bind(); glClear(GL_COLOR_BUFFER_BIT); irr_driver->renderSkybox(camnode); // Set the sun's color const SColor col = World::getWorld()->getTrack()->getSunColor(); ColorizeProvider * const colcb = (ColorizeProvider *)irr_driver->getCallback(ES_COLORIZE); colcb->setColor(col.getRed() / 255.0f, col.getGreen() / 255.0f, col.getBlue() / 255.0f); // The sun interposer STKMeshSceneNode *sun = irr_driver->getSunInterposer(); irr_driver->getSceneManager()->drawAll(ESNRP_CAMERA); irr_driver->setPhase(GLOW_PASS); sun->render(); glDisable(GL_DEPTH_TEST); // Fade to quarter irr_driver->getFBO(FBO_QUARTER1).Bind(); glViewport(0, 0, UserConfigParams::m_width / 4, UserConfigParams::m_height / 4); renderGodFade(out_fbo->getRTT()[0], col); // Blur renderGaussian3Blur(irr_driver->getFBO(FBO_QUARTER1), irr_driver->getFBO(FBO_QUARTER2)); // Calculate the sun's position in texcoords const core::vector3df pos = sun->getPosition(); float ndc[4]; core::matrix4 trans = camnode->getProjectionMatrix(); trans *= camnode->getViewMatrix(); trans.transformVect(ndc, pos); const float texh = m_vertices[0].v1.TCoords.Y - m_vertices[0].v0.TCoords.Y; const float texw = m_vertices[0].v3.TCoords.X - m_vertices[0].v0.TCoords.X; const float sunx = ((ndc[0] / ndc[3]) * 0.5f + 0.5f) * texw; const float suny = ((ndc[1] / ndc[3]) * 0.5f + 0.5f) * texh; // Rays please irr_driver->getFBO(FBO_QUARTER2).Bind(); renderGodRay(irr_driver->getRenderTargetTexture(RTT_QUARTER1), core::vector2df(sunx, suny)); // Blur renderGaussian3Blur(irr_driver->getFBO(FBO_QUARTER2), irr_driver->getFBO(FBO_QUARTER1)); // Blend glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glBlendEquation(GL_FUNC_ADD); in_fbo->Bind(); renderPassThrough(irr_driver->getRenderTargetTexture(RTT_QUARTER2)); glDisable(GL_BLEND); } PROFILER_POP_CPU_MARKER(); } // Simulate camera defects from there { PROFILER_PUSH_CPU_MARKER("- Bloom", 0xFF, 0x00, 0x00); ScopedGPUTimer Timer(irr_driver->getGPUTimer(Q_BLOOM)); if (UserConfigParams::m_bloom) { glClear(GL_STENCIL_BUFFER_BIT); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE); FrameBuffer::Blit(*in_fbo, irr_driver->getFBO(FBO_BLOOM_1024), GL_COLOR_BUFFER_BIT, GL_LINEAR); irr_driver->getFBO(FBO_BLOOM_512).Bind(); renderBloom(irr_driver->getRenderTargetTexture(RTT_BLOOM_1024)); // Downsample FrameBuffer::Blit(irr_driver->getFBO(FBO_BLOOM_512), irr_driver->getFBO(FBO_BLOOM_256), GL_COLOR_BUFFER_BIT, GL_LINEAR); FrameBuffer::Blit(irr_driver->getFBO(FBO_BLOOM_256), irr_driver->getFBO(FBO_BLOOM_128), GL_COLOR_BUFFER_BIT, GL_LINEAR); // Blur renderGaussian6Blur(irr_driver->getFBO(FBO_BLOOM_512), irr_driver->getFBO(FBO_TMP_512)); renderGaussian6Blur(irr_driver->getFBO(FBO_BLOOM_256), irr_driver->getFBO(FBO_TMP_256)); renderGaussian6Blur(irr_driver->getFBO(FBO_BLOOM_128), irr_driver->getFBO(FBO_TMP_128)); // Additively blend on top of tmp1 in_fbo->Bind(); glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glBlendEquation(GL_FUNC_ADD); setTexture(0, irr_driver->getRenderTargetTexture(RTT_BLOOM_128), GL_LINEAR, GL_LINEAR); setTexture(1, irr_driver->getRenderTargetTexture(RTT_BLOOM_256), GL_LINEAR, GL_LINEAR); setTexture(2, irr_driver->getRenderTargetTexture(RTT_BLOOM_512), GL_LINEAR, GL_LINEAR); glUseProgram(FullScreenShader::BloomBlendShader::Program); FullScreenShader::BloomBlendShader::setUniforms(0, 1, 2); glBindVertexArray(FullScreenShader::BloomBlendShader::vao); glDrawArrays(GL_TRIANGLES, 0, 3); glDisable(GL_BLEND); glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); } // end if bloom PROFILER_POP_CPU_MARKER(); } //computeLogLuminance(in_rtt); { PROFILER_PUSH_CPU_MARKER("- Tonemap", 0xFF, 0x00, 0x00); ScopedGPUTimer Timer(irr_driver->getGPUTimer(Q_TONEMAP)); toneMap(*out_fbo, in_fbo->getRTT()[0]); std::swap(in_fbo, out_fbo); PROFILER_POP_CPU_MARKER(); } { PROFILER_PUSH_CPU_MARKER("- Motion blur", 0xFF, 0x00, 0x00); ScopedGPUTimer Timer(irr_driver->getGPUTimer(Q_MOTIONBLUR)); if (UserConfigParams::m_motionblur && m_any_boost && World::getWorld() != NULL) // motion blur { renderMotionBlur(0, *in_fbo, *out_fbo); std::swap(in_fbo, out_fbo); } PROFILER_POP_CPU_MARKER(); } glEnable(GL_FRAMEBUFFER_SRGB); irr_driver->getFBO(FBO_MLAA_COLORS).Bind(); renderPassThrough(in_fbo->getRTT()[0]); out_fbo = &irr_driver->getFBO(FBO_MLAA_COLORS); if (UserConfigParams::m_mlaa) // MLAA. Must be the last pp filter. { PROFILER_PUSH_CPU_MARKER("- MLAA", 0xFF, 0x00, 0x00); ScopedGPUTimer Timer(irr_driver->getGPUTimer(Q_MLAA)); applyMLAA(); PROFILER_POP_CPU_MARKER(); } glDisable(GL_FRAMEBUFFER_SRGB); return out_fbo; } // render
/** Render the post-processed scene */ void PostProcessing::render() { if (!irr_driver->isGLSL()) return; IVideoDriver * const drv = irr_driver->getVideoDriver(); drv->setTransform(ETS_WORLD, core::IdentityMatrix); drv->setTransform(ETS_VIEW, core::IdentityMatrix); drv->setTransform(ETS_PROJECTION, core::IdentityMatrix); MotionBlurProvider * const mocb = (MotionBlurProvider *) irr_driver-> getCallback(ES_MOTIONBLUR); GaussianBlurProvider * const gacb = (GaussianBlurProvider *) irr_driver-> getCallback(ES_GAUSSIAN3H); const u32 cams = Camera::getNumCameras(); for(u32 cam = 0; cam < cams; cam++) { scene::ICameraSceneNode * const camnode = Camera::getCamera(cam)->getCameraSceneNode(); mocb->setCurrentCamera(cam); ITexture *in = irr_driver->getRTT(RTT_COLOR); ITexture *out = irr_driver->getRTT(RTT_TMP1); // Each effect uses these as named, and sets them up for the next effect. // This allows chaining effects where some may be disabled. // As the original color shouldn't be touched, the first effect can't be disabled. PROFILER_PUSH_CPU_MARKER("- Bloom", 0xFF, 0x00, 0x00); if (1) // bloom { // Blit the base to tmp1 drv->setRenderTarget(out, true, false); renderPassThrough(in); const bool globalbloom = World::getWorld()->getTrack()->getBloom(); if (globalbloom) { drv->setRenderTarget(irr_driver->getRTT(RTT_TMP3), true, false); renderBloom(in); } if (globalbloom) { // Clear the alpha to a suitable value, stencil glClearColor(0, 0, 0, 0.1f); glColorMask(0, 0, 0, 1); glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); glClearColor(0, 0, 0, 0); glColorMask(1, 1, 1, 1); // To half drv->setRenderTarget(irr_driver->getRTT(RTT_HALF1), true, false); renderPassThrough(irr_driver->getRTT(RTT_TMP3)); // To quarter drv->setRenderTarget(irr_driver->getRTT(RTT_QUARTER1), true, false); renderPassThrough(irr_driver->getRTT(RTT_HALF1)); // To eighth drv->setRenderTarget(irr_driver->getRTT(RTT_EIGHTH1), true, false); renderPassThrough(irr_driver->getRTT(RTT_QUARTER1)); // Blur it for distribution. renderGaussian6Blur(irr_driver->getRTT(RTT_EIGHTH1), irr_driver->getRTT(RTT_EIGHTH2), 8.f / UserConfigParams::m_width, 8.f / UserConfigParams::m_height); // Additively blend on top of tmp1 drv->setRenderTarget(out, false, false); renderBloomBlend(irr_driver->getRTT(RTT_EIGHTH1)); } // end if bloom in = irr_driver->getRTT(RTT_TMP1); out = irr_driver->getRTT(RTT_TMP2); } PROFILER_POP_CPU_MARKER(); PROFILER_PUSH_CPU_MARKER("- Godrays", 0xFF, 0x00, 0x00); if (m_sunpixels > 30)//World::getWorld()->getTrack()->hasGodRays() && ) // god rays { // Grab the sky drv->setRenderTarget(out, true, false); // irr_driver->getSceneManager()->drawAll(ESNRP_SKY_BOX); irr_driver->renderSkybox(); // Set the sun's color const SColor col = World::getWorld()->getTrack()->getSunColor(); ColorizeProvider * const colcb = (ColorizeProvider *) irr_driver->getCallback(ES_COLORIZE); colcb->setColor(col.getRed() / 255.0f, col.getGreen() / 255.0f, col.getBlue() / 255.0f); // The sun interposer STKMeshSceneNode *sun = irr_driver->getSunInterposer(); /* sun->getMaterial(0).ColorMask = ECP_ALL; irr_driver->getSceneManager()->setCurrentRendertime(ESNRP_SOLID);*/ irr_driver->getSceneManager()->drawAll(ESNRP_CAMERA); irr_driver->setPhase(GLOW_PASS); sun->render(); //sun->getMaterial(0).ColorMask = ECP_NONE; // Fade to quarter drv->setRenderTarget(irr_driver->getRTT(RTT_QUARTER1), false, false); renderGodFade(getTextureGLuint(out), col); // Blur renderGaussian3Blur(irr_driver->getRTT(RTT_QUARTER1), irr_driver->getRTT(RTT_QUARTER2), 4.f / UserConfigParams::m_width, 4.f / UserConfigParams::m_height); // Calculate the sun's position in texcoords const core::vector3df pos = sun->getPosition(); float ndc[4]; core::matrix4 trans = camnode->getProjectionMatrix(); trans *= camnode->getViewMatrix(); trans.transformVect(ndc, pos); const float texh = m_vertices[cam].v1.TCoords.Y - m_vertices[cam].v0.TCoords.Y; const float texw = m_vertices[cam].v3.TCoords.X - m_vertices[cam].v0.TCoords.X; const float sunx = ((ndc[0] / ndc[3]) * 0.5f + 0.5f) * texw; const float suny = ((ndc[1] / ndc[3]) * 0.5f + 0.5f) * texh; // ((GodRayProvider *) irr_driver->getCallback(ES_GODRAY))-> // setSunPosition(sunx, suny); // Rays please drv->setRenderTarget(irr_driver->getRTT(RTT_QUARTER2), true, false); renderGodRay(getTextureGLuint(irr_driver->getRTT(RTT_QUARTER1)), core::vector2df(sunx, suny)); // Blur renderGaussian3Blur(irr_driver->getRTT(RTT_QUARTER2), irr_driver->getRTT(RTT_QUARTER1), 4.f / UserConfigParams::m_width, 4.f / UserConfigParams::m_height); // Blend glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glBlendEquation(GL_FUNC_ADD); drv->setRenderTarget(in, false, false); renderPassThrough(irr_driver->getRTT(RTT_QUARTER2)); } PROFILER_POP_CPU_MARKER(); if (UserConfigParams::m_motionblur && m_any_boost) // motion blur { PROFILER_PUSH_CPU_MARKER("- Motion blur", 0xFF, 0x00, 0x00); renderMotionBlur(cam, in, out); ITexture *tmp = in; in = out; out = tmp; PROFILER_POP_CPU_MARKER(); } if (irr_driver->getDisplacingNodes().size()) // Displacement { PROFILER_PUSH_CPU_MARKER("- Displacement", 0xFF, 0x00, 0x00); drv->setRenderTarget(out, true, false); renderPPDisplace(in); ITexture *tmp = in; in = out; out = tmp; PROFILER_POP_CPU_MARKER(); } /* m_material.MaterialType = irr_driver->getShader(ES_RAIN); drv->setMaterial(m_material); static_cast<irr::video::COpenGLDriver*>(drv)->setRenderStates3DMode();*/ if (UserConfigParams::m_mlaa) // MLAA. Must be the last pp filter. { PROFILER_PUSH_CPU_MARKER("- MLAA", 0xFF, 0x00, 0x00); drv->setRenderTarget(out, false, false); glEnable(GL_STENCIL_TEST); glClearColor(0.0, 0.0, 0.0, 1.0); glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); glStencilFunc(GL_ALWAYS, 1, ~0); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); // Pass 1: color edge detection m_material.setFlag(EMF_BILINEAR_FILTER, false); m_material.setFlag(EMF_TRILINEAR_FILTER, false); m_material.MaterialType = irr_driver->getShader(ES_MLAA_COLOR1); m_material.setTexture(0, in); drawQuad(cam, m_material); m_material.setFlag(EMF_BILINEAR_FILTER, true); m_material.setFlag(EMF_TRILINEAR_FILTER, true); glStencilFunc(GL_EQUAL, 1, ~0); glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); // Pass 2: blend weights drv->setRenderTarget(irr_driver->getRTT(RTT_TMP3), true, false); m_material.MaterialType = irr_driver->getShader(ES_MLAA_BLEND2); m_material.setTexture(0, out); m_material.setTexture(1, m_areamap); m_material.TextureLayer[1].BilinearFilter = false; m_material.TextureLayer[1].TrilinearFilter = false; drawQuad(cam, m_material); m_material.TextureLayer[1].BilinearFilter = true; m_material.TextureLayer[1].TrilinearFilter = true; m_material.setTexture(1, 0); // Pass 3: gather drv->setRenderTarget(in, false, false); m_material.setFlag(EMF_BILINEAR_FILTER, false); m_material.setFlag(EMF_TRILINEAR_FILTER, false); m_material.MaterialType = irr_driver->getShader(ES_MLAA_NEIGH3); m_material.setTexture(0, irr_driver->getRTT(RTT_TMP3)); m_material.setTexture(1, irr_driver->getRTT(RTT_COLOR)); drawQuad(cam, m_material); m_material.setFlag(EMF_BILINEAR_FILTER, true); m_material.setFlag(EMF_TRILINEAR_FILTER, true); m_material.setTexture(1, 0); // Done. glDisable(GL_STENCIL_TEST); PROFILER_POP_CPU_MARKER(); } // Final blit // TODO : Use glBlitFramebuffer drv->setRenderTarget(ERT_FRAME_BUFFER, false, false); if (irr_driver->getNormals()) renderPassThrough(irr_driver->getRTT(RTT_NORMAL_AND_DEPTH)); else if (irr_driver->getSSAOViz()) renderPassThrough(irr_driver->getRTT(RTT_SSAO)); else renderColorLevel(in); } } // render