initial reverse-z depth implementation

This commit is contained in:
glassmancody.info 2021-06-01 12:15:25 -07:00
parent 10d100f205
commit 70fac33940
46 changed files with 614 additions and 92 deletions

View file

@ -226,6 +226,18 @@ namespace NifOsg
return sIntersectionDisabledNodeMask;
}
bool Loader::sReverseZ = false;
void Loader::setReverseZ(bool reverseZ)
{
sReverseZ = reverseZ;
}
bool Loader::getReverseZ()
{
return sReverseZ;
}
class LoaderImpl
{
public:
@ -1823,7 +1835,7 @@ namespace NifOsg
// Depth test flag
stateset->setMode(GL_DEPTH_TEST, zprop->flags&1 ? osg::StateAttribute::ON
: osg::StateAttribute::OFF);
osg::ref_ptr<osg::Depth> depth = new osg::Depth;
auto depth = SceneUtil::createDepth(Loader::getReverseZ());
// Depth write flag
depth->setWriteMask((zprop->flags>>1)&1);
// Morrowind ignores depth test function

View file

@ -51,10 +51,14 @@ 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;
};
}

View file

@ -275,6 +275,16 @@ namespace Resource
return mClampLighting;
}
void SceneManager::setReverseZ(bool reverseZ)
{
mReverseZ = reverseZ;
}
bool SceneManager::getReverseZ() const
{
return mReverseZ;
}
void SceneManager::setAutoUseNormalMaps(bool use)
{
mAutoUseNormalMaps = use;

View file

@ -92,6 +92,9 @@ namespace Resource
void setClampLighting(bool clamp);
bool getClampLighting() const;
void setReverseZ(bool reverseZ);
bool getReverseZ() const;
/// @see ShaderVisitor::setAutoUseNormalMaps
void setAutoUseNormalMaps(bool use);
@ -202,6 +205,7 @@ namespace Resource
SceneUtil::LightingMethod mLightingMethod;
SceneUtil::LightManager::SupportedMethods mSupportedLightingMethods;
bool mConvertAlphaTestToAlphaToCoverage;
bool mReverseZ;
osg::ref_ptr<MultiObjectCache> mInstanceCache;

View file

@ -23,10 +23,13 @@
#include <osg/Geometry>
#include <osg/io_utils>
#include <osg/Depth>
#include <osg/ClipControl>
#include <sstream>
#include "shadowsbin.hpp"
#include <components/sceneutil/util.hpp>
namespace {
using namespace osgShadow;
@ -347,6 +350,11 @@ void VDSMCameraCullCallback::operator()(osg::Node* node, osg::NodeVisitor* nv)
_projectionMatrix = cv->getProjectionMatrix();
}
bool isOrthographicViewFrustum(const osg::Matrix& m)
{
return m(0,3)==0.0 && m(1,3)==0.0 && m(2,3)==0.0;
}
} // namespace
MWShadowTechnique::ComputeLightSpaceBounds::ComputeLightSpaceBounds(osg::Viewport* viewport, const osg::Matrixd& projectionMatrix, osg::Matrixd& viewMatrix) :
@ -890,6 +898,16 @@ 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
@ -970,6 +988,9 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv)
return;
}
osg::Matrix shadowProj;
cv.getCurrentCamera()->getUserValue("shadowProj", shadowProj);
ViewDependentData* vdd = getViewDependentData(&cv);
if (!vdd)
@ -985,34 +1006,41 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv)
osg::CullSettings::ComputeNearFarMode cachedNearFarMode = cv.getComputeNearFarMode();
osg::RefMatrix& viewProjectionMatrix = *cv.getProjectionMatrix();
// check whether this main views projection is perspective or orthographic
bool orthographicViewFrustum = viewProjectionMatrix(0,3)==0.0 &&
viewProjectionMatrix(1,3)==0.0 &&
viewProjectionMatrix(2,3)==0.0;
double minZNear = 0.0;
double maxZFar = dbl_max;
bool orthographicViewFrustum;
if (cachedNearFarMode==osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR)
if (_reverseZ)
{
double left, right, top, bottom;
if (orthographicViewFrustum)
{
viewProjectionMatrix.getOrtho(left, right, bottom, top, minZNear, maxZFar);
}
else
{
viewProjectionMatrix.getFrustum(left, right, bottom, top, minZNear, maxZFar);
}
OSG_INFO<<"minZNear="<<minZNear<<", maxZFar="<<maxZFar<<std::endl;
cv.getCurrentCamera()->getUserValue("near", minZNear);
cv.getCurrentCamera()->getUserValue("far", maxZFar);
orthographicViewFrustum = isOrthographicViewFrustum(shadowProj);
}
// set the compute near/far mode to the highest quality setting to ensure we push the near plan out as far as possible
if (settings->getComputeNearFarModeOverride()!=osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR)
else
{
cv.setComputeNearFarMode(settings->getComputeNearFarModeOverride());
osg::RefMatrix& viewProjectionMatrix = *cv.getProjectionMatrix();
// check whether this main views projection is perspective or orthographic
orthographicViewFrustum = isOrthographicViewFrustum(viewProjectionMatrix);
if (cachedNearFarMode==osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR)
{
double left, right, top, bottom;
if (orthographicViewFrustum)
{
viewProjectionMatrix.getOrtho(left, right, bottom, top, minZNear, maxZFar);
}
else
{
viewProjectionMatrix.getFrustum(left, right, bottom, top, minZNear, maxZFar);
}
}
// set the compute near/far mode to the highest quality setting to ensure we push the near plan out as far as possible
if (settings->getComputeNearFarModeOverride()!=osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR)
{
cv.setComputeNearFarMode(settings->getComputeNearFarModeOverride());
}
}
// 1. Traverse main scene graph
@ -1024,6 +1052,9 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv)
cv.popStateSet();
if (_reverseZ)
cv.pushProjectionMatrix(new osg::RefMatrix(shadowProj));
if (cv.getComputeNearFarMode()!=osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR)
{
OSG_INFO<<"Just done main subgraph traversak"<<std::endl;
@ -1063,7 +1094,8 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv)
}
// return compute near far mode back to it's original settings
cv.setComputeNearFarMode(cachedNearFarMode);
if (!_reverseZ)
cv.setComputeNearFarMode(cachedNearFarMode);
OSG_INFO<<"frustum.eye="<<frustum.eye<<", frustum.centerNearPlane, "<<frustum.centerNearPlane<<" distance = "<<(frustum.eye-frustum.centerNearPlane).length()<<std::endl;
@ -1448,6 +1480,8 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv)
prepareStateSetForRenderingShadow(*vdd, cv.getTraversalNumber());
}
if (_reverseZ)
cv.popProjectionMatrix();
// OSG_NOTICE<<"End of shadow setup Projection matrix "<<*cv.getProjectionMatrix()<<std::endl;
}
@ -1636,6 +1670,9 @@ void MWShadowTechnique::createShaders()
_shadowCastingStateSet->addUniform(new osg::Uniform("alphaTestShadows", false));
osg::ref_ptr<osg::Depth> depth = new osg::Depth;
depth->setWriteMask(true);
osg::ref_ptr<osg::ClipControl> clipcontrol = new osg::ClipControl(osg::ClipControl::LOWER_LEFT, osg::ClipControl::NEGATIVE_ONE_TO_ONE);
if (_reverseZ)
_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);

