mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-19 22:23:51 +00:00
Misc new stereo integration fixes.
This commit is contained in:
parent
5a25691435
commit
1b193deeac
18 changed files with 498 additions and 258 deletions
|
@ -56,6 +56,7 @@
|
|||
#include "mwworld/worldimp.hpp"
|
||||
|
||||
#include "mwrender/vismask.hpp"
|
||||
#include "mwrender/camera.hpp"
|
||||
|
||||
#include "mwclass/classes.hpp"
|
||||
|
||||
|
@ -71,6 +72,7 @@
|
|||
#include "mwvr/vrinputmanager.hpp"
|
||||
#include "mwvr/vrviewer.hpp"
|
||||
#include "mwvr/vrgui.hpp"
|
||||
#include "mwvr/vrcamera.hpp"
|
||||
#endif
|
||||
|
||||
namespace
|
||||
|
@ -673,6 +675,20 @@ 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 = mEnvironment.getVrMode() || 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");
|
||||
|
@ -755,35 +771,28 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
|||
// Create sound system
|
||||
mEnvironment.setSoundManager (new MWSound::SoundManager(mVFS.get(), mUseSound));
|
||||
|
||||
// VR mode will override this setting by setting mStereoOverride.
|
||||
mStereoEnabled = mEnvironment.getVrMode() || Settings::Manager::getBool("stereo enabled", "Stereo");
|
||||
|
||||
// geometry shader must be enabled before the RenderingManager sets up any shaders
|
||||
// therefore this part is separate from the rest of stereo setup.
|
||||
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;
|
||||
auto geometryShaderMask = mViewer->getCamera()->getCullMask() & ~noShaderMask;
|
||||
mStereoView.reset(new Misc::StereoView(mViewer, Misc::getStereoTechnique(), geometryShaderMask, noShaderMask | MWRender::VisMask::Mask_Scene));
|
||||
}
|
||||
|
||||
#ifdef USE_OPENXR
|
||||
mXrEnvironment.setGUIManager(new MWVR::VRGUIManager(mViewer, mResourceSystem.get()));
|
||||
mXrEnvironment.setGUIManager(new MWVR::VRGUIManager(mViewer, mResourceSystem.get(), rootNode));
|
||||
mXrEnvironment.getViewer()->configureCallbacks();
|
||||
#endif
|
||||
|
||||
std::unique_ptr<MWRender::Camera> camera(
|
||||
#ifdef USE_OPENXR
|
||||
new MWVR::VRCamera(mViewer->getCamera())
|
||||
#else
|
||||
new Camera(mViewer->getCamera())
|
||||
#endif
|
||||
);
|
||||
|
||||
if (!mSkipMenu)
|
||||
{
|
||||
const std::string& logo = Fallback::Map::getString("Movies_Company_Logo");
|
||||
if (!logo.empty())
|
||||
window->playVideo(logo, true);
|
||||
mEnvironment.getWindowManager()->playVideo(logo, true);
|
||||
}
|
||||
|
||||
// Create the world
|
||||
mEnvironment.setWorld( new MWWorld::World (mViewer, rootNode, mResourceSystem.get(), mWorkQueue.get(),
|
||||
mEnvironment.setWorld( new MWWorld::World (mViewer, rootNode, std::move(camera), mResourceSystem.get(), mWorkQueue.get(),
|
||||
mFileCollections, mContentFiles, mEncoder, mActivationDistanceOverride, mCellName,
|
||||
mStartupScript, mResDir.string(), mCfgMgr.getUserDataPath().string()));
|
||||
mEnvironment.getWorld()->setupPlayer();
|
||||
|
@ -791,7 +800,9 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
|||
// Set up stereo
|
||||
if (mStereoEnabled)
|
||||
{
|
||||
mStereoView->setStereoTechnique(Misc::getStereoTechnique());
|
||||
mStereoView->initializeScene();
|
||||
mStereoView->setCullMask(mStereoView->getCullMask());
|
||||
}
|
||||
|
||||
window->setStore(mEnvironment.getWorld()->getStore());
|
||||
|
|
|
@ -592,7 +592,14 @@ namespace MWGui
|
|||
|
||||
void WindowManager::enableScene(bool enable)
|
||||
{
|
||||
|
||||
unsigned int disablemask = MWRender::Mask_GUI|MWRender::Mask_PreCompile;
|
||||
|
||||
// In VR mode we have a scene to render.
|
||||
// TODO: We should nonetheless disable the scene outside of the 3D GUI
|
||||
if (MWBase::Environment::get().getVrMode())
|
||||
return;
|
||||
|
||||
if (!enable && mViewer->getCamera()->getCullMask() != disablemask)
|
||||
{
|
||||
mOldUpdateMask = mViewer->getUpdateVisitor()->getTraversalMask();
|
||||
|
|
|
@ -200,7 +200,7 @@ namespace MWRender
|
|||
Resource::ResourceSystem* mResourceSystem;
|
||||
};
|
||||
|
||||
RenderingManager::RenderingManager(osgViewer::Viewer* viewer, osg::ref_ptr<osg::Group> rootNode,
|
||||
RenderingManager::RenderingManager(osgViewer::Viewer* viewer, osg::ref_ptr<osg::Group> rootNode, std::unique_ptr<Camera> camera,
|
||||
Resource::ResourceSystem* resourceSystem, SceneUtil::WorkQueue* workQueue,
|
||||
const std::string& resourcePath, DetourNavigator::Navigator& navigator)
|
||||
: mViewer(viewer)
|
||||
|
@ -316,11 +316,8 @@ namespace MWRender
|
|||
|
||||
// water goes after terrain for correct waterculling order
|
||||
mWater.reset(new Water(sceneRoot->getParent(0), sceneRoot, mResourceSystem, mViewer->getIncrementalCompileOperation(), resourcePath));
|
||||
#ifdef USE_OPENXR
|
||||
mCamera.reset(new MWVR::VRCamera(mViewer->getCamera()));
|
||||
#else
|
||||
mCamera.reset(new Camera(mViewer->getCamera()));
|
||||
#endif
|
||||
mCamera = std::move(camera);
|
||||
|
||||
if (Settings::Manager::getBool("view over shoulder", "Camera"))
|
||||
mViewOverShoulderController.reset(new ViewOverShoulderController(mCamera.get()));
|
||||
|
||||
|
|
|
@ -106,7 +106,7 @@ namespace MWRender
|
|||
class RenderingManager : public MWRender::RenderingInterface
|
||||
{
|
||||
public:
|
||||
RenderingManager(osgViewer::Viewer* viewer, osg::ref_ptr<osg::Group> rootNode,
|
||||
RenderingManager(osgViewer::Viewer* viewer, osg::ref_ptr<osg::Group> rootNode, std::unique_ptr<Camera> camera,
|
||||
Resource::ResourceSystem* resourceSystem, SceneUtil::WorkQueue* workQueue,
|
||||
const std::string& resourcePath, DetourNavigator::Navigator& navigator);
|
||||
~RenderingManager();
|
||||
|
|
|
@ -35,6 +35,9 @@ namespace MWVR
|
|||
|
||||
void VRCamera::recenter()
|
||||
{
|
||||
if (!mHasTrackingData)
|
||||
return;
|
||||
|
||||
// Move position of head to center of character
|
||||
// Z should not be affected
|
||||
mHeadOffset = osg::Vec3(0, 0, 0);
|
||||
|
@ -87,6 +90,7 @@ namespace MWVR
|
|||
osg::Vec3 vrMovement = currentHeadPose.position - mHeadPose.position;
|
||||
mHeadPose = currentHeadPose;
|
||||
mHeadOffset += stageRotation() * vrMovement;
|
||||
mHasTrackingData = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -73,6 +73,7 @@ namespace MWVR
|
|||
Pose mHeadPose{};
|
||||
osg::Vec3 mHeadOffset{ 0,0,0 };
|
||||
bool mShouldRecenter{ true };
|
||||
bool mHasTrackingData{ false };
|
||||
float mYawOffset{ 0.f };
|
||||
};
|
||||
}
|
||||
|
|
|
@ -497,16 +497,17 @@ namespace MWVR
|
|||
|
||||
VRGUIManager::VRGUIManager(
|
||||
osg::ref_ptr<osgViewer::Viewer> viewer,
|
||||
Resource::ResourceSystem* resourceSystem)
|
||||
Resource::ResourceSystem* resourceSystem,
|
||||
osg::Group* rootNode)
|
||||
: mOsgViewer(viewer)
|
||||
, mResourceSystem(resourceSystem)
|
||||
, mRootNode(rootNode)
|
||||
{
|
||||
mGUIGeometriesRoot->setName("VR GUI Geometry Root");
|
||||
mGUIGeometriesRoot->setUpdateCallback(new VRGUIManagerUpdateCallback(this));
|
||||
mGUICamerasRoot->setName("VR GUI Cameras Root");
|
||||
auto* root = viewer->getSceneData();
|
||||
root->asGroup()->addChild(mGUICamerasRoot);
|
||||
root->asGroup()->addChild(mGUIGeometriesRoot);
|
||||
mRootNode->asGroup()->addChild(mGUICamerasRoot);
|
||||
mRootNode->asGroup()->addChild(mGUIGeometriesRoot);
|
||||
mGUIGeometriesRoot->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
|
||||
|
||||
LayerConfig defaultConfig = createDefaultConfig(1);
|
||||
|
|
|
@ -137,7 +137,8 @@ namespace MWVR
|
|||
public:
|
||||
VRGUIManager(
|
||||
osg::ref_ptr<osgViewer::Viewer> viewer,
|
||||
Resource::ResourceSystem* resourceSystem);
|
||||
Resource::ResourceSystem* resourceSystem,
|
||||
osg::Group* rootNode);
|
||||
|
||||
~VRGUIManager(void);
|
||||
|
||||
|
@ -190,6 +191,7 @@ namespace MWVR
|
|||
osg::ref_ptr<osgViewer::Viewer> mOsgViewer{ nullptr };
|
||||
Resource::ResourceSystem* mResourceSystem;
|
||||
|
||||
osg::ref_ptr<osg::Group> mRootNode{ nullptr };
|
||||
osg::ref_ptr<osg::Group> mGUIGeometriesRoot{ new osg::Group };
|
||||
osg::ref_ptr<osg::Group> mGUICamerasRoot{ new osg::Group };
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <iostream>
|
||||
#include <time.h>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
|
||||
#ifdef max
|
||||
#undef max
|
||||
|
@ -192,24 +193,17 @@ namespace MWVR
|
|||
|
||||
void VRSession::beginPhase(FramePhase phase)
|
||||
{
|
||||
Log(Debug::Debug) << "beginPhase(" << ((int)phase) << ") " << std::this_thread::get_id();
|
||||
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mMutex);
|
||||
while (getFrame(phase))
|
||||
{
|
||||
Log(Debug::Verbose) << "Warning: beginPhase called with a frame already in the target phase";
|
||||
mCondition.wait(lock);
|
||||
}
|
||||
}
|
||||
|
||||
mCondition.notify_all();
|
||||
auto& frame = getFrame(phase);
|
||||
//if (frame)
|
||||
//{
|
||||
// // Happens once during startup but can be ignored that time.
|
||||
// // TODO: This issue would be cleaned up if beginPhase(Update) was called at a more appropriate location.
|
||||
// Log(Debug::Warning) << "advanceFramePhase called with a frame alreay in the target phase";
|
||||
// return;
|
||||
//}
|
||||
|
||||
|
||||
if (phase == FramePhase::Update)
|
||||
{
|
||||
|
@ -224,6 +218,8 @@ namespace MWVR
|
|||
frame = std::move(getFrame(previousPhase));
|
||||
}
|
||||
|
||||
mCondition.notify_all();
|
||||
|
||||
if (phase == mXrSyncPhase && frame->mShouldSyncFrameLoop)
|
||||
{
|
||||
// We may reach this point before xrEndFrame of the previous frame
|
||||
|
@ -237,7 +233,6 @@ namespace MWVR
|
|||
Environment::get().getManager()->beginFrame();
|
||||
}
|
||||
|
||||
mCondition.notify_all();
|
||||
}
|
||||
|
||||
std::unique_ptr<VRSession::VRFrameMeta>& VRSession::getFrame(FramePhase phase)
|
||||
|
@ -348,7 +343,7 @@ namespace MWVR
|
|||
void VRSession::movementAngles(float& yaw, float& pitch)
|
||||
{
|
||||
if (!getFrame(FramePhase::Update))
|
||||
beginPhase(FramePhase::Update);
|
||||
return;
|
||||
|
||||
if (mHandDirectedMovement)
|
||||
{
|
||||
|
|
|
@ -4,103 +4,103 @@
|
|||
|
||||
namespace MWVR
|
||||
{
|
||||
Pose Pose::operator+(const Pose& rhs)
|
||||
{
|
||||
Pose pose = *this;
|
||||
pose.position += this->orientation * rhs.position;
|
||||
pose.orientation = rhs.orientation * this->orientation;
|
||||
return pose;
|
||||
}
|
||||
//Pose Pose::operator+(const Pose& rhs)
|
||||
//{
|
||||
// Pose pose = *this;
|
||||
// pose.position += this->orientation * rhs.position;
|
||||
// pose.orientation = rhs.orientation * this->orientation;
|
||||
// return pose;
|
||||
//}
|
||||
|
||||
const Pose& Pose::operator+=(const Pose& rhs)
|
||||
{
|
||||
*this = *this + rhs;
|
||||
return *this;
|
||||
}
|
||||
//const Pose& Pose::operator+=(const Pose& rhs)
|
||||
//{
|
||||
// *this = *this + rhs;
|
||||
// return *this;
|
||||
//}
|
||||
|
||||
Pose Pose::operator*(float scalar)
|
||||
{
|
||||
Pose pose = *this;
|
||||
pose.position *= scalar;
|
||||
return pose;
|
||||
}
|
||||
//Pose Pose::operator*(float scalar)
|
||||
//{
|
||||
// Pose pose = *this;
|
||||
// pose.position *= scalar;
|
||||
// return pose;
|
||||
//}
|
||||
|
||||
const Pose& Pose::operator*=(float scalar)
|
||||
{
|
||||
*this = *this * scalar;
|
||||
return *this;
|
||||
}
|
||||
//const Pose& Pose::operator*=(float scalar)
|
||||
//{
|
||||
// *this = *this * scalar;
|
||||
// return *this;
|
||||
//}
|
||||
|
||||
Pose Pose::operator/(float scalar)
|
||||
{
|
||||
Pose pose = *this;
|
||||
pose.position /= scalar;
|
||||
return pose;
|
||||
}
|
||||
const Pose& Pose::operator/=(float scalar)
|
||||
{
|
||||
*this = *this / scalar;
|
||||
return *this;
|
||||
}
|
||||
//Pose Pose::operator/(float scalar)
|
||||
//{
|
||||
// Pose pose = *this;
|
||||
// pose.position /= scalar;
|
||||
// return pose;
|
||||
//}
|
||||
//const Pose& Pose::operator/=(float scalar)
|
||||
//{
|
||||
// *this = *this / scalar;
|
||||
// return *this;
|
||||
//}
|
||||
|
||||
bool Pose::operator==(const Pose& rhs) const
|
||||
{
|
||||
return position == rhs.position && orientation == rhs.orientation;
|
||||
}
|
||||
//bool Pose::operator==(const Pose& rhs) const
|
||||
//{
|
||||
// return position == rhs.position && orientation == rhs.orientation;
|
||||
//}
|
||||
|
||||
bool FieldOfView::operator==(const FieldOfView& rhs) const
|
||||
{
|
||||
return angleDown == rhs.angleDown
|
||||
&& angleUp == rhs.angleUp
|
||||
&& angleLeft == rhs.angleLeft
|
||||
&& angleRight == rhs.angleRight;
|
||||
}
|
||||
//bool FieldOfView::operator==(const FieldOfView& rhs) const
|
||||
//{
|
||||
// return angleDown == rhs.angleDown
|
||||
// && angleUp == rhs.angleUp
|
||||
// && angleLeft == rhs.angleLeft
|
||||
// && angleRight == rhs.angleRight;
|
||||
//}
|
||||
|
||||
// near and far named with an underscore because of windows' headers galaxy brain defines.
|
||||
osg::Matrix FieldOfView::perspectiveMatrix(float near_, float far_)
|
||||
{
|
||||
const float tanLeft = tanf(angleLeft);
|
||||
const float tanRight = tanf(angleRight);
|
||||
const float tanDown = tanf(angleDown);
|
||||
const float tanUp = tanf(angleUp);
|
||||
//// near and far named with an underscore because of windows' headers galaxy brain defines.
|
||||
//osg::Matrix FieldOfView::perspectiveMatrix(float near_, float far_)
|
||||
//{
|
||||
// const float tanLeft = tanf(angleLeft);
|
||||
// const float tanRight = tanf(angleRight);
|
||||
// const float tanDown = tanf(angleDown);
|
||||
// const float tanUp = tanf(angleUp);
|
||||
|
||||
const float tanWidth = tanRight - tanLeft;
|
||||
const float tanHeight = tanUp - tanDown;
|
||||
// const float tanWidth = tanRight - tanLeft;
|
||||
// const float tanHeight = tanUp - tanDown;
|
||||
|
||||
const float offset = near_;
|
||||
// const float offset = near_;
|
||||
|
||||
float matrix[16] = {};
|
||||
// float matrix[16] = {};
|
||||
|
||||
matrix[0] = 2 / tanWidth;
|
||||
matrix[4] = 0;
|
||||
matrix[8] = (tanRight + tanLeft) / tanWidth;
|
||||
matrix[12] = 0;
|
||||
// matrix[0] = 2 / tanWidth;
|
||||
// matrix[4] = 0;
|
||||
// matrix[8] = (tanRight + tanLeft) / tanWidth;
|
||||
// matrix[12] = 0;
|
||||
|
||||
matrix[1] = 0;
|
||||
matrix[5] = 2 / tanHeight;
|
||||
matrix[9] = (tanUp + tanDown) / tanHeight;
|
||||
matrix[13] = 0;
|
||||
// matrix[1] = 0;
|
||||
// matrix[5] = 2 / tanHeight;
|
||||
// matrix[9] = (tanUp + tanDown) / tanHeight;
|
||||
// matrix[13] = 0;
|
||||
|
||||
if (far_ <= near_) {
|
||||
matrix[2] = 0;
|
||||
matrix[6] = 0;
|
||||
matrix[10] = -1;
|
||||
matrix[14] = -(near_ + offset);
|
||||
}
|
||||
else {
|
||||
matrix[2] = 0;
|
||||
matrix[6] = 0;
|
||||
matrix[10] = -(far_ + offset) / (far_ - near_);
|
||||
matrix[14] = -(far_ * (near_ + offset)) / (far_ - near_);
|
||||
}
|
||||
// if (far_ <= near_) {
|
||||
// matrix[2] = 0;
|
||||
// matrix[6] = 0;
|
||||
// matrix[10] = -1;
|
||||
// matrix[14] = -(near_ + offset);
|
||||
// }
|
||||
// else {
|
||||
// matrix[2] = 0;
|
||||
// matrix[6] = 0;
|
||||
// matrix[10] = -(far_ + offset) / (far_ - near_);
|
||||
// matrix[14] = -(far_ * (near_ + offset)) / (far_ - near_);
|
||||
// }
|
||||
|
||||
matrix[3] = 0;
|
||||
matrix[7] = 0;
|
||||
matrix[11] = -1;
|
||||
matrix[15] = 0;
|
||||
// matrix[3] = 0;
|
||||
// matrix[7] = 0;
|
||||
// matrix[11] = -1;
|
||||
// matrix[15] = 0;
|
||||
|
||||
return osg::Matrix(matrix);
|
||||
}
|
||||
// return osg::Matrix(matrix);
|
||||
//}
|
||||
bool PoseSet::operator==(const PoseSet& rhs) const
|
||||
{
|
||||
return eye[0] == rhs.eye[0]
|
||||
|
@ -112,10 +112,10 @@ namespace MWVR
|
|||
&& head == rhs.head;
|
||||
|
||||
}
|
||||
bool View::operator==(const View& rhs) const
|
||||
{
|
||||
return pose == rhs.pose && fov == rhs.fov;
|
||||
}
|
||||
//bool View::operator==(const View& rhs) const
|
||||
//{
|
||||
// return pose == rhs.pose && fov == rhs.fov;
|
||||
//}
|
||||
|
||||
std::ostream& operator <<(
|
||||
std::ostream& os,
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <components/debug/debuglog.hpp>
|
||||
#include <components/sdlutil/sdlgraphicswindow.hpp>
|
||||
#include <components/settings/settings.hpp>
|
||||
#include <components/misc/stereo.hpp>
|
||||
#include <osg/Camera>
|
||||
#include <osgViewer/Viewer>
|
||||
|
||||
|
@ -37,47 +38,51 @@ namespace MWVR
|
|||
RIGHT_SIDE = 1
|
||||
};
|
||||
|
||||
//! Represents the relative pose in space of some limb or eye.
|
||||
struct Pose
|
||||
{
|
||||
//! Position in space
|
||||
osg::Vec3 position{ 0,0,0 };
|
||||
//! Orientation in space.
|
||||
osg::Quat orientation{ 0,0,0,1 };
|
||||
////! Represents the relative pose in space of some limb or eye.
|
||||
//struct Pose
|
||||
//{
|
||||
// //! Position in space
|
||||
// osg::Vec3 position{ 0,0,0 };
|
||||
// //! Orientation in space.
|
||||
// osg::Quat orientation{ 0,0,0,1 };
|
||||
|
||||
//! Add one pose to another
|
||||
Pose operator+(const Pose& rhs);
|
||||
const Pose& operator+=(const Pose& rhs);
|
||||
// //! Add one pose to another
|
||||
// Pose operator+(const Pose& rhs);
|
||||
// const Pose& operator+=(const Pose& rhs);
|
||||
|
||||
//! Scale a pose (does not affect orientation)
|
||||
Pose operator*(float scalar);
|
||||
const Pose& operator*=(float scalar);
|
||||
Pose operator/(float scalar);
|
||||
const Pose& operator/=(float scalar);
|
||||
// //! Scale a pose (does not affect orientation)
|
||||
// Pose operator*(float scalar);
|
||||
// const Pose& operator*=(float scalar);
|
||||
// Pose operator/(float scalar);
|
||||
// const Pose& operator/=(float scalar);
|
||||
|
||||
bool operator==(const Pose& rhs) const;
|
||||
};
|
||||
// bool operator==(const Pose& rhs) const;
|
||||
//};
|
||||
|
||||
//! Fov of a single eye
|
||||
struct FieldOfView {
|
||||
float angleLeft;
|
||||
float angleRight;
|
||||
float angleUp;
|
||||
float angleDown;
|
||||
////! Fov of a single eye
|
||||
//struct FieldOfView {
|
||||
// float angleLeft;
|
||||
// float angleRight;
|
||||
// float angleUp;
|
||||
// float angleDown;
|
||||
|
||||
bool operator==(const FieldOfView& rhs) const;
|
||||
// bool operator==(const FieldOfView& rhs) const;
|
||||
|
||||
//! Generate a perspective matrix from this fov
|
||||
osg::Matrix perspectiveMatrix(float near, float far);
|
||||
};
|
||||
// //! Generate a perspective matrix from this fov
|
||||
// osg::Matrix perspectiveMatrix(float near, float far);
|
||||
//};
|
||||
|
||||
//! Represents an eye in VR including both pose and fov. A view's pose is relative to the head.
|
||||
struct View
|
||||
{
|
||||
Pose pose;
|
||||
FieldOfView fov;
|
||||
bool operator==(const View& rhs) const;
|
||||
};
|
||||
////! Represents an eye in VR including both pose and fov. A view's pose is relative to the head.
|
||||
//struct View
|
||||
//{
|
||||
// Pose pose;
|
||||
// FieldOfView fov;
|
||||
// bool operator==(const View& rhs) const;
|
||||
//};
|
||||
|
||||
using Pose = Misc::Pose;
|
||||
using FieldOfView = Misc::FieldOfView;
|
||||
using View = Misc::View;
|
||||
|
||||
//! The complete set of poses tracked each frame by MWVR.
|
||||
struct PoseSet
|
||||
|
|
|
@ -189,6 +189,11 @@ namespace MWVR
|
|||
Misc::StereoView::instance().setPredrawCallback(mPreDraw);
|
||||
Misc::StereoView::instance().setPostdrawCallback(mPostDraw);
|
||||
Misc::StereoView::instance().setCullCallback(new CullCallback);
|
||||
//auto cullMask = Misc::StereoView::instance().getCullMask();
|
||||
auto cullMask = ~(MWRender::VisMask::Mask_UpdateVisitor | MWRender::VisMask::Mask_SimpleWater);
|
||||
cullMask &= ~MWRender::VisMask::Mask_GUI;
|
||||
cullMask |= MWRender::VisMask::Mask_3DGUI;
|
||||
Misc::StereoView::instance().setCullMask(cullMask);
|
||||
|
||||
mCallbacksConfigured = true;
|
||||
}
|
||||
|
@ -347,7 +352,73 @@ namespace MWVR
|
|||
Log(Debug::Warning) << ("osg overwrote predraw");
|
||||
}
|
||||
}
|
||||
|
||||
VRViewer::InitialDrawCallback::~InitialDrawCallback()
|
||||
{
|
||||
}
|
||||
|
||||
void VRViewer::updateView(Misc::View& left, Misc::View& right)
|
||||
{
|
||||
auto phase = VRSession::FramePhase::Update;
|
||||
auto session = Environment::get().getSession();
|
||||
auto& frame = session->getFrame(phase);
|
||||
|
||||
if (frame->mShouldRender)
|
||||
{
|
||||
//left.fov.angleLeft = frame->mPredictedPoses.view->fov.angleLeft;
|
||||
//left.fov.angleLeft = frame->mPredictedPoses.view->fov.angleDown;
|
||||
//left.fov.angleLeft = frame->mPredictedPoses.view->fov.angleRight;
|
||||
//left.fov.angleLeft = frame->mPredictedPoses.view->fov.angleUp;
|
||||
//frame->mPredictedPoses.eye;
|
||||
left = frame->mPredictedPoses.view[static_cast<int>(Side::LEFT_SIDE)];
|
||||
right = frame->mPredictedPoses.view[static_cast<int>(Side::RIGHT_SIDE)];
|
||||
}
|
||||
|
||||
// auto* camera = slave._camera.get();
|
||||
//
|
||||
// // Update current cached cull mask of camera if it is active
|
||||
// auto mask = camera->getCullMask();
|
||||
// if (mask == 0)
|
||||
// camera->setCullMask(mCullMask);
|
||||
// else
|
||||
// mCullMask = mask;
|
||||
//
|
||||
// // If the session is not active, we do not want to waste resources rendering frames.
|
||||
// if (Environment::get().getSession()->getFrame(VRSession::FramePhase::Update)->mShouldRender)
|
||||
// {
|
||||
// Side side = Side::RIGHT_SIDE;
|
||||
// if (mName == "LeftEye")
|
||||
// {
|
||||
//
|
||||
// Environment::get().getViewer()->vrShadow().updateShadowConfig(view);
|
||||
// side = Side::LEFT_SIDE;
|
||||
// }
|
||||
//
|
||||
// auto* session = Environment::get().getSession();
|
||||
// auto viewMatrix = view.getCamera()->getViewMatrix();
|
||||
//
|
||||
// // If the camera does not have a view, use the VR stage directly
|
||||
// bool useStage = !(viewMatrix.getTrans().length() > 0.01);
|
||||
//
|
||||
// // If the view matrix is still the identity matrix, conventions have to be swapped around.
|
||||
// bool swapConventions = viewMatrix.isIdentity();
|
||||
//
|
||||
// viewMatrix = viewMatrix * session->viewMatrix(VRSession::FramePhase::Update, side, !useStage, !swapConventions);
|
||||
//
|
||||
// camera->setViewMatrix(viewMatrix);
|
||||
//
|
||||
// auto projectionMatrix = session->projectionMatrix(VRSession::FramePhase::Update, side);
|
||||
// camera->setProjectionMatrix(projectionMatrix);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// camera->setCullMask(0);
|
||||
// }
|
||||
// slave.updateSlaveImplementation(view);
|
||||
}
|
||||
|
||||
void VRViewer::UpdateViewCallback::updateView(Misc::View& left, Misc::View& right)
|
||||
{
|
||||
mViewer->updateView(left, right);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "vrshadow.hpp"
|
||||
|
||||
#include <components/sceneutil/positionattitudetransform.hpp>
|
||||
#include <components/misc/stereo.hpp>
|
||||
|
||||
namespace MWVR
|
||||
{
|
||||
|
@ -27,6 +28,16 @@ namespace MWVR
|
|||
class VRViewer
|
||||
{
|
||||
public:
|
||||
struct UpdateViewCallback : public Misc::StereoView::UpdateViewCallback
|
||||
{
|
||||
UpdateViewCallback(VRViewer* viewer) : mViewer(viewer) {};
|
||||
|
||||
//! Called during the update traversal of every frame to source updated stereo values.
|
||||
virtual void updateView(Misc::View& left, Misc::View& right) override;
|
||||
|
||||
VRViewer* mViewer;
|
||||
};
|
||||
|
||||
class SwapBuffersCallback : public osg::GraphicsContext::SwapCallback
|
||||
{
|
||||
public:
|
||||
|
@ -104,6 +115,7 @@ namespace MWVR
|
|||
void configureCallbacks();
|
||||
void setupMirrorTexture();
|
||||
void processChangedSettings(const std::set< std::pair<std::string, std::string> >& changed);
|
||||
void updateView(Misc::View& left, Misc::View& right);
|
||||
|
||||
SubImage subImage(Side side);
|
||||
|
||||
|
|
|
@ -144,6 +144,7 @@ namespace MWWorld
|
|||
World::World (
|
||||
osgViewer::Viewer* viewer,
|
||||
osg::ref_ptr<osg::Group> rootNode,
|
||||
std::unique_ptr<MWRender::Camera> camera,
|
||||
Resource::ResourceSystem* resourceSystem, SceneUtil::WorkQueue* workQueue,
|
||||
const Files::Collections& fileCollections,
|
||||
const std::vector<std::string>& contentFiles,
|
||||
|
@ -204,7 +205,7 @@ namespace MWWorld
|
|||
mNavigator.reset(new DetourNavigator::NavigatorStub());
|
||||
}
|
||||
|
||||
mRendering.reset(new MWRender::RenderingManager(viewer, rootNode, resourceSystem, workQueue, resourcePath, *mNavigator));
|
||||
mRendering.reset(new MWRender::RenderingManager(viewer, rootNode, std::move(camera), resourceSystem, workQueue, resourcePath, *mNavigator));
|
||||
mProjectileManager.reset(new ProjectileManager(mRendering->getLightRoot(), resourceSystem, mRendering.get(), mPhysics.get()));
|
||||
mRendering->preloadCommonAssets();
|
||||
|
||||
|
|
|
@ -195,6 +195,7 @@ namespace MWWorld
|
|||
World (
|
||||
osgViewer::Viewer* viewer,
|
||||
osg::ref_ptr<osg::Group> rootNode,
|
||||
std::unique_ptr<MWRender::Camera> camera,
|
||||
Resource::ResourceSystem* resourceSystem, SceneUtil::WorkQueue* workQueue,
|
||||
const Files::Collections& fileCollections,
|
||||
const std::vector<std::string>& contentFiles,
|
||||
|
|
|
@ -234,14 +234,34 @@ namespace Misc
|
|||
return *sInstance;
|
||||
}
|
||||
|
||||
StereoView::StereoView(osgViewer::Viewer* viewer, Technique technique, osg::Node::NodeMask geometryShaderMask, osg::Node::NodeMask noShaderMask)
|
||||
static osg::Camera*
|
||||
createCamera(std::string name, GLbitfield clearMask)
|
||||
{
|
||||
auto* camera = new osg::Camera;
|
||||
|
||||
camera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
|
||||
camera->setProjectionResizePolicy(osg::Camera::FIXED);
|
||||
camera->setProjectionMatrix(osg::Matrix::identity());
|
||||
camera->setViewMatrix(osg::Matrix::identity());
|
||||
camera->setName(name);
|
||||
camera->setDataVariance(osg::Object::STATIC);
|
||||
camera->setRenderOrder(osg::Camera::NESTED_RENDER);
|
||||
camera->setClearMask(clearMask);
|
||||
camera->setUpdateCallback(new SceneUtil::StateSetUpdater());
|
||||
|
||||
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())
|
||||
, mStereoRoot(new osg::Group)
|
||||
, mTechnique(technique)
|
||||
, mGeometryShaderMask(geometryShaderMask)
|
||||
, mUpdateCallback(new StereoUpdateCallback(this))
|
||||
, mTechnique(Technique::None)
|
||||
, mNoShaderMask(noShaderMask)
|
||||
, mSceneMask(sceneMask)
|
||||
, mCullMask(mMainCamera->getCullMask())
|
||||
, mMasterConfig(new SharedShadowMapConfig)
|
||||
, mSlaveConfig(new SharedShadowMapConfig)
|
||||
, mSharedShadowMaps(Settings::Manager::getBool("shared shadow maps", "Stereo"))
|
||||
|
@ -257,38 +277,13 @@ namespace Misc
|
|||
mSlaveConfig->_id = "STEREO";
|
||||
mSlaveConfig->_master = false;
|
||||
|
||||
mLeftCamera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
|
||||
mLeftCamera->setProjectionResizePolicy(osg::Camera::FIXED);
|
||||
mLeftCamera->setProjectionMatrix(osg::Matrix::identity());
|
||||
mLeftCamera->setViewMatrix(osg::Matrix::identity());
|
||||
mLeftCamera->setName("Stereo Left");
|
||||
mLeftCamera->setDataVariance(osg::Object::STATIC);
|
||||
mRightCamera->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
|
||||
mRightCamera->setProjectionResizePolicy(osg::Camera::FIXED);
|
||||
mRightCamera->setProjectionMatrix(osg::Matrix::identity());
|
||||
mRightCamera->setViewMatrix(osg::Matrix::identity());
|
||||
mRightCamera->setName("Stereo Right");
|
||||
mRightCamera->setDataVariance(osg::Object::STATIC);
|
||||
mStereoRoot->setName("Stereo Root");
|
||||
mStereoRoot->setDataVariance(osg::Object::STATIC);
|
||||
mStereoRoot->addChild(mStereoGeometryShaderRoot);
|
||||
mStereoRoot->addChild(mStereoBruteForceRoot);
|
||||
mStereoRoot->addCullCallback(new StereoStatesetUpdateCallback(this));
|
||||
|
||||
// Update stereo statesets/matrices, but after the main camera updates.
|
||||
auto mainCameraCB = mMainCamera->getUpdateCallback();
|
||||
mMainCamera->removeUpdateCallback(mainCameraCB);
|
||||
mMainCamera->addUpdateCallback(new StereoUpdateCallback(this));
|
||||
mMainCamera->addUpdateCallback(mainCameraCB);
|
||||
|
||||
// Do a blank double buffering of camera statesets on update. Actual state updates are performed in StereoView::Update()
|
||||
mLeftCamera->setUpdateCallback(new SceneUtil::StateSetUpdater());
|
||||
mRightCamera->setUpdateCallback(new SceneUtil::StateSetUpdater());
|
||||
|
||||
|
||||
if (mTechnique == Technique::GeometryShader_IndexedViewports)
|
||||
{
|
||||
setupGeometryShaderIndexedViewportTechnique();
|
||||
}
|
||||
else
|
||||
{
|
||||
setupBruteForceTechnique();
|
||||
}
|
||||
setStereoTechnique(technique);
|
||||
|
||||
if (sInstance)
|
||||
throw std::logic_error("Double instance og StereoView");
|
||||
|
@ -297,14 +292,8 @@ namespace Misc
|
|||
|
||||
void StereoView::setupBruteForceTechnique()
|
||||
{
|
||||
mLeftCamera->setRenderOrder(osg::Camera::NESTED_RENDER);
|
||||
mLeftCamera->setClearColor(mMainCamera->getClearColor());
|
||||
mLeftCamera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
mLeftCamera->setCullMask(mMainCamera->getCullMask());
|
||||
mRightCamera->setRenderOrder(osg::Camera::NESTED_RENDER);
|
||||
mRightCamera->setClearColor(mMainCamera->getClearColor());
|
||||
mRightCamera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
mRightCamera->setCullMask(mMainCamera->getCullMask());
|
||||
mLeftCamera = createCamera("Stereo Left", GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
mRightCamera = createCamera("Stereo Right", GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
if (mSharedShadowMaps)
|
||||
{
|
||||
|
@ -318,39 +307,137 @@ namespace Misc
|
|||
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()
|
||||
{
|
||||
mLeftCamera->setRenderOrder(osg::Camera::NESTED_RENDER);
|
||||
mLeftCamera->setClearMask(GL_NONE);
|
||||
mLeftCamera->setCullMask(mNoShaderMask);
|
||||
mRightCamera->setRenderOrder(osg::Camera::NESTED_RENDER);
|
||||
mRightCamera->setClearMask(GL_NONE);
|
||||
mRightCamera->setCullMask(mNoShaderMask);
|
||||
mMainCamera->setCullMask(mGeometryShaderMask);
|
||||
|
||||
mStereoRoot->setName("Stereo Root");
|
||||
mStereoRoot->setDataVariance(osg::Object::STATIC);
|
||||
mStereoRoot->addChild(mStereoGeometryShaderRoot);
|
||||
mStereoRoot->addChild(mStereoBruteForceRoot);
|
||||
mLeftCamera = createCamera("Stereo Left", GL_NONE);
|
||||
mRightCamera = createCamera("Stereo Right", GL_NONE);
|
||||
mStereoBruteForceRoot->addChild(mLeftCamera);
|
||||
mStereoBruteForceRoot->addChild(mRightCamera);
|
||||
|
||||
mStereoRoot->addCullCallback(new StereoStatesetUpdateCallback(this));
|
||||
|
||||
// Inject self as the root of the scene graph
|
||||
mStereoGeometryShaderRoot->addChild(mRoot);
|
||||
mViewer->setSceneData(mStereoRoot);
|
||||
}
|
||||
|
||||
static void removeSlave(osgViewer::Viewer* viewer, osg::Camera* camera)
|
||||
{
|
||||
for (unsigned int i = 0; i < viewer->getNumSlaves(); i++)
|
||||
{
|
||||
auto& slave = viewer->getSlave(i);
|
||||
if (slave._camera == camera);
|
||||
{
|
||||
viewer->removeSlave(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
void StereoView::removeGeometryShaderIndexedViewportTechnique()
|
||||
{
|
||||
mStereoGeometryShaderRoot->removeChild(mRoot);
|
||||
mViewer->setSceneData(mRoot);
|
||||
mStereoBruteForceRoot->removeChild(mLeftCamera);
|
||||
mStereoBruteForceRoot->removeChild(mRightCamera);
|
||||
mLeftCamera = nullptr;
|
||||
mRightCamera = nullptr;
|
||||
}
|
||||
|
||||
void StereoView::disableStereo()
|
||||
{
|
||||
if (mTechnique == Technique::None)
|
||||
return;
|
||||
|
||||
mMainCamera->removeUpdateCallback(mUpdateCallback);
|
||||
|
||||
switch (mTechnique)
|
||||
{
|
||||
case Technique::GeometryShader_IndexedViewports:
|
||||
removeGeometryShaderIndexedViewportTechnique(); break;
|
||||
case Technique::BruteForce:
|
||||
removeBruteForceTechnique(); break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
mMainCamera->setCullMask(mCullMask);
|
||||
}
|
||||
|
||||
void StereoView::enableStereo()
|
||||
{
|
||||
if (mTechnique == Technique::None)
|
||||
return;
|
||||
|
||||
// Update stereo statesets/matrices, but after the main camera updates.
|
||||
auto mainCameraCB = mMainCamera->getUpdateCallback();
|
||||
mMainCamera->removeUpdateCallback(mainCameraCB);
|
||||
mMainCamera->addUpdateCallback(mUpdateCallback);
|
||||
mMainCamera->addUpdateCallback(mainCameraCB);
|
||||
|
||||
switch (mTechnique)
|
||||
{
|
||||
case Technique::GeometryShader_IndexedViewports:
|
||||
setupGeometryShaderIndexedViewportTechnique(); break;
|
||||
case Technique::BruteForce:
|
||||
setupBruteForceTechnique(); break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
setCullMask(mCullMask);
|
||||
}
|
||||
|
||||
void StereoView::setStereoTechnique(Technique technique)
|
||||
{
|
||||
if (technique == mTechnique)
|
||||
return;
|
||||
|
||||
auto cullCB = mCullCallback;
|
||||
auto initialDrawCB = mInitialDrawCallback;
|
||||
auto predrawCB = mPreDrawCallback;
|
||||
auto postDrawCB = mPostDrawCallback;
|
||||
|
||||
setCullCallback(nullptr);
|
||||
setInitialDrawCallback(nullptr);
|
||||
setPostdrawCallback(nullptr);
|
||||
setPredrawCallback(nullptr);
|
||||
|
||||
disableStereo();
|
||||
mTechnique = technique;
|
||||
enableStereo();
|
||||
|
||||
setCullCallback(cullCB);
|
||||
setInitialDrawCallback(initialDrawCB);
|
||||
setPostdrawCallback(predrawCB);
|
||||
setPredrawCallback(postDrawCB);
|
||||
}
|
||||
|
||||
void StereoView::update()
|
||||
{
|
||||
auto viewMatrix = mViewer->getCamera()->getViewMatrix();
|
||||
|
@ -358,13 +445,15 @@ namespace Misc
|
|||
|
||||
View left{};
|
||||
View right{};
|
||||
double near = 1.f;
|
||||
double far = 10000.f;
|
||||
if (!cb)
|
||||
double near_ = 1.f;
|
||||
double far_ = 10000.f;
|
||||
if (!mUpdateViewCallback)
|
||||
{
|
||||
Log(Debug::Error) << "No update view callback. Stereo rendering will not work.";
|
||||
}
|
||||
cb->updateView(left, right, near, far);
|
||||
mUpdateViewCallback->updateView(left, right);
|
||||
near_ = Settings::Manager::getFloat("near clip", "Camera");
|
||||
far_ = Settings::Manager::getFloat("viewing distance", "Camera");
|
||||
|
||||
osg::Vec3d leftEye = left.pose.position;
|
||||
osg::Vec3d rightEye = right.pose.position;
|
||||
|
@ -375,8 +464,8 @@ namespace Misc
|
|||
osg::Matrix leftViewMatrix = viewMatrix * leftViewOffset;
|
||||
osg::Matrix rightViewMatrix = viewMatrix * rightViewOffset;
|
||||
|
||||
osg::Matrix leftProjectionMatrix = left.fov.perspectiveMatrix(near, far);
|
||||
osg::Matrix rightProjectionMatrix = right.fov.perspectiveMatrix(near, far);
|
||||
osg::Matrix leftProjectionMatrix = left.fov.perspectiveMatrix(near_, far_);
|
||||
osg::Matrix rightProjectionMatrix = right.fov.perspectiveMatrix(near_, far_);
|
||||
|
||||
mRightCamera->setViewMatrix(rightViewMatrix);
|
||||
mLeftCamera->setViewMatrix(leftViewMatrix);
|
||||
|
@ -442,7 +531,7 @@ namespace Misc
|
|||
|
||||
// Generate the frustum matrices
|
||||
auto frustumViewMatrix = viewMatrix * frustumView.pose.viewMatrix(true);
|
||||
auto frustumProjectionMatrix = frustumView.fov.perspectiveMatrix(near + nearFarOffset, far + nearFarOffset);
|
||||
auto frustumProjectionMatrix = frustumView.fov.perspectiveMatrix(near_ + nearFarOffset, far_ + nearFarOffset);
|
||||
|
||||
if (mTechnique == Technique::GeometryShader_IndexedViewports)
|
||||
{
|
||||
|
@ -495,9 +584,9 @@ namespace Misc
|
|||
stereoViewProjectionsUniform->setElement(1, frustumViewMatrixInverse * mRightCamera->getViewMatrix() * mRightCamera->getProjectionMatrix());
|
||||
}
|
||||
|
||||
void StereoView::setUpdateViewCallback(std::shared_ptr<UpdateViewCallback> cb_)
|
||||
void StereoView::setUpdateViewCallback(std::shared_ptr<UpdateViewCallback> cb)
|
||||
{
|
||||
cb = cb_;
|
||||
mUpdateViewCallback = cb;
|
||||
}
|
||||
|
||||
void StereoView::initializeScene()
|
||||
|
@ -565,63 +654,85 @@ namespace Misc
|
|||
return StereoView::Technique::BruteForce;
|
||||
}
|
||||
|
||||
void StereoView::DefaultUpdateViewCallback::updateView(View& left, View& right, double& near, double& far)
|
||||
void StereoView::DefaultUpdateViewCallback::updateView(View& left, View& right)
|
||||
{
|
||||
left.pose.position = osg::Vec3(-2.2, 0, 0);
|
||||
right.pose.position = osg::Vec3(2.2, 0, 0);
|
||||
left.fov = { -0.767549932, 0.620896876, -0.837898076, 0.726982594 };
|
||||
right.fov = { -0.620896876, 0.767549932, -0.837898076, 0.726982594 };
|
||||
near = 1;
|
||||
far = 6656;
|
||||
}
|
||||
|
||||
void StereoView::setInitialDrawCallback(osg::ref_ptr<osg::Camera::DrawCallback> cb)
|
||||
{
|
||||
if (mTechnique == Technique::GeometryShader_IndexedViewports)
|
||||
mInitialDrawCallback = cb;
|
||||
switch (mTechnique)
|
||||
{
|
||||
mMainCamera->setInitialDrawCallback(cb);
|
||||
}
|
||||
else
|
||||
{
|
||||
mRightCamera->setInitialDrawCallback(cb);
|
||||
case Technique::GeometryShader_IndexedViewports:
|
||||
mMainCamera->setInitialDrawCallback(cb); break;
|
||||
case Technique::BruteForce:
|
||||
mRightCamera->setInitialDrawCallback(cb); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
void StereoView::setPredrawCallback(osg::ref_ptr<osg::Camera::DrawCallback> cb)
|
||||
{
|
||||
if (mTechnique == Technique::GeometryShader_IndexedViewports)
|
||||
{
|
||||
mMainCamera->setPreDrawCallback(cb);
|
||||
}
|
||||
else
|
||||
mPreDrawCallback = cb;
|
||||
switch (mTechnique)
|
||||
{
|
||||
case Technique::GeometryShader_IndexedViewports:
|
||||
mMainCamera->setPreDrawCallback(cb); break;
|
||||
case Technique::BruteForce:
|
||||
mLeftCamera->setPreDrawCallback(cb);
|
||||
mRightCamera->setPreDrawCallback(cb);
|
||||
mRightCamera->setPreDrawCallback(cb); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
void StereoView::setPostdrawCallback(osg::ref_ptr<osg::Camera::DrawCallback> cb)
|
||||
{
|
||||
if (mTechnique == Technique::GeometryShader_IndexedViewports)
|
||||
{
|
||||
mMainCamera->setPostDrawCallback(cb);
|
||||
}
|
||||
else
|
||||
mPostDrawCallback = cb;
|
||||
switch (mTechnique)
|
||||
{
|
||||
case Technique::GeometryShader_IndexedViewports:
|
||||
mMainCamera->setPostDrawCallback(cb); break;
|
||||
case Technique::BruteForce:
|
||||
mLeftCamera->setPostDrawCallback(cb);
|
||||
mRightCamera->setPostDrawCallback(cb);
|
||||
mRightCamera->setPostDrawCallback(cb); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
void StereoView::setCullCallback(osg::ref_ptr<osg::NodeCallback> cb)
|
||||
{
|
||||
mCullCallback = cb;
|
||||
switch (mTechnique)
|
||||
{
|
||||
case Technique::GeometryShader_IndexedViewports:
|
||||
mMainCamera->setCullCallback(cb); break;
|
||||
case Technique::BruteForce:
|
||||
mRightCamera->setCullCallback(cb); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
void StereoView::setCullMask(osg::Node::NodeMask cullMask)
|
||||
{
|
||||
mCullMask = cullMask;
|
||||
if (mTechnique == Technique::GeometryShader_IndexedViewports)
|
||||
{
|
||||
mMainCamera->setCullCallback(cb);
|
||||
mMainCamera->setCullMask(cullMask & ~mNoShaderMask);
|
||||
mLeftCamera->setCullMask((cullMask & mNoShaderMask) | mSceneMask);
|
||||
mRightCamera->setCullMask((cullMask & mNoShaderMask) | mSceneMask);
|
||||
}
|
||||
else
|
||||
{
|
||||
mRightCamera->setCullCallback(cb);
|
||||
mLeftCamera->setCullMask(cullMask);
|
||||
mRightCamera->setCullMask(cullMask);
|
||||
}
|
||||
}
|
||||
osg::Node::NodeMask StereoView::getCullMask()
|
||||
{
|
||||
return mCullMask;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -73,13 +73,13 @@ namespace Misc
|
|||
struct UpdateViewCallback
|
||||
{
|
||||
//! Called during the update traversal of every frame to source updated stereo values.
|
||||
virtual void updateView(View& left, View& right, double& near, double& far) = 0;
|
||||
virtual void updateView(View& left, View& right) = 0;
|
||||
};
|
||||
|
||||
//! Default implementation of UpdateViewCallback that just provides some hardcoded values for debugging purposes
|
||||
struct DefaultUpdateViewCallback : public UpdateViewCallback
|
||||
{
|
||||
virtual void updateView(View& left, View& right, double& near, double& far);
|
||||
virtual void updateView(View& left, View& right);
|
||||
};
|
||||
|
||||
enum class Technique
|
||||
|
@ -93,10 +93,10 @@ namespace Misc
|
|||
|
||||
//! Adds two cameras in stereo to the mainCamera.
|
||||
//! All nodes matching the mask are rendered in stereo using brute force via two camera transforms, the rest are rendered in stereo via a geometry shader.
|
||||
//! \param geometryShaderMask should mask in all nodes that use shaders.
|
||||
//! \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 geometryShaderMask, osg::Node::NodeMask noShaderMask);
|
||||
StereoView(osgViewer::Viewer* viewer, Technique technique, 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.
|
||||
|
@ -106,6 +106,8 @@ namespace Misc
|
|||
//! Initialized scene. Call when the "scene root" node has been created
|
||||
void initializeScene();
|
||||
|
||||
void setStereoTechnique(Technique technique);
|
||||
|
||||
//! Callback that updates stereo configuration during the update pass
|
||||
void setUpdateViewCallback(std::shared_ptr<UpdateViewCallback> cb);
|
||||
|
||||
|
@ -121,21 +123,33 @@ namespace Misc
|
|||
//! Set the cull callback on the appropriate camera object
|
||||
void setCullCallback(osg::ref_ptr<osg::NodeCallback> cb);
|
||||
|
||||
//! Apply the cullmask to the appropriate camera objects
|
||||
void setCullMask(osg::Node::NodeMask cullMask);
|
||||
|
||||
//! Get the last applied cullmask.
|
||||
osg::Node::NodeMask getCullMask();
|
||||
|
||||
private:
|
||||
void setupBruteForceTechnique();
|
||||
void setupGeometryShaderIndexedViewportTechnique();
|
||||
void removeBruteForceTechnique();
|
||||
void removeGeometryShaderIndexedViewportTechnique();
|
||||
void disableStereo();
|
||||
void enableStereo();
|
||||
|
||||
osg::ref_ptr<osgViewer::Viewer> mViewer;
|
||||
osg::ref_ptr<osg::Camera> mMainCamera;
|
||||
osg::ref_ptr<osg::Group> mRoot;
|
||||
osg::ref_ptr<osg::Group> mScene;
|
||||
osg::ref_ptr<osg::Group> mStereoRoot;
|
||||
osg::ref_ptr<osg::Callback> mUpdateCallback;
|
||||
Technique mTechnique;
|
||||
|
||||
// Keeps state relevant to doing stereo via the geometry shader
|
||||
osg::ref_ptr<osg::Group> mStereoGeometryShaderRoot{ new osg::Group };
|
||||
osg::Node::NodeMask mGeometryShaderMask;
|
||||
osg::Node::NodeMask mNoShaderMask;
|
||||
osg::Node::NodeMask mSceneMask;
|
||||
osg::Node::NodeMask mCullMask;
|
||||
|
||||
// Keeps state and cameras relevant to doing stereo via brute force
|
||||
osg::ref_ptr<osg::Group> mStereoBruteForceRoot{ new osg::Group };
|
||||
|
@ -151,7 +165,13 @@ namespace Misc
|
|||
bool flipViewOrder{ true };
|
||||
|
||||
// Updates stereo configuration during the update pass
|
||||
std::shared_ptr<UpdateViewCallback> cb{ new DefaultUpdateViewCallback };
|
||||
std::shared_ptr<UpdateViewCallback> mUpdateViewCallback{ new DefaultUpdateViewCallback };
|
||||
|
||||
// OSG camera callbacks set using set*callback. StereoView manages that these are always set on the appropriate camera(s);
|
||||
osg::ref_ptr<osg::NodeCallback> mCullCallback{ nullptr };
|
||||
osg::ref_ptr<osg::Camera::DrawCallback> mInitialDrawCallback{ nullptr };
|
||||
osg::ref_ptr<osg::Camera::DrawCallback> mPreDrawCallback{ nullptr };
|
||||
osg::ref_ptr<osg::Camera::DrawCallback> mPostDrawCallback{ nullptr };
|
||||
};
|
||||
|
||||
//! Overrides all stereo-related states/uniforms to disable stereo for the scene rendered by camera
|
||||
|
|
|
@ -375,6 +375,7 @@ public:
|
|||
setName("GUI Camera");
|
||||
mDrawable = new Drawable(filter, parent, this);
|
||||
mDrawable->setName("GUI Drawable");
|
||||
mDrawable->setDataVariance(osg::Object::STATIC);
|
||||
addChild(mDrawable.get());
|
||||
mDrawable->setCullingActive(false);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue