mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-02-04 12:39:55 +00:00
Merge branch 'to_infinity_and_beyond' into 'master'
Reverse-Z depth buffer See merge request OpenMW/openmw!889
This commit is contained in:
commit
b8878cb5f9
@ -38,7 +38,9 @@
|
||||
Feature #5489: MCP: Telekinesis fix for activators
|
||||
Feature #5996: Support Lua scripts in OpenMW
|
||||
Feature #6017: Separate persistent and temporary cell references when saving
|
||||
Feature #6032: Reverse-z depth buffer
|
||||
Feature #6162: Refactor GUI to use shaders and to be GLES and GL3+ friendly
|
||||
Feature #6199: Support FBO Rendering
|
||||
|
||||
0.47.0
|
||||
------
|
||||
|
@ -84,6 +84,7 @@ CSMWorld::Data::Data (ToUTF8::FromType encoding, bool fsStrict, const Files::Pat
|
||||
defines["preLightEnv"] = "0"; // Apply environment maps after lighting like Morrowind
|
||||
defines["radialFog"] = "0";
|
||||
defines["lightingModel"] = "0";
|
||||
defines["reverseZ"] = "0";
|
||||
for (const auto& define : shadowDefines)
|
||||
defines[define.first] = define.second;
|
||||
mResourceSystem->getSceneManager()->getShaderManager().setGlobalDefines(defines);
|
||||
|
@ -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
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "MyGUI_FactoryManager.h"
|
||||
|
||||
#include <components/misc/utf8stream.hpp>
|
||||
#include <components/sceneutil/util.hpp>
|
||||
|
||||
#include "../mwbase/environment.hpp"
|
||||
#include "../mwbase/windowmanager.hpp"
|
||||
@ -1217,8 +1218,10 @@ public:
|
||||
|
||||
RenderXform renderXform (mCroppedParent, textFormat.mRenderItem->getRenderTarget()->getInfo());
|
||||
|
||||
float z = SceneUtil::getReverseZ() ? 1.f : -1.f;
|
||||
|
||||
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));
|
||||
|
@ -450,6 +450,7 @@ namespace MWGui
|
||||
|
||||
osg::ref_ptr<osg::Texture2D> texture (new osg::Texture2D);
|
||||
texture->setImage(result.getImage());
|
||||
texture->setInternalFormat(GL_RGB);
|
||||
texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
|
||||
texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
|
||||
texture->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR);
|
||||
|
@ -2,9 +2,13 @@
|
||||
#include "vismask.hpp"
|
||||
|
||||
#include <components/sceneutil/agentpath.hpp>
|
||||
#include <components/resource/resourcesystem.hpp>
|
||||
#include <components/resource/scenemanager.hpp>
|
||||
|
||||
#include <osg/PositionAttitudeTransform>
|
||||
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
namespace MWRender
|
||||
{
|
||||
ActorsPaths::ActorsPaths(const osg::ref_ptr<osg::Group>& root, bool enabled)
|
||||
@ -43,6 +47,7 @@ namespace MWRender
|
||||
const auto newGroup = SceneUtil::createAgentPathGroup(path, halfExtents, start, end, settings);
|
||||
if (newGroup)
|
||||
{
|
||||
MWBase::Environment::get().getResourceSystem()->getSceneManager()->recreateShaders(newGroup, "debug");
|
||||
newGroup->setNodeMask(Mask_Debug);
|
||||
mRootNode->addChild(newGroup);
|
||||
mGroups[actor] = newGroup;
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include <osg/Geometry>
|
||||
#include <osg/Group>
|
||||
#include <osg/Material>
|
||||
|
||||
#include <components/debug/debuglog.hpp>
|
||||
#include <components/misc/convert.hpp>
|
||||
@ -14,6 +15,12 @@
|
||||
#include "bulletdebugdraw.hpp"
|
||||
#include "vismask.hpp"
|
||||
|
||||
#include <components/resource/resourcesystem.hpp>
|
||||
#include <components/resource/scenemanager.hpp>
|
||||
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
|
||||
namespace MWRender
|
||||
{
|
||||
|
||||
@ -43,6 +50,10 @@ void DebugDrawer::createGeometry()
|
||||
mGeometry->setDataVariance(osg::Object::DYNAMIC);
|
||||
mGeometry->addPrimitiveSet(mDrawArrays);
|
||||
|
||||
osg::ref_ptr<osg::Material> material = new osg::Material;
|
||||
material->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE);
|
||||
mGeometry->getOrCreateStateSet()->setAttribute(material);
|
||||
|
||||
mParentNode->addChild(mGeometry);
|
||||
|
||||
auto* stateSet = new osg::StateSet;
|
||||
@ -52,6 +63,8 @@ void DebugDrawer::createGeometry()
|
||||
mShapesRoot->setDataVariance(osg::Object::DYNAMIC);
|
||||
mShapesRoot->setNodeMask(Mask_Debug);
|
||||
mParentNode->addChild(mShapesRoot);
|
||||
|
||||
MWBase::Environment::get().getResourceSystem()->getSceneManager()->recreateShaders(mGeometry, "debug");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -187,6 +187,10 @@ namespace MWRender
|
||||
defaultMat->setDiffuse(osg::Material::FRONT_AND_BACK, osg::Vec4f(1,1,1,1));
|
||||
defaultMat->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4f(0.f, 0.f, 0.f, 0.f));
|
||||
stateset->setAttribute(defaultMat);
|
||||
stateset->addUniform(new osg::Uniform("projectionMatrix", static_cast<osg::Matrixf>(mCamera->getProjectionMatrix())));
|
||||
|
||||
osg::ref_ptr<osg::Depth> depth = new osg::Depth;
|
||||
stateset->setAttributeAndModes(depth, osg::StateAttribute::ON);
|
||||
|
||||
SceneUtil::ShadowManager::disableShadowsForStateSet(stateset);
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <components/debug/debuglog.hpp>
|
||||
|
||||
#include <components/sceneutil/workqueue.hpp>
|
||||
#include <components/sceneutil/util.hpp>
|
||||
|
||||
#include <components/esm/globalmap.hpp>
|
||||
|
||||
@ -24,6 +25,7 @@
|
||||
#include "../mwworld/esmstore.hpp"
|
||||
|
||||
#include "vismask.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
@ -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();
|
||||
depth->setWriteMask(0);
|
||||
osg::StateSet* stateset = geom->getOrCreateStateSet();
|
||||
stateset->setAttribute(depth);
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "../mwworld/cellstore.hpp"
|
||||
|
||||
#include "vismask.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
@ -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);
|
||||
camera->setProjectionMatrixAsOrtho(-width/2, width/2, -height/2, height/2, 5, (zmax-zmin) + 10);
|
||||
|
||||
if (SceneUtil::getReverseZ())
|
||||
camera->setProjectionMatrix(SceneUtil::getReversedZProjectionMatrixAsOrtho(-width/2, width/2, -height/2, height/2, 5, (zmax-zmin) + 10));
|
||||
else
|
||||
camera->setProjectionMatrixAsOrtho(-width/2, width/2, -height/2, height/2, 5, (zmax-zmin) + 10);
|
||||
|
||||
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 (SceneUtil::getReverseZ())
|
||||
stateset->setAttributeAndModes(SceneUtil::createDepth(), osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE);
|
||||
|
||||
SceneUtil::setCameraClearDepth(camera);
|
||||
|
||||
stateset->addUniform(new osg::Uniform("projectionMatrix", static_cast<osg::Matrixf>(camera->getProjectionMatrix())), 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);
|
||||
|
@ -2,9 +2,14 @@
|
||||
#include "vismask.hpp"
|
||||
|
||||
#include <components/sceneutil/navmesh.hpp>
|
||||
#include <components/resource/resourcesystem.hpp>
|
||||
#include <components/resource/scenemanager.hpp>
|
||||
|
||||
#include <osg/PositionAttitudeTransform>
|
||||
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
|
||||
namespace MWRender
|
||||
{
|
||||
NavMesh::NavMesh(const osg::ref_ptr<osg::Group>& root, bool enabled)
|
||||
@ -45,6 +50,7 @@ namespace MWRender
|
||||
mGroup = SceneUtil::createNavMeshGroup(navMesh, settings);
|
||||
if (mGroup)
|
||||
{
|
||||
MWBase::Environment::get().getResourceSystem()->getSceneManager()->recreateShaders(mGroup, "debug");
|
||||
mGroup->setNodeMask(Mask_Debug);
|
||||
mRootNode->addChild(mGroup);
|
||||
}
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include "rotatecontroller.hpp"
|
||||
#include "renderbin.hpp"
|
||||
#include "vismask.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
@ -372,7 +373,7 @@ class DepthClearCallback : public osgUtil::RenderBin::DrawCallback
|
||||
public:
|
||||
DepthClearCallback()
|
||||
{
|
||||
mDepth = new osg::Depth;
|
||||
mDepth = SceneUtil::createDepth();
|
||||
mDepth->setWriteMask(true);
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,10 @@
|
||||
|
||||
#include <components/esm/loadpgrd.hpp>
|
||||
#include <components/sceneutil/pathgridutil.hpp>
|
||||
#include <components/sceneutil/util.hpp>
|
||||
#include <components/misc/coordinateconverter.hpp>
|
||||
#include <components/resource/resourcesystem.hpp>
|
||||
#include <components/resource/scenemanager.hpp>
|
||||
|
||||
#include "../mwbase/world.hpp" // these includes can be removed once the static-hack is gone
|
||||
#include "../mwbase/environment.hpp"
|
||||
@ -112,6 +115,8 @@ void Pathgrid::enableCellPathgrid(const MWWorld::CellStore *store)
|
||||
|
||||
osg::ref_ptr<osg::Geometry> geometry = SceneUtil::createPathgridGeometry(*pathgrid);
|
||||
|
||||
MWBase::Environment::get().getResourceSystem()->getSceneManager()->recreateShaders(geometry, "debug");
|
||||
|
||||
cellPathGrid->addChild(geometry);
|
||||
|
||||
mPathGridRoot->addChild(cellPathGrid);
|
||||
|
266
apps/openmw/mwrender/postprocessor.cpp
Normal file
266
apps/openmw/mwrender/postprocessor.cpp
Normal file
@ -0,0 +1,266 @@
|
||||
#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>
|
||||
#include <components/sceneutil/util.hpp>
|
||||
#include <components/debug/debuglog.hpp>
|
||||
|
||||
#include "vismask.hpp"
|
||||
#include "renderingmanager.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()
|
||||
: 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;
|
||||
|
||||
MWRender::PostProcessor* postProcessor = dynamic_cast<MWRender::PostProcessor*>(nv->asCullVisitor()->getCurrentCamera()->getUserData());
|
||||
|
||||
if (!postProcessor)
|
||||
{
|
||||
Log(Debug::Error) << "Failed retrieving user data for master camera: FBO setup failed";
|
||||
traverse(node, nv);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!postProcessor->getMsaaFbo())
|
||||
{
|
||||
renderStage->setFrameBufferObject(postProcessor->getFbo());
|
||||
}
|
||||
else
|
||||
{
|
||||
renderStage->setMultisampleResolveFramebufferObject(postProcessor->getFbo());
|
||||
renderStage->setFrameBufferObject(postProcessor->getMsaaFbo());
|
||||
}
|
||||
}
|
||||
|
||||
traverse(node, nv);
|
||||
}
|
||||
|
||||
private:
|
||||
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
|
||||
{
|
||||
gc->resizedImplementation(x, y, width, height);
|
||||
mPostProcessor->resize(width, height);
|
||||
}
|
||||
|
||||
MWRender::PostProcessor* mPostProcessor;
|
||||
};
|
||||
}
|
||||
|
||||
namespace MWRender
|
||||
{
|
||||
PostProcessor::PostProcessor(RenderingManager& rendering, osgViewer::Viewer* viewer, osg::Group* rootNode)
|
||||
: mViewer(viewer)
|
||||
, mRootNode(new osg::Group)
|
||||
, mRendering(rendering)
|
||||
{
|
||||
osg::GraphicsContext* gc = viewer->getCamera()->getGraphicsContext();
|
||||
unsigned int contextID = gc->getState()->getContextID();
|
||||
osg::GLExtensions* ext = gc->getState()->get<osg::GLExtensions>();
|
||||
|
||||
constexpr char errPreamble[] = "Postprocessing and floating point depth buffers disabled: ";
|
||||
|
||||
if (!ext->isFrameBufferObjectSupported)
|
||||
{
|
||||
Log(Debug::Warning) << errPreamble << "FrameBufferObject unsupported.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (Settings::Manager::getInt("antialiasing", "Video") > 1 && !ext->isRenderbufferMultisampleSupported())
|
||||
{
|
||||
Log(Debug::Warning) << errPreamble << "RenderBufferMultiSample unsupported. Disabling antialiasing will resolve this issue.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (osg::isGLExtensionSupported(contextID, "GL_ARB_depth_buffer_float"))
|
||||
mDepthFormat = GL_DEPTH_COMPONENT32F;
|
||||
else if (osg::isGLExtensionSupported(contextID, "GL_NV_depth_buffer_float"))
|
||||
mDepthFormat = GL_DEPTH_COMPONENT32F_NV;
|
||||
else
|
||||
{
|
||||
// TODO: Once we have post-processing implemented we want to skip this return and continue with setup.
|
||||
// Rendering to a FBO to fullscreen geometry has overhead (especially when MSAA is enabled) and there are no
|
||||
// benefits if no floating point depth formats are supported.
|
||||
mDepthFormat = GL_DEPTH_COMPONENT24;
|
||||
Log(Debug::Warning) << errPreamble << "'GL_ARB_depth_buffer_float' and 'GL_NV_depth_buffer_float' unsupported.";
|
||||
return;
|
||||
}
|
||||
|
||||
int width = viewer->getCamera()->getViewport()->width();
|
||||
int height = viewer->getCamera()->getViewport()->height();
|
||||
|
||||
createTexturesAndCamera(width, height);
|
||||
resize(width, height, true);
|
||||
|
||||
mRootNode->addChild(mHUDCamera);
|
||||
mRootNode->addChild(rootNode);
|
||||
mViewer->setSceneData(mRootNode);
|
||||
|
||||
// We need to manually set the FBO and resolve FBO during the cull callback. If we were using a separate
|
||||
// RTT camera this would not be needed.
|
||||
mViewer->getCamera()->addCullCallback(new CullCallback);
|
||||
mViewer->getCamera()->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT);
|
||||
mViewer->getCamera()->attach(osg::Camera::COLOR_BUFFER0, mSceneTex);
|
||||
mViewer->getCamera()->attach(osg::Camera::DEPTH_BUFFER, mDepthTex);
|
||||
|
||||
mViewer->getCamera()->getGraphicsContext()->setResizedCallback(new ResizedCallback(this));
|
||||
mViewer->getCamera()->setUserData(this);
|
||||
}
|
||||
|
||||
void PostProcessor::resize(int width, int height, bool init)
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
if (init)
|
||||
return;
|
||||
|
||||
mViewer->getCamera()->resize(width, height);
|
||||
mHUDCamera->resize(width, height);
|
||||
|
||||
mRendering.updateProjectionMatrix();
|
||||
}
|
||||
|
||||
void PostProcessor::createTexturesAndCamera(int width, int height)
|
||||
{
|
||||
mDepthTex = new osg::Texture2D;
|
||||
mDepthTex->setTextureSize(width, height);
|
||||
mDepthTex->setSourceFormat(GL_DEPTH_COMPONENT);
|
||||
mDepthTex->setSourceType(SceneUtil::isFloatingPointDepthFormat(getDepthFormat()) ? GL_FLOAT : GL_UNSIGNED_INT);
|
||||
mDepthTex->setInternalFormat(mDepthFormat);
|
||||
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());
|
||||
mHUDCamera->setNodeMask(Mask_RenderToTexture);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
50
apps/openmw/mwrender/postprocessor.hpp
Normal file
50
apps/openmw/mwrender/postprocessor.hpp
Normal file
@ -0,0 +1,50 @@
|
||||
#ifndef OPENMW_MWRENDER_POSTPROCESSOR_H
|
||||
#define OPENMW_MWRENDER_POSTPROCESSOR_H
|
||||
|
||||
#include <osg/Texture2D>
|
||||
#include <osg/Group>
|
||||
#include <osg/FrameBufferObject>
|
||||
#include <osg/Camera>
|
||||
#include <osg/ref_ptr>
|
||||
|
||||
namespace osgViewer
|
||||
{
|
||||
class Viewer;
|
||||
}
|
||||
|
||||
namespace MWRender
|
||||
{
|
||||
class RenderingManager;
|
||||
|
||||
class PostProcessor : public osg::Referenced
|
||||
{
|
||||
public:
|
||||
PostProcessor(RenderingManager& rendering, osgViewer::Viewer* viewer, osg::Group* rootNode);
|
||||
|
||||
auto getMsaaFbo() { return mMsaaFbo; }
|
||||
auto getFbo() { return mFbo; }
|
||||
|
||||
int getDepthFormat() { return mDepthFormat; }
|
||||
|
||||
void resize(int width, int height, bool init=false);
|
||||
|
||||
private:
|
||||
void createTexturesAndCamera(int width, int height);
|
||||
|
||||
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;
|
||||
|
||||
int mDepthFormat;
|
||||
|
||||
RenderingManager& mRendering;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -1,11 +1,15 @@
|
||||
#include "recastmesh.hpp"
|
||||
|
||||
#include <components/sceneutil/recastmesh.hpp>
|
||||
#include <components/resource/resourcesystem.hpp>
|
||||
#include <components/resource/scenemanager.hpp>
|
||||
|
||||
#include <osg/PositionAttitudeTransform>
|
||||
|
||||
#include "vismask.hpp"
|
||||
|
||||
#include "../mwbase/world.hpp"
|
||||
#include "../mwbase/environment.hpp"
|
||||
namespace MWRender
|
||||
{
|
||||
RecastMesh::RecastMesh(const osg::ref_ptr<osg::Group>& root, bool enabled)
|
||||
@ -49,6 +53,7 @@ namespace MWRender
|
||||
|| it->second.mRevision != tile->second->getRevision())
|
||||
{
|
||||
const auto group = SceneUtil::createRecastMeshGroup(*tile->second, settings);
|
||||
MWBase::Environment::get().getResourceSystem()->getSceneManager()->recreateShaders(group, "debug");
|
||||
group->setNodeMask(Mask_Debug);
|
||||
mRootNode->removeChild(it->second.mValue);
|
||||
mRootNode->addChild(group);
|
||||
@ -66,6 +71,7 @@ namespace MWRender
|
||||
if (mGroups.count(tile.first))
|
||||
continue;
|
||||
const auto group = SceneUtil::createRecastMeshGroup(*tile.second, settings);
|
||||
MWBase::Environment::get().getResourceSystem()->getSceneManager()->recreateShaders(group, "debug");
|
||||
group->setNodeMask(Mask_Debug);
|
||||
mGroups.emplace(tile.first, Group {tile.second->getGeneration(), tile.second->getRevision(), group});
|
||||
mRootNode->addChild(group);
|
||||
|
@ -11,6 +11,8 @@
|
||||
#include <osg/Group>
|
||||
#include <osg/UserDataContainer>
|
||||
#include <osg/ComputeBoundsVisitor>
|
||||
#include <osg/Depth>
|
||||
#include <osg/ClipControl>
|
||||
|
||||
#include <osgUtil/LineSegmentIntersector>
|
||||
|
||||
@ -68,9 +70,74 @@
|
||||
#include "objectpaging.hpp"
|
||||
#include "screenshotmanager.hpp"
|
||||
#include "groundcover.hpp"
|
||||
#include "postprocessor.hpp"
|
||||
|
||||
namespace MWRender
|
||||
{
|
||||
class SharedUniformStateUpdater : public SceneUtil::StateSetUpdater
|
||||
{
|
||||
public:
|
||||
SharedUniformStateUpdater()
|
||||
: mLinearFac(0.f)
|
||||
, mNear(0.f)
|
||||
, mFar(0.f)
|
||||
{
|
||||
}
|
||||
|
||||
void setDefaults(osg::StateSet *stateset) override
|
||||
{
|
||||
stateset->addUniform(new osg::Uniform("projectionMatrix", osg::Matrixf{}));
|
||||
stateset->addUniform(new osg::Uniform("linearFac", 0.f));
|
||||
stateset->addUniform(new osg::Uniform("near", 0.f));
|
||||
stateset->addUniform(new osg::Uniform("far", 0.f));
|
||||
}
|
||||
|
||||
void apply(osg::StateSet* stateset, osg::NodeVisitor* nv) override
|
||||
{
|
||||
auto* uProjectionMatrix = stateset->getUniform("projectionMatrix");
|
||||
if (uProjectionMatrix)
|
||||
uProjectionMatrix->set(mProjectionMatrix);
|
||||
|
||||
auto* uLinearFac = stateset->getUniform("linearFac");
|
||||
if (uLinearFac)
|
||||
uLinearFac->set(mLinearFac);
|
||||
|
||||
auto* uNear = stateset->getUniform("near");
|
||||
if (uNear)
|
||||
uNear->set(mNear);
|
||||
|
||||
auto* uFar = stateset->getUniform("far");
|
||||
if (uFar)
|
||||
uFar->set(mFar);
|
||||
|
||||
}
|
||||
|
||||
void setProjectionMatrix(const osg::Matrixf& projectionMatrix)
|
||||
{
|
||||
mProjectionMatrix = projectionMatrix;
|
||||
}
|
||||
|
||||
void setLinearFac(float linearFac)
|
||||
{
|
||||
mLinearFac = linearFac;
|
||||
}
|
||||
|
||||
void setNear(float near)
|
||||
{
|
||||
mNear = near;
|
||||
}
|
||||
|
||||
void setFar(float far)
|
||||
{
|
||||
mFar = far;
|
||||
}
|
||||
|
||||
private:
|
||||
osg::Matrixf mProjectionMatrix;
|
||||
float mLinearFac;
|
||||
float mNear;
|
||||
float mFar;
|
||||
};
|
||||
|
||||
class StateUpdater : public SceneUtil::StateSetUpdater
|
||||
{
|
||||
@ -198,6 +265,13 @@ namespace MWRender
|
||||
, mFieldOfViewOverridden(false)
|
||||
, mFieldOfViewOverride(0.f)
|
||||
{
|
||||
bool reverseZ = SceneUtil::getReverseZ();
|
||||
|
||||
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);
|
||||
@ -205,7 +279,8 @@ namespace MWRender
|
||||
bool forceShaders = Settings::Manager::getBool("radial fog", "Shaders")
|
||||
|| Settings::Manager::getBool("force shaders", "Shaders")
|
||||
|| Settings::Manager::getBool("enable shadows", "Shadows")
|
||||
|| lightingMethod != SceneUtil::LightingMethod::FFP;
|
||||
|| lightingMethod != SceneUtil::LightingMethod::FFP
|
||||
|| reverseZ;
|
||||
resourceSystem->getSceneManager()->setForceShaders(forceShaders);
|
||||
// FIXME: calling dummy method because terrain needs to know whether lighting is clamped
|
||||
resourceSystem->getSceneManager()->setClampLighting(Settings::Manager::getBool("clamp lighting", "Shaders"));
|
||||
@ -267,6 +342,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);
|
||||
|
||||
@ -353,6 +430,13 @@ namespace MWRender
|
||||
// Use a stub grid to avoid splitting between chunks for active grid and chunks for distant cells.
|
||||
mGroundcoverWorld->setActiveGrid(osg::Vec4i(0, 0, 0, 0));
|
||||
}
|
||||
|
||||
mPostProcessor = new PostProcessor(*this, viewer, mRootNode);
|
||||
resourceSystem->getSceneManager()->setDepthFormat(mPostProcessor->getDepthFormat());
|
||||
|
||||
if (reverseZ && !SceneUtil::isFloatingPointDepthFormat(mPostProcessor->getDepthFormat()))
|
||||
Log(Debug::Warning) << "Floating point depth format not in use but reverse-z buffer is enabled, consider disabling it.";
|
||||
|
||||
// water goes after terrain for correct waterculling order
|
||||
mWater.reset(new Water(sceneRoot->getParent(0), sceneRoot, mResourceSystem, mViewer->getIncrementalCompileOperation(), resourcePath));
|
||||
|
||||
@ -395,6 +479,9 @@ namespace MWRender
|
||||
mStateUpdater = new StateUpdater;
|
||||
sceneRoot->addUpdateCallback(mStateUpdater);
|
||||
|
||||
mSharedUniformStateUpdater = new SharedUniformStateUpdater;
|
||||
rootNode->addUpdateCallback(mSharedUniformStateUpdater);
|
||||
|
||||
osg::Camera::CullingMode cullingMode = osg::Camera::DEFAULT_CULLING|osg::Camera::FAR_PLANE_CULLING;
|
||||
|
||||
if (!Settings::Manager::getBool("small feature culling", "Camera"))
|
||||
@ -415,7 +502,9 @@ namespace MWRender
|
||||
NifOsg::Loader::setIntersectionDisabledNodeMask(Mask_Effect);
|
||||
Nif::NIFFile::setLoadUnsupportedFiles(Settings::Manager::getBool("load unsupported nif files", "Models"));
|
||||
|
||||
mNearClip = Settings::Manager::getFloat("near clip", "Camera");
|
||||
// TODO: Near clip should not need to be bounded like this, but too small values break OSG shadow calculations CPU-side.
|
||||
// See issue: #6072
|
||||
mNearClip = std::max(0.005f, Settings::Manager::getFloat("near clip", "Camera"));
|
||||
mViewDistance = Settings::Manager::getFloat("viewing distance", "Camera");
|
||||
float fov = Settings::Manager::getFloat("field of view", "Camera");
|
||||
mFieldOfView = std::min(std::max(1.f, fov), 179.f);
|
||||
@ -423,8 +512,6 @@ namespace MWRender
|
||||
mFirstPersonFieldOfView = std::min(std::max(1.f, firstPersonFov), 179.f);
|
||||
mStateUpdater->setFogEnd(mViewDistance);
|
||||
|
||||
mRootNode->getOrCreateStateSet()->addUniform(new osg::Uniform("near", mNearClip));
|
||||
mRootNode->getOrCreateStateSet()->addUniform(new osg::Uniform("far", mViewDistance));
|
||||
mRootNode->getOrCreateStateSet()->addUniform(new osg::Uniform("simpleWater", false));
|
||||
|
||||
// Hopefully, anything genuinely requiring the default alpha func of GL_ALWAYS explicitly sets it
|
||||
@ -432,8 +519,15 @@ namespace MWRender
|
||||
// The transparent renderbin sets alpha testing on because that was faster on old GPUs. It's now slower and breaks things.
|
||||
mRootNode->getOrCreateStateSet()->setMode(GL_ALPHA_TEST, osg::StateAttribute::OFF);
|
||||
|
||||
mUniformNear = mRootNode->getOrCreateStateSet()->getUniform("near");
|
||||
mUniformFar = mRootNode->getOrCreateStateSet()->getUniform("far");
|
||||
if (reverseZ)
|
||||
{
|
||||
osg::ref_ptr<osg::ClipControl> clipcontrol = new osg::ClipControl(osg::ClipControl::LOWER_LEFT, osg::ClipControl::ZERO_TO_ONE);
|
||||
mRootNode->getOrCreateStateSet()->setAttributeAndModes(SceneUtil::createDepth(), osg::StateAttribute::ON);
|
||||
mRootNode->getOrCreateStateSet()->setAttributeAndModes(clipcontrol, osg::StateAttribute::ON);
|
||||
}
|
||||
|
||||
SceneUtil::setCameraClearDepth(mViewer->getCamera());
|
||||
|
||||
updateProjectionMatrix();
|
||||
}
|
||||
|
||||
@ -1066,10 +1160,19 @@ namespace MWRender
|
||||
float fov = mFieldOfView;
|
||||
if (mFieldOfViewOverridden)
|
||||
fov = mFieldOfViewOverride;
|
||||
|
||||
mViewer->getCamera()->setProjectionMatrixAsPerspective(fov, aspect, mNearClip, mViewDistance);
|
||||
|
||||
mUniformNear->set(mNearClip);
|
||||
mUniformFar->set(mViewDistance);
|
||||
if (SceneUtil::getReverseZ())
|
||||
{
|
||||
mSharedUniformStateUpdater->setLinearFac(-mNearClip / (mViewDistance - mNearClip) - 1.f);
|
||||
mSharedUniformStateUpdater->setProjectionMatrix(SceneUtil::getReversedZProjectionMatrixAsPerspective(fov, aspect, mNearClip, mViewDistance));
|
||||
}
|
||||
else
|
||||
mSharedUniformStateUpdater->setProjectionMatrix(mViewer->getCamera()->getProjectionMatrix());
|
||||
|
||||
mSharedUniformStateUpdater->setNear(mNearClip);
|
||||
mSharedUniformStateUpdater->setFar(mViewDistance);
|
||||
|
||||
// Since our fog is not radial yet, we should take FOV in account, otherwise terrain near viewing distance may disappear.
|
||||
// Limit FOV here just for sure, otherwise viewing distance can be too high.
|
||||
|
@ -72,6 +72,7 @@ namespace MWRender
|
||||
{
|
||||
class GroundcoverUpdater;
|
||||
class StateUpdater;
|
||||
class SharedUniformStateUpdater;
|
||||
|
||||
class EffectManager;
|
||||
class ScreenshotManager;
|
||||
@ -89,6 +90,7 @@ namespace MWRender
|
||||
class RecastMesh;
|
||||
class ObjectPaging;
|
||||
class Groundcover;
|
||||
class PostProcessor;
|
||||
|
||||
class RenderingManager : public MWRender::RenderingInterface
|
||||
{
|
||||
@ -108,9 +110,6 @@ namespace MWRender
|
||||
SceneUtil::UnrefQueue* getUnrefQueue();
|
||||
Terrain::World* getTerrain();
|
||||
|
||||
osg::Uniform* mUniformNear;
|
||||
osg::Uniform* mUniformFar;
|
||||
|
||||
void preloadCommonAssets();
|
||||
|
||||
double getReferenceTime() const;
|
||||
@ -240,8 +239,9 @@ namespace MWRender
|
||||
bool pagingUnlockCache();
|
||||
void getPagedRefnums(const osg::Vec4i &activeGrid, std::set<ESM::RefNum> &out);
|
||||
|
||||
private:
|
||||
void updateProjectionMatrix();
|
||||
|
||||
private:
|
||||
void updateTextureFiltering();
|
||||
void updateAmbient();
|
||||
void setFogColor(const osg::Vec4f& color);
|
||||
@ -287,6 +287,7 @@ namespace MWRender
|
||||
std::unique_ptr<ScreenshotManager> mScreenshotManager;
|
||||
std::unique_ptr<EffectManager> mEffectManager;
|
||||
std::unique_ptr<SceneUtil::ShadowManager> mShadowManager;
|
||||
osg::ref_ptr<PostProcessor> mPostProcessor;
|
||||
osg::ref_ptr<NpcAnimation> mPlayerAnimation;
|
||||
osg::ref_ptr<SceneUtil::PositionAttitudeTransform> mPlayerNode;
|
||||
std::unique_ptr<Camera> mCamera;
|
||||
@ -294,6 +295,7 @@ namespace MWRender
|
||||
osg::Vec3f mCurrentCameraPos;
|
||||
|
||||
osg::ref_ptr<StateUpdater> mStateUpdater;
|
||||
osg::ref_ptr<SharedUniformStateUpdater> mSharedUniformStateUpdater;
|
||||
|
||||
osg::Vec4f mAmbientColor;
|
||||
float mMinimumAmbientLuminance;
|
||||
|
@ -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,13 +56,13 @@ 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();
|
||||
depth->setWriteMask(false);
|
||||
stateset->setAttributeAndModes(depth, osg::StateAttribute::ON);
|
||||
|
||||
osg::ref_ptr<osg::PolygonOffset> polygonOffset (new osg::PolygonOffset);
|
||||
polygonOffset->setUnits(-1);
|
||||
polygonOffset->setFactor(-1);
|
||||
polygonOffset->setUnits(SceneUtil::getReverseZ() ? 1 : -1);
|
||||
polygonOffset->setFactor(SceneUtil::getReverseZ() ? 1 : -1);
|
||||
stateset->setAttributeAndModes(polygonOffset, osg::StateAttribute::ON);
|
||||
|
||||
stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <components/resource/resourcesystem.hpp>
|
||||
#include <components/resource/scenemanager.hpp>
|
||||
#include <components/shader/shadermanager.hpp>
|
||||
#include <components/sceneutil/util.hpp>
|
||||
|
||||
#include <components/settings/settings.hpp>
|
||||
|
||||
@ -22,6 +23,7 @@
|
||||
#include "util.hpp"
|
||||
#include "vismask.hpp"
|
||||
#include "water.hpp"
|
||||
#include "postprocessor.hpp"
|
||||
|
||||
namespace MWRender
|
||||
{
|
||||
@ -88,6 +90,18 @@ namespace MWRender
|
||||
int topPadding = std::max(0, static_cast<int>(screenH - screenW / imageaspect) / 2);
|
||||
int width = screenW - leftPadding*2;
|
||||
int height = screenH - topPadding*2;
|
||||
|
||||
// Ensure we are reading from the resolved framebuffer and not the multisampled render buffer when in use.
|
||||
// glReadPixel() cannot read from multisampled targets.
|
||||
PostProcessor* postProcessor = dynamic_cast<PostProcessor*>(renderInfo.getCurrentCamera()->getUserData());
|
||||
|
||||
if (postProcessor && postProcessor->getFbo() && postProcessor->getMsaaFbo())
|
||||
{
|
||||
osg::GLExtensions* ext = osg::GLExtensions::Get(renderInfo.getContextID(), false);
|
||||
if (ext)
|
||||
ext->glBindFramebuffer(GL_FRAMEBUFFER_EXT, postProcessor->getFbo()->getHandle(renderInfo.getContextID()));
|
||||
}
|
||||
|
||||
mImage->readPixels(leftPadding, topPadding, width, height, GL_RGB, GL_UNSIGNED_BYTE);
|
||||
mImage->scaleImage(mWidth, mHeight, 1);
|
||||
}
|
||||
@ -236,6 +250,7 @@ namespace MWRender
|
||||
|
||||
osg::ref_ptr<osg::Camera> screenshotCamera(new osg::Camera);
|
||||
osg::ref_ptr<osg::ShapeDrawable> quad(new osg::ShapeDrawable(new osg::Box(osg::Vec3(0,0,0), 2.0)));
|
||||
quad->getOrCreateStateSet()->setRenderBinDetails(100, "RenderBin", osg::StateSet::USE_RENDERBIN_DETAILS);
|
||||
|
||||
std::map<std::string, std::string> defineMap;
|
||||
|
||||
@ -282,9 +297,10 @@ namespace MWRender
|
||||
camera->setRenderOrder(osg::Camera::PRE_RENDER);
|
||||
camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF);
|
||||
camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT,osg::Camera::PIXEL_BUFFER_RTT);
|
||||
|
||||
camera->setViewport(0, 0, w, h);
|
||||
|
||||
SceneUtil::setCameraClearDepth(camera);
|
||||
|
||||
osg::ref_ptr<osg::Texture2D> texture (new osg::Texture2D);
|
||||
texture->setInternalFormat(GL_RGB);
|
||||
texture->setTextureSize(w,h);
|
||||
@ -318,7 +334,10 @@ namespace MWRender
|
||||
float nearClip = Settings::Manager::getFloat("near clip", "Camera");
|
||||
float viewDistance = Settings::Manager::getFloat("viewing distance", "Camera");
|
||||
// each cubemap side sees 90 degrees
|
||||
rttCamera->setProjectionMatrixAsPerspective(90.0, w/float(h), nearClip, viewDistance);
|
||||
if (SceneUtil::getReverseZ())
|
||||
rttCamera->setProjectionMatrix(SceneUtil::getReversedZProjectionMatrixAsPerspectiveInf(90.0, w/float(h), nearClip));
|
||||
else
|
||||
rttCamera->setProjectionMatrixAsPerspective(90.0, w/float(h), nearClip, viewDistance);
|
||||
rttCamera->setViewMatrix(mViewer->getCamera()->getViewMatrix() * cameraTransform);
|
||||
|
||||
rttCamera->setUpdateCallback(new NoTraverseCallback);
|
||||
|
@ -54,6 +54,7 @@
|
||||
|
||||
#include "vismask.hpp"
|
||||
#include "renderbin.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
@ -594,13 +595,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();
|
||||
// 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);
|
||||
double far = SceneUtil::getReverseZ() ? 0.0 : 1.0;
|
||||
depth->setZNear(far);
|
||||
depth->setZFar(far);
|
||||
depth->setWriteMask(false);
|
||||
queryStateSet->setAttributeAndModes(depth, osg::StateAttribute::ON);
|
||||
}
|
||||
@ -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();
|
||||
depth->setWriteMask(false);
|
||||
mEarlyRenderBinRoot->getOrCreateStateSet()->setAttributeAndModes(depth, osg::StateAttribute::ON);
|
||||
mEarlyRenderBinRoot->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON);
|
||||
|
@ -273,6 +273,7 @@ public:
|
||||
|
||||
void setDefaults(osg::Camera* camera) override
|
||||
{
|
||||
SceneUtil::setCameraClearDepth(camera);
|
||||
camera->setReferenceFrame(osg::Camera::RELATIVE_RF);
|
||||
camera->setSmallFeatureCullingPixelSize(Settings::Manager::getInt("small feature culling pixel size", "Water"));
|
||||
camera->setName("RefractionCamera");
|
||||
@ -338,6 +339,7 @@ public:
|
||||
|
||||
void setDefaults(osg::Camera* camera) override
|
||||
{
|
||||
SceneUtil::setCameraClearDepth(camera);
|
||||
camera->setReferenceFrame(osg::Camera::RELATIVE_RF);
|
||||
camera->setSmallFeatureCullingPixelSize(Settings::Manager::getInt("small feature culling pixel size", "Water"));
|
||||
camera->setName("ReflectionCamera");
|
||||
@ -614,7 +616,7 @@ public:
|
||||
{
|
||||
stateset->setMode(GL_BLEND, osg::StateAttribute::ON);
|
||||
stateset->setRenderBinDetails(MWRender::RenderBin_Water, "RenderBin");
|
||||
osg::ref_ptr<osg::Depth> depth(new osg::Depth);
|
||||
osg::ref_ptr<osg::Depth> depth = SceneUtil::createDepth();
|
||||
depth->setWriteMask(false);
|
||||
stateset->setAttributeAndModes(depth, osg::StateAttribute::ON);
|
||||
}
|
||||
|
@ -1823,7 +1823,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();
|
||||
// Depth write flag
|
||||
depth->setWriteMask((zprop->flags>>1)&1);
|
||||
// Morrowind ignores depth test function
|
||||
|
@ -275,6 +275,16 @@ namespace Resource
|
||||
return mClampLighting;
|
||||
}
|
||||
|
||||
void SceneManager::setDepthFormat(GLenum format)
|
||||
{
|
||||
mDepthFormat = format;
|
||||
}
|
||||
|
||||
GLenum SceneManager::getDepthFormat() const
|
||||
{
|
||||
return mDepthFormat;
|
||||
}
|
||||
|
||||
void SceneManager::setAutoUseNormalMaps(bool use)
|
||||
{
|
||||
mAutoUseNormalMaps = use;
|
||||
|
@ -92,6 +92,9 @@ namespace Resource
|
||||
void setClampLighting(bool clamp);
|
||||
bool getClampLighting() const;
|
||||
|
||||
void setDepthFormat(GLenum format);
|
||||
GLenum getDepthFormat() const;
|
||||
|
||||
/// @see ShaderVisitor::setAutoUseNormalMaps
|
||||
void setAutoUseNormalMaps(bool use);
|
||||
|
||||
@ -202,6 +205,7 @@ namespace Resource
|
||||
SceneUtil::LightingMethod mLightingMethod;
|
||||
SceneUtil::LightManager::SupportedMethods mSupportedLightingMethods;
|
||||
bool mConvertAlphaTestToAlphaToCoverage;
|
||||
GLenum mDepthFormat;
|
||||
|
||||
osg::ref_ptr<MultiObjectCache> mInstanceCache;
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
#include "agentpath.hpp"
|
||||
#include "detourdebugdraw.hpp"
|
||||
|
||||
#include <osg/Material>
|
||||
|
||||
#include <components/detournavigator/settings.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
@ -65,6 +67,10 @@ namespace SceneUtil
|
||||
|
||||
debugDraw.depthMask(true);
|
||||
|
||||
osg::ref_ptr<osg::Material> material = new osg::Material;
|
||||
material->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE);
|
||||
group->getOrCreateStateSet()->setAttribute(material);
|
||||
|
||||
return group;
|
||||
}
|
||||
}
|
||||
|
@ -23,8 +23,12 @@
|
||||
#include <osg/Geometry>
|
||||
#include <osg/io_utils>
|
||||
#include <osg/Depth>
|
||||
#include <osg/ClipControl>
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include <components/sceneutil/util.hpp>
|
||||
|
||||
#include "shadowsbin.hpp"
|
||||
|
||||
namespace {
|
||||
@ -1636,6 +1640,11 @@ void MWShadowTechnique::createShaders()
|
||||
_shadowCastingStateSet->addUniform(new osg::Uniform("alphaTestShadows", false));
|
||||
osg::ref_ptr<osg::Depth> depth = new osg::Depth;
|
||||
depth->setWriteMask(true);
|
||||
if (SceneUtil::getReverseZ())
|
||||
{
|
||||
osg::ref_ptr<osg::ClipControl> clipcontrol = new osg::ClipControl(osg::ClipControl::LOWER_LEFT, osg::ClipControl::NEGATIVE_ONE_TO_ONE);
|
||||
_shadowCastingStateSet->setAttribute(clipcontrol, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE);
|
||||
}
|
||||
_shadowCastingStateSet->setAttribute(depth, osg::StateAttribute::ON|osg::StateAttribute::OVERRIDE);
|
||||
_shadowCastingStateSet->setMode(GL_DEPTH_CLAMP, osg::StateAttribute::ON);
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <DetourDebugDraw.h>
|
||||
|
||||
#include <osg/Group>
|
||||
#include <osg/Material>
|
||||
|
||||
namespace SceneUtil
|
||||
{
|
||||
@ -17,6 +18,11 @@ namespace SceneUtil
|
||||
navMeshQuery.init(&navMesh, settings.mMaxNavMeshQueryNodes);
|
||||
duDebugDrawNavMeshWithClosedList(&debugDraw, navMesh, navMeshQuery,
|
||||
DU_DRAWNAVMESH_OFFMESHCONS | DU_DRAWNAVMESH_CLOSEDLIST);
|
||||
|
||||
osg::ref_ptr<osg::Material> material = new osg::Material;
|
||||
material->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE);
|
||||
group->getOrCreateStateSet()->setAttribute(material);
|
||||
|
||||
return group;
|
||||
}
|
||||
}
|
||||
|
@ -40,6 +40,8 @@
|
||||
|
||||
#include <iterator>
|
||||
|
||||
#include <components/sceneutil/util.hpp>
|
||||
|
||||
using namespace osgUtil;
|
||||
|
||||
namespace SceneUtil
|
||||
@ -1560,7 +1562,7 @@ bool Optimizer::MergeGeometryVisitor::mergeGroup(osg::Group& group)
|
||||
}
|
||||
if (_alphaBlendingActive && _mergeAlphaBlending && !geom->getStateSet())
|
||||
{
|
||||
osg::Depth* d = new osg::Depth;
|
||||
auto d = createDepth();
|
||||
d->setWriteMask(0);
|
||||
geom->getOrCreateStateSet()->setAttribute(d);
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "pathgridutil.hpp"
|
||||
|
||||
#include <osg/Geometry>
|
||||
#include <osg/Material>
|
||||
|
||||
#include <components/esm/loadpgrd.hpp>
|
||||
|
||||
@ -174,6 +175,11 @@ namespace SceneUtil
|
||||
gridGeometry->addPrimitiveSet(lineIndices);
|
||||
gridGeometry->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
|
||||
}
|
||||
|
||||
osg::ref_ptr<osg::Material> material = new osg::Material;
|
||||
material->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE);
|
||||
gridGeometry->getOrCreateStateSet()->setAttribute(material);
|
||||
|
||||
return gridGeometry;
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include <RecastDebugDraw.h>
|
||||
|
||||
#include <osg/Group>
|
||||
#include <osg/Material>
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
@ -65,6 +66,11 @@ namespace SceneUtil
|
||||
const auto texScale = 1.0f / (settings.mCellSize * 10.0f);
|
||||
duDebugDrawTriMesh(&debugDraw, vertices.data(), static_cast<int>(vertices.size() / 3),
|
||||
indices.data(), normals.data(), static_cast<int>(indices.size() / 3), nullptr, texScale);
|
||||
|
||||
osg::ref_ptr<osg::Material> material = new osg::Material;
|
||||
material->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE);
|
||||
group->getOrCreateStateSet()->setAttribute(material);
|
||||
|
||||
return group;
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,8 @@
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
#include <SDL_opengl_glext.h>
|
||||
|
||||
#include <osg/Node>
|
||||
#include <osg/NodeVisitor>
|
||||
#include <osg/TexGen>
|
||||
@ -13,6 +15,20 @@
|
||||
#include <components/resource/imagemanager.hpp>
|
||||
#include <components/resource/scenemanager.hpp>
|
||||
#include <components/settings/settings.hpp>
|
||||
#include <components/debug/debuglog.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
bool isReverseZSupported()
|
||||
{
|
||||
if (!Settings::Manager::mDefaultSettings.count({"Camera", "reverse z"}))
|
||||
return false;
|
||||
auto ext = osg::GLExtensions::Get(0, false);
|
||||
return Settings::Manager::getBool("reverse z", "Camera") && ext && ext->isClipControlSupported;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace SceneUtil
|
||||
{
|
||||
@ -150,6 +166,43 @@ void GlowUpdater::setDuration(float duration)
|
||||
mDuration = duration;
|
||||
}
|
||||
|
||||
// Allows camera to render to a color and floating point depth texture with a multisampled framebuffer.
|
||||
// Must be set on a camera's cull callback.
|
||||
class AttachMultisampledDepthColorCallback : public osg::NodeCallback
|
||||
{
|
||||
public:
|
||||
AttachMultisampledDepthColorCallback(osg::Texture2D* colorTex, osg::Texture2D* depthTex, int samples, int colorSamples)
|
||||
{
|
||||
int width = colorTex->getTextureWidth();
|
||||
int height = colorTex->getTextureHeight();
|
||||
|
||||
osg::ref_ptr<osg::RenderBuffer> rbColor = new osg::RenderBuffer(width, height, colorTex->getInternalFormat(), samples, colorSamples);
|
||||
osg::ref_ptr<osg::RenderBuffer> rbDepth = new osg::RenderBuffer(width, height, depthTex->getInternalFormat(), samples, colorSamples);
|
||||
|
||||
mMsaaFbo = new osg::FrameBufferObject;
|
||||
mMsaaFbo->setAttachment(osg::Camera::COLOR_BUFFER0, osg::FrameBufferAttachment(rbColor));
|
||||
mMsaaFbo->setAttachment(osg::Camera::DEPTH_BUFFER, osg::FrameBufferAttachment(rbDepth));
|
||||
|
||||
mFbo = new osg::FrameBufferObject;
|
||||
mFbo->setAttachment(osg::Camera::COLOR_BUFFER0, osg::FrameBufferAttachment(colorTex));
|
||||
mFbo->setAttachment(osg::Camera::DEPTH_BUFFER, osg::FrameBufferAttachment(depthTex));
|
||||
}
|
||||
|
||||
void operator()(osg::Node* node, osg::NodeVisitor* nv) override
|
||||
{
|
||||
osgUtil::RenderStage* renderStage = nv->asCullVisitor()->getCurrentRenderStage();
|
||||
|
||||
renderStage->setMultisampleResolveFramebufferObject(mFbo);
|
||||
renderStage->setFrameBufferObject(mMsaaFbo);
|
||||
|
||||
traverse(node, nv);
|
||||
}
|
||||
|
||||
private:
|
||||
osg::ref_ptr<osg::FrameBufferObject> mFbo;
|
||||
osg::ref_ptr<osg::FrameBufferObject> mMsaaFbo;
|
||||
};
|
||||
|
||||
void transformBoundingSphere (const osg::Matrixf& matrix, osg::BoundingSphere& bsphere)
|
||||
{
|
||||
osg::BoundingSphere::vec_type xdash = bsphere._center;
|
||||
@ -285,4 +338,81 @@ bool attachAlphaToCoverageFriendlyFramebufferToCamera(osg::Camera* camera, osg::
|
||||
return addMSAAIntermediateTarget;
|
||||
}
|
||||
|
||||
void attachAlphaToCoverageFriendlyDepthColor(osg::Camera* camera, osg::Texture2D* colorTex, osg::Texture2D* depthTex, GLenum depthFormat)
|
||||
{
|
||||
bool addMSAAIntermediateTarget = Settings::Manager::getBool("antialias alpha test", "Shaders") && Settings::Manager::getInt("antialiasing", "Video") > 1;
|
||||
|
||||
if (isFloatingPointDepthFormat(depthFormat) && addMSAAIntermediateTarget)
|
||||
{
|
||||
camera->attach(osg::Camera::COLOR_BUFFER0, colorTex);
|
||||
camera->attach(osg::Camera::DEPTH_BUFFER, depthTex);
|
||||
camera->addCullCallback(new AttachMultisampledDepthColorCallback(colorTex, depthTex, 2, 1));
|
||||
}
|
||||
else
|
||||
{
|
||||
attachAlphaToCoverageFriendlyFramebufferToCamera(camera, osg::Camera::COLOR_BUFFER, colorTex);
|
||||
camera->attach(osg::Camera::DEPTH_BUFFER, depthTex);
|
||||
}
|
||||
}
|
||||
|
||||
bool getReverseZ()
|
||||
{
|
||||
static bool reverseZ = isReverseZSupported();
|
||||
return reverseZ;
|
||||
}
|
||||
|
||||
void setCameraClearDepth(osg::Camera* camera)
|
||||
{
|
||||
camera->setClearDepth(getReverseZ() ? 0.0 : 1.0);
|
||||
}
|
||||
|
||||
osg::ref_ptr<osg::Depth> createDepth()
|
||||
{
|
||||
return new osg::Depth(getReverseZ() ? osg::Depth::GEQUAL : osg::Depth::LEQUAL);
|
||||
}
|
||||
|
||||
osg::Matrix getReversedZProjectionMatrixAsPerspectiveInf(double fov, double aspect, double near)
|
||||
{
|
||||
double A = 1.0/std::tan(osg::DegreesToRadians(fov)/2.0);
|
||||
return osg::Matrix(
|
||||
A/aspect, 0, 0, 0,
|
||||
0, A, 0, 0,
|
||||
0, 0, 0, -1,
|
||||
0, 0, near, 0
|
||||
);
|
||||
}
|
||||
|
||||
osg::Matrix getReversedZProjectionMatrixAsPerspective(double fov, double aspect, double near, double far)
|
||||
{
|
||||
double A = 1.0/std::tan(osg::DegreesToRadians(fov)/2.0);
|
||||
return osg::Matrix(
|
||||
A/aspect, 0, 0, 0,
|
||||
0, A, 0, 0,
|
||||
0, 0, near/(far-near), -1,
|
||||
0, 0, (far*near)/(far - near), 0
|
||||
);
|
||||
}
|
||||
|
||||
osg::Matrix getReversedZProjectionMatrixAsOrtho(double left, double right, double bottom, double top, double near, double far)
|
||||
{
|
||||
return osg::Matrix(
|
||||
2/(right-left), 0, 0, 0,
|
||||
0, 2/(top-bottom), 0, 0,
|
||||
0, 0, 1/(far-near), 0,
|
||||
(right+left)/(left-right), (top+bottom)/(bottom-top), far/(far-near), 1
|
||||
);
|
||||
}
|
||||
|
||||
bool isFloatingPointDepthFormat(GLenum format)
|
||||
{
|
||||
constexpr std::array<GLenum, 4> formats = {
|
||||
GL_DEPTH_COMPONENT32F,
|
||||
GL_DEPTH_COMPONENT32F_NV,
|
||||
GL_DEPTH32F_STENCIL8,
|
||||
GL_DEPTH32F_STENCIL8_NV,
|
||||
};
|
||||
|
||||
return std::find(formats.cbegin(), formats.cend(), format) != formats.cend();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <osg/NodeCallback>
|
||||
#include <osg/Texture2D>
|
||||
#include <osg/Vec4f>
|
||||
#include <osg/Depth>
|
||||
|
||||
#include <components/resource/resourcesystem.hpp>
|
||||
|
||||
@ -64,6 +65,31 @@ namespace SceneUtil
|
||||
|
||||
// Alpha-to-coverage requires a multisampled framebuffer, so we need to set that up for RTTs
|
||||
bool attachAlphaToCoverageFriendlyFramebufferToCamera(osg::Camera* camera, osg::Camera::BufferComponent buffer, osg::Texture* texture, unsigned int level = 0, unsigned int face = 0, bool mipMapGeneration = false);
|
||||
|
||||
void attachAlphaToCoverageFriendlyDepthColor(osg::Camera* camera, osg::Texture2D* colorTex, osg::Texture2D* depthTex, GLenum depthFormat);
|
||||
|
||||
bool getReverseZ();
|
||||
|
||||
void setCameraClearDepth(osg::Camera* camera);
|
||||
|
||||
// Returns a suitable depth state attribute dependent on whether a reverse-z
|
||||
// depth buffer is in use.
|
||||
osg::ref_ptr<osg::Depth> createDepth();
|
||||
|
||||
// Returns a perspective projection matrix for use with a reversed z-buffer
|
||||
// and an infinite far plane. This is derived by mapping the default z-range
|
||||
// of [0,1] to [1,0], then taking the limit as far plane approaches
|
||||
// infinity.
|
||||
osg::Matrix getReversedZProjectionMatrixAsPerspectiveInf(double fov, double aspect, double near);
|
||||
|
||||
// Returns a perspective projection matrix for use with a reversed z-buffer.
|
||||
osg::Matrix getReversedZProjectionMatrixAsPerspective(double fov, double aspect, double near, double far);
|
||||
|
||||
// Returns an orthographic projection matrix for use with a reversed z-buffer.
|
||||
osg::Matrix getReversedZProjectionMatrixAsOrtho(double left, double right, double bottom, double top, double near, double far);
|
||||
|
||||
// Returns true if the GL format is a floating point depth format
|
||||
bool isFloatingPointDepthFormat(GLenum format);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -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
|
||||
@ -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();
|
||||
depth->setWriteMask(false);
|
||||
stateset->setAttributeAndModes(depth, osg::StateAttribute::ON);
|
||||
|
||||
|
@ -8,13 +8,16 @@
|
||||
#include "world.hpp"
|
||||
#include "../esm/loadland.hpp"
|
||||
|
||||
#include <components/resource/scenemanager.hpp>
|
||||
|
||||
namespace Terrain
|
||||
{
|
||||
|
||||
CellBorder::CellBorder(Terrain::World *world, osg::Group *root, int borderMask):
|
||||
mWorld(world),
|
||||
mRoot(root),
|
||||
mBorderMask(borderMask)
|
||||
CellBorder::CellBorder(Terrain::World *world, osg::Group *root, int borderMask, Resource::SceneManager* sceneManager)
|
||||
: mWorld(world)
|
||||
, mSceneManager(sceneManager)
|
||||
, mRoot(root)
|
||||
, mBorderMask(borderMask)
|
||||
{
|
||||
}
|
||||
|
||||
@ -73,6 +76,8 @@ void CellBorder::createCellBorderGeometry(int x, int y)
|
||||
polygonmode->setMode(osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::LINE);
|
||||
stateSet->setAttributeAndModes(polygonmode,osg::StateAttribute::ON);
|
||||
|
||||
mSceneManager->recreateShaders(borderGeode, "debug");
|
||||
|
||||
borderGeode->setNodeMask(mBorderMask);
|
||||
|
||||
mRoot->addChild(borderGeode);
|
||||
|
@ -4,6 +4,11 @@
|
||||
#include <map>
|
||||
#include <osg/Group>
|
||||
|
||||
namespace Resource
|
||||
{
|
||||
class SceneManager;
|
||||
}
|
||||
|
||||
namespace Terrain
|
||||
{
|
||||
class World;
|
||||
@ -16,7 +21,7 @@ namespace Terrain
|
||||
public:
|
||||
typedef std::map<std::pair<int, int>, osg::ref_ptr<osg::Node> > CellGrid;
|
||||
|
||||
CellBorder(Terrain::World *world, osg::Group *root, int borderMask);
|
||||
CellBorder(Terrain::World *world, osg::Group *root, int borderMask, Resource::SceneManager* sceneManager);
|
||||
|
||||
void createCellBorderGeometry(int x, int y);
|
||||
void destroyCellBorderGeometry(int x, int y);
|
||||
@ -28,6 +33,7 @@ namespace Terrain
|
||||
|
||||
protected:
|
||||
Terrain::World *mWorld;
|
||||
Resource::SceneManager* mSceneManager;
|
||||
osg::Group *mRoot;
|
||||
|
||||
CellGrid mCellBorderNodes;
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include <osg/BlendFunc>
|
||||
|
||||
#include <components/shader/shadermanager.hpp>
|
||||
#include <components/sceneutil/util.hpp>
|
||||
|
||||
#include <mutex>
|
||||
|
||||
@ -105,9 +106,8 @@ namespace
|
||||
osg::ref_ptr<osg::Depth> mValue;
|
||||
|
||||
LequalDepth()
|
||||
: mValue(new osg::Depth)
|
||||
: mValue(SceneUtil::createDepth())
|
||||
{
|
||||
mValue->setFunction(osg::Depth::LEQUAL);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <osg/Camera>
|
||||
|
||||
#include <components/resource/resourcesystem.hpp>
|
||||
#include <components/resource/scenemanager.hpp>
|
||||
|
||||
#include "storage.hpp"
|
||||
#include "texturemanager.hpp"
|
||||
@ -43,7 +44,7 @@ World::World(osg::Group* parent, osg::Group* compileRoot, Resource::ResourceSyst
|
||||
mTextureManager.reset(new TextureManager(mResourceSystem->getSceneManager()));
|
||||
mChunkManager.reset(new ChunkManager(mStorage, mResourceSystem->getSceneManager(), mTextureManager.get(), mCompositeMapRenderer));
|
||||
mChunkManager->setNodeMask(nodeMask);
|
||||
mCellBorder.reset(new CellBorder(this,mTerrainRoot.get(),borderMask));
|
||||
mCellBorder.reset(new CellBorder(this,mTerrainRoot.get(),borderMask,mResourceSystem->getSceneManager()));
|
||||
|
||||
mResourceSystem->addResourceManager(mChunkManager.get());
|
||||
mResourceSystem->addResourceManager(mTextureManager.get());
|
||||
|
@ -5,8 +5,8 @@ near clip
|
||||
---------
|
||||
|
||||
:Type: floating point
|
||||
:Range: > 0
|
||||
:Default: 3.0
|
||||
:Range: >= 0.005
|
||||
:Default: 1.0
|
||||
|
||||
This setting controls the distance to the near clipping plane. The value must be greater than zero.
|
||||
Values greater than approximately 18.0 will occasionally clip objects in the world in front of the character.
|
||||
@ -235,3 +235,23 @@ Maximum roll angle in degrees.
|
||||
|
||||
This setting can only be configured by editing the settings configuration file.
|
||||
|
||||
reverse z
|
||||
---------
|
||||
|
||||
:Type: boolean
|
||||
:Range: True/False
|
||||
:Default: True
|
||||
|
||||
Enables a reverse-z depth buffer in which the depth range is reversed. This
|
||||
allows for small :ref:`near clip` values and removes almost all z-fighting with
|
||||
terrain and even tightly coupled meshes at extreme view distances. For this to
|
||||
be useful, a floating point depth buffer is required. These features require
|
||||
driver and hardware support, but should work on any semi-modern desktop hardware
|
||||
through OpenGL extensions. The exception is macOS, which has since dropped
|
||||
development of OpenGL drivers. If unsupported, this setting has no effect.
|
||||
|
||||
Note, this will force OpenMW to use shaders as if :ref:`force shaders` was enabled.
|
||||
The performance impact of this feature should be negligible.
|
||||
|
||||
This setting can only be configured by editing the settings configuration file.
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
||||
[Camera]
|
||||
|
||||
# Near clipping plane (>0.0, e.g. 0.01 to 18.0).
|
||||
near clip = 3
|
||||
near clip = 1
|
||||
|
||||
# Cull objects that occupy less than 'small feature culling pixel size' on the screen.
|
||||
small feature culling = true
|
||||
@ -67,6 +67,9 @@ head bobbing height = 3.0
|
||||
# Maximum camera roll angle (degrees)
|
||||
head bobbing roll = 0.2
|
||||
|
||||
# Reverse the depth range, reduces z-fighting of distant objects and terrain
|
||||
reverse z = true
|
||||
|
||||
[Cells]
|
||||
|
||||
# Preload cells in a background thread. All settings starting with 'preload' have no effect unless this is enabled.
|
||||
|
@ -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
|
||||
@ -33,6 +34,8 @@ set(SHADER_FILES
|
||||
nv_nolighting_fragment.glsl
|
||||
gui_vertex.glsl
|
||||
gui_fragment.glsl
|
||||
debug_vertex.glsl
|
||||
debug_fragment.glsl
|
||||
)
|
||||
|
||||
copy_all_resource_files(${CMAKE_CURRENT_SOURCE_DIR} ${OPENMW_SHADERS_ROOT} ${DDIRRELATIVE} "${SHADER_FILES}")
|
||||
|
8
files/shaders/debug_fragment.glsl
Normal file
8
files/shaders/debug_fragment.glsl
Normal file
@ -0,0 +1,8 @@
|
||||
#version 120
|
||||
|
||||
#include "vertexcolors.glsl"
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_FragData[0] = getDiffuseColor();
|
||||
}
|
12
files/shaders/debug_vertex.glsl
Normal file
12
files/shaders/debug_vertex.glsl
Normal file
@ -0,0 +1,12 @@
|
||||
#version 120
|
||||
|
||||
uniform mat4 projectionMatrix;
|
||||
|
||||
varying vec4 passColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
gl_Position = projectionMatrix * (gl_ModelViewMatrix * gl_Vertex);
|
||||
|
||||
passColor = gl_Color;
|
||||
}
|
12
files/shaders/depth.glsl
Normal file
12
files/shaders/depth.glsl
Normal file
@ -0,0 +1,12 @@
|
||||
#if @reverseZ
|
||||
uniform float linearFac;
|
||||
#endif
|
||||
|
||||
float getLinearDepth(in float z, in float viewZ)
|
||||
{
|
||||
#if @reverseZ
|
||||
return linearFac*viewZ;
|
||||
#else
|
||||
return z;
|
||||
#endif
|
||||
}
|
@ -39,12 +39,14 @@ centroid varying vec3 shadowDiffuseLighting;
|
||||
|
||||
#include "shadows_vertex.glsl"
|
||||
#include "lighting.glsl"
|
||||
#include "depth.glsl"
|
||||
|
||||
uniform float osg_SimulationTime;
|
||||
uniform mat4 osg_ViewMatrixInverse;
|
||||
uniform mat4 osg_ViewMatrix;
|
||||
uniform float windSpeed;
|
||||
uniform vec3 playerPos;
|
||||
uniform mat4 projectionMatrix;
|
||||
|
||||
#if @groundcoverStompMode == 0
|
||||
#else
|
||||
@ -141,9 +143,9 @@ void main(void)
|
||||
if (length(gl_ModelViewMatrix * vec4(position, 1.0)) > @groundcoverFadeEnd)
|
||||
gl_Position = vec4(0.0, 0.0, 0.0, 1.0);
|
||||
else
|
||||
gl_Position = gl_ProjectionMatrix * viewPos;
|
||||
gl_Position = projectionMatrix * viewPos;
|
||||
|
||||
linearDepth = gl_Position.z;
|
||||
linearDepth = getLinearDepth(gl_Position.z, viewPos.z);
|
||||
|
||||
#if (!PER_PIXEL_LIGHTING || @shadows_enabled)
|
||||
vec3 viewNormal = normalize((gl_NormalMatrix * rotation3(rotation) * gl_Normal).xyz);
|
||||
|
@ -8,6 +8,8 @@
|
||||
#extension GL_EXT_gpu_shader4: require
|
||||
#endif
|
||||
|
||||
uniform mat4 projectionMatrix;
|
||||
|
||||
#if @diffuseMap
|
||||
varying vec2 diffuseMapUV;
|
||||
#endif
|
||||
@ -32,15 +34,16 @@ varying vec3 passNormal;
|
||||
#include "vertexcolors.glsl"
|
||||
#include "shadows_vertex.glsl"
|
||||
#include "lighting.glsl"
|
||||
#include "depth.glsl"
|
||||
|
||||
void main(void)
|
||||
{
|
||||
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
|
||||
gl_Position = projectionMatrix * (gl_ModelViewMatrix * gl_Vertex);
|
||||
|
||||
vec4 viewPos = (gl_ModelViewMatrix * gl_Vertex);
|
||||
gl_ClipVertex = viewPos;
|
||||
euclideanDepth = length(viewPos.xyz);
|
||||
linearDepth = gl_Position.z;
|
||||
linearDepth = getLinearDepth(gl_Position.z, viewPos.z);
|
||||
|
||||
#if @diffuseMap
|
||||
diffuseMapUV = (gl_TextureMatrix[@diffuseMapUV] * gl_MultiTexCoord@diffuseMapUV).xy;
|
||||
|
@ -1,5 +1,7 @@
|
||||
#version 120
|
||||
|
||||
uniform mat4 projectionMatrix;
|
||||
|
||||
#if @diffuseMap
|
||||
varying vec2 diffuseMapUV;
|
||||
#endif
|
||||
@ -17,17 +19,18 @@ varying vec3 passViewPos;
|
||||
varying float passFalloff;
|
||||
|
||||
#include "vertexcolors.glsl"
|
||||
#include "depth.glsl"
|
||||
|
||||
void main(void)
|
||||
{
|
||||
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
|
||||
gl_Position = projectionMatrix * (gl_ModelViewMatrix * gl_Vertex);
|
||||
|
||||
vec4 viewPos = (gl_ModelViewMatrix * gl_Vertex);
|
||||
gl_ClipVertex = viewPos;
|
||||
#if @radialFog
|
||||
euclideanDepth = length(viewPos.xyz);
|
||||
#else
|
||||
linearDepth = gl_Position.z;
|
||||
linearDepth = getLinearDepth(gl_Position.z, viewPos.z);
|
||||
#endif
|
||||
|
||||
#if @diffuseMap
|
||||
|
@ -8,6 +8,8 @@
|
||||
#extension GL_EXT_gpu_shader4: require
|
||||
#endif
|
||||
|
||||
uniform mat4 projectionMatrix;
|
||||
|
||||
#if @diffuseMap
|
||||
varying vec2 diffuseMapUV;
|
||||
#endif
|
||||
@ -62,15 +64,17 @@ varying vec3 passNormal;
|
||||
#include "shadows_vertex.glsl"
|
||||
|
||||
#include "lighting.glsl"
|
||||
#include "depth.glsl"
|
||||
|
||||
void main(void)
|
||||
{
|
||||
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
|
||||
gl_Position = projectionMatrix * (gl_ModelViewMatrix * gl_Vertex);
|
||||
|
||||
vec4 viewPos = (gl_ModelViewMatrix * gl_Vertex);
|
||||
|
||||
gl_ClipVertex = viewPos;
|
||||
euclideanDepth = length(viewPos.xyz);
|
||||
linearDepth = gl_Position.z;
|
||||
linearDepth = getLinearDepth(gl_Position.z, viewPos.z);
|
||||
|
||||
#if (@envMap || !PER_PIXEL_LIGHTING || @shadows_enabled)
|
||||
vec3 viewNormal = normalize((gl_NormalMatrix * gl_Normal).xyz);
|
||||
|
@ -8,6 +8,8 @@
|
||||
#extension GL_EXT_gpu_shader4: require
|
||||
#endif
|
||||
|
||||
uniform mat4 projectionMatrix;
|
||||
|
||||
varying vec2 uv;
|
||||
varying float euclideanDepth;
|
||||
varying float linearDepth;
|
||||
@ -25,15 +27,16 @@ varying vec3 passNormal;
|
||||
#include "shadows_vertex.glsl"
|
||||
|
||||
#include "lighting.glsl"
|
||||
#include "depth.glsl"
|
||||
|
||||
void main(void)
|
||||
{
|
||||
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
|
||||
gl_Position = projectionMatrix * (gl_ModelViewMatrix * gl_Vertex);
|
||||
|
||||
vec4 viewPos = (gl_ModelViewMatrix * gl_Vertex);
|
||||
gl_ClipVertex = viewPos;
|
||||
euclideanDepth = length(viewPos.xyz);
|
||||
linearDepth = gl_Position.z;
|
||||
linearDepth = getLinearDepth(gl_Position.z, viewPos.z);
|
||||
|
||||
#if (!PER_PIXEL_LIGHTING || @shadows_enabled)
|
||||
vec3 viewNormal = normalize((gl_NormalMatrix * gl_Normal).xyz);
|
||||
|
@ -51,6 +51,8 @@ const float WIND_SPEED = 0.2f;
|
||||
|
||||
const vec3 WATER_COLOR = vec3(0.090195, 0.115685, 0.12745);
|
||||
|
||||
const float WOBBLY_SHORE_FADE_DISTANCE = 6200.0; // fade out wobbly shores to mask precision errors, the effect is almost impossible to see at a distance
|
||||
|
||||
// ---------------- rain ripples related stuff ---------------------
|
||||
|
||||
const float RAIN_RIPPLE_GAPS = 5.0;
|
||||
@ -158,11 +160,14 @@ uniform float rainIntensity;
|
||||
float frustumDepth;
|
||||
|
||||
float linearizeDepth(float depth)
|
||||
{
|
||||
float z_n = 2.0 * depth - 1.0;
|
||||
depth = 2.0 * near * far / (far + near - z_n * frustumDepth);
|
||||
return 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)
|
||||
{
|
||||
@ -267,10 +272,10 @@ void main(void)
|
||||
vec3 normalShoreRippleRain = texture2D(normalMap,normalCoords(UV, 2.0, 2.7, -1.0*waterTimer, 0.05, 0.1, normal3)).rgb - 0.5
|
||||
+ texture2D(normalMap,normalCoords(UV, 2.0, 2.7, waterTimer, 0.04, -0.13, normal4)).rgb - 0.5;
|
||||
float verticalWaterDepth = realWaterDepth * mix(abs(vVec.z), 1.0, 0.2); // an estimate
|
||||
float shoreOffset = verticalWaterDepth - (normal2.r + mix(0, normalShoreRippleRain.r, rainIntensity) + 0.15)*8;
|
||||
float fuzzFactor = min(1.0, 1000.0/surfaceDepth) * mix(abs(vVec.z), 1, 0.2);
|
||||
float shoreOffset = verticalWaterDepth - (normal2.r + mix(0.0, normalShoreRippleRain.r, rainIntensity) + 0.15)*8.0;
|
||||
float fuzzFactor = min(1.0, 1000.0/surfaceDepth) * mix(abs(vVec.z), 1.0, 0.2);
|
||||
shoreOffset *= fuzzFactor;
|
||||
shoreOffset = clamp(shoreOffset, 0, 1);
|
||||
shoreOffset = clamp(mix(shoreOffset, 1.0, clamp(linearDepth / WOBBLY_SHORE_FADE_DISTANCE, 0.0, 1.0)), 0.0, 1.0);
|
||||
gl_FragData[0].xyz = mix(rawRefraction, gl_FragData[0].xyz, shoreOffset);
|
||||
#else
|
||||
gl_FragData[0].xyz = mix(reflection, waterColor, (1.0-fresnel)*0.5) + specular * sunSpec.xyz + vec3(rainRipple.w) * 0.7;
|
||||
|
@ -1,14 +1,17 @@
|
||||
#version 120
|
||||
|
||||
|
||||
uniform mat4 projectionMatrix;
|
||||
|
||||
varying vec3 screenCoordsPassthrough;
|
||||
varying vec4 position;
|
||||
varying float linearDepth;
|
||||
|
||||
#include "shadows_vertex.glsl"
|
||||
#include "depth.glsl"
|
||||
|
||||
void main(void)
|
||||
{
|
||||
gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
|
||||
gl_Position = projectionMatrix * (gl_ModelViewMatrix * gl_Vertex);
|
||||
|
||||
mat4 scalemat = mat4(0.5, 0.0, 0.0, 0.0,
|
||||
0.0, -0.5, 0.0, 0.0,
|
||||
@ -20,7 +23,8 @@ void main(void)
|
||||
|
||||
position = gl_Vertex;
|
||||
|
||||
linearDepth = gl_Position.z;
|
||||
vec4 viewPos = gl_ModelViewMatrix * gl_Vertex;
|
||||
linearDepth = getLinearDepth(gl_Position.z, viewPos.z);
|
||||
|
||||
setupShadowCoords(gl_ModelViewMatrix * gl_Vertex, normalize((gl_NormalMatrix * gl_Normal).xyz));
|
||||
setupShadowCoords(viewPos, normalize((gl_NormalMatrix * gl_Normal).xyz));
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user