1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-03-03 15:09:39 +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 = SceneUtil::createWaterGeometry(size, segments, textureRepeats);
mWaterGeometry->setStateSet(SceneUtil::createSimpleWaterStateSet(Alpha, RenderBin)); mWaterGeometry->setStateSet(SceneUtil::createSimpleWaterStateSet(Alpha, RenderBin, false));
// Add water texture // Add water texture
std::string textureName = Fallback::Map::getString("Water_SurfaceTexture"); 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 actors objects renderingmanager animation rotatecontroller sky npcanimation vismask
creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation screenshotmanager creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation screenshotmanager
bulletdebugdraw globalmap characterpreview camera viewovershoulder localmap water terrainstorage ripplesimulation 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 add_openmw_dir (mwinput

View file

@ -8,7 +8,11 @@
#include "MyGUI_FactoryManager.h" #include "MyGUI_FactoryManager.h"
#include <components/misc/utf8stream.hpp> #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/environment.hpp"
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
@ -1217,8 +1221,10 @@ public:
RenderXform renderXform (mCroppedParent, textFormat.mRenderItem->getRenderTarget()->getInfo()); 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), 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_top = (std::max) (mViewTop, mViewTop + int (renderXform.clipTop ));
int visit_bottom = (std::min) (mViewBottom, mViewTop + int (renderXform.clipBottom)); 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") : WindowPinnableBase("openmw_map_window.layout")
, LocalMapBase(customMarkers, localMapRender) , LocalMapBase(customMarkers, localMapRender)
, NoDrop(drag, mMainWidget) , NoDrop(drag, mMainWidget)
@ -751,7 +751,7 @@ namespace MWGui
, mGlobal(Settings::Manager::getBool("global", "Map")) , mGlobal(Settings::Manager::getBool("global", "Map"))
, mEventBoxGlobal(nullptr) , mEventBoxGlobal(nullptr)
, mEventBoxLocal(nullptr) , mEventBoxLocal(nullptr)
, mGlobalMapRender(new MWRender::GlobalMap(localMapRender->getRoot(), workQueue)) , mGlobalMapRender(new MWRender::GlobalMap(localMapRender->getRoot(), workQueue, reverseZ))
, mEditNoteDialog() , mEditNoteDialog()
{ {
static bool registered = false; static bool registered = false;

View file

@ -222,7 +222,7 @@ namespace MWGui
class MapWindow : public MWGui::WindowPinnableBase, public LocalMapBase, public NoDrop class MapWindow : public MWGui::WindowPinnableBase, public LocalMapBase, public NoDrop
{ {
public: 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(); virtual ~MapWindow();
void setCellName(const std::string& cellName); void setCellName(const std::string& cellName);

View file

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

View file

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

View file

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

View file

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

View file

@ -83,13 +83,14 @@ namespace
namespace MWRender namespace MWRender
{ {
LocalMap::LocalMap(osg::Group* root) LocalMap::LocalMap(osg::Group* root, bool reverseZ)
: mRoot(root) : mRoot(root)
, mMapResolution(Settings::Manager::getInt("local map resolution", "Map")) , mMapResolution(Settings::Manager::getInt("local map resolution", "Map"))
, mMapWorldSize(Constants::CellSizeInUnits) , mMapWorldSize(Constants::CellSizeInUnits)
, mCellDistance(Constants::CellGridRadius) , mCellDistance(Constants::CellGridRadius)
, mAngle(0.f) , mAngle(0.f)
, mInterior(false) , mInterior(false)
, mReverseZ(reverseZ)
{ {
// Increase map resolution, if use UI scaling // Increase map resolution, if use UI scaling
float uiScale = MWBase::Environment::get().getWindowManager()->getScalingFactor(); 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> 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); osg::ref_ptr<osg::Camera> camera (new osg::Camera);
camera->setProjectionMatrixAsOrtho(-width/2, width/2, -height/2, height/2, 5, (zmax-zmin) + 10);
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->setComputeNearFarMode(osg::Camera::DO_NOT_COMPUTE_NEAR_FAR);
camera->setViewMatrixAsLookAt(osg::Vec3d(x, y, zmax + 5), osg::Vec3d(x, y, zmin), upVector); camera->setViewMatrixAsLookAt(osg::Vec3d(x, y, zmax + 5), osg::Vec3d(x, y, zmin), upVector);
camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF_INHERIT_VIEWPOINT); 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; 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); 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 // assign large value to effectively turn off fog
// shaders don't respect glDisable(GL_FOG) // shaders don't respect glDisable(GL_FOG)
osg::ref_ptr<osg::Fog> fog (new osg::Fog); osg::ref_ptr<osg::Fog> fog (new osg::Fog);

View file

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

View file

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

View file

@ -661,6 +661,7 @@ namespace MWRender
if (mergeGroup->getNumChildren()) if (mergeGroup->getNumChildren())
{ {
SceneUtil::Optimizer optimizer; SceneUtil::Optimizer optimizer;
optimizer.setReverseZ(mSceneManager->getReverseZ());
if (size > 1/8.f) if (size > 1/8.f)
{ {
optimizer.setViewPoint(relativeViewPoint); 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/Group>
#include <osg/UserDataContainer> #include <osg/UserDataContainer>
#include <osg/ComputeBoundsVisitor> #include <osg/ComputeBoundsVisitor>
#include <osg/Depth>
#include <osg/ClipControl>
#include <osgUtil/LineSegmentIntersector> #include <osgUtil/LineSegmentIntersector>
@ -68,6 +70,7 @@
#include "objectpaging.hpp" #include "objectpaging.hpp"
#include "screenshotmanager.hpp" #include "screenshotmanager.hpp"
#include "groundcover.hpp" #include "groundcover.hpp"
#include "postprocessor.hpp"
namespace MWRender namespace MWRender
{ {
@ -198,6 +201,17 @@ namespace MWRender
, mFieldOfViewOverridden(false) , mFieldOfViewOverridden(false)
, mFieldOfViewOverride(0.f) , 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")); auto lightingMethod = SceneUtil::LightManager::getLightingMethodFromString(Settings::Manager::getString("lighting method", "Shaders"));
resourceSystem->getSceneManager()->setParticleSystemMask(MWRender::Mask_ParticleSystem); resourceSystem->getSceneManager()->setParticleSystemMask(MWRender::Mask_ParticleSystem);
@ -216,6 +230,7 @@ namespace MWRender
resourceSystem->getSceneManager()->setSpecularMapPattern(Settings::Manager::getString("specular map pattern", "Shaders")); resourceSystem->getSceneManager()->setSpecularMapPattern(Settings::Manager::getString("specular map pattern", "Shaders"));
resourceSystem->getSceneManager()->setApplyLightingToEnvMaps(Settings::Manager::getBool("apply lighting to environment maps", "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()->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. // 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); 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")) if (Settings::Manager::getBool("object shadows", "Shadows"))
shadowCastingTraversalMask |= (Mask_Object|Mask_Static); 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 shadowDefines = mShadowManager->getShadowDefines();
Shader::ShaderManager::DefineMap lightDefines = sceneRoot->getLightDefines(); 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["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["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. // It is unnecessary to stop/start the viewer as no frames are being rendered yet.
mResourceSystem->getSceneManager()->getShaderManager().setGlobalDefines(globalDefines); mResourceSystem->getSceneManager()->getShaderManager().setGlobalDefines(globalDefines);
@ -413,6 +430,7 @@ namespace MWRender
mViewer->getCamera()->setCullMask(~(Mask_UpdateVisitor|Mask_SimpleWater)); mViewer->getCamera()->setCullMask(~(Mask_UpdateVisitor|Mask_SimpleWater));
NifOsg::Loader::setHiddenNodeMask(Mask_UpdateVisitor); NifOsg::Loader::setHiddenNodeMask(Mask_UpdateVisitor);
NifOsg::Loader::setIntersectionDisabledNodeMask(Mask_Effect); NifOsg::Loader::setIntersectionDisabledNodeMask(Mask_Effect);
NifOsg::Loader::setReverseZ(reverseZ);
Nif::NIFFile::setLoadUnsupportedFiles(Settings::Manager::getBool("load unsupported nif files", "Models")); Nif::NIFFile::setLoadUnsupportedFiles(Settings::Manager::getBool("load unsupported nif files", "Models"));
mNearClip = Settings::Manager::getFloat("near clip", "Camera"); mNearClip = Settings::Manager::getFloat("near clip", "Camera");
@ -434,6 +452,18 @@ namespace MWRender
mUniformNear = mRootNode->getOrCreateStateSet()->getUniform("near"); mUniformNear = mRootNode->getOrCreateStateSet()->getUniform("near");
mUniformFar = mRootNode->getOrCreateStateSet()->getUniform("far"); 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(); updateProjectionMatrix();
} }
@ -1066,7 +1096,20 @@ namespace MWRender
float fov = mFieldOfView; float fov = mFieldOfView;
if (mFieldOfViewOverridden) if (mFieldOfViewOverridden)
fov = mFieldOfViewOverride; fov = mFieldOfViewOverride;
mViewer->getCamera()->setProjectionMatrixAsPerspective(fov, aspect, mNearClip, mViewDistance);
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); mUniformNear->set(mNearClip);
mUniformFar->set(mViewDistance); mUniformFar->set(mViewDistance);

View file

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

View file

@ -16,6 +16,7 @@
#include <components/resource/resourcesystem.hpp> #include <components/resource/resourcesystem.hpp>
#include <components/resource/scenemanager.hpp> #include <components/resource/scenemanager.hpp>
#include <components/fallback/fallback.hpp> #include <components/fallback/fallback.hpp>
#include <components/sceneutil/util.hpp>
#include "vismask.hpp" #include "vismask.hpp"
@ -55,7 +56,7 @@ namespace
stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
stateset->setTextureAttributeAndModes(0, textures[0], osg::StateAttribute::ON); 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); depth->setWriteMask(false);
stateset->setAttributeAndModes(depth, osg::StateAttribute::ON); stateset->setAttributeAndModes(depth, osg::StateAttribute::ON);

View file

@ -473,7 +473,7 @@ const float CelestialBody::mDistance = 1000.0f;
class Sun : public CelestialBody class Sun : public CelestialBody
{ {
public: public:
Sun(osg::Group* parentNode, Resource::ImageManager& imageManager) Sun(osg::Group* parentNode, Resource::ImageManager& imageManager, bool reverseZ)
: CelestialBody(parentNode, 1.0f, 1, Mask_Sun) : CelestialBody(parentNode, 1.0f, 1, Mask_Sun)
, mUpdater(new Updater) , mUpdater(new Updater)
{ {
@ -502,8 +502,8 @@ public:
mTransform->addChild(queryNode); mTransform->addChild(queryNode);
mOcclusionQueryVisiblePixels = createOcclusionQueryNode(queryNode, true); mOcclusionQueryVisiblePixels = createOcclusionQueryNode(queryNode, true, reverseZ);
mOcclusionQueryTotalPixels = createOcclusionQueryNode(queryNode, false); mOcclusionQueryTotalPixels = createOcclusionQueryNode(queryNode, false, reverseZ);
createSunFlash(imageManager); createSunFlash(imageManager);
createSunGlare(); createSunGlare();
@ -556,7 +556,7 @@ private:
}; };
/// @param queryVisible If true, queries the amount of visible pixels. If false, queries the total amount of pixels. /// @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; osg::ref_ptr<osg::OcclusionQueryNode> oqn = new osg::OcclusionQueryNode;
oqn->setQueriesEnabled(true); oqn->setQueriesEnabled(true);
@ -594,13 +594,13 @@ private:
osg::StateSet* queryStateSet = new osg::StateSet; osg::StateSet* queryStateSet = new osg::StateSet;
if (queryVisible) if (queryVisible)
{ {
osg::ref_ptr<osg::Depth> depth (new osg::Depth); auto depth = SceneUtil::createDepth(reverseZ);
depth->setFunction(osg::Depth::LEQUAL);
// This is a trick to make fragments written by the query always use the maximum depth value, // 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. // without having to retrieve the current far clipping distance.
// We want the sun glare to be "infinitely" far away. // We want the sun glare to be "infinitely" far away.
depth->setZNear(1.0); float far = reverseZ ? 0.0 : 1.0;
depth->setZFar(1.0); depth->setZNear(far);
depth->setZFar(far);
depth->setWriteMask(false); depth->setWriteMask(false);
queryStateSet->setAttributeAndModes(depth, osg::StateAttribute::ON); queryStateSet->setAttributeAndModes(depth, osg::StateAttribute::ON);
} }
@ -1188,7 +1188,8 @@ void SkyManager::create()
mAtmosphereNightUpdater = new AtmosphereNightUpdater(mSceneManager->getImageManager()); mAtmosphereNightUpdater = new AtmosphereNightUpdater(mSceneManager->getImageManager());
atmosphereNight->addUpdateCallback(mAtmosphereNightUpdater); 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)); 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)); 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->addUpdateCallback(mCloudUpdater2);
mCloudMesh2->setNodeMask(0); mCloudMesh2->setNodeMask(0);
osg::ref_ptr<osg::Depth> depth = new osg::Depth; auto depth = SceneUtil::createDepth(reverseZ);
depth->setWriteMask(false); depth->setWriteMask(false);
mEarlyRenderBinRoot->getOrCreateStateSet()->setAttributeAndModes(depth, osg::StateAttribute::ON); mEarlyRenderBinRoot->getOrCreateStateSet()->setAttributeAndModes(depth, osg::StateAttribute::ON);
mEarlyRenderBinRoot->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON); mEarlyRenderBinRoot->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON);

View file

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

View file

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

View file

@ -51,10 +51,14 @@ namespace NifOsg
static void setIntersectionDisabledNodeMask(unsigned int mask); static void setIntersectionDisabledNodeMask(unsigned int mask);
static unsigned int getIntersectionDisabledNodeMask(); static unsigned int getIntersectionDisabledNodeMask();
static void setReverseZ(bool reverseZ);
static bool getReverseZ();
private: private:
static unsigned int sHiddenNodeMask; static unsigned int sHiddenNodeMask;
static unsigned int sIntersectionDisabledNodeMask; static unsigned int sIntersectionDisabledNodeMask;
static bool sShowMarkers; static bool sShowMarkers;
static bool sReverseZ;
}; };
} }

