diff --git a/CHANGELOG.md b/CHANGELOG.md index 22a48cd510..25ae0c45d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -70,6 +70,7 @@ Feature #5996: Support Lua scripts in OpenMW Feature #6017: Separate persistent and temporary cell references when saving Feature #6032: Reverse-z depth buffer + Feature #6078: First person should not clear depth buffer Feature #6162: Refactor GUI to use shaders and to be GLES and GL3+ friendly Feature #6199: Support FBO Rendering Feature #6249: Alpha testing support for Collada diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 28987064f3..0e100326dd 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -44,6 +44,7 @@ #include "renderbin.hpp" #include "vismask.hpp" #include "util.hpp" +#include "postprocessor.hpp" namespace { @@ -330,6 +331,8 @@ void NpcAnimation::setViewMode(NpcAnimation::ViewMode viewMode) } /// @brief A RenderBin callback to clear the depth buffer before rendering. +/// Switches depth attachments to a proxy renderbuffer, reattaches original depth then redraws first person root. +/// This gives a complete depth buffer which can be used for postprocessing, buffer resolves as if depth was never cleared. class DepthClearCallback : public osgUtil::RenderBin::DrawCallback { public: @@ -337,18 +340,49 @@ public: { mDepth = SceneUtil::createDepth(); mDepth->setWriteMask(true); + + mStateSet = new osg::StateSet; + mStateSet->setAttributeAndModes(new osg::ColorMask(false, false, false, false), osg::StateAttribute::ON); + mStateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF|osg::StateAttribute::OVERRIDE); } void drawImplementation(osgUtil::RenderBin* bin, osg::RenderInfo& renderInfo, osgUtil::RenderLeaf*& previous) override { - renderInfo.getState()->applyAttribute(mDepth); + osg::State* state = renderInfo.getState(); + + PostProcessor* postProcessor = dynamic_cast(renderInfo.getCurrentCamera()->getUserData()); + + state->applyAttribute(mDepth); + + if (postProcessor && postProcessor->getFirstPersonRBProxy()) + { + osg::GLExtensions* ext = state->get(); + + osg::FrameBufferAttachment(postProcessor->getFirstPersonRBProxy()).attach(*state, GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, ext); - glClear(GL_DEPTH_BUFFER_BIT); + glClear(GL_DEPTH_BUFFER_BIT); + // color accumulation pass + bin->drawImplementation(renderInfo, previous); - bin->drawImplementation(renderInfo, previous); + auto primaryFBO = postProcessor->getMsaaFbo() ? postProcessor->getMsaaFbo() : postProcessor->getFbo(); + primaryFBO->getAttachment(osg::FrameBufferObject::BufferComponent::DEPTH_BUFFER).attach(*state, GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, ext); + + state->pushStateSet(mStateSet); + state->apply(); + // depth accumulation pass + bin->drawImplementation(renderInfo, previous); + state->popStateSet(); + } + else + { + // fallback to standard depth clear when we are not rendering our main scene via an intermediate FBO + glClear(GL_DEPTH_BUFFER_BIT); + bin->drawImplementation(renderInfo, previous); + } } osg::ref_ptr mDepth; + osg::ref_ptr mStateSet; }; /// Overrides Field of View to given value for rendering the subgraph. diff --git a/apps/openmw/mwrender/postprocessor.cpp b/apps/openmw/mwrender/postprocessor.cpp index bc00676d7b..1ee5745cb4 100644 --- a/apps/openmw/mwrender/postprocessor.cpp +++ b/apps/openmw/mwrender/postprocessor.cpp @@ -183,6 +183,9 @@ namespace MWRender mMsaaFbo->setAttachment(osg::Camera::DEPTH_BUFFER, osg::FrameBufferAttachment(depthRB)); } + if (const auto depthProxy = std::getenv("OPENMW_ENABLE_DEPTH_CLEAR_PROXY")) + mFirstPersonDepthRBProxy = new osg::RenderBuffer(width, height, mDepthTex->getInternalFormat(), samples); + mViewer->getCamera()->resize(width, height); mHUDCamera->resize(width, height); mRendering.updateProjectionMatrix(); diff --git a/apps/openmw/mwrender/postprocessor.hpp b/apps/openmw/mwrender/postprocessor.hpp index f93f3a5b66..0d03d4b500 100644 --- a/apps/openmw/mwrender/postprocessor.hpp +++ b/apps/openmw/mwrender/postprocessor.hpp @@ -23,6 +23,7 @@ namespace MWRender auto getMsaaFbo() { return mMsaaFbo; } auto getFbo() { return mFbo; } + auto getFirstPersonRBProxy() { return mFirstPersonDepthRBProxy; } int getDepthFormat() { return mDepthFormat; } @@ -37,6 +38,7 @@ namespace MWRender osg::ref_ptr mMsaaFbo; osg::ref_ptr mFbo; + osg::ref_ptr mFirstPersonDepthRBProxy; osg::ref_ptr mSceneTex; osg::ref_ptr mDepthTex;