Better use of osg stereo, avoids redundant synchronization.

pull/615/head
Mads Buvik Sandvei 4 years ago
parent 4c9278522e
commit 74806e4893

@ -663,19 +663,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
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");
if (numThreads <= 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
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)
{
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()));
mEnvironment.getWorld()->setupPlayer();
// Set up stereo
if (mStereoEnabled)
{
// Stereo shader technique can be set up now.
mStereoView->setStereoTechnique(Misc::getStereoTechnique());
mStereoView->initializeScene();
mStereoView->setCullMask(mStereoView->getCullMask());
@ -871,6 +868,18 @@ void OMW::Engine::go()
// Create encoder
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
mViewer = new osgViewer::Viewer;
mViewer->setReleaseContextAtEndOfFrameHint(false);

@ -6,6 +6,7 @@
#include <osgUtil/CullVisitor>
#include <osgViewer/Renderer>
#include <osgViewer/Viewer>
#include <iostream>
@ -252,26 +253,20 @@ namespace Misc
return camera;
}
StereoView::StereoView(osgViewer::Viewer* viewer, Technique technique, osg::Node::NodeMask noShaderMask, osg::Node::NodeMask sceneMask)
: mViewer(viewer)
, mMainCamera(mViewer->getCamera())
, mRoot(mViewer->getSceneData()->asGroup())
StereoView::StereoView(osg::Node::NodeMask noShaderMask, osg::Node::NodeMask sceneMask)
: mViewer(nullptr)
, mMainCamera(nullptr)
, mRoot(nullptr)
, mStereoRoot(new osg::Group)
, mUpdateCallback(new StereoUpdateCallback(this))
, mTechnique(Technique::None)
, mNoShaderMask(noShaderMask)
, mSceneMask(sceneMask)
, mCullMask(mMainCamera->getCullMask())
, mCullMask(0)
, mMasterConfig(new SharedShadowMapConfig)
, mSlaveConfig(new SharedShadowMapConfig)
, mSharedShadowMaps(Settings::Manager::getBool("shared shadow maps", "Stereo"))
{
if (technique == Technique::None)
// Do nothing
return;
mRoot->setDataVariance(osg::Object::STATIC);
mMasterConfig->_id = "STEREO";
mMasterConfig->_master = true;
mSlaveConfig->_id = "STEREO";
@ -283,42 +278,90 @@ namespace Misc
mStereoRoot->addChild(mStereoBruteForceRoot);
mStereoRoot->addCullCallback(new StereoStatesetUpdateCallback(this));
setStereoTechnique(technique);
if (sInstance)
throw std::logic_error("Double instance og StereoView");
sInstance = this;
auto* ds = osg::DisplaySettings::instance().get();
ds->setStereo(true);
ds->setStereoMode(osg::DisplaySettings::StereoMode::HORIZONTAL_SPLIT);
ds->setUseSceneViewForStereoHint(true);
}
void StereoView::setupBruteForceTechnique()
void StereoView::initializeStereo(osgViewer::Viewer* viewer, Technique technique)
{
mLeftCamera = createCamera("Stereo Left", GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
mRightCamera = createCamera("Stereo Right", GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
mViewer = viewer;
mRoot = viewer->getSceneData()->asGroup();
mMainCamera = viewer->getCamera();
mCullMask = mMainCamera->getCullMask();
setStereoTechnique(technique);
}
if (mSharedShadowMaps)
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->setUserData(mSlaveConfig);
mRightCamera->setUserData(mMasterConfig);
mLeftCamera->addChild(mScene); // Use scene directly to avoid redundant shadow computation.
mRightCamera->addChild(mScene);
}
}
// Slave cameras must have their viewports defined immediately
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);
void StereoView::setupBruteForceTechnique()
{
auto* ds = osg::DisplaySettings::instance().get();
ds->setStereo(true);
ds->setStereoMode(osg::DisplaySettings::StereoMode::HORIZONTAL_SPLIT);
ds->setUseSceneViewForStereoHint(true);
struct ComputeStereoMatricesCallback : public osgUtil::SceneView::ComputeStereoMatricesCallback
{
ComputeStereoMatricesCallback(StereoView* sv)
: mStereoView(sv)
{
// 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);
osg::Matrixd computeLeftEyeProjection(const osg::Matrixd& projection) const override
{
return mStereoView->computeLeftEyeProjection(projection);
}
// Re-realize to ensure slave cameras are set up with appropriate settings
mViewer->realize();
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");
}
mMainCamera->setUserData(mMasterConfig);
}
void StereoView::setupGeometryShaderIndexedViewportTechnique()
@ -338,7 +381,7 @@ namespace Misc
for (unsigned int i = 0; i < viewer->getNumSlaves(); i++)
{
auto& slave = viewer->getSlave(i);
if (slave._camera == camera);
if (slave._camera == camera)
{
viewer->removeSlave(i);
return;
@ -348,17 +391,10 @@ namespace Misc
void StereoView::removeBruteForceTechnique()
{
mViewer->stopThreading();
removeSlave(mViewer, mRightCamera);
removeSlave(mViewer, mLeftCamera);
mLeftCamera->setUserData(nullptr);
mRightCamera->setUserData(nullptr);
mMainCamera->setGraphicsContext(mRightCamera->getGraphicsContext());
mLeftCamera = nullptr;
mRightCamera = nullptr;
mViewer->realize();
auto* ds = osg::DisplaySettings::instance().get();
ds->setStereo(false);
if(mMainCamera->getUserData() == mMasterConfig)
mMainCamera->setUserData(nullptr);
}
void StereoView::removeGeometryShaderIndexedViewportTechnique()
@ -589,21 +625,6 @@ namespace Misc
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)
{
auto* viewport = camera->getViewport();
@ -735,4 +756,20 @@ namespace Misc
{
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 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.
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
//! with a view and projection that closely envelopes the frustums of the two eyes.
void update();
void updateStateset(osg::StateSet* stateset);
void initializeStereo(osgViewer::Viewer* viewer, Technique technique);
//! Initialized scene. Call when the "scene root" node has been created
void initializeScene();
@ -129,6 +130,13 @@ namespace Misc
//! Get the last applied cullmask.
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:
void setupBruteForceTechnique();
void setupGeometryShaderIndexedViewportTechnique();

Loading…
Cancel
Save