View file

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

View file

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

View file

@ -23,10 +23,13 @@
#include <osg/Geometry> #include <osg/Geometry>
#include <osg/io_utils> #include <osg/io_utils>
#include <osg/Depth> #include <osg/Depth>
#include <osg/ClipControl>
#include <sstream> #include <sstream>
#include "shadowsbin.hpp" #include "shadowsbin.hpp"
#include <components/sceneutil/util.hpp>
namespace { namespace {
using namespace osgShadow; using namespace osgShadow;
@ -347,6 +350,11 @@ void VDSMCameraCullCallback::operator()(osg::Node* node, osg::NodeVisitor* nv)
_projectionMatrix = cv->getProjectionMatrix(); _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 } // namespace
MWShadowTechnique::ComputeLightSpaceBounds::ComputeLightSpaceBounds(osg::Viewport* viewport, const osg::Matrixd& projectionMatrix, osg::Matrixd& viewMatrix) : 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) 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 // 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; return;
} }
osg::Matrix shadowProj;
cv.getCurrentCamera()->getUserValue("shadowProj", shadowProj);
ViewDependentData* vdd = getViewDependentData(&cv); ViewDependentData* vdd = getViewDependentData(&cv);
if (!vdd) if (!vdd)
@ -985,34 +1006,41 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv)
osg::CullSettings::ComputeNearFarMode cachedNearFarMode = cv.getComputeNearFarMode(); 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 minZNear = 0.0;
double maxZFar = dbl_max; double maxZFar = dbl_max;
bool orthographicViewFrustum;
if (cachedNearFarMode==osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR) if (_reverseZ)
{ {
double left, right, top, bottom; cv.getCurrentCamera()->getUserValue("near", minZNear);
if (orthographicViewFrustum) cv.getCurrentCamera()->getUserValue("far", maxZFar);
{ orthographicViewFrustum = isOrthographicViewFrustum(shadowProj);
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;
} }
else
// 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()); 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 // 1. Traverse main scene graph
@ -1024,6 +1052,9 @@ void MWShadowTechnique::cull(osgUtil::CullVisitor& cv)
cv.popStateSet(); cv.popStateSet();
if (_reverseZ)
cv.pushProjectionMatrix(new osg::RefMatrix(shadowProj));
if (cv.getComputeNearFarMode()!=osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR) if (cv.getComputeNearFarMode()!=osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR)
{ {
OSG_INFO<<"Just done main subgraph traversak"<<std::endl; 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 // 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; 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()); prepareStateSetForRenderingShadow(*vdd, cv.getTraversalNumber());
} }
if (_reverseZ)
cv.popProjectionMatrix();
// OSG_NOTICE<<"End of shadow setup Projection matrix "<<*cv.getProjectionMatrix()<<std::endl; // 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)); _shadowCastingStateSet->addUniform(new osg::Uniform("alphaTestShadows", false));
osg::ref_ptr<osg::Depth> depth = new osg::Depth; osg::ref_ptr<osg::Depth> depth = new osg::Depth;
depth->setWriteMask(true); 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->setAttribute(depth, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE);
_shadowCastingStateSet->setMode(GL_DEPTH_CLAMP, osg::StateAttribute::ON); _shadowCastingStateSet->setMode(GL_DEPTH_CLAMP, osg::StateAttribute::ON);

View file

@ -85,6 +85,10 @@ namespace SceneUtil {
virtual void disableFrontFaceCulling(); virtual void disableFrontFaceCulling();
virtual void enableReverseZ();
virtual void disableReverseZ();
virtual void setupCastingShader(Shader::ShaderManager &shaderManager); virtual void setupCastingShader(Shader::ShaderManager &shaderManager);
class ComputeLightSpaceBounds : public osg::NodeVisitor, public osg::CullStack class ComputeLightSpaceBounds : public osg::NodeVisitor, public osg::CullStack
@ -266,6 +270,8 @@ namespace SceneUtil {
float _shadowFadeStart = 0.0; float _shadowFadeStart = 0.0;
bool _reverseZ = false;
class DebugHUD final : public osg::Referenced class DebugHUD final : public osg::Referenced
{ {
public: public:

View file

@ -40,6 +40,8 @@
#include <iterator> #include <iterator>
#include <components/sceneutil/util.hpp>
using namespace osgUtil; using namespace osgUtil;
namespace SceneUtil namespace SceneUtil
@ -107,6 +109,7 @@ void Optimizer::optimize(osg::Node* node, unsigned int options)
MergeGeometryVisitor mgv(this); MergeGeometryVisitor mgv(this);
mgv.setTargetMaximumNumberOfVertices(1000000); mgv.setTargetMaximumNumberOfVertices(1000000);
mgv.setMergeAlphaBlending(_mergeAlphaBlending); mgv.setMergeAlphaBlending(_mergeAlphaBlending);
mgv.setReverseZ(_reverseZ);
mgv.setViewPoint(_viewPoint); mgv.setViewPoint(_viewPoint);
node->accept(mgv); node->accept(mgv);
@ -1560,7 +1563,7 @@ bool Optimizer::MergeGeometryVisitor::mergeGroup(osg::Group& group)
} }
if (_alphaBlendingActive && _mergeAlphaBlending && !geom->getStateSet()) if (_alphaBlendingActive && _mergeAlphaBlending && !geom->getStateSet())
{ {
osg::Depth* d = new osg::Depth; auto d = createDepth(_reverseZ);
d->setWriteMask(0); d->setWriteMask(0);
geom->getOrCreateStateSet()->setAttribute(d); geom->getOrCreateStateSet()->setAttribute(d);
} }

View file

@ -65,7 +65,7 @@ class Optimizer
public: public:
Optimizer() : _mergeAlphaBlending(false) {} Optimizer() : _mergeAlphaBlending(false), _reverseZ(false) {}
virtual ~Optimizer() {} virtual ~Optimizer() {}
enum OptimizationOptions enum OptimizationOptions
@ -119,6 +119,7 @@ class Optimizer
}; };
void setMergeAlphaBlending(bool merge) { _mergeAlphaBlending = merge; } void setMergeAlphaBlending(bool merge) { _mergeAlphaBlending = merge; }
void setReverseZ(bool reverseZ) { _reverseZ = reverseZ; }
void setViewPoint(const osg::Vec3f& viewPoint) { _viewPoint = viewPoint; } void setViewPoint(const osg::Vec3f& viewPoint) { _viewPoint = viewPoint; }
/** Reset internal data to initial state - the getPermissibleOptionsMap is cleared.*/ /** Reset internal data to initial state - the getPermissibleOptionsMap is cleared.*/
@ -257,6 +258,7 @@ class Optimizer
osg::Vec3f _viewPoint; osg::Vec3f _viewPoint;
bool _mergeAlphaBlending; bool _mergeAlphaBlending;
bool _reverseZ;
public: public:
@ -377,12 +379,18 @@ class Optimizer
/// default to traversing all children. /// default to traversing all children.
MergeGeometryVisitor(Optimizer* optimizer=0) : MergeGeometryVisitor(Optimizer* optimizer=0) :
BaseOptimizerVisitor(optimizer, MERGE_GEOMETRY), BaseOptimizerVisitor(optimizer, MERGE_GEOMETRY),
_targetMaximumNumberOfVertices(10000), _alphaBlendingActive(false), _mergeAlphaBlending(false) {} _targetMaximumNumberOfVertices(10000), _alphaBlendingActive(false), _mergeAlphaBlending(false), _reverseZ(false) {}
void setMergeAlphaBlending(bool merge) void setMergeAlphaBlending(bool merge)
{ {
_mergeAlphaBlending = merge; _mergeAlphaBlending = merge;
} }
void setReverseZ(bool reverseZ)
{
_reverseZ = reverseZ;
}
void setViewPoint(const osg::Vec3f& viewPoint) void setViewPoint(const osg::Vec3f& viewPoint)
{ {
_viewPoint = viewPoint; _viewPoint = viewPoint;
@ -421,6 +429,7 @@ class Optimizer
std::vector<osg::StateSet*> _stateSetStack; std::vector<osg::StateSet*> _stateSetStack;
bool _alphaBlendingActive; bool _alphaBlendingActive;
bool _mergeAlphaBlending; bool _mergeAlphaBlending;
bool _reverseZ;
osg::Vec3f _viewPoint; 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), 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)
mShadowTechnique(new MWShadowTechnique), : mShadowedScene(new osgShadow::ShadowedScene)
mOutdoorShadowCastingMask(outdoorShadowCastingMask), , mReverseZ(reverseZ)
mIndoorShadowCastingMask(indoorShadowCastingMask) , mShadowTechnique(new MWShadowTechnique)
, mOutdoorShadowCastingMask(outdoorShadowCastingMask)
, mIndoorShadowCastingMask(indoorShadowCastingMask)
{ {
mShadowedScene->setShadowTechnique(mShadowTechnique); mShadowedScene->setShadowTechnique(mShadowTechnique);
@ -108,6 +110,9 @@ namespace SceneUtil
mShadowSettings = mShadowedScene->getShadowSettings(); mShadowSettings = mShadowedScene->getShadowSettings();
setupShadowSettings(); setupShadowSettings();
if (mReverseZ)
mShadowTechnique->enableReverseZ();
mShadowTechnique->setupCastingShader(shaderManager); mShadowTechnique->setupCastingShader(shaderManager);
enableOutdoorMode(); enableOutdoorMode();
@ -180,4 +185,9 @@ namespace SceneUtil
mShadowTechnique->enableShadows(); mShadowTechnique->enableShadows();
mShadowSettings->setCastsShadowTraversalMask(mOutdoorShadowCastingMask); mShadowSettings->setCastsShadowTraversalMask(mOutdoorShadowCastingMask);
} }
bool ShadowManager::getReverseZ() const
{
return mReverseZ;
}
} }