View file

@ -85,6 +85,10 @@ 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
@ -266,6 +270,8 @@ namespace SceneUtil {
float _shadowFadeStart = 0.0;
bool _reverseZ = false;
class DebugHUD final : public osg::Referenced
{
public:

View file

@ -40,6 +40,8 @@
#include <iterator>
#include <components/sceneutil/util.hpp>
using namespace osgUtil;
namespace SceneUtil
@ -107,6 +109,7 @@ 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);
@ -1560,7 +1563,7 @@ bool Optimizer::MergeGeometryVisitor::mergeGroup(osg::Group& group)
}
if (_alphaBlendingActive && _mergeAlphaBlending && !geom->getStateSet())
{
osg::Depth* d = new osg::Depth;
auto d = createDepth(_reverseZ);
d->setWriteMask(0);
geom->getOrCreateStateSet()->setAttribute(d);
}

View file

@ -65,7 +65,7 @@ class Optimizer
public:
Optimizer() : _mergeAlphaBlending(false) {}
Optimizer() : _mergeAlphaBlending(false), _reverseZ(false) {}
virtual ~Optimizer() {}
enum OptimizationOptions
@ -119,6 +119,7 @@ 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.*/
@ -257,6 +258,7 @@ class Optimizer
osg::Vec3f _viewPoint;
bool _mergeAlphaBlending;
bool _reverseZ;
public:
@ -377,12 +379,18 @@ class Optimizer
/// default to traversing all children.
MergeGeometryVisitor(Optimizer* optimizer=0) :
BaseOptimizerVisitor(optimizer, MERGE_GEOMETRY),
_targetMaximumNumberOfVertices(10000), _alphaBlendingActive(false), _mergeAlphaBlending(false) {}
_targetMaximumNumberOfVertices(10000), _alphaBlendingActive(false), _mergeAlphaBlending(false), _reverseZ(false) {}
void setMergeAlphaBlending(bool merge)
{
_mergeAlphaBlending = merge;
}
void setReverseZ(bool reverseZ)
{
_reverseZ = reverseZ;
}
void setViewPoint(const osg::Vec3f& viewPoint)
{
_viewPoint = viewPoint;
@ -421,6 +429,7 @@ class Optimizer
std::vector<osg::StateSet*> _stateSetStack;
bool _alphaBlendingActive;
bool _mergeAlphaBlending;
bool _reverseZ;
osg::Vec3f _viewPoint;
};

