1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-03-03 15:39:41 +00:00

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

@ -161,7 +161,7 @@ namespace CSVRender
}
mWaterGeometry = SceneUtil::createWaterGeometry(size, segments, textureRepeats);
mWaterGeometry->setStateSet(SceneUtil::createSimpleWaterStateSet(Alpha, RenderBin));
mWaterGeometry->setStateSet(SceneUtil::createSimpleWaterStateSet(Alpha, RenderBin, false));
// Add water texture
std::string textureName = Fallback::Map::getString("Water_SurfaceTexture");

View file

@ -21,7 +21,7 @@ add_openmw_dir (mwrender
actors objects renderingmanager animation rotatecontroller sky npcanimation vismask
creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation screenshotmanager
bulletdebugdraw globalmap characterpreview camera viewovershoulder localmap water terrainstorage ripplesimulation
renderbin actoranimation landmanager navmesh actorspaths recastmesh fogmanager objectpaging groundcover
renderbin actoranimation landmanager navmesh actorspaths recastmesh fogmanager objectpaging groundcover postprocessor
)
add_openmw_dir (mwinput

View file

@ -8,7 +8,11 @@
#include "MyGUI_FactoryManager.h"
#include <components/misc/utf8stream.hpp>
#include <components/sceneutil/util.hpp>
#include <components/resource/resourcesystem.hpp>
#include <components/resource/scenemanager.hpp>
#include "../mwbase/world.hpp"
#include "../mwbase/environment.hpp"
#include "../mwbase/windowmanager.hpp"
@ -1217,8 +1221,10 @@ public:
RenderXform renderXform (mCroppedParent, textFormat.mRenderItem->getRenderTarget()->getInfo());
float z = MWBase::Environment::get().getResourceSystem()->getSceneManager()->getReverseZ() ? 1.0 : -1.0;
GlyphStream glyphStream(textFormat.mFont, static_cast<float>(mCoord.left), static_cast<float>(mCoord.top - mViewTop),
-1 /*mNode->getNodeDepth()*/, vertices, renderXform);
z /*mNode->getNodeDepth()*/, vertices, renderXform);
int visit_top = (std::max) (mViewTop, mViewTop + int (renderXform.clipTop ));
int visit_bottom = (std::min) (mViewBottom, mViewTop + int (renderXform.clipBottom));

View file

@ -741,7 +741,7 @@ namespace MWGui
}
// ------------------------------------------------------------------------------------------
MapWindow::MapWindow(CustomMarkerCollection &customMarkers, DragAndDrop* drag, MWRender::LocalMap* localMapRender, SceneUtil::WorkQueue* workQueue)
MapWindow::MapWindow(CustomMarkerCollection &customMarkers, DragAndDrop* drag, MWRender::LocalMap* localMapRender, SceneUtil::WorkQueue* workQueue, bool reverseZ)
: WindowPinnableBase("openmw_map_window.layout")
, LocalMapBase(customMarkers, localMapRender)
, NoDrop(drag, mMainWidget)
@ -751,7 +751,7 @@ namespace MWGui
, mGlobal(Settings::Manager::getBool("global", "Map"))
, mEventBoxGlobal(nullptr)
, mEventBoxLocal(nullptr)
, mGlobalMapRender(new MWRender::GlobalMap(localMapRender->getRoot(), workQueue))
, mGlobalMapRender(new MWRender::GlobalMap(localMapRender->getRoot(), workQueue, reverseZ))
, mEditNoteDialog()
{
static bool registered = false;

View file

@ -222,7 +222,7 @@ namespace MWGui
class MapWindow : public MWGui::WindowPinnableBase, public LocalMapBase, public NoDrop
{
public:
MapWindow(CustomMarkerCollection& customMarkers, DragAndDrop* drag, MWRender::LocalMap* localMapRender, SceneUtil::WorkQueue* workQueue);
MapWindow(CustomMarkerCollection& customMarkers, DragAndDrop* drag, MWRender::LocalMap* localMapRender, SceneUtil::WorkQueue* workQueue, bool reverseZ);
virtual ~MapWindow();
void setCellName(const std::string& cellName);

View file

@ -305,8 +305,9 @@ namespace MWGui
mGuiModeStates[GM_MainMenu] = GuiModeState(menu);
mWindows.push_back(menu);
mLocalMapRender = new MWRender::LocalMap(mViewer->getSceneData()->asGroup());
mMap = new MapWindow(mCustomMarkers, mDragAndDrop, mLocalMapRender, mWorkQueue);
bool reverseZ = mResourceSystem->getSceneManager()->getReverseZ();
mLocalMapRender = new MWRender::LocalMap(mViewer->getSceneData()->asGroup(), reverseZ);
mMap = new MapWindow(mCustomMarkers, mDragAndDrop, mLocalMapRender, mWorkQueue, reverseZ);
mWindows.push_back(mMap);
mMap->renderGlobalMap();
trackWindow(mMap, "map");

View file

@ -168,7 +168,7 @@ namespace MWRender
mCamera->setRenderOrder(osg::Camera::PRE_RENDER);
mCamera->attach(osg::Camera::COLOR_BUFFER, mTexture, 0, 0, false, Settings::Manager::getInt("antialiasing", "Video"));
mCamera->setName("CharacterPreview");
mCamera->setComputeNearFarMode(osg::Camera::COMPUTE_NEAR_FAR_USING_BOUNDING_VOLUMES);
mCamera->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR);
mCamera->setCullMask(~(Mask_UpdateVisitor));
mCamera->setNodeMask(Mask_RenderToTexture);
@ -188,6 +188,9 @@ namespace MWRender
defaultMat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 0.f));
stateset->setAttribute(defaultMat);
osg::ref_ptr<osg::Depth> depth = new osg::Depth;
stateset->setAttributeAndModes(depth, osg::StateAttribute::ON);
SceneUtil::ShadowManager::disableShadowsForStateSet(stateset);
// assign large value to effectively turn off fog