View file

@ -17,7 +17,7 @@ namespace SceneUtil
static Shader::ShaderManager::DefineMap getShadowsDisabledDefines(); 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(); void setupShadowSettings();
@ -26,8 +26,11 @@ namespace SceneUtil
void enableIndoorMode(); void enableIndoorMode();
void enableOutdoorMode(); void enableOutdoorMode();
bool getReverseZ() const;
protected: protected:
bool mEnableShadows; bool mEnableShadows;
bool mReverseZ;
osg::ref_ptr<osgShadow::ShadowedScene> mShadowedScene; osg::ref_ptr<osgShadow::ShadowedScene> mShadowedScene;
osg::ref_ptr<osgShadow::ShadowSettings> mShadowSettings; osg::ref_ptr<osgShadow::ShadowSettings> mShadowSettings;

View file

@ -285,4 +285,43 @@ bool attachAlphaToCoverageFriendlyFramebufferToCamera(osg::Camera* camera, osg::
return addMSAAIntermediateTarget; 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/NodeCallback>
#include <osg/Texture2D> #include <osg/Texture2D>
#include <osg/Vec4f> #include <osg/Vec4f>
#include <osg/Depth>
#include <components/resource/resourcesystem.hpp> #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 // 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); 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 #endif

View file

@ -5,6 +5,8 @@
#include <osg/Material> #include <osg/Material>
#include <osg/StateSet> #include <osg/StateSet>
#include "util.hpp"
namespace SceneUtil namespace SceneUtil
{ {
// disable nonsense test against a worldsize bb what will always pass // disable nonsense test against a worldsize bb what will always pass
@ -62,7 +64,7 @@ namespace SceneUtil
return waterGeom; 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); 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_BLEND, osg::StateAttribute::ON);
stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF); stateset->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
osg::ref_ptr<osg::Depth> depth (new osg::Depth); auto depth = createDepth(reverseZ);
depth->setWriteMask(false); depth->setWriteMask(false);
stateset->setAttributeAndModes(depth, osg::StateAttribute::ON); 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::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 #endif