View file

@ -94,10 +94,12 @@ namespace SceneUtil
}
}
ShadowManager::ShadowManager(osg::ref_ptr<osg::Group> sceneRoot, osg::ref_ptr<osg::Group> rootNode, unsigned int outdoorShadowCastingMask, unsigned int indoorShadowCastingMask, Shader::ShaderManager &shaderManager) : mShadowedScene(new osgShadow::ShadowedScene),
mShadowTechnique(new MWShadowTechnique),
mOutdoorShadowCastingMask(outdoorShadowCastingMask),
mIndoorShadowCastingMask(indoorShadowCastingMask)
ShadowManager::ShadowManager(osg::ref_ptr<osg::Group> sceneRoot, osg::ref_ptr<osg::Group> rootNode, unsigned int outdoorShadowCastingMask, unsigned int indoorShadowCastingMask, Shader::ShaderManager &shaderManager, bool reverseZ)
: mShadowedScene(new osgShadow::ShadowedScene)
, mReverseZ(reverseZ)
, mShadowTechnique(new MWShadowTechnique)
, mOutdoorShadowCastingMask(outdoorShadowCastingMask)
, mIndoorShadowCastingMask(indoorShadowCastingMask)
{
mShadowedScene->setShadowTechnique(mShadowTechnique);
@ -108,6 +110,9 @@ namespace SceneUtil
mShadowSettings = mShadowedScene->getShadowSettings();
setupShadowSettings();
if (mReverseZ)
mShadowTechnique->enableReverseZ();
mShadowTechnique->setupCastingShader(shaderManager);
enableOutdoorMode();
@ -180,4 +185,9 @@ namespace SceneUtil
mShadowTechnique->enableShadows();
mShadowSettings->setCastsShadowTraversalMask(mOutdoorShadowCastingMask);
}
bool ShadowManager::getReverseZ() const
{
return mReverseZ;
}
}

View file

