/** Render the post-processed scene */ FrameBuffer *PostProcessing::render(scene::ICameraSceneNode * const camnode, bool isRace) { 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 (isRace && 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 (isRace && UserConfigParams::m_light_shaft && hasgodrays) { Track* track = World::getWorld()->getTrack(); 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 = track->getGodRaysColor(); 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->setGlowColors(col); sun->setPosition(track->getGodRaysPosition()); sun->updateAbsolutePosition(); 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 = track->getGodRaysPosition(); 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 (isRace && 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); FullScreenShader::BloomBlendShader::getInstance()->SetTextureUnits(createVector<GLuint>( irr_driver->getRenderTargetTexture(RTT_BLOOM_128), irr_driver->getRenderTargetTexture(RTT_BLOOM_256), irr_driver->getRenderTargetTexture(RTT_BLOOM_512) )); DrawFullScreenEffect<FullScreenShader::BloomBlendShader>(); 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 (isRace && UserConfigParams::m_motionblur && World::getWorld() != NULL) // motion blur { renderMotionBlur(0, *in_fbo, *out_fbo); std::swap(in_fbo, out_fbo); } PROFILER_POP_CPU_MARKER(); } // Workaround a bug with srgb fbo on sandy bridge windows if (irr_driver->needUBOWorkaround()) return in_fbo; 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
void IrrDriver::renderGlow(std::vector<GlowData>& glows) { m_scene_manager->setCurrentRendertime(scene::ESNRP_SOLID); m_rtts->getFBO(FBO_TMP1_WITH_DS).Bind(); glClearStencil(0); glClearColor(0, 0, 0, 0); glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); const u32 glowcount = (int)glows.size(); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); glStencilFunc(GL_ALWAYS, 1, ~0); glEnable(GL_STENCIL_TEST); glEnable(GL_DEPTH_TEST); glDepthMask(GL_FALSE); glDisable(GL_BLEND); if (CVS->isARBBaseInstanceUsable()) glBindVertexArray(VAOManager::getInstance()->getVAO(EVT_STANDARD)); for (u32 i = 0; i < glowcount; i++) { const GlowData &dat = glows[i]; scene::ISceneNode * cur = dat.node; STKMeshSceneNode *node = static_cast<STKMeshSceneNode *>(cur); node->setGlowColors(SColor(0, (unsigned) (dat.b * 255.f), (unsigned)(dat.g * 255.f), (unsigned)(dat.r * 255.f))); if (!CVS->supportsIndirectInstancingRendering()) node->render(); } if (CVS->supportsIndirectInstancingRendering()) { glBindBuffer(GL_DRAW_INDIRECT_BUFFER, GlowPassCmd::getInstance()->drawindirectcmd); glUseProgram(MeshShader::InstancedColorizeShader::getInstance()->Program); glBindVertexArray(VAOManager::getInstance()->getInstanceVAO(video::EVT_STANDARD, InstanceTypeGlow)); if (CVS->isAZDOEnabled()) { if (GlowPassCmd::getInstance()->Size) { glMultiDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_SHORT, (const void*)(GlowPassCmd::getInstance()->Offset * sizeof(DrawElementsIndirectCommand)), (int)GlowPassCmd::getInstance()->Size, sizeof(DrawElementsIndirectCommand)); } } else { for (unsigned i = 0; i < ListInstancedGlow::getInstance()->size(); i++) glDrawElementsIndirect(GL_TRIANGLES, GL_UNSIGNED_SHORT, (const void*)((GlowPassCmd::getInstance()->Offset + i) * sizeof(DrawElementsIndirectCommand))); } } glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); glDisable(GL_STENCIL_TEST); glDisable(GL_BLEND); // To half FrameBuffer::Blit(irr_driver->getFBO(FBO_TMP1_WITH_DS), irr_driver->getFBO(FBO_HALF1), GL_COLOR_BUFFER_BIT, GL_LINEAR); // To quarter FrameBuffer::Blit(irr_driver->getFBO(FBO_HALF1), irr_driver->getFBO(FBO_QUARTER1), GL_COLOR_BUFFER_BIT, GL_LINEAR); glEnable(GL_BLEND); glBlendEquation(GL_FUNC_ADD); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glStencilFunc(GL_EQUAL, 0, ~0); glEnable(GL_STENCIL_TEST); m_rtts->getFBO(FBO_COLORS).Bind(); m_post_processing->renderGlow(m_rtts->getRenderTarget(RTT_QUARTER1)); glDisable(GL_STENCIL_TEST); }