void DeferredLightingEffect::copyBack(RenderArgs* args) { auto textureCache = DependencyManager::get<TextureCache>(); QSize framebufferSize = textureCache->getFrameBufferSize(); auto freeFBO = DependencyManager::get<GlowEffect>()->getFreeFramebuffer(); //freeFBO->release(); glBindFramebuffer(GL_FRAMEBUFFER, 0); glDisable(GL_CULL_FACE); // now transfer the lit region to the primary fbo glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); glColorMask(true, true, true, false); auto primaryFBO = gpu::GLBackend::getFramebufferID(textureCache->getPrimaryFramebuffer()); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, primaryFBO); //primaryFBO->bind(); glBindTexture(GL_TEXTURE_2D, gpu::GLBackend::getTextureID(freeFBO->getRenderBuffer(0))); glEnable(GL_TEXTURE_2D); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); int viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); const int VIEWPORT_X_INDEX = 0; const int VIEWPORT_Y_INDEX = 1; const int VIEWPORT_WIDTH_INDEX = 2; const int VIEWPORT_HEIGHT_INDEX = 3; float sMin = viewport[VIEWPORT_X_INDEX] / (float)framebufferSize.width(); float sWidth = viewport[VIEWPORT_WIDTH_INDEX] / (float)framebufferSize.width(); float tMin = viewport[VIEWPORT_Y_INDEX] / (float)framebufferSize.height(); float tHeight = viewport[VIEWPORT_HEIGHT_INDEX] / (float)framebufferSize.height(); renderFullscreenQuad(sMin, sMin + sWidth, tMin, tMin + tHeight); glBindTexture(GL_TEXTURE_2D, 0); glDisable(GL_TEXTURE_2D); glColorMask(true, true, true, true); glEnable(GL_LIGHTING); glEnable(GL_COLOR_MATERIAL); glEnable(GL_DEPTH_TEST); glDepthMask(true); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); }
void AmbientOcclusionEffect::render() { glDisable(GL_BLEND); glDisable(GL_DEPTH_TEST); glDepthMask(GL_FALSE); glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getPrimaryDepthTextureID()); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, _rotationTextureID); // render with the occlusion shader to the secondary/tertiary buffer QOpenGLFramebufferObject* freeFBO = Application::getInstance()->getGlowEffect()->getFreeFramebufferObject(); freeFBO->bind(); float left, right, bottom, top, nearVal, farVal; glm::vec4 nearClipPlane, farClipPlane; Application::getInstance()->getViewFrustum()->computeOffAxisFrustum( left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane); _occlusionProgram->bind(); _occlusionProgram->setUniformValue(_nearLocation, nearVal); _occlusionProgram->setUniformValue(_farLocation, farVal); _occlusionProgram->setUniformValue(_leftBottomLocation, left, bottom); _occlusionProgram->setUniformValue(_rightTopLocation, right, top); QSize widgetSize = Application::getInstance()->getGLWidget()->size(); _occlusionProgram->setUniformValue(_noiseScaleLocation, widgetSize.width() / (float)ROTATION_WIDTH, widgetSize.height() / (float)ROTATION_HEIGHT); int viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); const int VIEWPORT_X_INDEX = 0; const int VIEWPORT_WIDTH_INDEX = 2; float sMin = viewport[VIEWPORT_X_INDEX] / (float)widgetSize.width(); float sMax = (viewport[VIEWPORT_X_INDEX] + viewport[VIEWPORT_WIDTH_INDEX]) / (float)widgetSize.width(); renderFullscreenQuad(sMin, sMax); _occlusionProgram->release(); freeFBO->release(); glBindTexture(GL_TEXTURE_2D, 0); glActiveTexture(GL_TEXTURE0); // now render secondary to primary with 4x4 blur Application::getInstance()->getTextureCache()->getPrimaryFramebufferObject()->bind(); glEnable(GL_BLEND); glBlendFuncSeparate(GL_ZERO, GL_SRC_COLOR, GL_ZERO, GL_ONE); glBindTexture(GL_TEXTURE_2D, freeFBO->texture()); _blurProgram->bind(); _blurProgram->setUniformValue(_blurScaleLocation, 1.0f / widgetSize.width(), 1.0f / widgetSize.height()); renderFullscreenQuad(sMin, sMax); _blurProgram->release(); glBindTexture(GL_TEXTURE_2D, 0); glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); }
QOpenGLFramebufferObject* GlowEffect::render(bool toTexture) { QOpenGLFramebufferObject* primaryFBO = Application::getInstance()->getTextureCache()->getPrimaryFramebufferObject(); primaryFBO->release(); glBindTexture(GL_TEXTURE_2D, primaryFBO->texture()); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glDisable(GL_BLEND); glDisable(GL_DEPTH_TEST); glDepthMask(GL_FALSE); QOpenGLFramebufferObject* destFBO = toTexture ? Application::getInstance()->getTextureCache()->getSecondaryFramebufferObject() : NULL; if (_isEmpty && _renderMode != DIFFUSE_ADD_MODE) { // copy the primary to the screen if (QOpenGLFramebufferObject::hasOpenGLFramebufferBlit()) { QOpenGLFramebufferObject::blitFramebuffer(destFBO, primaryFBO); } else { maybeBind(destFBO); glEnable(GL_TEXTURE_2D); glDisable(GL_LIGHTING); glColor3f(1.0f, 1.0f, 1.0f); renderFullscreenQuad(); glDisable(GL_TEXTURE_2D); glEnable(GL_LIGHTING); maybeRelease(destFBO); } } else if (_renderMode == ADD_MODE) { maybeBind(destFBO); _addProgram->bind(); renderFullscreenQuad(); _addProgram->release(); maybeRelease(destFBO); } else if (_renderMode == DIFFUSE_ADD_MODE) { // diffuse into the secondary/tertiary (alternating between frames) QOpenGLFramebufferObject* oldDiffusedFBO = Application::getInstance()->getTextureCache()->getSecondaryFramebufferObject(); QOpenGLFramebufferObject* newDiffusedFBO = Application::getInstance()->getTextureCache()->getTertiaryFramebufferObject(); if (_isOddFrame) { qSwap(oldDiffusedFBO, newDiffusedFBO); } newDiffusedFBO->bind(); if (_isFirstFrame) { glClear(GL_COLOR_BUFFER_BIT); } else { glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, oldDiffusedFBO->texture()); _diffuseProgram->bind(); QSize size = Application::getInstance()->getGLWidget()->size(); _diffuseProgram->setUniformValue(_diffusionScaleLocation, 1.0f / size.width(), 1.0f / size.height()); renderFullscreenQuad(); _diffuseProgram->release(); } newDiffusedFBO->release(); // add diffused texture to the primary glBindTexture(GL_TEXTURE_2D, newDiffusedFBO->texture()); if (toTexture) { destFBO = oldDiffusedFBO; } maybeBind(destFBO); _addSeparateProgram->bind(); renderFullscreenQuad(); _addSeparateProgram->release(); maybeRelease(destFBO); glBindTexture(GL_TEXTURE_2D, 0); glActiveTexture(GL_TEXTURE0); } else { // _renderMode == BLUR_ADD_MODE || _renderMode == BLUR_PERSIST_ADD_MODE // render the primary to the secondary with the horizontal blur QOpenGLFramebufferObject* secondaryFBO = Application::getInstance()->getTextureCache()->getSecondaryFramebufferObject(); secondaryFBO->bind(); _horizontalBlurProgram->bind(); renderFullscreenQuad(); _horizontalBlurProgram->release(); secondaryFBO->release(); if (_renderMode == BLUR_ADD_MODE) { // render the secondary to the screen with the vertical blur glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, secondaryFBO->texture()); if (toTexture) { destFBO = Application::getInstance()->getTextureCache()->getTertiaryFramebufferObject(); } maybeBind(destFBO); _verticalBlurAddProgram->bind(); renderFullscreenQuad(); _verticalBlurAddProgram->release(); maybeRelease(destFBO); } else { // _renderMode == BLUR_PERSIST_ADD_MODE // render the secondary to the tertiary with vertical blur and persistence QOpenGLFramebufferObject* tertiaryFBO = Application::getInstance()->getTextureCache()->getTertiaryFramebufferObject(); tertiaryFBO->bind(); glEnable(GL_BLEND); glBlendFunc(GL_ONE_MINUS_CONSTANT_ALPHA, GL_CONSTANT_ALPHA); const float PERSISTENCE_SMOOTHING = 0.9f; glBlendColor(0.0f, 0.0f, 0.0f, _isFirstFrame ? 0.0f : PERSISTENCE_SMOOTHING); glBindTexture(GL_TEXTURE_2D, secondaryFBO->texture()); _verticalBlurProgram->bind(); renderFullscreenQuad(); _verticalBlurProgram->release(); glBlendColor(0.0f, 0.0f, 0.0f, 0.0f); glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE); glDisable(GL_BLEND); // now add the tertiary to the primary buffer tertiaryFBO->release(); glBindTexture(GL_TEXTURE_2D, primaryFBO->texture()); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, tertiaryFBO->texture()); maybeBind(destFBO); _addSeparateProgram->bind(); renderFullscreenQuad(); _addSeparateProgram->release(); maybeRelease(destFBO); } glBindTexture(GL_TEXTURE_2D, 0); glActiveTexture(GL_TEXTURE0); } glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); glEnable(GL_BLEND); glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); glBindTexture(GL_TEXTURE_2D, 0); _isFirstFrame = false; return destFBO; }
void DeferredLightingEffect::render(RenderArgs* args) { // perform deferred lighting, rendering to free fbo glDisable(GL_BLEND); glDisable(GL_LIGHTING); glDisable(GL_DEPTH_TEST); glDisable(GL_COLOR_MATERIAL); glDepthMask(false); auto textureCache = DependencyManager::get<TextureCache>(); glBindFramebuffer(GL_FRAMEBUFFER, 0 ); QSize framebufferSize = textureCache->getFrameBufferSize(); // binding the first framebuffer auto freeFBO = DependencyManager::get<GlowEffect>()->getFreeFramebuffer(); glBindFramebuffer(GL_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(freeFBO)); glClear(GL_COLOR_BUFFER_BIT); // glEnable(GL_FRAMEBUFFER_SRGB); // glBindTexture(GL_TEXTURE_2D, primaryFBO->texture()); glBindTexture(GL_TEXTURE_2D, textureCache->getPrimaryColorTextureID()); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, textureCache->getPrimaryNormalTextureID()); glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, textureCache->getPrimarySpecularTextureID()); glActiveTexture(GL_TEXTURE3); glBindTexture(GL_TEXTURE_2D, textureCache->getPrimaryDepthTextureID()); // get the viewport side (left, right, both) int viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); const int VIEWPORT_X_INDEX = 0; const int VIEWPORT_Y_INDEX = 1; const int VIEWPORT_WIDTH_INDEX = 2; const int VIEWPORT_HEIGHT_INDEX = 3; float sMin = viewport[VIEWPORT_X_INDEX] / (float)framebufferSize.width(); float sWidth = viewport[VIEWPORT_WIDTH_INDEX] / (float)framebufferSize.width(); float tMin = viewport[VIEWPORT_Y_INDEX] / (float)framebufferSize.height(); float tHeight = viewport[VIEWPORT_HEIGHT_INDEX] / (float)framebufferSize.height(); bool useSkyboxCubemap = (_skybox) && (_skybox->getCubemap()); // Fetch the ViewMatrix; glm::mat4 invViewMat; _viewState->getViewTransform().getMatrix(invViewMat); ProgramObject* program = &_directionalLight; const LightLocations* locations = &_directionalLightLocations; bool shadowsEnabled = _viewState->getShadowsEnabled(); if (shadowsEnabled) { glActiveTexture(GL_TEXTURE4); glBindTexture(GL_TEXTURE_2D, textureCache->getShadowDepthTextureID()); program = &_directionalLightShadowMap; locations = &_directionalLightShadowMapLocations; if (_viewState->getCascadeShadowsEnabled()) { program = &_directionalLightCascadedShadowMap; locations = &_directionalLightCascadedShadowMapLocations; if (useSkyboxCubemap) { program = &_directionalSkyboxLightCascadedShadowMap; locations = &_directionalSkyboxLightCascadedShadowMapLocations; } else if (_ambientLightMode > -1) { program = &_directionalAmbientSphereLightCascadedShadowMap; locations = &_directionalAmbientSphereLightCascadedShadowMapLocations; } program->bind(); program->setUniform(locations->shadowDistances, _viewState->getShadowDistances()); } else { if (useSkyboxCubemap) { program = &_directionalSkyboxLightShadowMap; locations = &_directionalSkyboxLightShadowMapLocations; } else if (_ambientLightMode > -1) { program = &_directionalAmbientSphereLightShadowMap; locations = &_directionalAmbientSphereLightShadowMapLocations; } program->bind(); } program->setUniformValue(locations->shadowScale, 1.0f / textureCache->getShadowFramebuffer()->getWidth()); } else { if (useSkyboxCubemap) { program = &_directionalSkyboxLight; locations = &_directionalSkyboxLightLocations; } else if (_ambientLightMode > -1) { program = &_directionalAmbientSphereLight; locations = &_directionalAmbientSphereLightLocations; } program->bind(); } { auto globalLight = _allocatedLights[_globalLights.front()]; if (locations->ambientSphere >= 0) { gpu::SphericalHarmonics sh = globalLight->getAmbientSphere(); if (useSkyboxCubemap && _skybox->getCubemap()->getIrradiance()) { sh = (*_skybox->getCubemap()->getIrradiance()); } for (int i =0; i <gpu::SphericalHarmonics::NUM_COEFFICIENTS; i++) { program->setUniformValue(locations->ambientSphere + i, *(((QVector4D*) &sh) + i)); } } if (useSkyboxCubemap) { glActiveTexture(GL_TEXTURE5); glBindTexture(GL_TEXTURE_CUBE_MAP, gpu::GLBackend::getTextureID(_skybox->getCubemap())); } if (locations->lightBufferUnit >= 0) { gpu::Batch batch; batch.setUniformBuffer(locations->lightBufferUnit, globalLight->getSchemaBuffer()); gpu::GLBackend::renderBatch(batch); } if (_atmosphere && (locations->atmosphereBufferUnit >= 0)) { gpu::Batch batch; batch.setUniformBuffer(locations->atmosphereBufferUnit, _atmosphere->getDataBuffer()); gpu::GLBackend::renderBatch(batch); } glUniformMatrix4fv(locations->invViewMat, 1, false, reinterpret_cast< const GLfloat* >(&invViewMat)); } float left, right, bottom, top, nearVal, farVal; glm::vec4 nearClipPlane, farClipPlane; _viewState->computeOffAxisFrustum(left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane); program->setUniformValue(locations->nearLocation, nearVal); float depthScale = (farVal - nearVal) / farVal; program->setUniformValue(locations->depthScale, depthScale); float nearScale = -1.0f / nearVal; float depthTexCoordScaleS = (right - left) * nearScale / sWidth; float depthTexCoordScaleT = (top - bottom) * nearScale / tHeight; float depthTexCoordOffsetS = left * nearScale - sMin * depthTexCoordScaleS; float depthTexCoordOffsetT = bottom * nearScale - tMin * depthTexCoordScaleT; program->setUniformValue(locations->depthTexCoordOffset, depthTexCoordOffsetS, depthTexCoordOffsetT); program->setUniformValue(locations->depthTexCoordScale, depthTexCoordScaleS, depthTexCoordScaleT); renderFullscreenQuad(sMin, sMin + sWidth, tMin, tMin + tHeight); program->release(); if (useSkyboxCubemap) { glBindTexture(GL_TEXTURE_CUBE_MAP, 0); if (!shadowsEnabled) { glActiveTexture(GL_TEXTURE3); } } if (shadowsEnabled) { glBindTexture(GL_TEXTURE_2D, 0); glActiveTexture(GL_TEXTURE3); } // additive blending glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glEnable(GL_CULL_FACE); glm::vec4 sCoefficients(sWidth / 2.0f, 0.0f, 0.0f, sMin + sWidth / 2.0f); glm::vec4 tCoefficients(0.0f, tHeight / 2.0f, 0.0f, tMin + tHeight / 2.0f); glTexGenfv(GL_S, GL_OBJECT_PLANE, (const GLfloat*)&sCoefficients); glTexGenfv(GL_T, GL_OBJECT_PLANE, (const GLfloat*)&tCoefficients); // enlarge the scales slightly to account for tesselation const float SCALE_EXPANSION = 0.05f; const glm::vec3& eyePoint = _viewState->getCurrentViewFrustum()->getPosition(); float nearRadius = glm::distance(eyePoint, _viewState->getCurrentViewFrustum()->getNearTopLeft()); auto geometryCache = DependencyManager::get<GeometryCache>(); if (!_pointLights.empty()) { _pointLight.bind(); _pointLight.setUniformValue(_pointLightLocations.nearLocation, nearVal); _pointLight.setUniformValue(_pointLightLocations.depthScale, depthScale); _pointLight.setUniformValue(_pointLightLocations.depthTexCoordOffset, depthTexCoordOffsetS, depthTexCoordOffsetT); _pointLight.setUniformValue(_pointLightLocations.depthTexCoordScale, depthTexCoordScaleS, depthTexCoordScaleT); for (auto lightID : _pointLights) { auto light = _allocatedLights[lightID]; if (_pointLightLocations.lightBufferUnit >= 0) { gpu::Batch batch; batch.setUniformBuffer(_pointLightLocations.lightBufferUnit, light->getSchemaBuffer()); gpu::GLBackend::renderBatch(batch); } glUniformMatrix4fv(_pointLightLocations.invViewMat, 1, false, reinterpret_cast< const GLfloat* >(&invViewMat)); glPushMatrix(); float expandedRadius = light->getMaximumRadius() * (1.0f + SCALE_EXPANSION); if (glm::distance(eyePoint, glm::vec3(light->getPosition())) < expandedRadius + nearRadius) { glLoadIdentity(); glTranslatef(0.0f, 0.0f, -1.0f); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); renderFullscreenQuad(); glPopMatrix(); glMatrixMode(GL_MODELVIEW); } else { glTranslatef(light->getPosition().x, light->getPosition().y, light->getPosition().z); geometryCache->renderSphere(expandedRadius, 32, 32, glm::vec4(1.0f, 1.0f, 1.0f, 1.0f)); } glPopMatrix(); } _pointLights.clear(); _pointLight.release(); } if (!_spotLights.empty()) { _spotLight.bind(); _spotLight.setUniformValue(_spotLightLocations.nearLocation, nearVal); _spotLight.setUniformValue(_spotLightLocations.depthScale, depthScale); _spotLight.setUniformValue(_spotLightLocations.depthTexCoordOffset, depthTexCoordOffsetS, depthTexCoordOffsetT); _spotLight.setUniformValue(_spotLightLocations.depthTexCoordScale, depthTexCoordScaleS, depthTexCoordScaleT); for (auto lightID : _spotLights) { auto light = _allocatedLights[lightID]; if (_spotLightLocations.lightBufferUnit >= 0) { gpu::Batch batch; batch.setUniformBuffer(_spotLightLocations.lightBufferUnit, light->getSchemaBuffer()); gpu::GLBackend::renderBatch(batch); } glUniformMatrix4fv(_spotLightLocations.invViewMat, 1, false, reinterpret_cast< const GLfloat* >(&invViewMat)); glPushMatrix(); float expandedRadius = light->getMaximumRadius() * (1.0f + SCALE_EXPANSION); float edgeRadius = expandedRadius / glm::cos(light->getSpotAngle()); if (glm::distance(eyePoint, glm::vec3(light->getPosition())) < edgeRadius + nearRadius) { glLoadIdentity(); glTranslatef(0.0f, 0.0f, -1.0f); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); renderFullscreenQuad(); glPopMatrix(); glMatrixMode(GL_MODELVIEW); } else { glTranslatef(light->getPosition().x, light->getPosition().y, light->getPosition().z); glm::quat spotRotation = rotationBetween(glm::vec3(0.0f, 0.0f, -1.0f), light->getDirection()); glm::vec3 axis = glm::axis(spotRotation); glRotatef(glm::degrees(glm::angle(spotRotation)), axis.x, axis.y, axis.z); glTranslatef(0.0f, 0.0f, -light->getMaximumRadius() * (1.0f + SCALE_EXPANSION * 0.5f)); geometryCache->renderCone(expandedRadius * glm::tan(light->getSpotAngle()), expandedRadius, 32, 1); } glPopMatrix(); } _spotLights.clear(); _spotLight.release(); } glBindTexture(GL_TEXTURE_2D, 0); glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, 0); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, 0); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, 0); // glDisable(GL_FRAMEBUFFER_SRGB); // End of the Lighting pass }
QOpenGLFramebufferObject* GlowEffect::render(bool toTexture) { PerformanceTimer perfTimer("glowEffect"); TextureCache* textureCache = DependencyManager::get<TextureCache>(); QOpenGLFramebufferObject* primaryFBO = textureCache->getPrimaryFramebufferObject(); primaryFBO->release(); glBindTexture(GL_TEXTURE_2D, primaryFBO->texture()); glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glDisable(GL_BLEND); glDisable(GL_DEPTH_TEST); glDepthMask(GL_FALSE); QOpenGLFramebufferObject* destFBO = toTexture ? textureCache->getSecondaryFramebufferObject() : NULL; if (!Menu::getInstance()->isOptionChecked(MenuOption::EnableGlowEffect) || _isEmpty) { // copy the primary to the screen if (destFBO && QOpenGLFramebufferObject::hasOpenGLFramebufferBlit()) { QOpenGLFramebufferObject::blitFramebuffer(destFBO, primaryFBO); } else { maybeBind(destFBO); if (!destFBO) { glViewport(0, 0, Application::getInstance()->getGLWidget()->getDeviceWidth(), Application::getInstance()->getGLWidget()->getDeviceHeight()); } glEnable(GL_TEXTURE_2D); glDisable(GL_LIGHTING); glColor3f(1.0f, 1.0f, 1.0f); renderFullscreenQuad(); glDisable(GL_TEXTURE_2D); glEnable(GL_LIGHTING); maybeRelease(destFBO); } } else { // diffuse into the secondary/tertiary (alternating between frames) QOpenGLFramebufferObject* oldDiffusedFBO = textureCache->getSecondaryFramebufferObject(); QOpenGLFramebufferObject* newDiffusedFBO = textureCache->getTertiaryFramebufferObject(); if (_isOddFrame) { qSwap(oldDiffusedFBO, newDiffusedFBO); } newDiffusedFBO->bind(); if (_isFirstFrame) { glClear(GL_COLOR_BUFFER_BIT); } else { glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, oldDiffusedFBO->texture()); _diffuseProgram->bind(); QSize size = primaryFBO->size(); _diffuseProgram->setUniformValue(_diffusionScaleLocation, 1.0f / size.width(), 1.0f / size.height()); renderFullscreenQuad(); _diffuseProgram->release(); } newDiffusedFBO->release(); // add diffused texture to the primary glBindTexture(GL_TEXTURE_2D, newDiffusedFBO->texture()); if (toTexture) { destFBO = oldDiffusedFBO; } maybeBind(destFBO); if (!destFBO) { glViewport(0, 0, Application::getInstance()->getGLWidget()->getDeviceWidth(), Application::getInstance()->getGLWidget()->getDeviceHeight()); } _addSeparateProgram->bind(); renderFullscreenQuad(); _addSeparateProgram->release(); maybeRelease(destFBO); glBindTexture(GL_TEXTURE_2D, 0); glActiveTexture(GL_TEXTURE0); } glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); glEnable(GL_BLEND); glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); glBindTexture(GL_TEXTURE_2D, 0); _isFirstFrame = false; return destFBO; }
void DeferredLightingEffect::render() { // perform deferred lighting, rendering to free fbo glColor4f(1.0f, 1.0f, 1.0f, 1.0f); glDisable(GL_BLEND); glDisable(GL_LIGHTING); glDisable(GL_DEPTH_TEST); glDisable(GL_COLOR_MATERIAL); glDepthMask(false); QOpenGLFramebufferObject* primaryFBO = Application::getInstance()->getTextureCache()->getPrimaryFramebufferObject(); primaryFBO->release(); QOpenGLFramebufferObject* freeFBO = Application::getInstance()->getGlowEffect()->getFreeFramebufferObject(); freeFBO->bind(); glClear(GL_COLOR_BUFFER_BIT); glBindTexture(GL_TEXTURE_2D, primaryFBO->texture()); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getPrimaryNormalTextureID()); glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getPrimarySpecularTextureID()); glActiveTexture(GL_TEXTURE3); glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getPrimaryDepthTextureID()); // get the viewport side (left, right, both) int viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); const int VIEWPORT_X_INDEX = 0; const int VIEWPORT_Y_INDEX = 1; const int VIEWPORT_WIDTH_INDEX = 2; const int VIEWPORT_HEIGHT_INDEX = 3; float sMin = viewport[VIEWPORT_X_INDEX] / (float)primaryFBO->width(); float sWidth = viewport[VIEWPORT_WIDTH_INDEX] / (float)primaryFBO->width(); float tMin = viewport[VIEWPORT_Y_INDEX] / (float)primaryFBO->height(); float tHeight = viewport[VIEWPORT_HEIGHT_INDEX] / (float)primaryFBO->height(); ProgramObject* program = &_directionalLight; const LightLocations* locations = &_directionalLightLocations; bool shadowsEnabled = Menu::getInstance()->getShadowsEnabled(); if (shadowsEnabled) { glActiveTexture(GL_TEXTURE4); glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getShadowDepthTextureID()); program = &_directionalLightShadowMap; locations = &_directionalLightShadowMapLocations; if (Menu::getInstance()->isOptionChecked(MenuOption::CascadedShadows)) { program = &_directionalLightCascadedShadowMap; locations = &_directionalLightCascadedShadowMapLocations; _directionalLightCascadedShadowMap.bind(); _directionalLightCascadedShadowMap.setUniform(locations->shadowDistances, Application::getInstance()->getShadowDistances()); } else { program->bind(); } program->setUniformValue(locations->shadowScale, 1.0f / Application::getInstance()->getTextureCache()->getShadowFramebufferObject()->width()); } else { program->bind(); } float left, right, bottom, top, nearVal, farVal; glm::vec4 nearClipPlane, farClipPlane; Application::getInstance()->computeOffAxisFrustum( left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane); program->setUniformValue(locations->nearLocation, nearVal); float depthScale = (farVal - nearVal) / farVal; program->setUniformValue(locations->depthScale, depthScale); float nearScale = -1.0f / nearVal; float depthTexCoordScaleS = (right - left) * nearScale / sWidth; float depthTexCoordScaleT = (top - bottom) * nearScale / tHeight; float depthTexCoordOffsetS = left * nearScale - sMin * depthTexCoordScaleS; float depthTexCoordOffsetT = bottom * nearScale - tMin * depthTexCoordScaleT; program->setUniformValue(locations->depthTexCoordOffset, depthTexCoordOffsetS, depthTexCoordOffsetT); program->setUniformValue(locations->depthTexCoordScale, depthTexCoordScaleS, depthTexCoordScaleT); renderFullscreenQuad(sMin, sMin + sWidth, tMin, tMin + tHeight); program->release(); if (shadowsEnabled) { glBindTexture(GL_TEXTURE_2D, 0); glActiveTexture(GL_TEXTURE3); } // additive blending glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ONE); glEnable(GL_CULL_FACE); glm::vec4 sCoefficients(sWidth / 2.0f, 0.0f, 0.0f, sMin + sWidth / 2.0f); glm::vec4 tCoefficients(0.0f, tHeight / 2.0f, 0.0f, tMin + tHeight / 2.0f); glTexGenfv(GL_S, GL_OBJECT_PLANE, (const GLfloat*)&sCoefficients); glTexGenfv(GL_T, GL_OBJECT_PLANE, (const GLfloat*)&tCoefficients); // enlarge the scales slightly to account for tesselation const float SCALE_EXPANSION = 0.05f; const glm::vec3& eyePoint = Application::getInstance()->getDisplayViewFrustum()->getPosition(); float nearRadius = glm::distance(eyePoint, Application::getInstance()->getDisplayViewFrustum()->getNearTopLeft()); if (!_pointLights.isEmpty()) { _pointLight.bind(); _pointLight.setUniformValue(_pointLightLocations.nearLocation, nearVal); _pointLight.setUniformValue(_pointLightLocations.depthScale, depthScale); _pointLight.setUniformValue(_pointLightLocations.depthTexCoordOffset, depthTexCoordOffsetS, depthTexCoordOffsetT); _pointLight.setUniformValue(_pointLightLocations.depthTexCoordScale, depthTexCoordScaleS, depthTexCoordScaleT); foreach (const PointLight& light, _pointLights) { _pointLight.setUniformValue(_pointLightLocations.radius, light.radius); glLightfv(GL_LIGHT1, GL_AMBIENT, (const GLfloat*)&light.ambient); glLightfv(GL_LIGHT1, GL_DIFFUSE, (const GLfloat*)&light.diffuse); glLightfv(GL_LIGHT1, GL_SPECULAR, (const GLfloat*)&light.specular); glLightfv(GL_LIGHT1, GL_POSITION, (const GLfloat*)&light.position); glLightf(GL_LIGHT1, GL_CONSTANT_ATTENUATION, (light.constantAttenuation > 0.0f ? light.constantAttenuation : 0.0f)); glLightf(GL_LIGHT1, GL_LINEAR_ATTENUATION, (light.linearAttenuation > 0.0f ? light.linearAttenuation : 0.0f)); glLightf(GL_LIGHT1, GL_QUADRATIC_ATTENUATION, (light.quadraticAttenuation > 0.0f ? light.quadraticAttenuation : 0.0f)); glPushMatrix(); float expandedRadius = light.radius * (1.0f + SCALE_EXPANSION); if (glm::distance(eyePoint, glm::vec3(light.position)) < expandedRadius + nearRadius) { glLoadIdentity(); glTranslatef(0.0f, 0.0f, -1.0f); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); renderFullscreenQuad(); glPopMatrix(); glMatrixMode(GL_MODELVIEW); } else { glTranslatef(light.position.x, light.position.y, light.position.z); Application::getInstance()->getGeometryCache()->renderSphere(expandedRadius, 32, 32); } glPopMatrix(); }