From d85f772269241cb2f6fe95b74734ff675c007c82 Mon Sep 17 00:00:00 2001 From: Cody Glassman Date: Sun, 21 Nov 2021 02:25:05 +0000 Subject: [PATCH] Depth refactor --- apps/openmw/engine.cpp | 17 +++ apps/openmw/mwgui/bookpage.cpp | 4 +- apps/openmw/mwrender/bulletdebugdraw.cpp | 4 +- apps/openmw/mwrender/characterpreview.cpp | 51 ++------- apps/openmw/mwrender/globalmap.cpp | 7 +- apps/openmw/mwrender/localmap.cpp | 12 +-- apps/openmw/mwrender/npcanimation.cpp | 3 +- apps/openmw/mwrender/postprocessor.cpp | 6 +- apps/openmw/mwrender/renderingmanager.cpp | 14 +-- apps/openmw/mwrender/ripplesimulation.cpp | 8 +- apps/openmw/mwrender/screenshotmanager.cpp | 4 +- apps/openmw/mwrender/sky.cpp | 4 +- apps/openmw/mwrender/skyutil.cpp | 6 +- apps/openmw/mwrender/water.cpp | 6 +- components/CMakeLists.txt | 2 +- components/nifosg/nifloader.cpp | 3 +- components/resource/scenemanager.cpp | 8 +- components/sceneutil/depth.cpp | 63 +++++++++++ components/sceneutil/depth.hpp | 117 +++++++++++++++++++++ components/sceneutil/mwshadowtechnique.cpp | 9 +- components/sceneutil/optimizer.cpp | 6 +- components/sceneutil/rtt.cpp | 2 + components/sceneutil/util.cpp | 98 ----------------- components/sceneutil/util.hpp | 26 ----- components/sceneutil/waterutil.cpp | 4 +- components/shader/shadervisitor.cpp | 4 +- components/terrain/material.cpp | 6 +- 27 files changed, 262 insertions(+), 232 deletions(-) create mode 100644 components/sceneutil/depth.cpp create mode 100644 components/sceneutil/depth.hpp diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 70d5a26c7a..0d97ebee4e 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -42,6 +42,7 @@ #include #include +#include #include "mwinput/inputmanagerimp.hpp" @@ -761,6 +762,22 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings) osg::ref_ptr exts = osg::GLExtensions::Get(0, false); bool shadersSupported = exts && (exts->glslLanguageVersion >= 1.2f); + bool enableReverseZ = false; + + if (Settings::Manager::getBool("reverse z", "Camera")) + { + if (exts && exts->isClipControlSupported) + { + enableReverseZ = true; + Log(Debug::Info) << "Using reverse-z depth buffer"; + } + else + Log(Debug::Warning) << "GL_ARB_clip_control not supported: disabling reverse-z depth buffer"; + } + else + Log(Debug::Info) << "Using standard depth buffer"; + + SceneUtil::AutoDepth::setReversed(enableReverseZ); #if OSG_VERSION_LESS_THAN(3, 6, 6) // hack fix for https://github.com/openscenegraph/OpenSceneGraph/issues/1028 diff --git a/apps/openmw/mwgui/bookpage.cpp b/apps/openmw/mwgui/bookpage.cpp index 874d1d866b..b2d2c39fd6 100644 --- a/apps/openmw/mwgui/bookpage.cpp +++ b/apps/openmw/mwgui/bookpage.cpp @@ -8,7 +8,7 @@ #include "MyGUI_FactoryManager.h" #include -#include +#include #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" @@ -1221,7 +1221,7 @@ public: RenderXform renderXform (mCroppedParent, textFormat.mRenderItem->getRenderTarget()->getInfo()); - float z = SceneUtil::getReverseZ() ? 1.f : -1.f; + float z = SceneUtil::AutoDepth::isReversed() ? 1.f : -1.f; GlyphStream glyphStream(textFormat.mFont, static_cast(mCoord.left), static_cast(mCoord.top - mViewTop), z /*mNode->getNodeDepth()*/, vertices, renderXform); diff --git a/apps/openmw/mwrender/bulletdebugdraw.cpp b/apps/openmw/mwrender/bulletdebugdraw.cpp index 9155132871..b169251465 100644 --- a/apps/openmw/mwrender/bulletdebugdraw.cpp +++ b/apps/openmw/mwrender/bulletdebugdraw.cpp @@ -8,7 +8,7 @@ #include #include -#include +#include #include #include #include @@ -66,7 +66,7 @@ void DebugDrawer::createGeometry() auto* stateSet = new osg::StateSet; stateSet->setAttributeAndModes(new osg::PolygonMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::LINE), osg::StateAttribute::ON); - stateSet->setAttributeAndModes(new osg::PolygonOffset(SceneUtil::getReverseZ() ? 1.0 : -1.0, SceneUtil::getReverseZ() ? 1.0 : -1.0)); + stateSet->setAttributeAndModes(new osg::PolygonOffset(SceneUtil::AutoDepth::isReversed() ? 1.0 : -1.0, SceneUtil::AutoDepth::isReversed() ? 1.0 : -1.0)); osg::ref_ptr material = new osg::Material; material->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE); stateSet->setAttribute(material); diff --git a/apps/openmw/mwrender/characterpreview.cpp b/apps/openmw/mwrender/characterpreview.cpp index c717806e35..7cca787580 100644 --- a/apps/openmw/mwrender/characterpreview.cpp +++ b/apps/openmw/mwrender/characterpreview.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include "../mwbase/world.hpp" #include "../mwworld/class.hpp" @@ -132,43 +133,6 @@ namespace MWRender newStateSet->setTextureMode(7, GL_TEXTURE_2D, osg::StateAttribute::OFF); newStateSet->setDefine("FORCE_OPAQUE", "0", osg::StateAttribute::ON); } - if (SceneUtil::getReverseZ() && stateset->getAttribute(osg::StateAttribute::DEPTH)) - { - bool depthModified = false; - osg::Depth* depth = static_cast(stateset->getAttribute(osg::StateAttribute::DEPTH)); - depth->getUserValue("depthModified", depthModified); - - if (!depthModified) - { - if (!newStateSet) - { - newStateSet = new osg::StateSet(*stateset, osg::CopyOp::SHALLOW_COPY); - node.setStateSet(newStateSet); - } - // Setup standard depth ranges - osg::ref_ptr newDepth = new osg::Depth(*depth); - - switch (newDepth->getFunction()) - { - case osg::Depth::LESS: - newDepth->setFunction(osg::Depth::GREATER); - break; - case osg::Depth::LEQUAL: - newDepth->setFunction(osg::Depth::GEQUAL); - break; - case osg::Depth::GREATER: - newDepth->setFunction(osg::Depth::LESS); - break; - case osg::Depth::GEQUAL: - newDepth->setFunction(osg::Depth::LEQUAL); - break; - default: - break; - } - newStateSet->setAttribute(newDepth, osg::StateAttribute::ON); - newDepth->setUserValue("depthModified", true); - } - } } traverse(node); } @@ -200,8 +164,6 @@ namespace MWRender mCamera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT, osg::Camera::PIXEL_BUFFER_RTT); mCamera->setClearColor(osg::Vec4(0.f, 0.f, 0.f, 0.f)); mCamera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - const float fovYDegrees = 12.3f; - mCamera->setProjectionMatrixAsPerspective(fovYDegrees, sizeX/static_cast(sizeY), 0.1f, 10000.f); // zNear and zFar are autocomputed mCamera->setViewport(0, 0, sizeX, sizeY); mCamera->setRenderOrder(osg::Camera::PRE_RENDER); mCamera->attach(osg::Camera::COLOR_BUFFER, mTexture, 0, 0, false, Settings::Manager::getInt("antialiasing", "Video")); @@ -211,6 +173,8 @@ namespace MWRender mCamera->setNodeMask(Mask_RenderToTexture); + SceneUtil::setCameraClearDepth(mCamera); + bool ffp = mResourceSystem->getSceneManager()->getLightingMethod() == SceneUtil::LightingMethod::FFP; osg::ref_ptr lightManager = new SceneUtil::LightManager(ffp); @@ -226,9 +190,14 @@ namespace MWRender defaultMat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,1)); defaultMat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 0.f)); stateset->setAttribute(defaultMat); - stateset->addUniform(new osg::Uniform("projectionMatrix", static_cast(mCamera->getProjectionMatrix()))); - stateset->setAttributeAndModes(new osg::Depth, osg::StateAttribute::ON); + const float fovYDegrees = 12.3f; + const float aspectRatio = static_cast(sizeX) / static_cast(sizeY); + const float znear = 0.1f; + const float zfar = 10000.f; + mCamera->setProjectionMatrixAsPerspective(fovYDegrees, aspectRatio, znear, zfar); + osg::Matrixf projectionMatrix = SceneUtil::AutoDepth::isReversed() ? static_cast(SceneUtil::getReversedZProjectionMatrixAsPerspective(fovYDegrees, aspectRatio, znear, zfar)) : static_cast(mCamera->getProjectionMatrix()); + stateset->addUniform(new osg::Uniform("projectionMatrix", projectionMatrix)); SceneUtil::ShadowManager::disableShadowsForStateSet(stateset); diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index b248efad4e..ba8749d81c 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -4,7 +4,6 @@ #include #include #include -#include #include #include @@ -15,8 +14,8 @@ #include #include -#include #include +#include #include @@ -326,8 +325,8 @@ namespace MWRender if (texture) { osg::ref_ptr geom = createTexturedQuad(srcLeft, srcTop, srcRight, srcBottom); - auto depth = SceneUtil::createDepth(); - depth->setWriteMask(0); + osg::ref_ptr depth = new SceneUtil::AutoDepth; + depth->setWriteMask(false); osg::StateSet* stateset = geom->getOrCreateStateSet(); stateset->setAttribute(depth); stateset->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 66c8c55c60..d9982d35c3 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include #include @@ -178,7 +178,7 @@ osg::ref_ptr LocalMap::createOrthographicCamera(float x, float y, f { osg::ref_ptr camera (new osg::Camera); - if (SceneUtil::getReverseZ()) + if (SceneUtil::AutoDepth::isReversed()) camera->setProjectionMatrix(SceneUtil::getReversedZProjectionMatrixAsOrtho(-width/2, width/2, -height/2, height/2, 5, (zmax-zmin) + 10)); else camera->setProjectionMatrixAsOrtho(-width/2, width/2, -height/2, height/2, 5, (zmax-zmin) + 10); @@ -198,14 +198,10 @@ osg::ref_ptr LocalMap::createOrthographicCamera(float x, float y, f osg::Camera::CullingMode cullingMode = (osg::Camera::DEFAULT_CULLING|osg::Camera::FAR_PLANE_CULLING) & ~(osg::Camera::SMALL_FEATURE_CULLING); camera->setCullingMode(cullingMode); - osg::ref_ptr stateset = new osg::StateSet; - stateset->setAttribute(new osg::PolygonMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::FILL), osg::StateAttribute::OVERRIDE); - - if (SceneUtil::getReverseZ()) - stateset->setAttributeAndModes(SceneUtil::createDepth(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); - SceneUtil::setCameraClearDepth(camera); + osg::ref_ptr stateset = new osg::StateSet; + stateset->setAttribute(new osg::PolygonMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::FILL), osg::StateAttribute::OVERRIDE); stateset->addUniform(new osg::Uniform("projectionMatrix", static_cast(camera->getProjectionMatrix())), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); // assign large value to effectively turn off fog diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 7031b5a02b..da361aec25 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include @@ -310,7 +311,7 @@ class DepthClearCallback : public osgUtil::RenderBin::DrawCallback public: DepthClearCallback() { - mDepth = SceneUtil::createDepth(); + mDepth = new SceneUtil::AutoDepth; mDepth->setWriteMask(true); mStateSet = new osg::StateSet; diff --git a/apps/openmw/mwrender/postprocessor.cpp b/apps/openmw/mwrender/postprocessor.cpp index 7405098a03..b08cfe1f71 100644 --- a/apps/openmw/mwrender/postprocessor.cpp +++ b/apps/openmw/mwrender/postprocessor.cpp @@ -9,7 +9,7 @@ #include #include -#include +#include #include #include @@ -140,7 +140,7 @@ namespace MWRender { bool softParticles = Settings::Manager::getBool("soft particles", "Shaders"); - if (!SceneUtil::getReverseZ() && !softParticles) + if (!SceneUtil::AutoDepth::isReversed() && !softParticles) return; osg::GraphicsContext* gc = viewer->getCamera()->getGraphicsContext(); @@ -161,7 +161,7 @@ namespace MWRender return; } - if (SceneUtil::getReverseZ()) + if (SceneUtil::AutoDepth::isReversed()) { if (osg::isGLExtensionSupported(contextID, "GL_ARB_depth_buffer_float")) mDepthFormat = GL_DEPTH_COMPONENT32F; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index b3b0d880c5..30be74c839 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -32,7 +32,7 @@ #include -#include +#include #include #include #include @@ -310,13 +310,7 @@ namespace MWRender , mFieldOfView(std::clamp(Settings::Manager::getFloat("field of view", "Camera"), 1.f, 179.f)) , mFirstPersonFieldOfView(std::clamp(Settings::Manager::getFloat("first person field of view", "Camera"), 1.f, 179.f)) { - bool reverseZ = SceneUtil::getReverseZ(); - - if (reverseZ) - Log(Debug::Info) << "Using reverse-z depth buffer"; - else - Log(Debug::Info) << "Using standard depth buffer"; - + bool reverseZ = SceneUtil::AutoDepth::isReversed(); auto lightingMethod = SceneUtil::LightManager::getLightingMethodFromString(Settings::Manager::getString("lighting method", "Shaders")); resourceSystem->getSceneManager()->setParticleSystemMask(MWRender::Mask_ParticleSystem); @@ -538,7 +532,7 @@ namespace MWRender if (reverseZ) { osg::ref_ptr clipcontrol = new osg::ClipControl(osg::ClipControl::LOWER_LEFT, osg::ClipControl::ZERO_TO_ONE); - mRootNode->getOrCreateStateSet()->setAttributeAndModes(SceneUtil::createDepth(), osg::StateAttribute::ON); + mRootNode->getOrCreateStateSet()->setAttributeAndModes(new SceneUtil::AutoDepth, osg::StateAttribute::ON); mRootNode->getOrCreateStateSet()->setAttributeAndModes(clipcontrol, osg::StateAttribute::ON); } @@ -1150,7 +1144,7 @@ namespace MWRender mViewer->getCamera()->setProjectionMatrixAsPerspective(fov, aspect, mNearClip, mViewDistance); - if (SceneUtil::getReverseZ()) + if (SceneUtil::AutoDepth::isReversed()) { mSharedUniformStateUpdater->setLinearFac(-mNearClip / (mViewDistance - mNearClip) - 1.f); mSharedUniformStateUpdater->setProjectionMatrix(SceneUtil::getReversedZProjectionMatrixAsPerspective(fov, aspect, mNearClip, mViewDistance)); diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp index fdfc3db63d..282362ea56 100644 --- a/apps/openmw/mwrender/ripplesimulation.cpp +++ b/apps/openmw/mwrender/ripplesimulation.cpp @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include "vismask.hpp" @@ -56,13 +56,13 @@ namespace stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); stateset->setTextureAttributeAndModes(0, textures[0], osg::StateAttribute::ON); - auto depth = SceneUtil::createDepth(); + osg::ref_ptr depth = new SceneUtil::AutoDepth; depth->setWriteMask(false); stateset->setAttributeAndModes(depth, osg::StateAttribute::ON); osg::ref_ptr polygonOffset (new osg::PolygonOffset); - polygonOffset->setUnits(SceneUtil::getReverseZ() ? 1 : -1); - polygonOffset->setFactor(SceneUtil::getReverseZ() ? 1 : -1); + polygonOffset->setUnits(SceneUtil::AutoDepth::isReversed() ? 1 : -1); + polygonOffset->setFactor(SceneUtil::AutoDepth::isReversed() ? 1 : -1); stateset->setAttributeAndModes(polygonOffset, osg::StateAttribute::ON); stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); diff --git a/apps/openmw/mwrender/screenshotmanager.cpp b/apps/openmw/mwrender/screenshotmanager.cpp index ab7d0d93f0..1973ca4025 100644 --- a/apps/openmw/mwrender/screenshotmanager.cpp +++ b/apps/openmw/mwrender/screenshotmanager.cpp @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include @@ -331,7 +331,7 @@ namespace MWRender float nearClip = Settings::Manager::getFloat("near clip", "Camera"); float viewDistance = Settings::Manager::getFloat("viewing distance", "Camera"); // each cubemap side sees 90 degrees - if (SceneUtil::getReverseZ()) + if (SceneUtil::AutoDepth::isReversed()) rttCamera->setProjectionMatrix(SceneUtil::getReversedZProjectionMatrixAsPerspectiveInf(90.0, w/float(h), nearClip)); else rttCamera->setProjectionMatrixAsPerspective(90.0, w/float(h), nearClip, viewDistance); diff --git a/apps/openmw/mwrender/sky.cpp b/apps/openmw/mwrender/sky.cpp index b6b0a3669b..fcb7447cf3 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include @@ -338,7 +338,7 @@ namespace MWRender mEarlyRenderBinRoot->getOrCreateStateSet()->setAttributeAndModes(program, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); } - auto depth = SceneUtil::createDepth(); + osg::ref_ptr depth = new SceneUtil::AutoDepth; depth->setWriteMask(false); mEarlyRenderBinRoot->getOrCreateStateSet()->setAttributeAndModes(depth); mEarlyRenderBinRoot->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON); diff --git a/apps/openmw/mwrender/skyutil.cpp b/apps/openmw/mwrender/skyutil.cpp index 0e2955333f..b98e489738 100644 --- a/apps/openmw/mwrender/skyutil.cpp +++ b/apps/openmw/mwrender/skyutil.cpp @@ -25,7 +25,7 @@ #include #include -#include +#include #include @@ -811,11 +811,11 @@ namespace MWRender osg::StateSet* queryStateSet = new osg::StateSet; if (queryVisible) { - auto depth = SceneUtil::createDepth(); + osg::ref_ptr depth = new SceneUtil::AutoDepth; // This is a trick to make fragments written by the query always use the maximum depth value, // without having to retrieve the current far clipping distance. // We want the sun glare to be "infinitely" far away. - double far = SceneUtil::getReverseZ() ? 0.0 : 1.0; + double far = SceneUtil::AutoDepth::isReversed() ? 0.0 : 1.0; depth->setZNear(far); depth->setZFar(far); depth->setWriteMask(false); diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index ca42423efe..fd5cbe0f79 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -27,7 +27,7 @@ #include #include -#include +#include #include #include @@ -268,7 +268,6 @@ public: void setDefaults(osg::Camera* camera) override { - SceneUtil::setCameraClearDepth(camera); camera->setReferenceFrame(osg::Camera::RELATIVE_RF); camera->setSmallFeatureCullingPixelSize(Settings::Manager::getInt("small feature culling pixel size", "Water")); camera->setName("RefractionCamera"); @@ -344,7 +343,6 @@ public: void setDefaults(osg::Camera* camera) override { - SceneUtil::setCameraClearDepth(camera); camera->setReferenceFrame(osg::Camera::RELATIVE_RF); camera->setSmallFeatureCullingPixelSize(Settings::Manager::getInt("small feature culling pixel size", "Water")); camera->setName("ReflectionCamera"); @@ -645,7 +643,7 @@ public: { stateset->setMode(GL_BLEND, osg::StateAttribute::ON); stateset->setRenderBinDetails(MWRender::RenderBin_Water, "RenderBin"); - osg::ref_ptr depth = SceneUtil::createDepth(); + osg::ref_ptr depth = new SceneUtil::AutoDepth; depth->setWriteMask(false); stateset->setAttributeAndModes(depth, osg::StateAttribute::ON); } diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 7d62824f4d..56371a8c02 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -57,7 +57,7 @@ add_component_dir (sceneutil clone attach visitor util statesetupdater controller skeleton riggeometry morphgeometry lightcontroller lightmanager lightutil positionattitudetransform workqueue pathgridutil waterutil writescene serialize optimizer actorutil detourdebugdraw navmesh agentpath shadow mwshadowtechnique recastmesh shadowsbin osgacontroller rtt - screencapture + screencapture depth ) add_component_dir (nif diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 90046ecff1..91d2300161 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -16,7 +16,6 @@ #include #include #include -#include #include // particle @@ -1838,7 +1837,7 @@ namespace NifOsg // Depth test flag stateset->setMode(GL_DEPTH_TEST, zprop->flags&1 ? osg::StateAttribute::ON : osg::StateAttribute::OFF); - auto depth = SceneUtil::createDepth(); + osg::ref_ptr depth = new osg::Depth; // Depth write flag depth->setWriteMask((zprop->flags>>1)&1); // Morrowind ignores depth test function diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index f39a5919b6..16d942ecec 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -252,14 +253,14 @@ namespace Resource { if (stateset->getRenderingHint() == osg::StateSet::TRANSPARENT_BIN) { - osg::ref_ptr depth = SceneUtil::createDepth(); + osg::ref_ptr depth = new osg::Depth; depth->setWriteMask(false); stateset->setAttributeAndModes(depth, osg::StateAttribute::ON); } else if (stateset->getRenderingHint() == osg::StateSet::OPAQUE_BIN) { - osg::ref_ptr depth = SceneUtil::createDepth(); + osg::ref_ptr depth = new osg::Depth; depth->setWriteMask(true); stateset->setAttributeAndModes(depth, osg::StateAttribute::ON); @@ -692,6 +693,9 @@ namespace Resource SetFilterSettingsControllerVisitor setFilterSettingsControllerVisitor(mMinFilter, mMagFilter, mMaxAnisotropy); loaded->accept(setFilterSettingsControllerVisitor); + SceneUtil::ReplaceDepthVisitor replaceDepthVisitor; + loaded->accept(replaceDepthVisitor); + osg::ref_ptr shaderVisitor (createShaderVisitor()); loaded->accept(*shaderVisitor); diff --git a/components/sceneutil/depth.cpp b/components/sceneutil/depth.cpp new file mode 100644 index 0000000000..5d53b97726 --- /dev/null +++ b/components/sceneutil/depth.cpp @@ -0,0 +1,63 @@ +#include "depth.hpp" + +#include + +#include + +#include + +#ifndef GL_DEPTH32F_STENCIL8_NV +#define GL_DEPTH32F_STENCIL8_NV 0x8DAC +#endif + +namespace SceneUtil +{ + void setCameraClearDepth(osg::Camera* camera) + { + camera->setClearDepth(AutoDepth::isReversed() ? 0.0 : 1.0); + } + + osg::Matrix getReversedZProjectionMatrixAsPerspectiveInf(double fov, double aspect, double near) + { + double A = 1.0/std::tan(osg::DegreesToRadians(fov)/2.0); + return osg::Matrix( + A/aspect, 0, 0, 0, + 0, A, 0, 0, + 0, 0, 0, -1, + 0, 0, near, 0 + ); + } + + osg::Matrix getReversedZProjectionMatrixAsPerspective(double fov, double aspect, double near, double far) + { + double A = 1.0/std::tan(osg::DegreesToRadians(fov)/2.0); + return osg::Matrix( + A/aspect, 0, 0, 0, + 0, A, 0, 0, + 0, 0, near/(far-near), -1, + 0, 0, (far*near)/(far - near), 0 + ); + } + + osg::Matrix getReversedZProjectionMatrixAsOrtho(double left, double right, double bottom, double top, double near, double far) + { + return osg::Matrix( + 2/(right-left), 0, 0, 0, + 0, 2/(top-bottom), 0, 0, + 0, 0, 1/(far-near), 0, + (right+left)/(left-right), (top+bottom)/(bottom-top), far/(far-near), 1 + ); + } + + bool isFloatingPointDepthFormat(GLenum format) + { + constexpr std::array formats = { + GL_DEPTH_COMPONENT32F, + GL_DEPTH_COMPONENT32F_NV, + GL_DEPTH32F_STENCIL8, + GL_DEPTH32F_STENCIL8_NV, + }; + + return std::find(formats.cbegin(), formats.cend(), format) != formats.cend(); + } +} \ No newline at end of file diff --git a/components/sceneutil/depth.hpp b/components/sceneutil/depth.hpp new file mode 100644 index 0000000000..11a863ef7a --- /dev/null +++ b/components/sceneutil/depth.hpp @@ -0,0 +1,117 @@ +#ifndef OPENMW_COMPONENTS_SCENEUTIL_DEPTH_H +#define OPENMW_COMPONENTS_SCENEUTIL_DEPTH_H + +#include + +#include "util.hpp" + +namespace SceneUtil +{ + // Sets camera clear depth to 0 if reversed depth buffer is in use, 1 otherwise. + void setCameraClearDepth(osg::Camera* camera); + + // Returns a perspective projection matrix for use with a reversed z-buffer + // and an infinite far plane. This is derived by mapping the default z-range + // of [0,1] to [1,0], then taking the limit as far plane approaches infinity. + osg::Matrix getReversedZProjectionMatrixAsPerspectiveInf(double fov, double aspect, double near); + + // Returns a perspective projection matrix for use with a reversed z-buffer. + osg::Matrix getReversedZProjectionMatrixAsPerspective(double fov, double aspect, double near, double far); + + // Returns an orthographic projection matrix for use with a reversed z-buffer. + osg::Matrix getReversedZProjectionMatrixAsOrtho(double left, double right, double bottom, double top, double near, double far); + + // Returns true if the GL format is a floating point depth format. + bool isFloatingPointDepthFormat(GLenum format); + + // Brief wrapper around an osg::Depth that applies the reversed depth function when a reversed depth buffer is in use + class AutoDepth : public osg::Depth + { + public: + AutoDepth(osg::Depth::Function func=osg::Depth::LESS, double zNear=0.0, double zFar=1.0, bool writeMask=true) + { + setFunction(func); + setZNear(zNear); + setZFar(zFar); + setWriteMask(writeMask); + } + + AutoDepth(const osg::Depth& copy, const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY) : osg::Depth(copy, copyop) {} + + osg::Object* cloneType() const override { return new AutoDepth; } + osg::Object* clone(const osg::CopyOp& copyop) const override { return new AutoDepth(*this,copyop); } + + void apply(osg::State& state) const override + { + glDepthFunc(static_cast(AutoDepth::isReversed() ? getReversedDepthFunction() : getFunction())); + glDepthMask(static_cast(getWriteMask())); + #if defined(OSG_GLES1_AVAILABLE) || defined(OSG_GLES2_AVAILABLE) || defined(OSG_GLES3_AVAILABLE) + glDepthRangef(getZNear(),getZFar()); + #else + glDepthRange(getZNear(),getZFar()); + #endif + } + + static void setReversed(bool reverseZ) + { + static bool init = false; + + if (!init) + { + AutoDepth::sReversed = reverseZ; + init = true; + } + } + + static bool isReversed() + { + return AutoDepth::sReversed; + } + + private: + + static inline bool sReversed = false; + + osg::Depth::Function getReversedDepthFunction() const + { + const osg::Depth::Function func = getFunction(); + + switch (func) + { + case osg::Depth::LESS: + return osg::Depth::GREATER; + case osg::Depth::LEQUAL: + return osg::Depth::GEQUAL; + case osg::Depth::GREATER: + return osg::Depth::LESS; + case osg::Depth::GEQUAL: + return osg::Depth::LEQUAL; + default: + return func; + } + } + + }; + + // Replaces all nodes osg::Depth state attributes with SceneUtil::AutoDepth. + class ReplaceDepthVisitor : public osg::NodeVisitor + { + public: + ReplaceDepthVisitor() : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) {} + + void apply(osg::Node& node) override + { + osg::StateSet* stateSet = node.getStateSet(); + + if (stateSet) + { + if (osg::Depth* depth = static_cast(stateSet->getAttribute(osg::StateAttribute::DEPTH))) + stateSet->setAttribute(new SceneUtil::AutoDepth(*depth)); + }; + + traverse(node); + } + }; +} + +#endif diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 770917eda7..daf6bb80ab 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -27,8 +27,6 @@ #include -#include - #include "shadowsbin.hpp" namespace { @@ -1652,11 +1650,8 @@ void MWShadowTechnique::createShaders() _shadowCastingStateSet->addUniform(new osg::Uniform("alphaTestShadows", false)); osg::ref_ptr depth = new osg::Depth; depth->setWriteMask(true); - if (SceneUtil::getReverseZ()) - { - osg::ref_ptr clipcontrol = new osg::ClipControl(osg::ClipControl::LOWER_LEFT, osg::ClipControl::NEGATIVE_ONE_TO_ONE); - _shadowCastingStateSet->setAttribute(clipcontrol, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); - } + osg::ref_ptr clipcontrol = new osg::ClipControl(osg::ClipControl::LOWER_LEFT, osg::ClipControl::NEGATIVE_ONE_TO_ONE); + _shadowCastingStateSet->setAttribute(clipcontrol, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); _shadowCastingStateSet->setAttribute(depth, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); _shadowCastingStateSet->setMode(GL_DEPTH_CLAMP, osg::StateAttribute::ON); diff --git a/components/sceneutil/optimizer.cpp b/components/sceneutil/optimizer.cpp index e2fcaedbd7..748ceee952 100644 --- a/components/sceneutil/optimizer.cpp +++ b/components/sceneutil/optimizer.cpp @@ -42,7 +42,7 @@ #include -#include +#include using namespace osgUtil; @@ -1597,8 +1597,8 @@ bool Optimizer::MergeGeometryVisitor::mergeGroup(osg::Group& group) } if (_alphaBlendingActive && _mergeAlphaBlending && !geom->getStateSet()) { - auto d = createDepth(); - d->setWriteMask(0); + osg::ref_ptr d = new SceneUtil::AutoDepth; + d->setWriteMask(false); geom->getOrCreateStateSet()->setAttribute(d); } } diff --git a/components/sceneutil/rtt.cpp b/components/sceneutil/rtt.cpp index 3b60c80afd..0765a2e835 100644 --- a/components/sceneutil/rtt.cpp +++ b/components/sceneutil/rtt.cpp @@ -8,6 +8,7 @@ #include #include +#include namespace SceneUtil { @@ -69,6 +70,7 @@ namespace SceneUtil camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); camera->setViewport(0, 0, mTextureWidth, mTextureHeight); + SceneUtil::setCameraClearDepth(camera); setDefaults(mViewDependentDataMap[cv]->mCamera.get()); diff --git a/components/sceneutil/util.cpp b/components/sceneutil/util.cpp index 5b6e0a3ee0..7065fae933 100644 --- a/components/sceneutil/util.cpp +++ b/components/sceneutil/util.cpp @@ -4,8 +4,6 @@ #include #include -#include - #include #include #include @@ -16,27 +14,8 @@ #include #include -#include -#include #include -#ifndef GL_DEPTH32F_STENCIL8_NV -#define GL_DEPTH32F_STENCIL8_NV 0x8DAC -#endif - -namespace -{ - -bool isReverseZSupported() -{ - if (!Settings::Manager::mDefaultSettings.count({"Camera", "reverse z"})) - return false; - auto ext = osg::GLExtensions::Get(0, false); - return Settings::Manager::getBool("reverse z", "Camera") && ext && ext->isClipControlSupported; -} - -} - namespace SceneUtil { @@ -338,81 +317,4 @@ bool attachAlphaToCoverageFriendlyFramebufferToCamera(osg::Camera* camera, osg:: return addMSAAIntermediateTarget; } -void attachAlphaToCoverageFriendlyDepthColor(osg::Camera* camera, osg::Texture2D* colorTex, osg::Texture2D* depthTex, GLenum depthFormat) -{ - bool addMSAAIntermediateTarget = Settings::Manager::getBool("antialias alpha test", "Shaders") && Settings::Manager::getInt("antialiasing", "Video") > 1; - - if (isFloatingPointDepthFormat(depthFormat) && addMSAAIntermediateTarget) - { - camera->attach(osg::Camera::COLOR_BUFFER0, colorTex); - camera->attach(osg::Camera::DEPTH_BUFFER, depthTex); - camera->addCullCallback(new AttachMultisampledDepthColorCallback(colorTex, depthTex, 2, 1)); - } - else - { - attachAlphaToCoverageFriendlyFramebufferToCamera(camera, osg::Camera::COLOR_BUFFER, colorTex); - camera->attach(osg::Camera::DEPTH_BUFFER, depthTex); - } -} - -bool getReverseZ() -{ - static bool reverseZ = isReverseZSupported(); - return reverseZ; -} - -void setCameraClearDepth(osg::Camera* camera) -{ - camera->setClearDepth(getReverseZ() ? 0.0 : 1.0); -} - -osg::ref_ptr createDepth() -{ - return new osg::Depth(getReverseZ() ? osg::Depth::GEQUAL : osg::Depth::LEQUAL); -} - -osg::Matrix getReversedZProjectionMatrixAsPerspectiveInf(double fov, double aspect, double near) -{ - double A = 1.0/std::tan(osg::DegreesToRadians(fov)/2.0); - return osg::Matrix( - A/aspect, 0, 0, 0, - 0, A, 0, 0, - 0, 0, 0, -1, - 0, 0, near, 0 - ); -} - -osg::Matrix getReversedZProjectionMatrixAsPerspective(double fov, double aspect, double near, double far) -{ - double A = 1.0/std::tan(osg::DegreesToRadians(fov)/2.0); - return osg::Matrix( - A/aspect, 0, 0, 0, - 0, A, 0, 0, - 0, 0, near/(far-near), -1, - 0, 0, (far*near)/(far - near), 0 - ); -} - -osg::Matrix getReversedZProjectionMatrixAsOrtho(double left, double right, double bottom, double top, double near, double far) -{ - return osg::Matrix( - 2/(right-left), 0, 0, 0, - 0, 2/(top-bottom), 0, 0, - 0, 0, 1/(far-near), 0, - (right+left)/(left-right), (top+bottom)/(bottom-top), far/(far-near), 1 - ); -} - -bool isFloatingPointDepthFormat(GLenum format) -{ - constexpr std::array formats = { - GL_DEPTH_COMPONENT32F, - GL_DEPTH_COMPONENT32F_NV, - GL_DEPTH32F_STENCIL8, - GL_DEPTH32F_STENCIL8_NV, - }; - - return std::find(formats.cbegin(), formats.cend(), format) != formats.cend(); -} - } diff --git a/components/sceneutil/util.hpp b/components/sceneutil/util.hpp index 4d19714d66..ddc2db845d 100644 --- a/components/sceneutil/util.hpp +++ b/components/sceneutil/util.hpp @@ -6,7 +6,6 @@ #include #include #include -#include #include @@ -64,31 +63,6 @@ namespace SceneUtil // Alpha-to-coverage requires a multisampled framebuffer, so we need to set that up for RTTs bool attachAlphaToCoverageFriendlyFramebufferToCamera(osg::Camera* camera, osg::Camera::BufferComponent buffer, osg::Texture* texture, unsigned int level = 0, unsigned int face = 0, bool mipMapGeneration = false); - - void attachAlphaToCoverageFriendlyDepthColor(osg::Camera* camera, osg::Texture2D* colorTex, osg::Texture2D* depthTex, GLenum depthFormat); - - bool getReverseZ(); - - void setCameraClearDepth(osg::Camera* camera); - - // Returns a suitable depth state attribute dependent on whether a reverse-z - // depth buffer is in use. - osg::ref_ptr createDepth(); - - // Returns a perspective projection matrix for use with a reversed z-buffer - // and an infinite far plane. This is derived by mapping the default z-range - // of [0,1] to [1,0], then taking the limit as far plane approaches - // infinity. - osg::Matrix getReversedZProjectionMatrixAsPerspectiveInf(double fov, double aspect, double near); - - // Returns a perspective projection matrix for use with a reversed z-buffer. - osg::Matrix getReversedZProjectionMatrixAsPerspective(double fov, double aspect, double near, double far); - - // Returns an orthographic projection matrix for use with a reversed z-buffer. - osg::Matrix getReversedZProjectionMatrixAsOrtho(double left, double right, double bottom, double top, double near, double far); - - // Returns true if the GL format is a floating point depth format - bool isFloatingPointDepthFormat(GLenum format); } #endif diff --git a/components/sceneutil/waterutil.cpp b/components/sceneutil/waterutil.cpp index ac171005ae..e22070f40f 100644 --- a/components/sceneutil/waterutil.cpp +++ b/components/sceneutil/waterutil.cpp @@ -5,7 +5,7 @@ #include #include -#include "util.hpp" +#include "depth.hpp" namespace SceneUtil { @@ -78,7 +78,7 @@ namespace SceneUtil stateset->setMode(GL_BLEND, osg::StateAttribute::ON); stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); - auto depth = createDepth(); + osg::ref_ptr depth = new SceneUtil::AutoDepth; depth->setWriteMask(false); stateset->setAttributeAndModes(depth, osg::StateAttribute::ON); diff --git a/components/shader/shadervisitor.cpp b/components/shader/shadervisitor.cpp index 1e9acdb35f..95e0a75f18 100644 --- a/components/shader/shadervisitor.cpp +++ b/components/shader/shadervisitor.cpp @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include "removedalphafunc.hpp" #include "shadermanager.hpp" @@ -567,7 +567,7 @@ namespace Shader { softParticles = true; - auto depth = SceneUtil::createDepth(); + auto depth = new SceneUtil::AutoDepth; depth->setWriteMask(false); writableStateSet->setAttributeAndModes(depth, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); writableStateSet->addUniform(new osg::Uniform("particleSize", partsys->getDefaultParticleTemplate().getSizeRange().maximum)); diff --git a/components/terrain/material.cpp b/components/terrain/material.cpp index 22f507b3a2..ae432d262e 100644 --- a/components/terrain/material.cpp +++ b/components/terrain/material.cpp @@ -8,7 +8,7 @@ #include #include -#include +#include #include @@ -87,7 +87,7 @@ namespace osg::ref_ptr mValue; EqualDepth() - : mValue(new osg::Depth) + : mValue(new SceneUtil::AutoDepth) { mValue->setFunction(osg::Depth::EQUAL); } @@ -106,7 +106,7 @@ namespace osg::ref_ptr mValue; LequalDepth() - : mValue(SceneUtil::createDepth()) + : mValue(new SceneUtil::AutoDepth) { } };