mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-19 22:23:51 +00:00
Better use of osg stereo, avoids redundant synchronization.
This commit is contained in:
parent
4c9278522e
commit
74806e4893
3 changed files with 132 additions and 78 deletions
|
@ -663,19 +663,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
||||||
Settings::Manager::getInt("anisotropy", "General")
|
Settings::Manager::getInt("anisotropy", "General")
|
||||||
);
|
);
|
||||||
|
|
||||||
// geometry shader must be enabled before the RenderingManager sets up any shaders
|
|
||||||
// therefore this part is separate from the rest of stereo setup.
|
|
||||||
mStereoEnabled = Settings::Manager::getBool("stereo enabled", "Stereo");
|
|
||||||
if (mStereoEnabled)
|
|
||||||
{
|
|
||||||
mResourceSystem->getSceneManager()->getShaderManager().setStereoGeometryShaderEnabled(Misc::getStereoTechnique() == Misc::StereoView::Technique::GeometryShader_IndexedViewports);
|
|
||||||
// Mask in everything that does not currently use shaders.
|
|
||||||
// Remove that altogether when the sky finally uses them.
|
|
||||||
auto noShaderMask = MWRender::VisMask::Mask_Sky | MWRender::VisMask::Mask_Sun | MWRender::VisMask::Mask_WeatherParticles;
|
|
||||||
// Since shaders are not yet created, we need to use the brute force technique initially
|
|
||||||
mStereoView.reset(new Misc::StereoView(mViewer, Misc::StereoView::Technique::BruteForce, noShaderMask, MWRender::VisMask::Mask_Scene));
|
|
||||||
}
|
|
||||||
|
|
||||||
int numThreads = Settings::Manager::getInt("preload num threads", "Cells");
|
int numThreads = Settings::Manager::getInt("preload num threads", "Cells");
|
||||||
if (numThreads <= 0)
|
if (numThreads <= 0)
|
||||||
throw std::runtime_error("Invalid setting: 'preload num threads' must be >0");
|
throw std::runtime_error("Invalid setting: 'preload num threads' must be >0");
|
||||||
|
@ -734,6 +721,16 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
||||||
// Create sound system
|
// Create sound system
|
||||||
mEnvironment.setSoundManager (new MWSound::SoundManager(mVFS.get(), mUseSound));
|
mEnvironment.setSoundManager (new MWSound::SoundManager(mVFS.get(), mUseSound));
|
||||||
|
|
||||||
|
|
||||||
|
if (mStereoEnabled)
|
||||||
|
{
|
||||||
|
// Set up stereo
|
||||||
|
// Stereo setup is split in two because the GeometryShader approach cannot be used before the RenderingManager has been created.
|
||||||
|
// To be able to see the logo and initial loading screen the BruteForce technique must be set up here.
|
||||||
|
mStereoView->initializeStereo(mViewer, Misc::StereoView::Technique::BruteForce);
|
||||||
|
mResourceSystem->getSceneManager()->getShaderManager().setStereoGeometryShaderEnabled(Misc::getStereoTechnique() == Misc::StereoView::Technique::GeometryShader_IndexedViewports);
|
||||||
|
}
|
||||||
|
|
||||||
if (!mSkipMenu)
|
if (!mSkipMenu)
|
||||||
{
|
{
|
||||||
const std::string& logo = Fallback::Map::getString("Movies_Company_Logo");
|
const std::string& logo = Fallback::Map::getString("Movies_Company_Logo");
|
||||||
|
@ -747,9 +744,9 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
||||||
mStartupScript, mResDir.string(), mCfgMgr.getUserDataPath().string()));
|
mStartupScript, mResDir.string(), mCfgMgr.getUserDataPath().string()));
|
||||||
mEnvironment.getWorld()->setupPlayer();
|
mEnvironment.getWorld()->setupPlayer();
|
||||||
|
|
||||||
// Set up stereo
|
|
||||||
if (mStereoEnabled)
|
if (mStereoEnabled)
|
||||||
{
|
{
|
||||||
|
// Stereo shader technique can be set up now.
|
||||||
mStereoView->setStereoTechnique(Misc::getStereoTechnique());
|
mStereoView->setStereoTechnique(Misc::getStereoTechnique());
|
||||||
mStereoView->initializeScene();
|
mStereoView->initializeScene();
|
||||||
mStereoView->setCullMask(mStereoView->getCullMask());
|
mStereoView->setCullMask(mStereoView->getCullMask());
|
||||||
|
@ -871,6 +868,18 @@ void OMW::Engine::go()
|
||||||
// Create encoder
|
// Create encoder
|
||||||
mEncoder = new ToUTF8::Utf8Encoder(mEncoding);
|
mEncoder = new ToUTF8::Utf8Encoder(mEncoding);
|
||||||
|
|
||||||
|
// geometry shader must be enabled before the RenderingManager sets up any shaders
|
||||||
|
// therefore this part is separate from the rest of stereo setup.
|
||||||
|
mStereoEnabled = Settings::Manager::getBool("stereo enabled", "Stereo");
|
||||||
|
if (mStereoEnabled)
|
||||||
|
{
|
||||||
|
// Mask in everything that does not currently use shaders.
|
||||||
|
// Remove that altogether when the sky finally uses them.
|
||||||
|
auto noShaderMask = MWRender::VisMask::Mask_Sky | MWRender::VisMask::Mask_Sun | MWRender::VisMask::Mask_WeatherParticles;
|
||||||
|
// Since shaders are not yet created, we need to use the brute force technique initially
|
||||||
|
mStereoView.reset(new Misc::StereoView(noShaderMask, MWRender::VisMask::Mask_Scene));
|
||||||
|
}
|
||||||
|
|
||||||
// Setup viewer
|
// Setup viewer
|
||||||
mViewer = new osgViewer::Viewer;
|
mViewer = new osgViewer::Viewer;
|
||||||
mViewer->setReleaseContextAtEndOfFrameHint(false);
|
mViewer->setReleaseContextAtEndOfFrameHint(false);
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include <osgUtil/CullVisitor>
|
#include <osgUtil/CullVisitor>
|
||||||
|
|
||||||
|
#include <osgViewer/Renderer>
|
||||||
#include <osgViewer/Viewer>
|
#include <osgViewer/Viewer>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
@ -252,26 +253,20 @@ namespace Misc
|
||||||
return camera;
|
return camera;
|
||||||
}
|
}
|
||||||
|
|
||||||
StereoView::StereoView(osgViewer::Viewer* viewer, Technique technique, osg::Node::NodeMask noShaderMask, osg::Node::NodeMask sceneMask)
|
StereoView::StereoView(osg::Node::NodeMask noShaderMask, osg::Node::NodeMask sceneMask)
|
||||||
: mViewer(viewer)
|
: mViewer(nullptr)
|
||||||
, mMainCamera(mViewer->getCamera())
|
, mMainCamera(nullptr)
|
||||||
, mRoot(mViewer->getSceneData()->asGroup())
|
, mRoot(nullptr)
|
||||||
, mStereoRoot(new osg::Group)
|
, mStereoRoot(new osg::Group)
|
||||||
, mUpdateCallback(new StereoUpdateCallback(this))
|
, mUpdateCallback(new StereoUpdateCallback(this))
|
||||||
, mTechnique(Technique::None)
|
, mTechnique(Technique::None)
|
||||||
, mNoShaderMask(noShaderMask)
|
, mNoShaderMask(noShaderMask)
|
||||||
, mSceneMask(sceneMask)
|
, mSceneMask(sceneMask)
|
||||||
, mCullMask(mMainCamera->getCullMask())
|
, mCullMask(0)
|
||||||
, mMasterConfig(new SharedShadowMapConfig)
|
, mMasterConfig(new SharedShadowMapConfig)
|
||||||
, mSlaveConfig(new SharedShadowMapConfig)
|
, mSlaveConfig(new SharedShadowMapConfig)
|
||||||
, mSharedShadowMaps(Settings::Manager::getBool("shared shadow maps", "Stereo"))
|
, mSharedShadowMaps(Settings::Manager::getBool("shared shadow maps", "Stereo"))
|
||||||
{
|
{
|
||||||
if (technique == Technique::None)
|
|
||||||
// Do nothing
|
|
||||||
return;
|
|
||||||
|
|
||||||
mRoot->setDataVariance(osg::Object::STATIC);
|
|
||||||
|
|
||||||
mMasterConfig->_id = "STEREO";
|
mMasterConfig->_id = "STEREO";
|
||||||
mMasterConfig->_master = true;
|
mMasterConfig->_master = true;
|
||||||
mSlaveConfig->_id = "STEREO";
|
mSlaveConfig->_id = "STEREO";
|
||||||
|
@ -283,42 +278,90 @@ namespace Misc
|
||||||
mStereoRoot->addChild(mStereoBruteForceRoot);
|
mStereoRoot->addChild(mStereoBruteForceRoot);
|
||||||
mStereoRoot->addCullCallback(new StereoStatesetUpdateCallback(this));
|
mStereoRoot->addCullCallback(new StereoStatesetUpdateCallback(this));
|
||||||
|
|
||||||
setStereoTechnique(technique);
|
|
||||||
|
|
||||||
if (sInstance)
|
if (sInstance)
|
||||||
throw std::logic_error("Double instance og StereoView");
|
throw std::logic_error("Double instance og StereoView");
|
||||||
sInstance = this;
|
sInstance = this;
|
||||||
|
|
||||||
|
auto* ds = osg::DisplaySettings::instance().get();
|
||||||
|
ds->setStereo(true);
|
||||||
|
ds->setStereoMode(osg::DisplaySettings::StereoMode::HORIZONTAL_SPLIT);
|
||||||
|
ds->setUseSceneViewForStereoHint(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StereoView::initializeStereo(osgViewer::Viewer* viewer, Technique technique)
|
||||||
|
{
|
||||||
|
mViewer = viewer;
|
||||||
|
mRoot = viewer->getSceneData()->asGroup();
|
||||||
|
mMainCamera = viewer->getCamera();
|
||||||
|
mCullMask = mMainCamera->getCullMask();
|
||||||
|
|
||||||
|
setStereoTechnique(technique);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StereoView::initializeScene()
|
||||||
|
{
|
||||||
|
SceneUtil::FindByNameVisitor findScene("Scene Root");
|
||||||
|
mRoot->accept(findScene);
|
||||||
|
mScene = findScene.mFoundNode;
|
||||||
|
if (!mScene)
|
||||||
|
throw std::logic_error("Couldn't find scene root");
|
||||||
|
|
||||||
|
if (mTechnique == Technique::GeometryShader_IndexedViewports)
|
||||||
|
{
|
||||||
|
mLeftCamera->addChild(mScene); // Use scene directly to avoid redundant shadow computation.
|
||||||
|
mRightCamera->addChild(mScene);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void StereoView::setupBruteForceTechnique()
|
void StereoView::setupBruteForceTechnique()
|
||||||
{
|
{
|
||||||
mLeftCamera = createCamera("Stereo Left", GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
auto* ds = osg::DisplaySettings::instance().get();
|
||||||
mRightCamera = createCamera("Stereo Right", GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
ds->setStereo(true);
|
||||||
|
ds->setStereoMode(osg::DisplaySettings::StereoMode::HORIZONTAL_SPLIT);
|
||||||
|
ds->setUseSceneViewForStereoHint(true);
|
||||||
|
|
||||||
if (mSharedShadowMaps)
|
struct ComputeStereoMatricesCallback : public osgUtil::SceneView::ComputeStereoMatricesCallback
|
||||||
{
|
{
|
||||||
mLeftCamera->setUserData(mSlaveConfig);
|
ComputeStereoMatricesCallback(StereoView* sv)
|
||||||
mRightCamera->setUserData(mMasterConfig);
|
: mStereoView(sv)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
osg::Matrixd computeLeftEyeProjection(const osg::Matrixd& projection) const override
|
||||||
|
{
|
||||||
|
return mStereoView->computeLeftEyeProjection(projection);
|
||||||
|
}
|
||||||
|
|
||||||
|
osg::Matrixd computeLeftEyeView(const osg::Matrixd& view) const override
|
||||||
|
{
|
||||||
|
return mStereoView->computeLeftEyeView(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
osg::Matrixd computeRightEyeProjection(const osg::Matrixd& projection) const override
|
||||||
|
{
|
||||||
|
return mStereoView->computeRightEyeProjection(projection);
|
||||||
|
}
|
||||||
|
|
||||||
|
osg::Matrixd computeRightEyeView(const osg::Matrixd& view) const override
|
||||||
|
{
|
||||||
|
return mStereoView->computeRightEyeView(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
StereoView* mStereoView;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto* renderer = static_cast<osgViewer::Renderer*>(mMainCamera->getRenderer());
|
||||||
|
|
||||||
|
// osgViewer::Renderer always has two scene views
|
||||||
|
for (auto* sceneView : { renderer->getSceneView(0), renderer->getSceneView(1) })
|
||||||
|
{
|
||||||
|
sceneView->setComputeStereoMatricesCallback(new ComputeStereoMatricesCallback(this));
|
||||||
|
sceneView->getCullVisitorLeft()->setName("LEFT");
|
||||||
|
sceneView->getCullVisitorRight()->setName("RIGHT");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Slave cameras must have their viewports defined immediately
|
mMainCamera->setUserData(mMasterConfig);
|
||||||
auto width = mMainCamera->getViewport()->width();
|
|
||||||
auto height = mMainCamera->getViewport()->height();
|
|
||||||
mLeftCamera->setViewport(0, 0, width / 2, height);
|
|
||||||
mRightCamera->setViewport(width / 2, 0, width / 2, height);
|
|
||||||
|
|
||||||
// Threading should be stopped before adding new slave cameras
|
|
||||||
mViewer->stopThreading();
|
|
||||||
mViewer->addSlave(mRightCamera, true);
|
|
||||||
mViewer->addSlave(mLeftCamera, true);
|
|
||||||
mRightCamera->setGraphicsContext(mViewer->getCamera()->getGraphicsContext());
|
|
||||||
mLeftCamera->setGraphicsContext(mViewer->getCamera()->getGraphicsContext());
|
|
||||||
|
|
||||||
// Remove main camera's graphics context to ensure it does not do any work
|
|
||||||
mViewer->getCamera()->setGraphicsContext(nullptr);
|
|
||||||
|
|
||||||
// Re-realize to ensure slave cameras are set up with appropriate settings
|
|
||||||
mViewer->realize();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void StereoView::setupGeometryShaderIndexedViewportTechnique()
|
void StereoView::setupGeometryShaderIndexedViewportTechnique()
|
||||||
|
@ -338,7 +381,7 @@ namespace Misc
|
||||||
for (unsigned int i = 0; i < viewer->getNumSlaves(); i++)
|
for (unsigned int i = 0; i < viewer->getNumSlaves(); i++)
|
||||||
{
|
{
|
||||||
auto& slave = viewer->getSlave(i);
|
auto& slave = viewer->getSlave(i);
|
||||||
if (slave._camera == camera);
|
if (slave._camera == camera)
|
||||||
{
|
{
|
||||||
viewer->removeSlave(i);
|
viewer->removeSlave(i);
|
||||||
return;
|
return;
|
||||||
|
@ -348,17 +391,10 @@ namespace Misc
|
||||||
|
|
||||||
void StereoView::removeBruteForceTechnique()
|
void StereoView::removeBruteForceTechnique()
|
||||||
{
|
{
|
||||||
mViewer->stopThreading();
|
auto* ds = osg::DisplaySettings::instance().get();
|
||||||
removeSlave(mViewer, mRightCamera);
|
ds->setStereo(false);
|
||||||
removeSlave(mViewer, mLeftCamera);
|
if(mMainCamera->getUserData() == mMasterConfig)
|
||||||
mLeftCamera->setUserData(nullptr);
|
mMainCamera->setUserData(nullptr);
|
||||||
mRightCamera->setUserData(nullptr);
|
|
||||||
|
|
||||||
mMainCamera->setGraphicsContext(mRightCamera->getGraphicsContext());
|
|
||||||
mLeftCamera = nullptr;
|
|
||||||
mRightCamera = nullptr;
|
|
||||||
|
|
||||||
mViewer->realize();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void StereoView::removeGeometryShaderIndexedViewportTechnique()
|
void StereoView::removeGeometryShaderIndexedViewportTechnique()
|
||||||
|
@ -589,21 +625,6 @@ namespace Misc
|
||||||
mUpdateViewCallback = cb;
|
mUpdateViewCallback = cb;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StereoView::initializeScene()
|
|
||||||
{
|
|
||||||
SceneUtil::FindByNameVisitor findScene("Scene Root");
|
|
||||||
mRoot->accept(findScene);
|
|
||||||
mScene = findScene.mFoundNode;
|
|
||||||
if (!mScene)
|
|
||||||
throw std::logic_error("Couldn't find scene root");
|
|
||||||
|
|
||||||
if (mTechnique == Technique::GeometryShader_IndexedViewports)
|
|
||||||
{
|
|
||||||
mLeftCamera->addChild(mScene); // Use scene directly to avoid redundant shadow computation.
|
|
||||||
mRightCamera->addChild(mScene);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void disableStereoForCamera(osg::Camera* camera)
|
void disableStereoForCamera(osg::Camera* camera)
|
||||||
{
|
{
|
||||||
auto* viewport = camera->getViewport();
|
auto* viewport = camera->getViewport();
|
||||||
|
@ -735,4 +756,20 @@ namespace Misc
|
||||||
{
|
{
|
||||||
return mCullMask;
|
return mCullMask;
|
||||||
}
|
}
|
||||||
|
osg::Matrixd StereoView::computeLeftEyeProjection(const osg::Matrixd& projection) const
|
||||||
|
{
|
||||||
|
return mLeftCamera->getProjectionMatrix();
|
||||||
|
}
|
||||||
|
osg::Matrixd StereoView::computeLeftEyeView(const osg::Matrixd& view) const
|
||||||
|
{
|
||||||
|
return mLeftCamera->getViewMatrix();
|
||||||
|
}
|
||||||
|
osg::Matrixd StereoView::computeRightEyeProjection(const osg::Matrixd& projection) const
|
||||||
|
{
|
||||||
|
return mRightCamera->getProjectionMatrix();
|
||||||
|
}
|
||||||
|
osg::Matrixd StereoView::computeRightEyeView(const osg::Matrixd& view) const
|
||||||
|
{
|
||||||
|
return mRightCamera->getViewMatrix();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,13 +96,14 @@ namespace Misc
|
||||||
//! \param noShaderMask mask in all nodes that do not use shaders and must be rendered brute force.
|
//! \param noShaderMask mask in all nodes that do not use shaders and must be rendered brute force.
|
||||||
//! \param sceneMask must equal MWRender::VisMask::Mask_Scene. Necessary while VisMask is still not in components/
|
//! \param sceneMask must equal MWRender::VisMask::Mask_Scene. Necessary while VisMask is still not in components/
|
||||||
//! \note the masks apply only to the GeometryShader_IndexdViewports technique and can be 0 for the BruteForce technique.
|
//! \note the masks apply only to the GeometryShader_IndexdViewports technique and can be 0 for the BruteForce technique.
|
||||||
StereoView(osgViewer::Viewer* viewer, Technique technique, osg::Node::NodeMask noShaderMask, osg::Node::NodeMask sceneMask);
|
StereoView(osg::Node::NodeMask noShaderMask, osg::Node::NodeMask sceneMask);
|
||||||
|
|
||||||
//! Updates uniforms with the view and projection matrices of each stereo view, and replaces the camera's view and projection matrix
|
//! Updates uniforms with the view and projection matrices of each stereo view, and replaces the camera's view and projection matrix
|
||||||
//! with a view and projection that closely envelopes the frustums of the two eyes.
|
//! with a view and projection that closely envelopes the frustums of the two eyes.
|
||||||
void update();
|
void update();
|
||||||
void updateStateset(osg::StateSet* stateset);
|
void updateStateset(osg::StateSet* stateset);
|
||||||
|
|
||||||
|
void initializeStereo(osgViewer::Viewer* viewer, Technique technique);
|
||||||
//! Initialized scene. Call when the "scene root" node has been created
|
//! Initialized scene. Call when the "scene root" node has been created
|
||||||
void initializeScene();
|
void initializeScene();
|
||||||
|
|
||||||
|
@ -129,6 +130,13 @@ namespace Misc
|
||||||
//! Get the last applied cullmask.
|
//! Get the last applied cullmask.
|
||||||
osg::Node::NodeMask getCullMask();
|
osg::Node::NodeMask getCullMask();
|
||||||
|
|
||||||
|
|
||||||
|
osg::Matrixd computeLeftEyeProjection(const osg::Matrixd& projection) const;
|
||||||
|
osg::Matrixd computeLeftEyeView(const osg::Matrixd& view) const;
|
||||||
|
|
||||||
|
osg::Matrixd computeRightEyeProjection(const osg::Matrixd& projection) const;
|
||||||
|
osg::Matrixd computeRightEyeView(const osg::Matrixd& view) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void setupBruteForceTechnique();
|
void setupBruteForceTechnique();
|
||||||
void setupGeometryShaderIndexedViewportTechnique();
|
void setupGeometryShaderIndexedViewportTechnique();
|
||||||
|
|
Loading…
Reference in a new issue