@ -17,7 +17,7 @@ namespace SceneUtil
static Shader::ShaderManager::DefineMap getShadowsDisabledDefines();
ShadowManager(osg::ref_ptr<osg::Group> sceneRoot, osg::ref_ptr<osg::Group> rootNode, unsigned int outdoorShadowCastingMask, unsigned int indoorShadowCastingMask, Shader::ShaderManager &shaderManager);
ShadowManager(osg::ref_ptr<osg::Group> sceneRoot, osg::ref_ptr<osg::Group> rootNode, unsigned int outdoorShadowCastingMask, unsigned int indoorShadowCastingMask, Shader::ShaderManager &shaderManager, bool reverseZ);
void setupShadowSettings();
@ -26,8 +26,11 @@ namespace SceneUtil
void enableIndoorMode();
void enableOutdoorMode();
bool getReverseZ() const;
protected:
bool mEnableShadows;
bool mReverseZ;
osg::ref_ptr<osgShadow::ShadowedScene> mShadowedScene;
osg::ref_ptr<osgShadow::ShadowSettings> mShadowSettings;

View file

@ -285,4 +285,43 @@ bool attachAlphaToCoverageFriendlyFramebufferToCamera(osg::Camera* camera, osg::
return addMSAAIntermediateTarget;
}
osg::ref_ptr<osg::Depth> createDepth(bool reverseZ)
{
static osg::Depth::Function func = reverseZ ? osg::Depth::GEQUAL : osg::Depth::LEQUAL;
return new osg::Depth(func);
}
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, far/(far-near)-1.0, -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
);
}
}

View file

@ -7,6 +7,7 @@
#include <osg/NodeCallback>
#include <osg/Texture2D>
#include <osg/Vec4f>
#include <osg/Depth>
#include <components/resource/resourcesystem.hpp>
@ -64,6 +65,23 @@ 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);
// Returns a suitable depth state attribute dependent on whether a reverse-z
// depth buffer is in use.
osg::ref_ptr<osg::Depth> createDepth(bool reverseZ);
// 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);
}
#endif

View file