View file

@ -163,7 +163,7 @@ std::vector<osg::ref_ptr<osg::StateSet> > ChunkManager::createPasses(float chunk
float blendmapScale = mStorage->getBlendmapScale(chunkSize); 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) 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.mDiffuseMap = compositeMap->mTexture;
layer.mParallax = false; layer.mParallax = false;
layer.mSpecular = 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 else
{ {

View file

@ -7,7 +7,9 @@
#include <osg/TexMat> #include <osg/TexMat>
#include <osg/BlendFunc> #include <osg/BlendFunc>
#include <components/resource/scenemanager.hpp>
#include <components/shader/shadermanager.hpp> #include <components/shader/shadermanager.hpp>
#include <components/sceneutil/util.hpp>
#include <mutex> #include <mutex>
@ -95,19 +97,18 @@ namespace
class LequalDepth class LequalDepth
{ {
public: 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; return instance.mValue;
} }
private: private:
osg::ref_ptr<osg::Depth> mValue; osg::ref_ptr<osg::Depth> mValue;
LequalDepth() LequalDepth(bool reverseZ)
: mValue(new osg::Depth) : mValue(SceneUtil::createDepth(reverseZ))
{ {
mValue->setFunction(osg::Depth::LEQUAL);
} }
}; };
@ -170,9 +171,10 @@ namespace
namespace Terrain 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) 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; std::vector<osg::ref_ptr<osg::StateSet> > passes;
unsigned int blendmapIndex = 0; unsigned int blendmapIndex = 0;
@ -195,7 +197,7 @@ namespace Terrain
else else
{ {
stateset->setAttributeAndModes(BlendFuncFirst::value(), osg::StateAttribute::ON); 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) if (!vertexShader || !fragmentShader)
{ {
// Try again without shader. Error already logged by above // 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)); stateset->setAttributeAndModes(shaderManager->getProgram(vertexShader, fragmentShader));

View file

@ -10,9 +10,9 @@ namespace osg
class Texture2D; class Texture2D;
} }
namespace Shader namespace Resource
{ {
class ShaderManager; class SceneManager;
} }
namespace Terrain namespace Terrain
@ -26,7 +26,7 @@ namespace Terrain
bool mSpecular; 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<TextureLayer>& layers,
const std::vector<osg::ref_ptr<osg::Texture2D> >& blendmaps, int blendmapScale, float layerTileSize); 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_fragment.glsl
water_nm.png water_nm.png
alpha.glsl alpha.glsl
depth.glsl
objects_vertex.glsl objects_vertex.glsl
objects_fragment.glsl objects_fragment.glsl
terrain_vertex.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 "shadows_vertex.glsl"
#include "lighting.glsl" #include "lighting.glsl"
#include "depth.glsl"
uniform float osg_SimulationTime; uniform float osg_SimulationTime;
uniform mat4 osg_ViewMatrixInverse; uniform mat4 osg_ViewMatrixInverse;
@ -143,7 +144,7 @@ void main(void)
else else
gl_Position = gl_ProjectionMatrix * viewPos; gl_Position = gl_ProjectionMatrix * viewPos;
linearDepth = gl_Position.z; linearDepth = getLinearDepth(viewPos);
#if (!PER_PIXEL_LIGHTING || @shadows_enabled) #if (!PER_PIXEL_LIGHTING || @shadows_enabled)
vec3 viewNormal = normalize((gl_NormalMatrix * rotation3(rotation) * gl_Normal).xyz); vec3 viewNormal = normalize((gl_NormalMatrix * rotation3(rotation) * gl_Normal).xyz);

View file

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

View file

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

View file

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

View file

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

View file

@ -158,11 +158,14 @@ uniform float rainIntensity;
float frustumDepth; float frustumDepth;
float linearizeDepth(float depth) float linearizeDepth(float depth)
{ {
float z_n = 2.0 * depth - 1.0; #if @reverseZ
depth = 2.0 * near * far / (far + near - z_n * frustumDepth); depth = 1.0 - depth;
return 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) void main(void)
{ {

View file

@ -5,6 +5,7 @@ varying vec4 position;
varying float linearDepth; varying float linearDepth;
#include "shadows_vertex.glsl" #include "shadows_vertex.glsl"
#include "depth.glsl"
void main(void) void main(void)
{ {
@ -20,7 +21,8 @@ void main(void)
position = gl_Vertex; 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));
} }