diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 7fad196cd0..17d36380ee 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1735,6 +1735,7 @@ void Application::init() { _environment.init(); + _deferredLightingEffect.init(); _glowEffect.init(); _ambientOcclusionEffect.init(); _voxelShader.init(); @@ -2842,11 +2843,13 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { } // Draw voxels + bool deferredLightingRequired = false; if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) { PerformanceTimer perfTimer("voxels"); PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide() ... voxels..."); _voxels.render(); + deferredLightingRequired = true; } // also, metavoxels @@ -2855,6 +2858,11 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide() ... metavoxels..."); _metavoxels.render(); + deferredLightingRequired = true; + } + + if (deferredLightingRequired) { + _deferredLightingEffect.render(); } if (Menu::getInstance()->isOptionChecked(MenuOption::BuckyBalls)) { diff --git a/interface/src/Application.h b/interface/src/Application.h index fbcc67cf80..aa7ef94c5b 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -68,6 +68,7 @@ #include "entities/EntityTreeRenderer.h" #include "particles/ParticleTreeRenderer.h" #include "renderer/AmbientOcclusionEffect.h" +#include "renderer/DeferredLightingEffect.h" #include "renderer/GeometryCache.h" #include "renderer/GlowEffect.h" #include "renderer/PointShader.h" @@ -556,6 +557,7 @@ private: AnimationCache _animationCache; TextureCache _textureCache; + DeferredLightingEffect _deferredLightingEffect; GlowEffect _glowEffect; AmbientOcclusionEffect _ambientOcclusionEffect; VoxelShader _voxelShader; diff --git a/interface/src/MetavoxelSystem.cpp b/interface/src/MetavoxelSystem.cpp index 903e443cda..b3e31ce56e 100644 --- a/interface/src/MetavoxelSystem.cpp +++ b/interface/src/MetavoxelSystem.cpp @@ -51,12 +51,6 @@ void MetavoxelSystem::init() { new BufferDataAttribute("voxelBuffer")); _voxelBufferAttribute->setLODThresholdMultiplier( AttributeRegistry::getInstance()->getVoxelColorAttribute()->getLODThresholdMultiplier()); - - loadLightProgram("shaders/directional_light.frag", _directionalLight, _directionalLightLocations); - loadLightProgram("shaders/directional_light_shadow_map.frag", _directionalLightShadowMap, - _directionalLightShadowMapLocations); - loadLightProgram("shaders/directional_light_cascaded_shadow_map.frag", _directionalLightCascadedShadowMap, - _directionalLightCascadedShadowMapLocations); } MetavoxelLOD MetavoxelSystem::getLOD() { @@ -138,8 +132,6 @@ void MetavoxelSystem::render() { viewFrustum->getFarBottomRight(), viewFrustum->getNearTopLeft(), viewFrustum->getNearTopRight(), viewFrustum->getNearBottomLeft(), viewFrustum->getNearBottomRight()); - _needToLight = false; - // clear the normal buffer glDrawBuffers(sizeof(NORMAL_DRAW_BUFFERS) / sizeof(NORMAL_DRAW_BUFFERS[0]), NORMAL_DRAW_BUFFERS); glClear(GL_COLOR_BUFFER_BIT); @@ -151,126 +143,6 @@ void MetavoxelSystem::render() { // give external parties a chance to join in emit rendering(); - - if (!_needToLight) { - return; // skip lighting if not needed - } - - // perform deferred lighting, rendering to free fbo - glPushMatrix(); - glLoadIdentity(); - - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - - glDisable(GL_BLEND); - glDisable(GL_LIGHTING); - glDisable(GL_DEPTH_TEST); - 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()); - - // get the viewport side (left, right, both) - 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)primaryFBO->width(); - float sWidth = viewport[VIEWPORT_WIDTH_INDEX] / (float)primaryFBO->width(); - - if (Menu::getInstance()->getShadowsEnabled()) { - glActiveTexture(GL_TEXTURE2); - glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getPrimaryDepthTextureID()); - - glActiveTexture(GL_TEXTURE3); - glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getShadowDepthTextureID()); - - ProgramObject* program = &_directionalLightShadowMap; - const LightLocations* 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()); - - 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); - program->setUniformValue(locations->depthScale, (farVal - nearVal) / farVal); - float nearScale = -1.0f / nearVal; - float sScale = 1.0f / sWidth; - float depthTexCoordScaleS = (right - left) * nearScale * sScale; - program->setUniformValue(locations->depthTexCoordOffset, left * nearScale - sMin * depthTexCoordScaleS, - bottom * nearScale); - program->setUniformValue(locations->depthTexCoordScale, depthTexCoordScaleS, (top - bottom) * nearScale); - - renderFullscreenQuad(sMin, sMin + sWidth); - - program->release(); - - glBindTexture(GL_TEXTURE_2D, 0); - - glActiveTexture(GL_TEXTURE2); - glBindTexture(GL_TEXTURE_2D, 0); - - glActiveTexture(GL_TEXTURE1); - - } else { - _directionalLight.bind(); - renderFullscreenQuad(sMin, sMin + sWidth); - _directionalLight.release(); - } - - glBindTexture(GL_TEXTURE_2D, 0); - glActiveTexture(GL_TEXTURE0); - - freeFBO->release(); - - // now transfer the lit region to the primary fbo - glEnable(GL_BLEND); - - primaryFBO->bind(); - - glBindTexture(GL_TEXTURE_2D, freeFBO->texture()); - glEnable(GL_TEXTURE_2D); - - glColor4f(1.0f, 1.0f, 1.0f, 1.0f); - - renderFullscreenQuad(sMin, sMin + sWidth); - - glBindTexture(GL_TEXTURE_2D, 0); - glDisable(GL_TEXTURE_2D); - - glEnable(GL_LIGHTING); - glEnable(GL_DEPTH_TEST); - glDepthMask(true); - - glDisable(GL_ALPHA_TEST); - - glPopMatrix(); - - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); } class RayHeightfieldIntersectionVisitor : public RayIntersectionVisitor { @@ -630,24 +502,6 @@ void MetavoxelSystem::guideToAugmented(MetavoxelVisitor& visitor, bool render) { } } -void MetavoxelSystem::loadLightProgram(const char* name, ProgramObject& program, LightLocations& locations) { - program.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + name); - program.link(); - - program.bind(); - program.setUniformValue("diffuseMap", 0); - program.setUniformValue("normalMap", 1); - program.setUniformValue("depthMap", 2); - program.setUniformValue("shadowMap", 3); - locations.shadowDistances = program.uniformLocation("shadowDistances"); - locations.shadowScale = program.uniformLocation("shadowScale"); - locations.nearLocation = program.uniformLocation("near"); - locations.depthScale = program.uniformLocation("depthScale"); - locations.depthTexCoordOffset = program.uniformLocation("depthTexCoordOffset"); - locations.depthTexCoordScale = program.uniformLocation("depthTexCoordScale"); - program.release(); -} - MetavoxelSystemClient::MetavoxelSystemClient(const SharedNodePointer& node, MetavoxelUpdater* updater) : MetavoxelClient(node, updater) { } @@ -1077,8 +931,6 @@ void HeightfieldBuffer::render(bool cursor) { bufferPair.first.release(); bufferPair.second.release(); - - Application::getInstance()->getMetavoxels()->noteNeedToLight(); } QHash HeightfieldBuffer::_bufferPairs; @@ -1245,8 +1097,6 @@ void VoxelBuffer::render(bool cursor) { _vertexBuffer.release(); _indexBuffer.release(); - - Application::getInstance()->getMetavoxels()->noteNeedToLight(); } BufferDataAttribute::BufferDataAttribute(const QString& name) : diff --git a/interface/src/MetavoxelSystem.h b/interface/src/MetavoxelSystem.h index f3b9a02117..f99a5834c9 100644 --- a/interface/src/MetavoxelSystem.h +++ b/interface/src/MetavoxelSystem.h @@ -52,8 +52,6 @@ public: Q_INVOKABLE void deleteTextures(int heightID, int colorID, int textureID); - void noteNeedToLight() { _needToLight = true; } - signals: void rendering(); @@ -66,18 +64,6 @@ private: void guideToAugmented(MetavoxelVisitor& visitor, bool render = false); - class LightLocations { - public: - int shadowDistances; - int shadowScale; - int nearLocation; - int depthScale; - int depthTexCoordOffset; - int depthTexCoordScale; - }; - - static void loadLightProgram(const char* name, ProgramObject& program, LightLocations& locations); - AttributePointer _pointBufferAttribute; AttributePointer _heightfieldBufferAttribute; AttributePointer _voxelBufferAttribute; @@ -85,14 +71,6 @@ private: MetavoxelLOD _lod; QReadWriteLock _lodLock; Frustum _frustum; - bool _needToLight; - - ProgramObject _directionalLight; - LightLocations _directionalLightLocations; - ProgramObject _directionalLightShadowMap; - LightLocations _directionalLightShadowMapLocations; - ProgramObject _directionalLightCascadedShadowMap; - LightLocations _directionalLightCascadedShadowMapLocations; }; /// Describes contents of a point in a point buffer. diff --git a/interface/src/renderer/DeferredLightingEffect.cpp b/interface/src/renderer/DeferredLightingEffect.cpp new file mode 100644 index 0000000000..95df2d5c72 --- /dev/null +++ b/interface/src/renderer/DeferredLightingEffect.cpp @@ -0,0 +1,163 @@ +// +// DeferredLightingEffect.cpp +// interface/src/renderer +// +// Created by Andrzej Kapolka on 9/11/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +// include this before QOpenGLFramebufferObject, which includes an earlier version of OpenGL +#include "InterfaceConfig.h" + +#include + +#include "Application.h" +#include "DeferredLightingEffect.h" +#include "RenderUtil.h" + +void DeferredLightingEffect::init() { + loadLightProgram("shaders/directional_light.frag", _directionalLight, _directionalLightLocations); + loadLightProgram("shaders/directional_light_shadow_map.frag", _directionalLightShadowMap, + _directionalLightShadowMapLocations); + loadLightProgram("shaders/directional_light_cascaded_shadow_map.frag", _directionalLightCascadedShadowMap, + _directionalLightCascadedShadowMapLocations); +} + +void DeferredLightingEffect::render() { + // perform deferred lighting, rendering to free fbo + glPushMatrix(); + glLoadIdentity(); + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + + glDisable(GL_BLEND); + glDisable(GL_LIGHTING); + glDisable(GL_DEPTH_TEST); + 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()); + + // get the viewport side (left, right, both) + 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)primaryFBO->width(); + float sWidth = viewport[VIEWPORT_WIDTH_INDEX] / (float)primaryFBO->width(); + + if (Menu::getInstance()->getShadowsEnabled()) { + glActiveTexture(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getPrimaryDepthTextureID()); + + glActiveTexture(GL_TEXTURE3); + glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getShadowDepthTextureID()); + + ProgramObject* program = &_directionalLightShadowMap; + const LightLocations* 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()); + + 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); + program->setUniformValue(locations->depthScale, (farVal - nearVal) / farVal); + float nearScale = -1.0f / nearVal; + float sScale = 1.0f / sWidth; + float depthTexCoordScaleS = (right - left) * nearScale * sScale; + program->setUniformValue(locations->depthTexCoordOffset, left * nearScale - sMin * depthTexCoordScaleS, + bottom * nearScale); + program->setUniformValue(locations->depthTexCoordScale, depthTexCoordScaleS, (top - bottom) * nearScale); + + renderFullscreenQuad(sMin, sMin + sWidth); + + program->release(); + + glBindTexture(GL_TEXTURE_2D, 0); + + glActiveTexture(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_2D, 0); + + glActiveTexture(GL_TEXTURE1); + + } else { + _directionalLight.bind(); + renderFullscreenQuad(sMin, sMin + sWidth); + _directionalLight.release(); + } + + glBindTexture(GL_TEXTURE_2D, 0); + glActiveTexture(GL_TEXTURE0); + + freeFBO->release(); + + // now transfer the lit region to the primary fbo + glEnable(GL_BLEND); + + primaryFBO->bind(); + + glBindTexture(GL_TEXTURE_2D, freeFBO->texture()); + glEnable(GL_TEXTURE_2D); + + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + + renderFullscreenQuad(sMin, sMin + sWidth); + + glBindTexture(GL_TEXTURE_2D, 0); + glDisable(GL_TEXTURE_2D); + + glEnable(GL_LIGHTING); + glEnable(GL_DEPTH_TEST); + glDepthMask(true); + + glDisable(GL_ALPHA_TEST); + + glPopMatrix(); + + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); +} + +void DeferredLightingEffect::loadLightProgram(const char* name, ProgramObject& program, LightLocations& locations) { + program.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + name); + program.link(); + + program.bind(); + program.setUniformValue("diffuseMap", 0); + program.setUniformValue("normalMap", 1); + program.setUniformValue("depthMap", 2); + program.setUniformValue("shadowMap", 3); + locations.shadowDistances = program.uniformLocation("shadowDistances"); + locations.shadowScale = program.uniformLocation("shadowScale"); + locations.nearLocation = program.uniformLocation("near"); + locations.depthScale = program.uniformLocation("depthScale"); + locations.depthTexCoordOffset = program.uniformLocation("depthTexCoordOffset"); + locations.depthTexCoordScale = program.uniformLocation("depthTexCoordScale"); + program.release(); +} diff --git a/interface/src/renderer/DeferredLightingEffect.h b/interface/src/renderer/DeferredLightingEffect.h new file mode 100644 index 0000000000..e67b3b9153 --- /dev/null +++ b/interface/src/renderer/DeferredLightingEffect.h @@ -0,0 +1,46 @@ +// +// DeferredLightingEffect.h +// interface/src/renderer +// +// Created by Andrzej Kapolka on 9/11/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_DeferredLightingEffect_h +#define hifi_DeferredLightingEffect_h + +#include "ProgramObject.h" + +/// Handles deferred lighting for the bits that require it (voxels, metavoxels...) +class DeferredLightingEffect { +public: + + void init(); + void render(); + +private: + + class LightLocations { + public: + int shadowDistances; + int shadowScale; + int nearLocation; + int depthScale; + int depthTexCoordOffset; + int depthTexCoordScale; + }; + + static void loadLightProgram(const char* name, ProgramObject& program, LightLocations& locations); + + ProgramObject _directionalLight; + LightLocations _directionalLightLocations; + ProgramObject _directionalLightShadowMap; + LightLocations _directionalLightShadowMapLocations; + ProgramObject _directionalLightCascadedShadowMap; + LightLocations _directionalLightCascadedShadowMapLocations; +}; + +#endif // hifi_DeferredLightingEffect_h