@ -5,6 +5,8 @@
#include <osg/Material>
#include <osg/StateSet>
#include "util.hpp"
namespace SceneUtil
{
// disable nonsense test against a worldsize bb what will always pass
@ -62,7 +64,7 @@ namespace SceneUtil
return waterGeom;
}
osg::ref_ptr<osg::StateSet> createSimpleWaterStateSet(float alpha, int renderBin)
osg::ref_ptr<osg::StateSet> createSimpleWaterStateSet(float alpha, int renderBin, bool reverseZ)
{
osg::ref_ptr<osg::StateSet> stateset (new osg::StateSet);
@ -76,7 +78,7 @@ namespace SceneUtil
stateset->setMode(GL_BLEND, osg::StateAttribute::ON);
stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
osg::ref_ptr<osg::Depth> depth (new osg::Depth);
auto depth = createDepth(reverseZ);
depth->setWriteMask(false);
stateset->setAttributeAndModes(depth, osg::StateAttribute::ON);

View file

@ -13,7 +13,7 @@ namespace SceneUtil
{
osg::ref_ptr<osg::Geometry> createWaterGeometry(float size, int segments, float textureRepeats);
osg::ref_ptr<osg::StateSet> createSimpleWaterStateSet(float alpha, int renderBin);
osg::ref_ptr<osg::StateSet> createSimpleWaterStateSet(float alpha, int renderBin, bool reverseZ);
}
#endif

View file

@ -163,7 +163,7 @@ std::vector<osg::ref_ptr<osg::StateSet> > ChunkManager::createPasses(float chunk
float blendmapScale = mStorage->getBlendmapScale(chunkSize);
return ::Terrain::createPasses(useShaders, &mSceneManager->getShaderManager(), layers, blendmapTextures, blendmapScale, blendmapScale);
return ::Terrain::createPasses(useShaders, mSceneManager, layers, blendmapTextures, blendmapScale, blendmapScale);
}
osg::ref_ptr<osg::Node> ChunkManager::createChunk(float chunkSize, const osg::Vec2f &chunkCenter, unsigned char lod, unsigned int lodFlags, bool compile)
@ -219,7 +219,7 @@ osg::ref_ptr<osg::Node> 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->getShaderManager(), std::vector<TextureLayer>(1, layer), std::vector<osg::ref_ptr<osg::Texture2D> >(), 1.f, 1.f));
geometry->setPasses(::Terrain::createPasses(mSceneManager->getForceShaders() || !mSceneManager->getClampLighting(), mSceneManager, std::vector<TextureLayer>(1, layer), std::vector<osg::ref_ptr<osg::Texture2D> >(), 1.f, 1.f));
}
else
{

View file

@ -7,7 +7,9 @@
#include <osg/TexMat>
#include <osg/BlendFunc>
#include <components/resource/scenemanager.hpp>
#include <components/shader/shadermanager.hpp>
#include <components/sceneutil/util.hpp>
#include <mutex>
@ -95,19 +97,18 @@ namespace
class LequalDepth
{
public:
static const osg::ref_ptr<osg::Depth>& value()
static const osg::ref_ptr<osg::Depth>& value(bool reverseZ)
{
static LequalDepth instance;
static LequalDepth instance(reverseZ);
return instance.mValue;
}
private:
osg::ref_ptr<osg::Depth> mValue;
LequalDepth()
: mValue(new osg::Depth)
LequalDepth(bool reverseZ)
: mValue(SceneUtil::createDepth(reverseZ))
{
mValue->setFunction(osg::Depth::LEQUAL);
}
};
@ -170,9 +171,10 @@ namespace
namespace Terrain
{
std::vector<osg::ref_ptr<osg::StateSet> > createPasses(bool useShaders, Shader::ShaderManager* shaderManager, const std::vector<TextureLayer> &layers,
std::vector<osg::ref_ptr<osg::StateSet> > createPasses(bool useShaders, Resource::SceneManager* sceneManager, const std::vector<TextureLayer> &layers,
const std::vector<osg::ref_ptr<osg::Texture2D> > &blendmaps, int blendmapScale, float layerTileSize)
{
Shader::ShaderManager* shaderManager = &sceneManager->getShaderManager();
std::vector<osg::ref_ptr<osg::StateSet> > passes;
unsigned int blendmapIndex = 0;
@ -195,7 +197,7 @@ namespace Terrain
else
{
stateset->setAttributeAndModes(BlendFuncFirst::value(), osg::StateAttribute::ON);
stateset->setAttributeAndModes(LequalDepth::value(), osg::StateAttribute::ON);
stateset->setAttributeAndModes(LequalDepth::value(sceneManager->getReverseZ()), osg::StateAttribute::ON);
}
}
@ -238,7 +240,7 @@ namespace Terrain
if (!vertexShader || !fragmentShader)
{
// Try again without shader. Error already logged by above
return createPasses(false, shaderManager, layers, blendmaps, blendmapScale, layerTileSize);
return createPasses(false, sceneManager, layers, blendmaps, blendmapScale, layerTileSize);
}
stateset->setAttributeAndModes(shaderManager->getProgram(vertexShader, fragmentShader));

View file

@ -10,9 +10,9 @@ namespace osg
class Texture2D;
}
namespace Shader
namespace Resource
{
class ShaderManager;
class SceneManager;
}
namespace Terrain
@ -26,7 +26,7 @@ namespace Terrain
bool mSpecular;
};
std::vector<osg::ref_ptr<osg::StateSet> > createPasses(bool useShaders, Shader::ShaderManager* shaderManager,
std::vector<osg::ref_ptr<osg::StateSet> > createPasses(bool useShaders, Resource::SceneManager* sceneManager,
const std::vector<TextureLayer>& layers,
const std::vector<osg::ref_ptr<osg::Texture2D> >& blendmaps, int blendmapScale, float layerTileSize);