View file

@ -15,6 +15,7 @@
#include <components/debug/debuglog.hpp>
#include <components/sceneutil/workqueue.hpp>
#include <components/sceneutil/util.hpp>
#include <components/esm/globalmap.hpp>
@ -219,13 +220,14 @@ namespace MWRender
osg::ref_ptr<osg::Texture2D> mOverlayTexture;
};
GlobalMap::GlobalMap(osg::Group* root, SceneUtil::WorkQueue* workQueue)
GlobalMap::GlobalMap(osg::Group* root, SceneUtil::WorkQueue* workQueue, bool reverseZ)
: mRoot(root)
, mWorkQueue(workQueue)
, mWidth(0)
, mHeight(0)
, mMinX(0), mMaxX(0)
, mMinY(0), mMaxY(0)
, mReverseZ(reverseZ)
{
mCellSize = Settings::Manager::getInt("global map cell size", "Map");
@ -323,7 +325,7 @@ namespace MWRender
if (texture)
{
osg::ref_ptr<osg::Geometry> geom = createTexturedQuad(srcLeft, srcTop, srcRight, srcBottom);
osg::ref_ptr<osg::Depth> depth = new osg::Depth;
auto depth = SceneUtil::createDepth(mReverseZ);
depth->setWriteMask(0);
osg::StateSet* stateset = geom->getOrCreateStateSet();
stateset->setAttribute(depth);

View file

@ -33,7 +33,7 @@ namespace MWRender
class GlobalMap
{
public:
GlobalMap(osg::Group* root, SceneUtil::WorkQueue* workQueue);
GlobalMap(osg::Group* root, SceneUtil::WorkQueue* workQueue, bool reverseZ);
~GlobalMap();
void render();
@ -126,6 +126,8 @@ namespace MWRender
int mHeight;
int mMinX, mMaxX, mMinY, mMaxY;
bool mReverseZ;
};
}

View file

@ -83,13 +83,14 @@ namespace
namespace MWRender
{
LocalMap::LocalMap(osg::Group* root)
LocalMap::LocalMap(osg::Group* root, bool reverseZ)
: mRoot(root)
, mMapResolution(Settings::Manager::getInt("local map resolution", "Map"))
, mMapWorldSize(Constants::CellSizeInUnits)
, mCellDistance(Constants::CellGridRadius)
, mAngle(0.f)
, mInterior(false)
, mReverseZ(reverseZ)
{
// Increase map resolution, if use UI scaling
float uiScale = MWBase::Environment::get().getWindowManager()->getScalingFactor();
@ -176,7 +177,12 @@ void LocalMap::saveFogOfWar(MWWorld::CellStore* cell)
osg::ref_ptr<osg::Camera> LocalMap::createOrthographicCamera(float x, float y, float width, float height, const osg::Vec3d& upVector, float zmin, float zmax)
{
osg::ref_ptr<osg::Camera> camera (new osg::Camera);
if (mReverseZ)
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);
camera->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR);
camera->setViewMatrixAsLookAt(osg::Vec3d(x, y, zmax + 5), osg::Vec3d(x, y, zmin), upVector);
camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF_INHERIT_VIEWPOINT);
@ -195,6 +201,13 @@ osg::ref_ptr<osg::Camera> LocalMap::createOrthographicCamera(float x, float y, f
osg::ref_ptr<osg::StateSet> stateset = new osg::StateSet;
stateset->setAttribute(new osg::PolygonMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::FILL), osg::StateAttribute::OVERRIDE);
if (mReverseZ)
{
camera->setClearDepth(0.0);
auto depth = SceneUtil::createDepth(mReverseZ);
stateset->setAttributeAndModes(depth, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE);
}
// assign large value to effectively turn off fog
// shaders don't respect glDisable(GL_FOG)
osg::ref_ptr<osg::Fog> fog (new osg::Fog);

View file

@ -36,7 +36,7 @@ namespace MWRender
class LocalMap
{
public:
LocalMap(osg::Group* root);
LocalMap(osg::Group* root, bool reverseZ);
~LocalMap();
/**
@ -156,6 +156,7 @@ namespace MWRender
void setupRenderToTexture(osg::ref_ptr<osg::Camera> camera, int x, int y);
bool mInterior;
bool mReverseZ;
osg::BoundingBox mBounds;
};

View file

@ -370,9 +370,9 @@ void NpcAnimation::setViewMode(NpcAnimation::ViewMode viewMode)
class DepthClearCallback : public osgUtil::RenderBin::DrawCallback
{
public:
DepthClearCallback()
DepthClearCallback(bool reverseZ)
{
mDepth = new osg::Depth;
mDepth = SceneUtil::createDepth(reverseZ);
mDepth->setWriteMask(true);
}
@ -432,7 +432,7 @@ void NpcAnimation::setRenderBin()
if (!prototypeAdded)
{
osg::ref_ptr<osgUtil::RenderBin> depthClearBin (new osgUtil::RenderBin);
depthClearBin->setDrawCallback(new DepthClearCallback);
depthClearBin->setDrawCallback(new DepthClearCallback(mResourceSystem->getSceneManager()->getReverseZ()));
osgUtil::RenderBin::addRenderBinPrototype("DepthClear", depthClearBin);
prototypeAdded = true;
}

View file

@ -661,6 +661,7 @@ namespace MWRender
if (mergeGroup->getNumChildren())
{
SceneUtil::Optimizer optimizer;
optimizer.setReverseZ(mSceneManager->getReverseZ());
if (size > 1/8.f)
{
optimizer.setViewPoint(relativeViewPoint);

View file

@ -0,0 +1,216 @@
#include "postprocessor.hpp"
#include <osg/Group>
#include <osg/Camera>
#include <osg/Callback>
#include <osg/Texture2D>
#include <osg/FrameBufferObject>
#include <osgViewer/Viewer>
#include <components/settings/settings.hpp>
namespace
{
osg::ref_ptr<osg::Geometry> createFullScreenTri()
{
osg::ref_ptr<osg::Geometry> geom = new osg::Geometry;
osg::ref_ptr<osg::Vec3Array> verts = new osg::Vec3Array;
verts->push_back(osg::Vec3f(-1, -1, 0));
verts->push_back(osg::Vec3f(-1, 3, 0));
verts->push_back(osg::Vec3f(3, -1, 0));
geom->setVertexArray(verts);
geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES, 0, 3));
return geom;
}
class CullCallback : public osg::NodeCallback
{
public:
CullCallback(MWRender::PostProcessor* postProcessor)
: mPostProcessor(postProcessor)
, mLastFrameNumber(0)
{}
void operator()(osg::Node* node, osg::NodeVisitor* nv) override
{
osgUtil::RenderStage* renderStage = nv->asCullVisitor()->getCurrentRenderStage();
unsigned int frame = nv->getTraversalNumber();
if (frame != mLastFrameNumber)
{
mLastFrameNumber = frame;
if (!mPostProcessor->getMsaaFbo())
{
renderStage->setFrameBufferObject(mPostProcessor->getFbo());
}
else
{
renderStage->setMultisampleResolveFramebufferObject(mPostProcessor->getFbo());
renderStage->setFrameBufferObject(mPostProcessor->getMsaaFbo());
}
}
traverse(node, nv);
}
MWRender::PostProcessor* mPostProcessor;
unsigned int mLastFrameNumber;
};
struct ResizedCallback : osg::GraphicsContext::ResizedCallback
{
ResizedCallback(MWRender::PostProcessor* postProcessor)
: mPostProcessor(postProcessor)
{
}
void resizedImplementation(osg::GraphicsContext* gc, int x, int y, int width, int height) override
{
mPostProcessor->resize(width, height);
}
MWRender::PostProcessor* mPostProcessor;
};
}
namespace MWRender
{
PostProcessor::PostProcessor(osgViewer::Viewer* viewer, osg::Group* rootNode)
: mViewer(viewer)
, mRootNode(new osg::Group)
{
int width = viewer->getCamera()->getViewport()->width();
int height = viewer->getCamera()->getViewport()->height();
createTexturesAndCamera(width, height);
resize(width, height);
mRootNode->addChild(mHUDCamera);
mRootNode->addChild(rootNode);
mViewer->setSceneData(mRootNode);
// Main camera is treated specially, we need to manually set the FBO and
// resolve FBO during the cull callback.
mViewer->getCamera()->addCullCallback(new CullCallback(this));
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));
}
void PostProcessor::resize(int width, int height)
{
mDepthTex->setTextureSize(width, height);
mSceneTex->setTextureSize(width, height);
mDepthTex->dirtyTextureObject();
mSceneTex->dirtyTextureObject();
int samples = Settings::Manager::getInt("antialiasing", "Video");
mFbo = new osg::FrameBufferObject;
mFbo->setAttachment(osg::Camera::COLOR_BUFFER0, osg::FrameBufferAttachment(mSceneTex));
mFbo->setAttachment(osg::Camera::DEPTH_BUFFER, osg::FrameBufferAttachment(mDepthTex));
// 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.
if (samples > 0)
{
mMsaaFbo = new osg::FrameBufferObject;
osg::ref_ptr<osg::RenderBuffer> colorRB = new osg::RenderBuffer(width, height, mSceneTex->getInternalFormat(), samples);
osg::ref_ptr<osg::RenderBuffer> depthRB = new osg::RenderBuffer(width, height, mDepthTex->getInternalFormat(), samples);
mMsaaFbo->setAttachment(osg::Camera::COLOR_BUFFER0, osg::FrameBufferAttachment(colorRB));
mMsaaFbo->setAttachment(osg::Camera::DEPTH_BUFFER, osg::FrameBufferAttachment(depthRB));
}
double prevWidth = mViewer->getCamera()->getViewport()->width();
double prevHeight = mViewer->getCamera()->getViewport()->height();
double scaleX = prevWidth / width;
double scaleY = prevHeight / height;
mViewer->getCamera()->resize(width,height);
mHUDCamera->resize(width,height);
mViewer->getCamera()->getProjectionMatrix() *= osg::Matrix::scale(scaleX, scaleY, 1.0);
}
void PostProcessor::createTexturesAndCamera(int width, int height)
{
mDepthTex = new osg::Texture2D;
mDepthTex->setTextureSize(width, height);
mDepthTex->setSourceFormat(GL_DEPTH_COMPONENT);
mDepthTex->setSourceType(GL_FLOAT);
mDepthTex->setInternalFormat(GL_DEPTH_COMPONENT32F);
mDepthTex->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture2D::NEAREST);
mDepthTex->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture2D::NEAREST);
mDepthTex->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
mDepthTex->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
mDepthTex->setResizeNonPowerOfTwoHint(false);
mSceneTex = new osg::Texture2D;
mSceneTex->setTextureSize(width, height);
mSceneTex->setSourceFormat(GL_RGB);
mSceneTex->setSourceType(GL_UNSIGNED_BYTE);
mSceneTex->setInternalFormat(GL_RGB);
mSceneTex->setFilter(osg::Texture2D::MIN_FILTER, osg::Texture2D::NEAREST);
mSceneTex->setFilter(osg::Texture2D::MAG_FILTER, osg::Texture2D::NEAREST);
mSceneTex->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
mSceneTex->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
mSceneTex->setResizeNonPowerOfTwoHint(false);
mHUDCamera = new osg::Camera;
mHUDCamera->setReferenceFrame(osg::Camera::ABSOLUTE_RF);
mHUDCamera->setRenderOrder(osg::Camera::POST_RENDER);
mHUDCamera->setClearColor(osg::Vec4(0.45, 0.45, 0.14, 1.0));
mHUDCamera->setProjectionMatrix(osg::Matrix::ortho2D(0, 1, 0, 1));
mHUDCamera->setAllowEventFocus(false);
mHUDCamera->setViewport(0, 0, width, height);
// Shaders calculate correct UV coordinates for our fullscreen triangle
constexpr char vertSrc[] = R"GLSL(
#version 120
varying vec2 uv;
void main()
{
gl_Position = vec4(gl_Vertex.xy, 0.0, 1.0);
uv = gl_Position.xy * 0.5 + 0.5;
}
)GLSL";
constexpr char fragSrc[] = R"GLSL(
#version 120
varying vec2 uv;
uniform sampler2D sceneTex;
void main()
{
gl_FragData[0] = texture2D(sceneTex, uv);
}
)GLSL";
osg::ref_ptr<osg::Shader> vertShader = new osg::Shader(osg::Shader::VERTEX, vertSrc);
osg::ref_ptr<osg::Shader> fragShader = new osg::Shader(osg::Shader::FRAGMENT, fragSrc);
osg::ref_ptr<osg::Program> program = new osg::Program;
program->addShader(vertShader);
program->addShader(fragShader);
mHUDCamera->addChild(createFullScreenTri());
auto* stateset = mHUDCamera->getOrCreateStateSet();
stateset->setTextureAttributeAndModes(0, mSceneTex, osg::StateAttribute::ON);
stateset->setAttributeAndModes(program, osg::StateAttribute::ON);
stateset->addUniform(new osg::Uniform("sceneTex", 0));
stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
stateset->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
}
}

View file

@ -0,0 +1,46 @@
#ifndef OPENMW_MWRENDER_POSTPROCESSOR_H
#define OPENMW_MWRENDER_POSTPROCESSOR_H
#include <osg/ref_ptr>
namespace osg
{
class Texture2D;
class Group;
class FrameBufferObject;
class Camera;
}
namespace osgViewer
{
class Viewer;
}
namespace MWRender
{
class PostProcessor
{
public:
PostProcessor(osgViewer::Viewer* viewer, osg::Group* rootNode);
auto getMsaaFbo() { return mMsaaFbo; }
auto getFbo() { return mFbo; }
void resize(int width, int height);
private:
osgViewer::Viewer* mViewer;
osg::ref_ptr<osg::Group> mRootNode;
osg::ref_ptr<osg::Camera> mHUDCamera;
osg::ref_ptr<osg::FrameBufferObject> mMsaaFbo;
osg::ref_ptr<osg::FrameBufferObject> mFbo;
osg::ref_ptr<osg::Texture2D> mSceneTex;
osg::ref_ptr<osg::Texture2D> mDepthTex;
void createTexturesAndCamera(int width, int height);
};
}
#endif

View file

@ -11,6 +11,8 @@
#include <osg/Group>
#include <osg/UserDataContainer>
#include <osg/ComputeBoundsVisitor>
#include <osg/Depth>
#include <osg/ClipControl>
#include <osgUtil/LineSegmentIntersector>
@ -68,6 +70,7 @@
#include "objectpaging.hpp"
#include "screenshotmanager.hpp"
#include "groundcover.hpp"
#include "postprocessor.hpp"
namespace MWRender
{
@ -198,6 +201,17 @@ namespace MWRender
, mFieldOfViewOverridden(false)
, mFieldOfViewOverride(0.f)
{
auto ext = osg::GLExtensions::Get(0, false);
bool reverseZ = ext && ext->isClipControlSupported;
if (getenv("OPENMW_DISABLE_REVERSEZ") != nullptr)
reverseZ = false;
if (reverseZ)
Log(Debug::Info) << "Using reverse-z depth buffer";
else
Log(Debug::Info) << "Using standard depth buffer";
auto lightingMethod = SceneUtil::LightManager::getLightingMethodFromString(Settings::Manager::getString("lighting method", "Shaders"));
resourceSystem->getSceneManager()->setParticleSystemMask(MWRender::Mask_ParticleSystem);
@ -216,6 +230,7 @@ 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<SceneUtil::LightManager> sceneRoot = new SceneUtil::LightManager(lightingMethod == SceneUtil::LightingMethod::FFP);
@ -242,7 +257,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()));
mShadowManager.reset(new SceneUtil::ShadowManager(sceneRoot, mRootNode, shadowCastingTraversalMask, indoorShadowCastingTraversalMask, mResourceSystem->getSceneManager()->getShaderManager(), reverseZ));
Shader::ShaderManager::DefineMap shadowDefines = mShadowManager->getShadowDefines();
Shader::ShaderManager::DefineMap lightDefines = sceneRoot->getLightDefines();
@ -267,6 +282,8 @@ namespace MWRender
globalDefines["groundcoverStompMode"] = std::to_string(std::clamp(Settings::Manager::getInt("stomp mode", "Groundcover"), 0, 2));
globalDefines["groundcoverStompIntensity"] = std::to_string(std::clamp(Settings::Manager::getInt("stomp intensity", "Groundcover"), 0, 2));
globalDefines["reverseZ"] = reverseZ ? "1" : "0";
// It is unnecessary to stop/start the viewer as no frames are being rendered yet.
mResourceSystem->getSceneManager()->getShaderManager().setGlobalDefines(globalDefines);
@ -413,6 +430,7 @@ 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"));
mNearClip = Settings::Manager::getFloat("near clip", "Camera");
@ -434,6 +452,18 @@ namespace MWRender
mUniformNear = mRootNode->getOrCreateStateSet()->getUniform("near");
mUniformFar = mRootNode->getOrCreateStateSet()->getUniform("far");
if (reverseZ)
{
auto depth = SceneUtil::createDepth(reverseZ);
osg::ref_ptr<osg::ClipControl> 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(clipcontrol, osg::StateAttribute::ON);
}
mPostProcessor.reset(new PostProcessor(viewer, mRootNode));
updateProjectionMatrix();
}
@ -1066,6 +1096,19 @@ namespace MWRender
float fov = mFieldOfView;
if (mFieldOfViewOverridden)
fov = mFieldOfViewOverride;
if (mResourceSystem->getSceneManager()->getReverseZ())
{
mViewer->getCamera()->setProjectionMatrix(SceneUtil::getReversedZProjectionMatrixAsPerspectiveInf(fov, aspect, mNearClip));
float linearFac = -mNearClip / (mViewDistance - mNearClip) - 1.0;
mRootNode->getOrCreateStateSet()->getOrCreateUniform("linearFac", osg::Uniform::FLOAT, 1)->set(linearFac);
osg::Matrix shadowProj = osg::Matrix::perspective(fov, aspect, mNearClip, mViewDistance);
mViewer->getCamera()->setUserValue("shadowProj", shadowProj);
mViewer->getCamera()->setUserValue("near", static_cast<double>(mNearClip));
mViewer->getCamera()->setUserValue("far", static_cast<double>(mViewDistance));
}
else
mViewer->getCamera()->setProjectionMatrixAsPerspective(fov, aspect, mNearClip, mViewDistance);
mUniformNear->set(mNearClip);

View file

@ -89,6 +89,7 @@ namespace MWRender
class RecastMesh;
class ObjectPaging;
class Groundcover;
class PostProcessor;
class RenderingManager : public MWRender::RenderingInterface
{
@ -287,6 +288,7 @@ namespace MWRender
std::unique_ptr<ScreenshotManager> mScreenshotManager;
std::unique_ptr<EffectManager> mEffectManager;
std::unique_ptr<SceneUtil::ShadowManager> mShadowManager;
std::unique_ptr<PostProcessor> mPostProcessor;
osg::ref_ptr<NpcAnimation> mPlayerAnimation;
osg::ref_ptr<SceneUtil::PositionAttitudeTransform> mPlayerNode;
std::unique_ptr<Camera> mCamera;

View file

@ -16,6 +16,7 @@
#include <components/resource/resourcesystem.hpp>
#include <components/resource/scenemanager.hpp>
#include <components/fallback/fallback.hpp>
#include <components/sceneutil/util.hpp>
#include "vismask.hpp"
@ -55,7 +56,7 @@ namespace
stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
stateset->setTextureAttributeAndModes(0, textures[0], osg::StateAttribute::ON);
osg::ref_ptr<osg::Depth> depth (new osg::Depth);
auto depth = SceneUtil::createDepth(resourceSystem->getSceneManager()->getReverseZ());
depth->setWriteMask(false);
stateset->setAttributeAndModes(depth, osg::StateAttribute::ON);

View file

@ -473,7 +473,7 @@ const float CelestialBody::mDistance = 1000.0f;
class Sun : public CelestialBody
{
public:
Sun(osg::Group* parentNode, Resource::ImageManager& imageManager)
Sun(osg::Group* parentNode, Resource::ImageManager& imageManager, bool reverseZ)
: CelestialBody(parentNode, 1.0f, 1, Mask_Sun)
, mUpdater(new Updater)
{
@ -502,8 +502,8 @@ public:
mTransform->addChild(queryNode);
mOcclusionQueryVisiblePixels = createOcclusionQueryNode(queryNode, true);
mOcclusionQueryTotalPixels = createOcclusionQueryNode(queryNode, false);
mOcclusionQueryVisiblePixels = createOcclusionQueryNode(queryNode, true, reverseZ);
mOcclusionQueryTotalPixels = createOcclusionQueryNode(queryNode, false, reverseZ);
createSunFlash(imageManager);
createSunGlare();
@ -556,7 +556,7 @@ private:
};
/// @param queryVisible If true, queries the amount of visible pixels. If false, queries the total amount of pixels.
osg::ref_ptr<osg::OcclusionQueryNode> createOcclusionQueryNode(osg::Group* parent, bool queryVisible)
osg::ref_ptr<osg::OcclusionQueryNode> createOcclusionQueryNode(osg::Group* parent, bool queryVisible, bool reverseZ)
{
osg::ref_ptr<osg::OcclusionQueryNode> oqn = new osg::OcclusionQueryNode;
oqn->setQueriesEnabled(true);
@ -594,13 +594,13 @@ private:
osg::StateSet* queryStateSet = new osg::StateSet;
if (queryVisible)
{
osg::ref_ptr<osg::Depth> depth (new osg::Depth);
depth->setFunction(osg::Depth::LEQUAL);
auto depth = SceneUtil::createDepth(reverseZ);
// 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.
depth->setZNear(1.0);
depth->setZFar(1.0);
float far = reverseZ ? 0.0 : 1.0;
depth->setZNear(far);
depth->setZFar(far);
depth->setWriteMask(false);
queryStateSet->setAttributeAndModes(depth, osg::StateAttribute::ON);
}
@ -1188,7 +1188,8 @@ void SkyManager::create()
mAtmosphereNightUpdater = new AtmosphereNightUpdater(mSceneManager->getImageManager());
atmosphereNight->addUpdateCallback(mAtmosphereNightUpdater);
mSun.reset(new Sun(mEarlyRenderBinRoot, *mSceneManager->getImageManager()));
bool reverseZ = mSceneManager->getReverseZ();
mSun.reset(new Sun(mEarlyRenderBinRoot, *mSceneManager->getImageManager(), reverseZ));
mMasser.reset(new Moon(mEarlyRenderBinRoot, *mSceneManager->getImageManager(), Fallback::Map::getFloat("Moons_Masser_Size")/125, Moon::Type_Masser));
mSecunda.reset(new Moon(mEarlyRenderBinRoot, *mSceneManager->getImageManager(), Fallback::Map::getFloat("Moons_Secunda_Size")/125, Moon::Type_Secunda));
@ -1209,7 +1210,7 @@ void SkyManager::create()
mCloudMesh2->addUpdateCallback(mCloudUpdater2);
mCloudMesh2->setNodeMask(0);
osg::ref_ptr<osg::Depth> depth = new osg::Depth;
auto depth = SceneUtil::createDepth(reverseZ);
depth->setWriteMask(false);
mEarlyRenderBinRoot->getOrCreateStateSet()->setAttributeAndModes(depth, osg::StateAttribute::ON);
mEarlyRenderBinRoot->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON);

View file

@ -273,6 +273,7 @@ public:
void setDefaults(osg::Camera* camera) override
{
camera->setClearDepth(1.0);
camera->setReferenceFrame(osg::Camera::RELATIVE_RF);
camera->setSmallFeatureCullingPixelSize(Settings::Manager::getInt("small feature culling pixel size", "Water"));
camera->setName("RefractionCamera");
@ -338,6 +339,7 @@ public:
void setDefaults(osg::Camera* camera) override
{
camera->setClearDepth(1.0);
camera->setReferenceFrame(osg::Camera::RELATIVE_RF);
camera->setSmallFeatureCullingPixelSize(Settings::Manager::getInt("small feature culling pixel size", "Water"));
camera->setName("ReflectionCamera");
@ -544,7 +546,7 @@ osg::Node* Water::getRefractionNode()
void Water::createSimpleWaterStateSet(osg::Node* node, float alpha)
{
osg::ref_ptr<osg::StateSet> stateset = SceneUtil::createSimpleWaterStateSet(alpha, MWRender::RenderBin_Water);
osg::ref_ptr<osg::StateSet> stateset = SceneUtil::createSimpleWaterStateSet(alpha, MWRender::RenderBin_Water, mResourceSystem->getSceneManager()->getReverseZ());
node->setStateSet(stateset);
node->setUpdateCallback(nullptr);

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,15 +1006,22 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv)
osg::CullSettings::ComputeNearFarMode cachedNearFarMode = cv.getComputeNearFarMode();
double minZNear = 0.0;
double maxZFar = dbl_max;
bool orthographicViewFrustum;
if (_reverseZ)
{
cv.getCurrentCamera()->getUserValue("near", minZNear);
cv.getCurrentCamera()->getUserValue("far", maxZFar);
orthographicViewFrustum = isOrthographicViewFrustum(shadowProj);
}
else
{
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;
orthographicViewFrustum = isOrthographicViewFrustum(viewProjectionMatrix);
if (cachedNearFarMode==osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR)
{
@ -1006,7 +1034,6 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv)
{
viewProjectionMatrix.getFrustum(left, right, bottom, top, minZNear, maxZFar);
}
OSG_INFO<<"minZNear="<<minZNear<<", maxZFar="<<maxZFar<<std::endl;
}
// set the compute near/far mode to the highest quality setting to ensure we push the near plan out as far as possible
@ -1014,6 +1041,7 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv)
{
cv.setComputeNearFarMode(settings->getComputeNearFarModeOverride());
}
}
// 1. Traverse main scene graph
auto* shadowReceiverStateSet = vdd->getStateSet(cv.getTraversalNumber());
@ -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,6 +1094,7 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv)
}
// return compute near far mode back to it's original settings
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);

View file

@ -13,6 +13,7 @@ set(SHADER_FILES
water_fragment.glsl
water_nm.png
alpha.glsl
depth.glsl
objects_vertex.glsl
objects_fragment.glsl
terrain_vertex.glsl

12
files/shaders/depth.glsl Normal file
View file

@ -0,0 +1,12 @@
#if @reverseZ
uniform float linearFac;
#endif
float getLinearDepth(in vec4 viewPos)
{
#if @reverseZ
return linearFac*viewPos.z;
#else
return gl_Position.z;
#endif
}

View file

@ -39,6 +39,7 @@ centroid varying vec3 shadowDiffuseLighting;
#include "shadows_vertex.glsl"
#include "lighting.glsl"
#include "depth.glsl"
uniform float osg_SimulationTime;
uniform mat4 osg_ViewMatrixInverse;
@ -143,7 +144,7 @@ void main(void)
else
gl_Position = gl_ProjectionMatrix * viewPos;
linearDepth = gl_Position.z;
linearDepth = getLinearDepth(viewPos);
#if (!PER_PIXEL_LIGHTING || @shadows_enabled)
vec3 viewNormal = normalize((gl_NormalMatrix * rotation3(rotation) * gl_Normal).xyz);

View file

@ -32,6 +32,7 @@ varying vec3 passNormal;
#include "vertexcolors.glsl"
#include "shadows_vertex.glsl"
#include "lighting.glsl"
#include "depth.glsl"
void main(void)
{
@ -40,7 +41,7 @@ void main(void)
vec4 viewPos = (gl_ModelViewMatrix * gl_Vertex);
gl_ClipVertex = viewPos;
euclideanDepth = length(viewPos.xyz);
linearDepth = gl_Position.z;
linearDepth = getLinearDepth(viewPos);
#if @diffuseMap
diffuseMapUV = (gl_TextureMatrix[@diffuseMapUV] * gl_MultiTexCoord@diffuseMapUV).xy;

View file

@ -17,6 +17,7 @@ varying vec3 passViewPos;
varying float passFalloff;
#include "vertexcolors.glsl"
#include "depth.glsl"
void main(void)
{
@ -27,7 +28,7 @@ void main(void)
#if @radialFog
euclideanDepth = length(viewPos.xyz);
#else
linearDepth = gl_Position.z;
linearDepth = getLinearDepth(viewPos);
#endif
#if @diffuseMap

View file

@ -62,6 +62,7 @@ varying vec3 passNormal;
#include "shadows_vertex.glsl"
#include "lighting.glsl"
#include "depth.glsl"
void main(void)
{
@ -70,7 +71,7 @@ void main(void)
vec4 viewPos = (gl_ModelViewMatrix * gl_Vertex);
gl_ClipVertex = viewPos;
euclideanDepth = length(viewPos.xyz);
linearDepth = gl_Position.z;
linearDepth = getLinearDepth(viewPos);
#if (@envMap || !PER_PIXEL_LIGHTING || @shadows_enabled)
vec3 viewNormal = normalize((gl_NormalMatrix * gl_Normal).xyz);

View file

@ -25,6 +25,7 @@ varying vec3 passNormal;
#include "shadows_vertex.glsl"
#include "lighting.glsl"
#include "depth.glsl"
void main(void)
{
@ -33,7 +34,7 @@ void main(void)
vec4 viewPos = (gl_ModelViewMatrix * gl_Vertex);
gl_ClipVertex = viewPos;
euclideanDepth = length(viewPos.xyz);
linearDepth = gl_Position.z;
linearDepth = getLinearDepth(viewPos);
#if (!PER_PIXEL_LIGHTING || @shadows_enabled)
vec3 viewNormal = normalize((gl_NormalMatrix * gl_Normal).xyz);

View file

@ -158,11 +158,14 @@ uniform float rainIntensity;
float frustumDepth;
float linearizeDepth(float depth)
{
{
#if @reverseZ
depth = 1.0 - depth;
#endif
float z_n = 2.0 * depth - 1.0;
depth = 2.0 * near * far / (far + near - z_n * frustumDepth);
return depth;
}
}
void main(void)
{

View file

@ -5,6 +5,7 @@ varying vec4 position;
varying float linearDepth;
#include "shadows_vertex.glsl"
#include "depth.glsl"
void main(void)
{
@ -20,7 +21,8 @@ void main(void)
position = gl_Vertex;
linearDepth = gl_Position.z;
vec4 viewPos = gl_ModelViewMatrix * gl_Vertex;
linearDepth = getLinearDepth(viewPos);
setupShadowCoords(gl_ModelViewMatrix * gl_Vertex, normalize((gl_NormalMatrix * gl_Normal).xyz));
setupShadowCoords(viewPos, normalize((gl_NormalMatrix * gl_Normal).xyz));
}