mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-03-31 14:07:38 +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")
|
||||
);
|
||||
|
||||
// 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::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()
|
||||
{
|
||||
mLeftCamera = createCamera("Stereo Left", GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
mRightCamera = createCamera("Stereo Right", GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
auto* ds = osg::DisplaySettings::instance().get();
|
||||
ds->setStereo(true);
|
||||
ds->setStereoMode(osg::DisplaySettings::StereoMode::HORIZONTAL_SPLIT);
|
||||
ds->setUseSceneViewForStereoHint(true);
|
||||
|
||||
if (mSharedShadowMaps)
|
||||
struct ComputeStereoMatricesCallback : public osgUtil::SceneView::ComputeStereoMatricesCallback
|
||||
{
|
||||
mLeftCamera->setUserData(mSlaveConfig);
|
||||
mRightCamera->setUserData(mMasterConfig);
|
||||
ComputeStereoMatricesCallback(StereoView* sv)
|
||||
: 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
|
||||
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();
|
||||
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…
Reference in a new issue