diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e136d707a..801d05d357 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,7 @@ Feature #6017: Separate persistent and temporary cell references when saving Feature #6032: Reverse-z depth buffer Feature #6162: Refactor GUI to use shaders and to be GLES and GL3+ friendly + Feature #6199: Support FBO Rendering 0.47.0 ------ diff --git a/apps/opencs/model/world/data.cpp b/apps/opencs/model/world/data.cpp index 192602290d..5e8c548368 100644 --- a/apps/opencs/model/world/data.cpp +++ b/apps/opencs/model/world/data.cpp @@ -84,6 +84,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, bool fsStrict, const Files::Pat defines["preLightEnv"] = "0"; // Apply environment maps after lighting like Morrowind defines["radialFog"] = "0"; defines["lightingModel"] = "0"; + defines["reverseZ"] = "0"; for (const auto& define : shadowDefines) defines[define.first] = define.second; mResourceSystem->getSceneManager()->getShaderManager().setGlobalDefines(defines); diff --git a/apps/opencs/view/render/cellwater.cpp b/apps/opencs/view/render/cellwater.cpp index 485eed00fe..f8857c3afc 100644 --- a/apps/opencs/view/render/cellwater.cpp +++ b/apps/opencs/view/render/cellwater.cpp @@ -161,7 +161,7 @@ namespace CSVRender } mWaterGeometry = SceneUtil::createWaterGeometry(size, segments, textureRepeats); - mWaterGeometry->setStateSet(SceneUtil::createSimpleWaterStateSet(Alpha, RenderBin, false)); + mWaterGeometry->setStateSet(SceneUtil::createSimpleWaterStateSet(Alpha, RenderBin)); // Add water texture std::string textureName = Fallback::Map::getString("Water_SurfaceTexture"); diff --git a/apps/openmw/mwgui/bookpage.cpp b/apps/openmw/mwgui/bookpage.cpp index e4ce2a9593..2f12b83572 100644 --- a/apps/openmw/mwgui/bookpage.cpp +++ b/apps/openmw/mwgui/bookpage.cpp @@ -8,12 +8,11 @@ #include "MyGUI_FactoryManager.h" #include +#include #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" -#include "../mwrender/util.hpp" - namespace MWGui { struct TypesetBookImpl; @@ -1219,7 +1218,7 @@ public: RenderXform renderXform (mCroppedParent, textFormat.mRenderItem->getRenderTarget()->getInfo()); - float z = MWRender::getReverseZ() ? 1.f : -1.f; + float z = SceneUtil::getReverseZ() ? 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/mwgui/savegamedialog.cpp b/apps/openmw/mwgui/savegamedialog.cpp index 987d27c9a6..086135d035 100644 --- a/apps/openmw/mwgui/savegamedialog.cpp +++ b/apps/openmw/mwgui/savegamedialog.cpp @@ -450,7 +450,7 @@ namespace MWGui osg::ref_ptr texture (new osg::Texture2D); texture->setImage(result.getImage()); - texture->setInternalFormat(GL_RGBA); + texture->setInternalFormat(GL_RGB); texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE); texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE); texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index e42d606966..6eeb2d3654 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -35,6 +35,7 @@ #include #include +#include #include diff --git a/apps/openmw/mwrender/bulletdebugdraw.cpp b/apps/openmw/mwrender/bulletdebugdraw.cpp index 9039ec53ce..b008ebc6d9 100644 --- a/apps/openmw/mwrender/bulletdebugdraw.cpp +++ b/apps/openmw/mwrender/bulletdebugdraw.cpp @@ -4,13 +4,13 @@ #include #include +#include #include #include #include #include #include -#include #include "bulletdebugdraw.hpp" #include "vismask.hpp" @@ -18,8 +18,6 @@ #include #include -#include - #include "../mwbase/world.hpp" #include "../mwbase/environment.hpp" @@ -39,6 +37,7 @@ void DebugDrawer::createGeometry() { mGeometry = new osg::Geometry; mGeometry->setNodeMask(Mask_Debug); + mVertices = new osg::Vec3Array; mColors = new osg::Vec4Array; @@ -50,8 +49,10 @@ void DebugDrawer::createGeometry() mGeometry->setColorBinding(osg::Geometry::BIND_PER_VERTEX); mGeometry->setDataVariance(osg::Object::DYNAMIC); mGeometry->addPrimitiveSet(mDrawArrays); - // make this friendly to recreateShaders() - mGeometry->setStateSet(new osg::StateSet); + + osg::ref_ptr material = new osg::Material; + material->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE); + mGeometry->getOrCreateStateSet()->setAttribute(material); mParentNode->addChild(mGeometry); diff --git a/apps/openmw/mwrender/globalmap.cpp b/apps/openmw/mwrender/globalmap.cpp index 2f160933fd..7d7c6e45df 100644 --- a/apps/openmw/mwrender/globalmap.cpp +++ b/apps/openmw/mwrender/globalmap.cpp @@ -325,7 +325,7 @@ namespace MWRender if (texture) { osg::ref_ptr geom = createTexturedQuad(srcLeft, srcTop, srcRight, srcBottom); - auto depth = SceneUtil::createDepth(getReverseZ()); + auto depth = SceneUtil::createDepth(); depth->setWriteMask(0); osg::StateSet* stateset = geom->getOrCreateStateSet(); stateset->setAttribute(depth); diff --git a/apps/openmw/mwrender/localmap.cpp b/apps/openmw/mwrender/localmap.cpp index 72f2828ace..02f59e0ed0 100644 --- a/apps/openmw/mwrender/localmap.cpp +++ b/apps/openmw/mwrender/localmap.cpp @@ -178,7 +178,7 @@ osg::ref_ptr LocalMap::createOrthographicCamera(float x, float y, f { osg::ref_ptr camera (new osg::Camera); - if (getReverseZ()) + if (SceneUtil::getReverseZ()) 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); @@ -201,12 +201,10 @@ osg::ref_ptr LocalMap::createOrthographicCamera(float x, float y, f osg::ref_ptr stateset = new osg::StateSet; stateset->setAttribute(new osg::PolygonMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::FILL), osg::StateAttribute::OVERRIDE); - if (getReverseZ()) - { - camera->setClearDepth(0.0); - auto depth = SceneUtil::createDepth(true); - stateset->setAttributeAndModes(depth, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); - } + if (SceneUtil::getReverseZ()) + stateset->setAttributeAndModes(SceneUtil::createDepth(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); + + SceneUtil::setCameraClearDepth(camera); stateset->addUniform(new osg::Uniform("projectionMatrix", static_cast(camera->getProjectionMatrix())), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE); diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 64dc9ecfe0..12ed88e55d 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -373,7 +373,7 @@ class DepthClearCallback : public osgUtil::RenderBin::DrawCallback public: DepthClearCallback() { - mDepth = SceneUtil::createDepth(getReverseZ()); + mDepth = SceneUtil::createDepth(); mDepth->setWriteMask(true); } diff --git a/apps/openmw/mwrender/objectpaging.cpp b/apps/openmw/mwrender/objectpaging.cpp index 709c67bc2d..aae8f2e4f1 100644 --- a/apps/openmw/mwrender/objectpaging.cpp +++ b/apps/openmw/mwrender/objectpaging.cpp @@ -661,7 +661,6 @@ namespace MWRender if (mergeGroup->getNumChildren()) { SceneUtil::Optimizer optimizer; - optimizer.setReverseZ(mSceneManager->getReverseZ()); if (size > 1/8.f) { optimizer.setViewPoint(relativeViewPoint); diff --git a/apps/openmw/mwrender/postprocessor.cpp b/apps/openmw/mwrender/postprocessor.cpp index a412ca8cfa..eff7d46892 100644 --- a/apps/openmw/mwrender/postprocessor.cpp +++ b/apps/openmw/mwrender/postprocessor.cpp @@ -36,10 +36,10 @@ namespace class CullCallback : public osg::NodeCallback { public: - CullCallback(MWRender::PostProcessor* postProcessor) - : mPostProcessor(postProcessor) - , mLastFrameNumber(0) - {} + CullCallback() + : mLastFrameNumber(0) + { + } void operator()(osg::Node* node, osg::NodeVisitor* nv) override { @@ -49,14 +49,24 @@ namespace if (frame != mLastFrameNumber) { mLastFrameNumber = frame; - if (!mPostProcessor->getMsaaFbo()) + + MWRender::PostProcessor* postProcessor = dynamic_cast(nv->asCullVisitor()->getCurrentCamera()->getUserData()); + + if (!postProcessor) { - renderStage->setFrameBufferObject(mPostProcessor->getFbo()); + Log(Debug::Error) << "Failed retrieving user data for master camera: FBO setup failed"; + traverse(node, nv); + return; + } + + if (!postProcessor->getMsaaFbo()) + { + renderStage->setFrameBufferObject(postProcessor->getFbo()); } else { - renderStage->setMultisampleResolveFramebufferObject(mPostProcessor->getFbo()); - renderStage->setFrameBufferObject(mPostProcessor->getMsaaFbo()); + renderStage->setMultisampleResolveFramebufferObject(postProcessor->getFbo()); + renderStage->setFrameBufferObject(postProcessor->getMsaaFbo()); } } @@ -64,7 +74,6 @@ namespace } private: - MWRender::PostProcessor* mPostProcessor; unsigned int mLastFrameNumber; }; @@ -117,7 +126,7 @@ namespace MWRender else { // TODO: Once we have post-processing implemented we want to skip this return and continue with setup. - // Rendering to a FBO to fullscreen geometry has overhead (especially when MSAA is enabled) and there are no + // Rendering to a FBO to fullscreen geometry has overhead (especially when MSAA is enabled) and there are no // benefits if no floating point depth formats are supported. mDepthFormat = GL_DEPTH_COMPONENT24; Log(Debug::Warning) << errPreamble << "'GL_ARB_depth_buffer_float' and 'GL_NV_depth_buffer_float' unsupported."; @@ -136,12 +145,13 @@ namespace MWRender // We need to manually set the FBO and resolve FBO during the cull callback. If we were using a separate // RTT camera this would not be needed. - mViewer->getCamera()->addCullCallback(new CullCallback(this)); + mViewer->getCamera()->addCullCallback(new CullCallback); mViewer->getCamera()->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT); mViewer->getCamera()->attach(osg::Camera::COLOR_BUFFER0, mSceneTex); mViewer->getCamera()->attach(osg::Camera::DEPTH_BUFFER, mDepthTex); mViewer->getCamera()->getGraphicsContext()->setResizedCallback(new ResizedCallback(this)); + mViewer->getCamera()->setUserData(this); } void PostProcessor::resize(int width, int height, bool init) @@ -157,8 +167,6 @@ namespace MWRender mFbo->setAttachment(osg::Camera::COLOR_BUFFER0, osg::FrameBufferAttachment(mSceneTex)); mFbo->setAttachment(osg::Camera::DEPTH_BUFFER, osg::FrameBufferAttachment(mDepthTex)); - mViewer->getCamera()->setUserData(mFbo); - // When MSAA is enabled we must first render to a render buffer, then // blit the result to the FBO which is either passed to the main frame // buffer for display or used as the entry point for a post process chain. diff --git a/apps/openmw/mwrender/postprocessor.hpp b/apps/openmw/mwrender/postprocessor.hpp index 5be58f33ac..ad922c1cbc 100644 --- a/apps/openmw/mwrender/postprocessor.hpp +++ b/apps/openmw/mwrender/postprocessor.hpp @@ -1,16 +1,12 @@ #ifndef OPENMW_MWRENDER_POSTPROCESSOR_H #define OPENMW_MWRENDER_POSTPROCESSOR_H +#include +#include +#include +#include #include -namespace osg -{ - class Texture2D; - class Group; - class FrameBufferObject; - class Camera; -} - namespace osgViewer { class Viewer; @@ -20,7 +16,7 @@ namespace MWRender { class RenderingManager; - class PostProcessor + class PostProcessor : public osg::Referenced { public: PostProcessor(RenderingManager& rendering, osgViewer::Viewer* viewer, osg::Group* rootNode); @@ -33,6 +29,8 @@ namespace MWRender void resize(int width, int height, bool init=false); private: + void createTexturesAndCamera(int width, int height); + osgViewer::Viewer* mViewer; osg::ref_ptr mRootNode; osg::ref_ptr mHUDCamera; @@ -45,8 +43,6 @@ namespace MWRender int mDepthFormat; - void createTexturesAndCamera(int width, int height); - RenderingManager& mRendering; }; } diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index c64bcd3383..5ffc54f3f8 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -79,6 +79,8 @@ namespace MWRender public: SharedUniformStateUpdater() : mLinearFac(0.f) + , mNear(0.f) + , mFar(0.f) { } @@ -86,6 +88,8 @@ namespace MWRender { stateset->addUniform(new osg::Uniform("projectionMatrix", osg::Matrixf{})); stateset->addUniform(new osg::Uniform("linearFac", 0.f)); + stateset->addUniform(new osg::Uniform("near", 0.f)); + stateset->addUniform(new osg::Uniform("far", 0.f)); } void apply(osg::StateSet* stateset, osg::NodeVisitor* nv) override @@ -97,6 +101,15 @@ namespace MWRender auto* uLinearFac = stateset->getUniform("linearFac"); if (uLinearFac) uLinearFac->set(mLinearFac); + + auto* uNear = stateset->getUniform("near"); + if (uNear) + uNear->set(mNear); + + auto* uFar = stateset->getUniform("far"); + if (uFar) + uFar->set(mFar); + } void setProjectionMatrix(const osg::Matrixf& projectionMatrix) @@ -109,9 +122,21 @@ namespace MWRender mLinearFac = linearFac; } + void setNear(float near) + { + mNear = near; + } + + void setFar(float far) + { + mFar = far; + } + private: osg::Matrixf mProjectionMatrix; float mLinearFac; + float mNear; + float mFar; }; class StateUpdater : public SceneUtil::StateSetUpdater @@ -240,8 +265,7 @@ namespace MWRender , mFieldOfViewOverridden(false) , mFieldOfViewOverride(0.f) { - auto ext = osg::GLExtensions::Get(0, false); - bool reverseZ = Settings::Manager::getBool("reverse z", "Camera") && ext && ext->isClipControlSupported; + bool reverseZ = SceneUtil::getReverseZ(); if (reverseZ) Log(Debug::Info) << "Using reverse-z depth buffer"; @@ -267,7 +291,6 @@ namespace MWRender resourceSystem->getSceneManager()->setSpecularMapPattern(Settings::Manager::getString("specular map pattern", "Shaders")); resourceSystem->getSceneManager()->setApplyLightingToEnvMaps(Settings::Manager::getBool("apply lighting to environment maps", "Shaders")); resourceSystem->getSceneManager()->setConvertAlphaTestToAlphaToCoverage(Settings::Manager::getBool("antialias alpha test", "Shaders") && Settings::Manager::getInt("antialiasing", "Video") > 1); - resourceSystem->getSceneManager()->setReverseZ(reverseZ); // Let LightManager choose which backend to use based on our hint. For methods besides legacy lighting, this depends on support for various OpenGL extensions. osg::ref_ptr sceneRoot = new SceneUtil::LightManager(lightingMethod == SceneUtil::LightingMethod::FFP); @@ -294,7 +317,7 @@ namespace MWRender if (Settings::Manager::getBool("object shadows", "Shadows")) shadowCastingTraversalMask |= (Mask_Object|Mask_Static); - mShadowManager.reset(new SceneUtil::ShadowManager(sceneRoot, mRootNode, shadowCastingTraversalMask, indoorShadowCastingTraversalMask, mResourceSystem->getSceneManager()->getShaderManager(), reverseZ)); + mShadowManager.reset(new SceneUtil::ShadowManager(sceneRoot, mRootNode, shadowCastingTraversalMask, indoorShadowCastingTraversalMask, mResourceSystem->getSceneManager()->getShaderManager())); Shader::ShaderManager::DefineMap shadowDefines = mShadowManager->getShadowDefines(); Shader::ShaderManager::DefineMap lightDefines = sceneRoot->getLightDefines(); @@ -408,9 +431,12 @@ namespace MWRender mGroundcoverWorld->setActiveGrid(osg::Vec4i(0, 0, 0, 0)); } - mPostProcessor.reset(new PostProcessor(*this, viewer, mRootNode)); + mPostProcessor = new PostProcessor(*this, viewer, mRootNode); resourceSystem->getSceneManager()->setDepthFormat(mPostProcessor->getDepthFormat()); + if (reverseZ && !SceneUtil::isFloatingPointDepthFormat(mPostProcessor->getDepthFormat())) + Log(Debug::Warning) << "Floating point depth format not in use but reverse-z buffer is enabled, consider disabling it."; + // water goes after terrain for correct waterculling order mWater.reset(new Water(sceneRoot->getParent(0), sceneRoot, mResourceSystem, mViewer->getIncrementalCompileOperation(), resourcePath)); @@ -474,7 +500,6 @@ namespace MWRender mViewer->getCamera()->setCullMask(~(Mask_UpdateVisitor|Mask_SimpleWater)); NifOsg::Loader::setHiddenNodeMask(Mask_UpdateVisitor); NifOsg::Loader::setIntersectionDisabledNodeMask(Mask_Effect); - NifOsg::Loader::setReverseZ(reverseZ); Nif::NIFFile::setLoadUnsupportedFiles(Settings::Manager::getBool("load unsupported nif files", "Models")); // TODO: Near clip should not need to be bounded like this, but too small values break OSG shadow calculations CPU-side. @@ -487,8 +512,6 @@ namespace MWRender mFirstPersonFieldOfView = std::min(std::max(1.f, firstPersonFov), 179.f); mStateUpdater->setFogEnd(mViewDistance); - mRootNode->getOrCreateStateSet()->addUniform(new osg::Uniform("near", mNearClip)); - mRootNode->getOrCreateStateSet()->addUniform(new osg::Uniform("far", mViewDistance)); mRootNode->getOrCreateStateSet()->addUniform(new osg::Uniform("simpleWater", false)); // Hopefully, anything genuinely requiring the default alpha func of GL_ALWAYS explicitly sets it @@ -496,18 +519,15 @@ namespace MWRender // The transparent renderbin sets alpha testing on because that was faster on old GPUs. It's now slower and breaks things. mRootNode->getOrCreateStateSet()->setMode(GL_ALPHA_TEST, osg::StateAttribute::OFF); - mUniformNear = mRootNode->getOrCreateStateSet()->getUniform("near"); - mUniformFar = mRootNode->getOrCreateStateSet()->getUniform("far"); - if (reverseZ) { - auto depth = SceneUtil::createDepth(reverseZ); osg::ref_ptr clipcontrol = new osg::ClipControl(osg::ClipControl::LOWER_LEFT, osg::ClipControl::ZERO_TO_ONE); - mViewer->getCamera()->setClearDepth(0.0); - mRootNode->getOrCreateStateSet()->setAttributeAndModes(depth, osg::StateAttribute::ON); + mRootNode->getOrCreateStateSet()->setAttributeAndModes(SceneUtil::createDepth(), osg::StateAttribute::ON); mRootNode->getOrCreateStateSet()->setAttributeAndModes(clipcontrol, osg::StateAttribute::ON); } + SceneUtil::setCameraClearDepth(mViewer->getCamera()); + updateProjectionMatrix(); } @@ -1143,7 +1163,7 @@ namespace MWRender mViewer->getCamera()->setProjectionMatrixAsPerspective(fov, aspect, mNearClip, mViewDistance); - if (mResourceSystem->getSceneManager()->getReverseZ()) + if (SceneUtil::getReverseZ()) { mSharedUniformStateUpdater->setLinearFac(-mNearClip / (mViewDistance - mNearClip) - 1.f); mSharedUniformStateUpdater->setProjectionMatrix(SceneUtil::getReversedZProjectionMatrixAsPerspective(fov, aspect, mNearClip, mViewDistance)); @@ -1151,8 +1171,8 @@ namespace MWRender else mSharedUniformStateUpdater->setProjectionMatrix(mViewer->getCamera()->getProjectionMatrix()); - mUniformNear->set(mNearClip); - mUniformFar->set(mViewDistance); + mSharedUniformStateUpdater->setNear(mNearClip); + mSharedUniformStateUpdater->setFar(mViewDistance); // Since our fog is not radial yet, we should take FOV in account, otherwise terrain near viewing distance may disappear. // Limit FOV here just for sure, otherwise viewing distance can be too high. diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index cbe25addf1..d6d7e74634 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -110,9 +110,6 @@ namespace MWRender SceneUtil::UnrefQueue* getUnrefQueue(); Terrain::World* getTerrain(); - osg::Uniform* mUniformNear; - osg::Uniform* mUniformFar; - void preloadCommonAssets(); double getReferenceTime() const; @@ -241,8 +238,9 @@ namespace MWRender void pagingBlacklistObject(int type, const MWWorld::ConstPtr &ptr); bool pagingUnlockCache(); void getPagedRefnums(const osg::Vec4i &activeGrid, std::set &out); - + void updateProjectionMatrix(); + private: void updateTextureFiltering(); void updateAmbient(); @@ -289,7 +287,7 @@ namespace MWRender std::unique_ptr mScreenshotManager; std::unique_ptr mEffectManager; std::unique_ptr mShadowManager; - std::unique_ptr mPostProcessor; + osg::ref_ptr mPostProcessor; osg::ref_ptr mPlayerAnimation; osg::ref_ptr mPlayerNode; std::unique_ptr mCamera; diff --git a/apps/openmw/mwrender/ripplesimulation.cpp b/apps/openmw/mwrender/ripplesimulation.cpp index c7deac51de..fdfc3db63d 100644 --- a/apps/openmw/mwrender/ripplesimulation.cpp +++ b/apps/openmw/mwrender/ripplesimulation.cpp @@ -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(resourceSystem->getSceneManager()->getReverseZ()); + auto depth = SceneUtil::createDepth(); depth->setWriteMask(false); stateset->setAttributeAndModes(depth, osg::StateAttribute::ON); osg::ref_ptr polygonOffset (new osg::PolygonOffset); - polygonOffset->setUnits(-1); - polygonOffset->setFactor(-1); + polygonOffset->setUnits(SceneUtil::getReverseZ() ? 1 : -1); + polygonOffset->setFactor(SceneUtil::getReverseZ() ? 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 967e282f30..96a8a9450a 100644 --- a/apps/openmw/mwrender/screenshotmanager.cpp +++ b/apps/openmw/mwrender/screenshotmanager.cpp @@ -23,6 +23,7 @@ #include "util.hpp" #include "vismask.hpp" #include "water.hpp" +#include "postprocessor.hpp" namespace MWRender { @@ -92,14 +93,13 @@ namespace MWRender // Ensure we are reading from the resolved framebuffer and not the multisampled render buffer when in use. // glReadPixel() cannot read from multisampled targets. + PostProcessor* postProcessor = dynamic_cast(renderInfo.getCurrentCamera()->getUserData()); - osg::FrameBufferObject* fbo = dynamic_cast(renderInfo.getCurrentCamera()->getUserData()); - - if (fbo) + if (postProcessor && postProcessor->getFbo() && postProcessor->getMsaaFbo()) { osg::GLExtensions* ext = osg::GLExtensions::Get(renderInfo.getContextID(), false); if (ext) - ext->glBindFramebuffer(GL_FRAMEBUFFER_EXT, fbo->getHandle(renderInfo.getContextID())); + ext->glBindFramebuffer(GL_FRAMEBUFFER_EXT, postProcessor->getFbo()->getHandle(renderInfo.getContextID())); } mImage->readPixels(leftPadding, topPadding, width, height, GL_RGB, GL_UNSIGNED_BYTE); @@ -297,12 +297,10 @@ namespace MWRender camera->setRenderOrder(osg::Camera::PRE_RENDER); camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF); camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT,osg::Camera::PIXEL_BUFFER_RTT); - - if (getReverseZ()) - camera->setClearDepth(0.0); - camera->setViewport(0, 0, w, h); + SceneUtil::setCameraClearDepth(camera); + osg::ref_ptr texture (new osg::Texture2D); texture->setInternalFormat(GL_RGB); texture->setTextureSize(w,h); @@ -336,7 +334,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 (getReverseZ()) + if (SceneUtil::getReverseZ()) 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 dd97f79eda..2b58730fe1 100644 --- a/apps/openmw/mwrender/sky.cpp +++ b/apps/openmw/mwrender/sky.cpp @@ -595,11 +595,11 @@ private: osg::StateSet* queryStateSet = new osg::StateSet; if (queryVisible) { - auto depth = SceneUtil::createDepth(getReverseZ()); + auto depth = SceneUtil::createDepth(); // 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 = getReverseZ() ? 0.0 : 1.0; + double far = SceneUtil::getReverseZ() ? 0.0 : 1.0; depth->setZNear(far); depth->setZFar(far); depth->setWriteMask(false); @@ -1210,7 +1210,7 @@ void SkyManager::create() mCloudMesh2->addUpdateCallback(mCloudUpdater2); mCloudMesh2->setNodeMask(0); - auto depth = SceneUtil::createDepth(mSceneManager->getReverseZ()); + auto depth = SceneUtil::createDepth(); depth->setWriteMask(false); mEarlyRenderBinRoot->getOrCreateStateSet()->setAttributeAndModes(depth, osg::StateAttribute::ON); mEarlyRenderBinRoot->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON); diff --git a/apps/openmw/mwrender/util.cpp b/apps/openmw/mwrender/util.cpp index 5740f7df6c..e3fc48040f 100644 --- a/apps/openmw/mwrender/util.cpp +++ b/apps/openmw/mwrender/util.cpp @@ -4,13 +4,10 @@ #include #include -#include #include #include #include -#include "../mwbase/environment.hpp" - namespace MWRender { @@ -67,9 +64,4 @@ void overrideTexture(const std::string &texture, Resource::ResourceSystem *resou node->setStateSet(stateset); } -bool getReverseZ() -{ - return MWBase::Environment::get().getResourceSystem()->getSceneManager()->getReverseZ(); -} - } diff --git a/apps/openmw/mwrender/util.hpp b/apps/openmw/mwrender/util.hpp index c005dd9b23..a89baa22b1 100644 --- a/apps/openmw/mwrender/util.hpp +++ b/apps/openmw/mwrender/util.hpp @@ -32,8 +32,6 @@ namespace MWRender // no traverse() } }; - - bool getReverseZ(); } #endif diff --git a/apps/openmw/mwrender/water.cpp b/apps/openmw/mwrender/water.cpp index 1318921688..da26595c8c 100644 --- a/apps/openmw/mwrender/water.cpp +++ b/apps/openmw/mwrender/water.cpp @@ -273,7 +273,7 @@ public: void setDefaults(osg::Camera* camera) override { - camera->setClearDepth(1.0); + SceneUtil::setCameraClearDepth(camera); camera->setReferenceFrame(osg::Camera::RELATIVE_RF); camera->setSmallFeatureCullingPixelSize(Settings::Manager::getInt("small feature culling pixel size", "Water")); camera->setName("RefractionCamera"); @@ -339,7 +339,7 @@ public: void setDefaults(osg::Camera* camera) override { - camera->setClearDepth(1.0); + SceneUtil::setCameraClearDepth(camera); camera->setReferenceFrame(osg::Camera::RELATIVE_RF); camera->setSmallFeatureCullingPixelSize(Settings::Manager::getInt("small feature culling pixel size", "Water")); camera->setName("ReflectionCamera"); @@ -546,7 +546,7 @@ osg::Node* Water::getRefractionNode() void Water::createSimpleWaterStateSet(osg::Node* node, float alpha) { - osg::ref_ptr stateset = SceneUtil::createSimpleWaterStateSet(alpha, MWRender::RenderBin_Water, mResourceSystem->getSceneManager()->getReverseZ()); + osg::ref_ptr stateset = SceneUtil::createSimpleWaterStateSet(alpha, MWRender::RenderBin_Water); node->setStateSet(stateset); node->setUpdateCallback(nullptr); @@ -616,7 +616,7 @@ public: { stateset->setMode(GL_BLEND, osg::StateAttribute::ON); stateset->setRenderBinDetails(MWRender::RenderBin_Water, "RenderBin"); - osg::ref_ptr depth(new osg::Depth); + osg::ref_ptr depth = SceneUtil::createDepth(); depth->setWriteMask(false); stateset->setAttributeAndModes(depth, osg::StateAttribute::ON); } diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 384c640388..83b9fb61c2 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -226,18 +226,6 @@ namespace NifOsg return sIntersectionDisabledNodeMask; } - bool Loader::sReverseZ = false; - - void Loader::setReverseZ(bool reverseZ) - { - sReverseZ = reverseZ; - } - - bool Loader::getReverseZ() - { - return sReverseZ; - } - class LoaderImpl { public: @@ -1835,7 +1823,7 @@ namespace NifOsg // Depth test flag stateset->setMode(GL_DEPTH_TEST, zprop->flags&1 ? osg::StateAttribute::ON : osg::StateAttribute::OFF); - auto depth = SceneUtil::createDepth(Loader::getReverseZ()); + auto depth = SceneUtil::createDepth(); // Depth write flag depth->setWriteMask((zprop->flags>>1)&1); // Morrowind ignores depth test function diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index cee75de6d2..8ee6b41674 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -51,14 +51,10 @@ namespace NifOsg static void setIntersectionDisabledNodeMask(unsigned int mask); static unsigned int getIntersectionDisabledNodeMask(); - static void setReverseZ(bool reverseZ); - static bool getReverseZ(); - private: static unsigned int sHiddenNodeMask; static unsigned int sIntersectionDisabledNodeMask; static bool sShowMarkers; - static bool sReverseZ; }; } diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 3c548ead23..ffcd4c3308 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -275,16 +275,6 @@ namespace Resource return mClampLighting; } - void SceneManager::setReverseZ(bool reverseZ) - { - mReverseZ = reverseZ; - } - - bool SceneManager::getReverseZ() const - { - return mReverseZ; - } - void SceneManager::setDepthFormat(GLenum format) { mDepthFormat = format; diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index 780375f77e..9d798177a1 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -92,9 +92,6 @@ namespace Resource void setClampLighting(bool clamp); bool getClampLighting() const; - void setReverseZ(bool reverseZ); - bool getReverseZ() const; - void setDepthFormat(GLenum format); GLenum getDepthFormat() const; @@ -208,7 +205,6 @@ namespace Resource SceneUtil::LightingMethod mLightingMethod; SceneUtil::LightManager::SupportedMethods mSupportedLightingMethods; bool mConvertAlphaTestToAlphaToCoverage; - bool mReverseZ; GLenum mDepthFormat; osg::ref_ptr mInstanceCache; diff --git a/components/sceneutil/agentpath.cpp b/components/sceneutil/agentpath.cpp index abe332f758..5f9b574e7d 100644 --- a/components/sceneutil/agentpath.cpp +++ b/components/sceneutil/agentpath.cpp @@ -1,6 +1,8 @@ #include "agentpath.hpp" #include "detourdebugdraw.hpp" +#include + #include #include @@ -65,6 +67,10 @@ namespace SceneUtil debugDraw.depthMask(true); + osg::ref_ptr material = new osg::Material; + material->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE); + group->getOrCreateStateSet()->setAttribute(material); + return group; } } diff --git a/components/sceneutil/mwshadowtechnique.cpp b/components/sceneutil/mwshadowtechnique.cpp index 0004045dc8..19222eda23 100644 --- a/components/sceneutil/mwshadowtechnique.cpp +++ b/components/sceneutil/mwshadowtechnique.cpp @@ -26,6 +26,9 @@ #include #include + +#include + #include "shadowsbin.hpp" namespace { @@ -891,16 +894,6 @@ void SceneUtil::MWShadowTechnique::disableFrontFaceCulling() } } -void SceneUtil::MWShadowTechnique::enableReverseZ() -{ - _reverseZ = true; -} - -void SceneUtil::MWShadowTechnique::disableReverseZ() -{ - _reverseZ = false; -} - void SceneUtil::MWShadowTechnique::setupCastingShader(Shader::ShaderManager & shaderManager) { // This can't be part of the constructor as OSG mandates that there be a trivial constructor available @@ -1647,7 +1640,7 @@ void MWShadowTechnique::createShaders() _shadowCastingStateSet->addUniform(new osg::Uniform("alphaTestShadows", false)); osg::ref_ptr depth = new osg::Depth; depth->setWriteMask(true); - if (_reverseZ) + 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); diff --git a/components/sceneutil/mwshadowtechnique.hpp b/components/sceneutil/mwshadowtechnique.hpp index 7fde0d7dbb..de57bf1fdc 100644 --- a/components/sceneutil/mwshadowtechnique.hpp +++ b/components/sceneutil/mwshadowtechnique.hpp @@ -85,10 +85,6 @@ namespace SceneUtil { virtual void disableFrontFaceCulling(); - virtual void enableReverseZ(); - - virtual void disableReverseZ(); - virtual void setupCastingShader(Shader::ShaderManager &shaderManager); class ComputeLightSpaceBounds : public osg::NodeVisitor, public osg::CullStack @@ -270,8 +266,6 @@ namespace SceneUtil { float _shadowFadeStart = 0.0; - bool _reverseZ = false; - class DebugHUD final : public osg::Referenced { public: diff --git a/components/sceneutil/navmesh.cpp b/components/sceneutil/navmesh.cpp index aeb1779bd6..b0f356f089 100644 --- a/components/sceneutil/navmesh.cpp +++ b/components/sceneutil/navmesh.cpp @@ -6,6 +6,7 @@ #include #include +#include namespace SceneUtil { @@ -17,6 +18,11 @@ namespace SceneUtil navMeshQuery.init(&navMesh, settings.mMaxNavMeshQueryNodes); duDebugDrawNavMeshWithClosedList(&debugDraw, navMesh, navMeshQuery, DU_DRAWNAVMESH_OFFMESHCONS | DU_DRAWNAVMESH_CLOSEDLIST); + + osg::ref_ptr material = new osg::Material; + material->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE); + group->getOrCreateStateSet()->setAttribute(material); + return group; } } diff --git a/components/sceneutil/optimizer.cpp b/components/sceneutil/optimizer.cpp index 6bde81c12d..5fbeb681fc 100644 --- a/components/sceneutil/optimizer.cpp +++ b/components/sceneutil/optimizer.cpp @@ -109,7 +109,6 @@ void Optimizer::optimize(osg::Node* node, unsigned int options) MergeGeometryVisitor mgv(this); mgv.setTargetMaximumNumberOfVertices(1000000); mgv.setMergeAlphaBlending(_mergeAlphaBlending); - mgv.setReverseZ(_reverseZ); mgv.setViewPoint(_viewPoint); node->accept(mgv); @@ -1563,7 +1562,7 @@ bool Optimizer::MergeGeometryVisitor::mergeGroup(osg::Group& group) } if (_alphaBlendingActive && _mergeAlphaBlending && !geom->getStateSet()) { - auto d = createDepth(_reverseZ); + auto d = createDepth(); d->setWriteMask(0); geom->getOrCreateStateSet()->setAttribute(d); } diff --git a/components/sceneutil/optimizer.hpp b/components/sceneutil/optimizer.hpp index 9f9c788445..2d6293e231 100644 --- a/components/sceneutil/optimizer.hpp +++ b/components/sceneutil/optimizer.hpp @@ -65,7 +65,7 @@ class Optimizer public: - Optimizer() : _mergeAlphaBlending(false), _reverseZ(false) {} + Optimizer() : _mergeAlphaBlending(false) {} virtual ~Optimizer() {} enum OptimizationOptions @@ -119,7 +119,6 @@ class Optimizer }; void setMergeAlphaBlending(bool merge) { _mergeAlphaBlending = merge; } - void setReverseZ(bool reverseZ) { _reverseZ = reverseZ; } void setViewPoint(const osg::Vec3f& viewPoint) { _viewPoint = viewPoint; } /** Reset internal data to initial state - the getPermissibleOptionsMap is cleared.*/ @@ -258,7 +257,6 @@ class Optimizer osg::Vec3f _viewPoint; bool _mergeAlphaBlending; - bool _reverseZ; public: @@ -379,18 +377,12 @@ class Optimizer /// default to traversing all children. MergeGeometryVisitor(Optimizer* optimizer=0) : BaseOptimizerVisitor(optimizer, MERGE_GEOMETRY), - _targetMaximumNumberOfVertices(10000), _alphaBlendingActive(false), _mergeAlphaBlending(false), _reverseZ(false) {} + _targetMaximumNumberOfVertices(10000), _alphaBlendingActive(false), _mergeAlphaBlending(false) {} void setMergeAlphaBlending(bool merge) { _mergeAlphaBlending = merge; } - - void setReverseZ(bool reverseZ) - { - _reverseZ = reverseZ; - } - void setViewPoint(const osg::Vec3f& viewPoint) { _viewPoint = viewPoint; @@ -429,7 +421,6 @@ class Optimizer std::vector _stateSetStack; bool _alphaBlendingActive; bool _mergeAlphaBlending; - bool _reverseZ; osg::Vec3f _viewPoint; }; diff --git a/components/sceneutil/pathgridutil.cpp b/components/sceneutil/pathgridutil.cpp index f37a8ba597..9ebdef61b0 100644 --- a/components/sceneutil/pathgridutil.cpp +++ b/components/sceneutil/pathgridutil.cpp @@ -1,6 +1,7 @@ #include "pathgridutil.hpp" #include +#include #include @@ -174,6 +175,11 @@ namespace SceneUtil gridGeometry->addPrimitiveSet(lineIndices); gridGeometry->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); } + + osg::ref_ptr material = new osg::Material; + material->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE); + gridGeometry->getOrCreateStateSet()->setAttribute(material); + return gridGeometry; } diff --git a/components/sceneutil/recastmesh.cpp b/components/sceneutil/recastmesh.cpp index 85f3e7177b..8d6d47c2b6 100644 --- a/components/sceneutil/recastmesh.cpp +++ b/components/sceneutil/recastmesh.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -65,6 +66,11 @@ namespace SceneUtil const auto texScale = 1.0f / (settings.mCellSize * 10.0f); duDebugDrawTriMesh(&debugDraw, vertices.data(), static_cast(vertices.size() / 3), indices.data(), normals.data(), static_cast(indices.size() / 3), nullptr, texScale); + + osg::ref_ptr material = new osg::Material; + material->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE); + group->getOrCreateStateSet()->setAttribute(material); + return group; } } diff --git a/components/sceneutil/shadow.cpp b/components/sceneutil/shadow.cpp index 7ca15e612d..3244dc672a 100644 --- a/components/sceneutil/shadow.cpp +++ b/components/sceneutil/shadow.cpp @@ -94,12 +94,10 @@ namespace SceneUtil } } - ShadowManager::ShadowManager(osg::ref_ptr sceneRoot, osg::ref_ptr rootNode, unsigned int outdoorShadowCastingMask, unsigned int indoorShadowCastingMask, Shader::ShaderManager &shaderManager, bool reverseZ) - : mReverseZ(reverseZ) - , mShadowedScene(new osgShadow::ShadowedScene) - , mShadowTechnique(new MWShadowTechnique) - , mOutdoorShadowCastingMask(outdoorShadowCastingMask) - , mIndoorShadowCastingMask(indoorShadowCastingMask) + ShadowManager::ShadowManager(osg::ref_ptr sceneRoot, osg::ref_ptr rootNode, unsigned int outdoorShadowCastingMask, unsigned int indoorShadowCastingMask, Shader::ShaderManager &shaderManager) : mShadowedScene(new osgShadow::ShadowedScene), + mShadowTechnique(new MWShadowTechnique), + mOutdoorShadowCastingMask(outdoorShadowCastingMask), + mIndoorShadowCastingMask(indoorShadowCastingMask) { mShadowedScene->setShadowTechnique(mShadowTechnique); @@ -110,9 +108,6 @@ namespace SceneUtil mShadowSettings = mShadowedScene->getShadowSettings(); setupShadowSettings(); - if (mReverseZ) - mShadowTechnique->enableReverseZ(); - mShadowTechnique->setupCastingShader(shaderManager); enableOutdoorMode(); @@ -185,9 +180,4 @@ namespace SceneUtil mShadowTechnique->enableShadows(); mShadowSettings->setCastsShadowTraversalMask(mOutdoorShadowCastingMask); } - - bool ShadowManager::getReverseZ() const - { - return mReverseZ; - } } diff --git a/components/sceneutil/shadow.hpp b/components/sceneutil/shadow.hpp index 8092f77f93..c823ecf860 100644 --- a/components/sceneutil/shadow.hpp +++ b/components/sceneutil/shadow.hpp @@ -17,7 +17,7 @@ namespace SceneUtil static Shader::ShaderManager::DefineMap getShadowsDisabledDefines(); - ShadowManager(osg::ref_ptr sceneRoot, osg::ref_ptr rootNode, unsigned int outdoorShadowCastingMask, unsigned int indoorShadowCastingMask, Shader::ShaderManager &shaderManager, bool reverseZ); + ShadowManager(osg::ref_ptr sceneRoot, osg::ref_ptr rootNode, unsigned int outdoorShadowCastingMask, unsigned int indoorShadowCastingMask, Shader::ShaderManager &shaderManager); void setupShadowSettings(); @@ -26,11 +26,8 @@ namespace SceneUtil void enableIndoorMode(); void enableOutdoorMode(); - - bool getReverseZ() const; protected: bool mEnableShadows; - bool mReverseZ; osg::ref_ptr mShadowedScene; osg::ref_ptr mShadowSettings; diff --git a/components/sceneutil/util.cpp b/components/sceneutil/util.cpp index 1f79469a19..02cd9295e7 100644 --- a/components/sceneutil/util.cpp +++ b/components/sceneutil/util.cpp @@ -4,16 +4,31 @@ #include #include +#include + #include #include #include #include #include -#include #include #include #include +#include + +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 { @@ -151,32 +166,42 @@ void GlowUpdater::setDuration(float duration) mDuration = duration; } -AttachMultisampledDepthColorCallback::AttachMultisampledDepthColorCallback(const osg::ref_ptr& colorTex, const osg::ref_ptr& depthTex, int samples, int colorSamples) +// Allows camera to render to a color and floating point depth texture with a multisampled framebuffer. +// Must be set on a camera's cull callback. +class AttachMultisampledDepthColorCallback : public osg::NodeCallback { - int width = colorTex->getTextureWidth(); - int height = colorTex->getTextureHeight(); +public: + AttachMultisampledDepthColorCallback(osg::Texture2D* colorTex, osg::Texture2D* depthTex, int samples, int colorSamples) + { + int width = colorTex->getTextureWidth(); + int height = colorTex->getTextureHeight(); - osg::ref_ptr rbColor = new osg::RenderBuffer(width, height, colorTex->getInternalFormat(), samples, colorSamples); - osg::ref_ptr rbDepth = new osg::RenderBuffer(width, height, depthTex->getInternalFormat(), samples, colorSamples); + osg::ref_ptr rbColor = new osg::RenderBuffer(width, height, colorTex->getInternalFormat(), samples, colorSamples); + osg::ref_ptr rbDepth = new osg::RenderBuffer(width, height, depthTex->getInternalFormat(), samples, colorSamples); - mMsaaFbo = new osg::FrameBufferObject; - mMsaaFbo->setAttachment(osg::Camera::COLOR_BUFFER0, osg::FrameBufferAttachment(rbColor)); - mMsaaFbo->setAttachment(osg::Camera::DEPTH_BUFFER, osg::FrameBufferAttachment(rbDepth)); + mMsaaFbo = new osg::FrameBufferObject; + mMsaaFbo->setAttachment(osg::Camera::COLOR_BUFFER0, osg::FrameBufferAttachment(rbColor)); + mMsaaFbo->setAttachment(osg::Camera::DEPTH_BUFFER, osg::FrameBufferAttachment(rbDepth)); - mFbo = new osg::FrameBufferObject; - mFbo->setAttachment(osg::Camera::COLOR_BUFFER0, osg::FrameBufferAttachment(colorTex)); - mFbo->setAttachment(osg::Camera::DEPTH_BUFFER, osg::FrameBufferAttachment(depthTex)); -} + mFbo = new osg::FrameBufferObject; + mFbo->setAttachment(osg::Camera::COLOR_BUFFER0, osg::FrameBufferAttachment(colorTex)); + mFbo->setAttachment(osg::Camera::DEPTH_BUFFER, osg::FrameBufferAttachment(depthTex)); + } -void AttachMultisampledDepthColorCallback::operator()(osg::Node* node, osg::NodeVisitor* nv) -{ - osgUtil::RenderStage* renderStage = nv->asCullVisitor()->getCurrentRenderStage(); + void operator()(osg::Node* node, osg::NodeVisitor* nv) override + { + osgUtil::RenderStage* renderStage = nv->asCullVisitor()->getCurrentRenderStage(); - renderStage->setMultisampleResolveFramebufferObject(mFbo); - renderStage->setFrameBufferObject(mMsaaFbo); + renderStage->setMultisampleResolveFramebufferObject(mFbo); + renderStage->setFrameBufferObject(mMsaaFbo); - traverse(node, nv); -} + traverse(node, nv); + } + +private: + osg::ref_ptr mFbo; + osg::ref_ptr mMsaaFbo; +}; void transformBoundingSphere (const osg::Matrixf& matrix, osg::BoundingSphere& bsphere) { @@ -313,9 +338,37 @@ bool attachAlphaToCoverageFriendlyFramebufferToCamera(osg::Camera* camera, osg:: return addMSAAIntermediateTarget; } -osg::ref_ptr createDepth(bool reverseZ) +void attachAlphaToCoverageFriendlyDepthColor(osg::Camera* camera, osg::Texture2D* colorTex, osg::Texture2D* depthTex, GLenum depthFormat) { - return new osg::Depth(reverseZ ? osg::Depth::GEQUAL : osg::Depth::LEQUAL); + 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) @@ -352,7 +405,14 @@ osg::Matrix getReversedZProjectionMatrixAsOrtho(double left, double right, doubl bool isFloatingPointDepthFormat(GLenum format) { - return format == GL_DEPTH_COMPONENT32F || format == GL_DEPTH_COMPONENT32F_NV; + 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 bd4df5441a..0bca32c325 100644 --- a/components/sceneutil/util.hpp +++ b/components/sceneutil/util.hpp @@ -8,7 +8,6 @@ #include #include #include -#include #include @@ -49,22 +48,6 @@ namespace SceneUtil bool mDone; }; - // Allows camera to render to a color and floating point depth texture with a multisampled framebuffer. - // Must be set on a camera's cull callback. - // When the depth texture isn't needed as a sampler, use osg::Camera::attach(osg::Camera::DEPTH_COMPONENT, GL_DEPTH_COMPONENT32F) instead. - // If multisampling is not being used on the color buffer attachment, use the osg::Camera::attach() method. - class AttachMultisampledDepthColorCallback : public osg::NodeCallback - { - public: - AttachMultisampledDepthColorCallback(const osg::ref_ptr& colorTex, const osg::ref_ptr& depthTex, int samples, int colorSamples); - - void operator()(osg::Node* node, osg::NodeVisitor* nv) override; - - private: - osg::ref_ptr mFbo; - osg::ref_ptr mMsaaFbo; - }; - // Transform a bounding sphere by a matrix // based off private code in osg::Transform // TODO: patch osg to make public @@ -83,9 +66,15 @@ 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(bool reverseZ); + 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 @@ -100,7 +89,7 @@ namespace SceneUtil 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); + bool isFloatingPointDepthFormat(GLenum format); } #endif diff --git a/components/sceneutil/waterutil.cpp b/components/sceneutil/waterutil.cpp index dccc534ecc..ac171005ae 100644 --- a/components/sceneutil/waterutil.cpp +++ b/components/sceneutil/waterutil.cpp @@ -64,7 +64,7 @@ namespace SceneUtil return waterGeom; } - osg::ref_ptr createSimpleWaterStateSet(float alpha, int renderBin, bool reverseZ) + osg::ref_ptr createSimpleWaterStateSet(float alpha, int renderBin) { osg::ref_ptr stateset (new osg::StateSet); @@ -78,7 +78,7 @@ namespace SceneUtil stateset->setMode(GL_BLEND, osg::StateAttribute::ON); stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); - auto depth = createDepth(reverseZ); + auto depth = createDepth(); depth->setWriteMask(false); stateset->setAttributeAndModes(depth, osg::StateAttribute::ON); diff --git a/components/sceneutil/waterutil.hpp b/components/sceneutil/waterutil.hpp index 7f08dbcfa9..7b8c380109 100644 --- a/components/sceneutil/waterutil.hpp +++ b/components/sceneutil/waterutil.hpp @@ -13,7 +13,7 @@ namespace SceneUtil { osg::ref_ptr createWaterGeometry(float size, int segments, float textureRepeats); - osg::ref_ptr createSimpleWaterStateSet(float alpha, int renderBin, bool reverseZ); + osg::ref_ptr createSimpleWaterStateSet(float alpha, int renderBin); } #endif diff --git a/components/terrain/chunkmanager.cpp b/components/terrain/chunkmanager.cpp index 5354b9d8a2..a744471de5 100644 --- a/components/terrain/chunkmanager.cpp +++ b/components/terrain/chunkmanager.cpp @@ -163,7 +163,7 @@ std::vector > ChunkManager::createPasses(float chunk float blendmapScale = mStorage->getBlendmapScale(chunkSize); - return ::Terrain::createPasses(useShaders, mSceneManager, layers, blendmapTextures, blendmapScale, blendmapScale); + return ::Terrain::createPasses(useShaders, &mSceneManager->getShaderManager(), layers, blendmapTextures, blendmapScale, blendmapScale); } osg::ref_ptr ChunkManager::createChunk(float chunkSize, const osg::Vec2f &chunkCenter, unsigned char lod, unsigned int lodFlags, bool compile) @@ -219,7 +219,7 @@ osg::ref_ptr ChunkManager::createChunk(float chunkSize, const osg::Ve layer.mDiffuseMap = compositeMap->mTexture; layer.mParallax = false; layer.mSpecular = false; - geometry->setPasses(::Terrain::createPasses(mSceneManager->getForceShaders() || !mSceneManager->getClampLighting(), mSceneManager, std::vector(1, layer), std::vector >(), 1.f, 1.f)); + geometry->setPasses(::Terrain::createPasses(mSceneManager->getForceShaders() || !mSceneManager->getClampLighting(), &mSceneManager->getShaderManager(), std::vector(1, layer), std::vector >(), 1.f, 1.f)); } else { diff --git a/components/terrain/material.cpp b/components/terrain/material.cpp index dc74b58560..2fbd0a7fc0 100644 --- a/components/terrain/material.cpp +++ b/components/terrain/material.cpp @@ -7,7 +7,6 @@ #include #include -#include #include #include @@ -97,17 +96,17 @@ namespace class LequalDepth { public: - static const osg::ref_ptr& value(bool reverseZ) + static const osg::ref_ptr& value() { - static LequalDepth instance(reverseZ); + static LequalDepth instance; return instance.mValue; } private: osg::ref_ptr mValue; - LequalDepth(bool reverseZ) - : mValue(SceneUtil::createDepth(reverseZ)) + LequalDepth() + : mValue(SceneUtil::createDepth()) { } }; @@ -171,10 +170,9 @@ namespace namespace Terrain { - std::vector > createPasses(bool useShaders, Resource::SceneManager* sceneManager, const std::vector &layers, + std::vector > createPasses(bool useShaders, Shader::ShaderManager* shaderManager, const std::vector &layers, const std::vector > &blendmaps, int blendmapScale, float layerTileSize) { - Shader::ShaderManager* shaderManager = &sceneManager->getShaderManager(); std::vector > passes; unsigned int blendmapIndex = 0; @@ -197,7 +195,7 @@ namespace Terrain else { stateset->setAttributeAndModes(BlendFuncFirst::value(), osg::StateAttribute::ON); - stateset->setAttributeAndModes(LequalDepth::value(sceneManager->getReverseZ()), osg::StateAttribute::ON); + stateset->setAttributeAndModes(LequalDepth::value(), osg::StateAttribute::ON); } } @@ -240,7 +238,7 @@ namespace Terrain if (!vertexShader || !fragmentShader) { // Try again without shader. Error already logged by above - return createPasses(false, sceneManager, layers, blendmaps, blendmapScale, layerTileSize); + return createPasses(false, shaderManager, layers, blendmaps, blendmapScale, layerTileSize); } stateset->setAttributeAndModes(shaderManager->getProgram(vertexShader, fragmentShader)); diff --git a/components/terrain/material.hpp b/components/terrain/material.hpp index d5ef40a29e..5f78af6a06 100644 --- a/components/terrain/material.hpp +++ b/components/terrain/material.hpp @@ -10,9 +10,9 @@ namespace osg class Texture2D; } -namespace Resource +namespace Shader { - class SceneManager; + class ShaderManager; } namespace Terrain @@ -26,7 +26,7 @@ namespace Terrain bool mSpecular; }; - std::vector > createPasses(bool useShaders, Resource::SceneManager* sceneManager, + std::vector > createPasses(bool useShaders, Shader::ShaderManager* shaderManager, const std::vector& layers, const std::vector >& blendmaps, int blendmapScale, float layerTileSize); diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 4943ce969b..2c287a889c 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -67,7 +67,7 @@ head bobbing height = 3.0 # Maximum camera roll angle (degrees) head bobbing roll = 0.2 -# Reverse the depth range from [0,1] to [1,0]. +# Reverse the depth range, reduces z-fighting of distant objects and terrain reverse z = true [Cells] diff --git a/files/shaders/debug_fragment.glsl b/files/shaders/debug_fragment.glsl index 263d4e1f24..1b25510d66 100644 --- a/files/shaders/debug_fragment.glsl +++ b/files/shaders/debug_fragment.glsl @@ -1,8 +1,8 @@ #version 120 -varying vec4 passColor; +#include "vertexcolors.glsl" void main() { - gl_FragData[0] = passColor; + gl_FragData[0] = getDiffuseColor(); } diff --git a/files/shaders/water_fragment.glsl b/files/shaders/water_fragment.glsl index ed0ebdc913..26f83e052c 100644 --- a/files/shaders/water_fragment.glsl +++ b/files/shaders/water_fragment.glsl @@ -51,6 +51,8 @@ const float WIND_SPEED = 0.2f; const vec3 WATER_COLOR = vec3(0.090195, 0.115685, 0.12745); +const float WOBBLY_SHORE_FADE_DISTANCE = 6200.0; // fade out wobbly shores to mask precision errors, the effect is almost impossible to see at a distance + // ---------------- rain ripples related stuff --------------------- const float RAIN_RIPPLE_GAPS = 5.0; @@ -270,10 +272,10 @@ void main(void) vec3 normalShoreRippleRain = texture2D(normalMap,normalCoords(UV, 2.0, 2.7, -1.0*waterTimer, 0.05, 0.1, normal3)).rgb - 0.5 + texture2D(normalMap,normalCoords(UV, 2.0, 2.7, waterTimer, 0.04, -0.13, normal4)).rgb - 0.5; float verticalWaterDepth = realWaterDepth * mix(abs(vVec.z), 1.0, 0.2); // an estimate - float shoreOffset = verticalWaterDepth - (normal2.r + mix(0, normalShoreRippleRain.r, rainIntensity) + 0.15)*8; - float fuzzFactor = min(1.0, 1000.0/surfaceDepth) * mix(abs(vVec.z), 1, 0.2); + float shoreOffset = verticalWaterDepth - (normal2.r + mix(0.0, normalShoreRippleRain.r, rainIntensity) + 0.15)*8.0; + float fuzzFactor = min(1.0, 1000.0/surfaceDepth) * mix(abs(vVec.z), 1.0, 0.2); shoreOffset *= fuzzFactor; - shoreOffset = clamp(shoreOffset, 0, 1); + shoreOffset = clamp(mix(shoreOffset, 1.0, clamp(linearDepth / WOBBLY_SHORE_FADE_DISTANCE, 0.0, 1.0)), 0.0, 1.0); gl_FragData[0].xyz = mix(rawRefraction, gl_FragData[0].xyz, shoreOffset); #else gl_FragData[0].xyz = mix(reflection, waterColor, (1.0-fresnel)*0.5) + specular * sunSpec.xyz + vec3(rainRipple.w) * 0.7;