mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-20 05:53:50 +00:00
More refactoring of VRSession. Moved call of BeginFrame and WaitFrame to the start of cull to keep shadow technique within openxr specs. There is still some jitter unless i change to single-threaded, and now i have no idea why.
This commit is contained in:
parent
31336aba79
commit
f25c3af9cb
10 changed files with 199 additions and 153 deletions
|
@ -564,10 +564,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
|
|||
// Create sound system
|
||||
mEnvironment.setSoundManager (new MWSound::SoundManager(mVFS.get(), mUseSound));
|
||||
|
||||
#ifdef USE_OPENXR
|
||||
mXrEnvironment.setGUIManager(new MWVR::VRGUIManager(mViewer));
|
||||
#endif
|
||||
|
||||
if (!mSkipMenu)
|
||||
{
|
||||
const std::string& logo = Fallback::Map::getString("Movies_Company_Logo");
|
||||
|
@ -735,6 +731,7 @@ void OMW::Engine::go()
|
|||
|
||||
#ifdef USE_OPENXR
|
||||
mXrEnvironment.setGUIManager(new MWVR::VRGUIManager(mViewer));
|
||||
//mViewer->setThreadingModel(osgViewer::ViewerBase::SingleThreaded);
|
||||
#endif
|
||||
|
||||
// Start the game
|
||||
|
|
|
@ -1008,12 +1008,15 @@ private:
|
|||
|
||||
|
||||
auto* vrGuiManager = Environment::get().getGUIManager();
|
||||
if (vrGuiManager)
|
||||
{
|
||||
bool vrHasFocus = vrGuiManager->updateFocus();
|
||||
auto guiCursor = vrGuiManager->guiCursor();
|
||||
if (vrHasFocus)
|
||||
{
|
||||
mMouseManager->setMousePosition(guiCursor.x(), guiCursor.y());
|
||||
}
|
||||
}
|
||||
|
||||
while (auto* action = mXRInput->nextAction())
|
||||
{
|
||||
|
@ -1237,7 +1240,7 @@ private:
|
|||
void OpenXRInputManager::updateHead()
|
||||
{
|
||||
auto* session = Environment::get().getSession();
|
||||
auto currentHeadPose = session->predictedPoses(VRSession::FramePhase::Predraw).head;
|
||||
auto currentHeadPose = session->predictedPoses(VRSession::FramePhase::Update).head;
|
||||
currentHeadPose.position *= Environment::get().unitsPerMeter();
|
||||
osg::Vec3 vrMovement = currentHeadPose.position - mHeadPose.position;
|
||||
mHeadPose = currentHeadPose;
|
||||
|
|
|
@ -277,44 +277,58 @@ namespace MWVR
|
|||
void
|
||||
OpenXRManagerImpl::waitFrame()
|
||||
{
|
||||
|
||||
auto DC = wglGetCurrentDC();
|
||||
auto GLRC = wglGetCurrentContext();
|
||||
auto XRDC = mGraphicsBinding.hDC;
|
||||
auto XRGLRC = mGraphicsBinding.hGLRC;
|
||||
wglMakeCurrent(XRDC, XRGLRC);
|
||||
|
||||
Timer timer("waitFrame()");
|
||||
|
||||
static std::mutex waitFrameMutex;
|
||||
|
||||
if (!mSessionRunning)
|
||||
return;
|
||||
|
||||
XrFrameWaitInfo frameWaitInfo{ XR_TYPE_FRAME_WAIT_INFO };
|
||||
XrFrameState frameState{ XR_TYPE_FRAME_STATE };
|
||||
|
||||
CHECK_XRCMD(xrWaitFrame(mSession, &frameWaitInfo, &frameState));
|
||||
|
||||
std::unique_lock<std::mutex> lock(mFrameStateMutex);
|
||||
mFrameState = frameState;
|
||||
|
||||
wglMakeCurrent(DC, GLRC);
|
||||
}
|
||||
|
||||
void
|
||||
OpenXRManagerImpl::beginFrame()
|
||||
{
|
||||
auto DC = wglGetCurrentDC();
|
||||
auto GLRC = wglGetCurrentContext();
|
||||
auto XRDC = mGraphicsBinding.hDC;
|
||||
auto XRGLRC = mGraphicsBinding.hGLRC;
|
||||
wglMakeCurrent(XRDC, XRGLRC);
|
||||
|
||||
Timer timer("beginFrame");
|
||||
XrFrameBeginInfo frameBeginInfo{ XR_TYPE_FRAME_BEGIN_INFO };
|
||||
CHECK_XRCMD(xrBeginFrame(mSession, &frameBeginInfo));
|
||||
|
||||
wglMakeCurrent(DC, GLRC);
|
||||
}
|
||||
|
||||
void
|
||||
OpenXRManagerImpl::endFrame(int64_t displayTime, int layerCount, XrCompositionLayerBaseHeader** layerStack)
|
||||
{
|
||||
Timer timer("endFrame()");
|
||||
if (!mSessionRunning)
|
||||
return;
|
||||
auto DC = wglGetCurrentDC();
|
||||
auto GLRC = wglGetCurrentContext();
|
||||
auto XRDC = mGraphicsBinding.hDC;
|
||||
auto XRGLRC = mGraphicsBinding.hGLRC;
|
||||
wglMakeCurrent(XRDC, XRGLRC);
|
||||
|
||||
Timer timer("endFrame()");
|
||||
XrFrameEndInfo frameEndInfo{ XR_TYPE_FRAME_END_INFO };
|
||||
frameEndInfo.displayTime = displayTime;
|
||||
frameEndInfo.environmentBlendMode = mEnvironmentBlendMode;
|
||||
frameEndInfo.layerCount = layerCount;
|
||||
frameEndInfo.layers = layerStack;
|
||||
|
||||
CHECK_XRCMD(xrEndFrame(mSession, &frameEndInfo));
|
||||
|
||||
wglMakeCurrent(DC, GLRC);
|
||||
}
|
||||
|
||||
std::array<XrView, 2>
|
||||
|
|
|
@ -103,7 +103,7 @@ void StateMachine::update(float dt, bool enabled)
|
|||
{
|
||||
auto* session = Environment::get().getSession();
|
||||
auto* world = MWBase::Environment::get().getWorld();
|
||||
auto& predictedPoses = session->predictedPoses(VRSession::FramePhase::Predraw);
|
||||
auto& predictedPoses = session->predictedPoses(VRSession::FramePhase::Update);
|
||||
auto& handPose = predictedPoses.hands[(int)MWVR::Side::RIGHT_HAND];
|
||||
auto weaponType = world->getActiveWeaponType();
|
||||
|
||||
|
|
|
@ -114,8 +114,8 @@ void ForearmController::operator()(osg::Node* node, osg::NodeVisitor* nv)
|
|||
MWBase::Environment::get().getWorld()->getRenderingManager().getCamera()->updateCamera();
|
||||
}
|
||||
|
||||
MWVR::Pose handStage = session->predictedPoses(VRSession::FramePhase::Predraw).hands[side];
|
||||
MWVR::Pose headStage = session->predictedPoses(VRSession::FramePhase::Predraw).head;
|
||||
MWVR::Pose handStage = session->predictedPoses(VRSession::FramePhase::Update).hands[side];
|
||||
MWVR::Pose headStage = session->predictedPoses(VRSession::FramePhase::Update).head;
|
||||
|
||||
auto orientation = handStage.orientation;
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "vrsession.hpp"
|
||||
#include "vrgui.hpp"
|
||||
#include <time.h>
|
||||
#include <thread>
|
||||
|
||||
namespace MWVR
|
||||
{
|
||||
|
@ -38,7 +39,7 @@ VRSession::~VRSession()
|
|||
osg::Matrix VRSession::projectionMatrix(FramePhase phase, Side side)
|
||||
{
|
||||
assert(((int)side) < 2);
|
||||
auto fov = predictedPoses(VRSession::FramePhase::Predraw).view[(int)side].fov;
|
||||
auto fov = predictedPoses(VRSession::FramePhase::Update).view[(int)side].fov;
|
||||
float near_ = Settings::Manager::getFloat("near clip", "Camera");
|
||||
float far_ = Settings::Manager::getFloat("viewing distance", "Camera");
|
||||
return fov.perspectiveMatrix(near_, far_);
|
||||
|
@ -46,7 +47,7 @@ osg::Matrix VRSession::projectionMatrix(FramePhase phase, Side side)
|
|||
|
||||
osg::Matrix VRSession::viewMatrix(FramePhase phase, Side side)
|
||||
{
|
||||
MWVR::Pose pose = predictedPoses(VRSession::FramePhase::Predraw).view[(int)side].pose;
|
||||
MWVR::Pose pose = predictedPoses(phase).view[(int)side].pose;
|
||||
osg::Vec3 position = pose.position * Environment::get().unitsPerMeter();
|
||||
osg::Quat orientation = pose.orientation;
|
||||
|
||||
|
@ -77,26 +78,15 @@ void VRSession::swapBuffers(osg::GraphicsContext* gc, VRViewer& viewer)
|
|||
Timer timer("VRSession::SwapBuffers");
|
||||
auto* xr = Environment::get().getManager();
|
||||
|
||||
beginPhase(FramePhase::Swap);
|
||||
|
||||
if (getFrame(FramePhase::Swap)->mShouldRender)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mMutex);
|
||||
|
||||
xr->handleEvents();
|
||||
|
||||
mPostdrawFrame = std::move(mDrawFrame);
|
||||
assert(mPostdrawFrame);
|
||||
}
|
||||
|
||||
// TODO: Should blit mirror texture regardless
|
||||
if (!isRunning())
|
||||
return;
|
||||
|
||||
xr->waitFrame();
|
||||
xr->beginFrame();
|
||||
viewer.swapBuffers(gc);
|
||||
|
||||
auto leftView = viewer.mViews["LeftEye"];
|
||||
auto rightView = viewer.mViews["RightEye"];
|
||||
|
||||
viewer.blitEyesToMirrorTexture(gc);
|
||||
gc->swapBuffersImplementation();
|
||||
leftView->swapBuffers(gc);
|
||||
rightView->swapBuffers(gc);
|
||||
|
||||
|
@ -105,10 +95,10 @@ void VRSession::swapBuffers(osg::GraphicsContext* gc, VRViewer& viewer)
|
|||
compositionLayerProjectionViews[1].type = XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW;
|
||||
compositionLayerProjectionViews[0].subImage = leftView->swapchain().subImage();
|
||||
compositionLayerProjectionViews[1].subImage = rightView->swapchain().subImage();
|
||||
compositionLayerProjectionViews[0].pose = toXR(mPostdrawFrame->mPredictedPoses.eye[(int)Side::LEFT_HAND]);
|
||||
compositionLayerProjectionViews[1].pose = toXR(mPostdrawFrame->mPredictedPoses.eye[(int)Side::RIGHT_HAND]);
|
||||
compositionLayerProjectionViews[0].fov = toXR(mPostdrawFrame->mPredictedPoses.view[(int)Side::LEFT_HAND].fov);
|
||||
compositionLayerProjectionViews[1].fov = toXR(mPostdrawFrame->mPredictedPoses.view[(int)Side::RIGHT_HAND].fov);
|
||||
compositionLayerProjectionViews[0].pose = toXR(getFrame(FramePhase::Swap)->mPredictedPoses.eye[(int)Side::LEFT_HAND]);
|
||||
compositionLayerProjectionViews[1].pose = toXR(getFrame(FramePhase::Swap)->mPredictedPoses.eye[(int)Side::RIGHT_HAND]);
|
||||
compositionLayerProjectionViews[0].fov = toXR(getFrame(FramePhase::Swap)->mPredictedPoses.view[(int)Side::LEFT_HAND].fov);
|
||||
compositionLayerProjectionViews[1].fov = toXR(getFrame(FramePhase::Swap)->mPredictedPoses.view[(int)Side::RIGHT_HAND].fov);
|
||||
XrCompositionLayerProjection layer{};
|
||||
layer.type = XR_TYPE_COMPOSITION_LAYER_PROJECTION;
|
||||
layer.space = xr->impl().getReferenceSpace(TrackedSpace::STAGE);
|
||||
|
@ -116,33 +106,92 @@ void VRSession::swapBuffers(osg::GraphicsContext* gc, VRViewer& viewer)
|
|||
layer.views = compositionLayerProjectionViews.data();
|
||||
auto* layerStack = reinterpret_cast<XrCompositionLayerBaseHeader*>(&layer);
|
||||
|
||||
xr->endFrame(mPostdrawFrame->mPredictedDisplayTime, 1, &layerStack);
|
||||
mLastRenderedFrame = mPostdrawFrame->mFrameNo;
|
||||
Log(Debug::Debug) << getFrame(FramePhase::Swap)->mFrameNo << ": EndFrame";
|
||||
xr->endFrame(getFrame(FramePhase::Swap)->mPredictedDisplayTime, 1, &layerStack);
|
||||
}
|
||||
|
||||
std::unique_lock<std::mutex> lock(mMutex);
|
||||
auto xrPredictionChange = xr->impl().frameState().predictedDisplayTime - mLastPredictedDisplayTime;
|
||||
mLastPredictedDisplayTime = xr->impl().frameState().predictedDisplayTime;
|
||||
mLastPredictedDisplayPeriod = xr->impl().frameState().predictedDisplayPeriod;
|
||||
auto now = std::chrono::steady_clock::now();
|
||||
mLastFrameInterval = std::chrono::duration_cast<std::chrono::nanoseconds>(now - mLastRenderedFrameTimestamp);
|
||||
mLastRenderedFrameTimestamp = now;
|
||||
mLastRenderedFrame = getFrame(FramePhase::Swap)->mFrameNo;
|
||||
|
||||
//Log(Debug::Verbose) << getFrame(FramePhase::Swap)->mFrameNo << ": xrPrediction=" << xr->impl().frameState().predictedDisplayTime << ", ourPrediction=" << getFrame(FramePhase::Swap)->mPredictedDisplayTime << ", miss=" << miss << "ms";
|
||||
Log(Debug::Debug) << "xrPredictionChange=" << (xrPredictionChange / 1000000) << "ms";
|
||||
auto seconds = std::chrono::duration_cast<std::chrono::duration<double>>(now - mStart).count();
|
||||
static int sBaseFrames = 0;
|
||||
if (seconds > 10.f)
|
||||
{
|
||||
Log(Debug::Verbose) << "Fps: " << (static_cast<double>(mLastRenderedFrame - sBaseFrames) / seconds);
|
||||
mStart = now;
|
||||
sBaseFrames = mLastRenderedFrame;
|
||||
}
|
||||
|
||||
getFrame(FramePhase::Swap) = nullptr;
|
||||
mCondition.notify_one();
|
||||
}
|
||||
|
||||
void VRSession::advanceFramePhase(void)
|
||||
void VRSession::beginPhase(FramePhase phase)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mMutex);
|
||||
Timer timer("VRSession::advanceFrame");
|
||||
Log(Debug::Debug) << "beginPhase(" << ((int)phase) << ")";
|
||||
|
||||
assert(!mDrawFrame);
|
||||
mDrawFrame = std::move(mPredrawFrame);
|
||||
if (phase != FramePhase::Update)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mMutex);
|
||||
FramePhase previousPhase = static_cast<FramePhase>((int)phase - 1);
|
||||
|
||||
if (getFrame(phase))
|
||||
throw std::logic_error("advanceFramePhase called with a frame alreay in the target phase");
|
||||
if (!getFrame(previousPhase))
|
||||
throw std::logic_error("advanceFramePhase called without a frame in the predraw phase");
|
||||
getFrame(phase) = std::move(getFrame(previousPhase));
|
||||
}
|
||||
else
|
||||
prepareFrame();
|
||||
|
||||
if (phase == FramePhase::Cull && getFrame(phase)->mShouldRender)
|
||||
{
|
||||
auto* xr = Environment::get().getManager();
|
||||
// Since i am forced to do xr->beginFrame() before cull instead of draw
|
||||
// i have to explicitly wait for xr->endFrame() to finish to avoid an
|
||||
// out-of-order error from openxr.
|
||||
// If i don't wait, we might hit beginFrame() before the previous frame
|
||||
// reaches endFrame() in which case openxr will cancel the previous frame
|
||||
// and we will get an out-of-order error due to two back-to-back calls to endFrame()
|
||||
while (getFrame(phase)->mFrameNo != (mLastRenderedFrame + 1))
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mMutex);
|
||||
mCondition.wait(lock);
|
||||
}
|
||||
Log(Debug::Debug) << getFrame(phase)->mFrameNo << ": WaitFrame";
|
||||
xr->waitFrame();
|
||||
Log(Debug::Debug) << getFrame(phase)->mFrameNo << ": BeginFrame";
|
||||
xr->beginFrame();
|
||||
}
|
||||
}
|
||||
|
||||
void VRSession::startFrame()
|
||||
std::unique_ptr<VRSession::VRFrame>& VRSession::getFrame(FramePhase phase)
|
||||
{
|
||||
if ((unsigned int)phase >= mFrame.size())
|
||||
throw std::logic_error("Invalid frame phase");
|
||||
return mFrame[(int)phase];
|
||||
}
|
||||
|
||||
void VRSession::prepareFrame()
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mMutex);
|
||||
assert(!mPredrawFrame);
|
||||
|
||||
Timer timer("VRSession::startFrame");
|
||||
auto* xr = Environment::get().getManager();
|
||||
auto* input = Environment::get().getInputManager();
|
||||
xr->handleEvents();
|
||||
|
||||
// Until OpenXR allows us to get a prediction without waiting
|
||||
// we make our own (bad) prediction and let openxr wait
|
||||
// we make our own (bad) prediction and call xrWaitFrame when it is more convenient
|
||||
auto frameState = xr->impl().frameState();
|
||||
long long predictedDisplayTime = 0;
|
||||
mFrames++;
|
||||
|
@ -154,17 +203,19 @@ void VRSession::startFrame()
|
|||
else if (mFrames > mLastRenderedFrame)
|
||||
{
|
||||
//predictedDisplayTime = mLastPredictedDisplayTime + mLastFrameInterval.count() * (mFrames - mLastRenderedFrame);
|
||||
float intervalsf = static_cast<double>(mLastFrameInterval.count()) / static_cast<double>(frameState.predictedDisplayPeriod);
|
||||
int intervals = (int)std::roundf(intervalsf);
|
||||
predictedDisplayTime = mLastPredictedDisplayTime + intervals * (mFrames - mLastRenderedFrame) * frameState.predictedDisplayPeriod;
|
||||
float intervalsf = static_cast<double>(mLastFrameInterval.count()) / static_cast<double>(mLastPredictedDisplayPeriod);
|
||||
#ifdef max
|
||||
#undef max
|
||||
#endif
|
||||
int intervals = std::max((int)std::roundf(intervalsf), 1);
|
||||
predictedDisplayTime = mLastPredictedDisplayTime + intervals * (mFrames - mLastRenderedFrame) * mLastPredictedDisplayPeriod;
|
||||
}
|
||||
|
||||
PoseSet predictedPoses{};
|
||||
if (isRunning())
|
||||
{
|
||||
xr->impl().enablePredictions();
|
||||
predictedPoses.head = xr->impl().getPredictedLimbPose(predictedDisplayTime, TrackedLimb::HEAD, TrackedSpace::STAGE) * mPlayerScale;
|
||||
predictedPoses.hands[(int)Side::LEFT_HAND] = input->getHandPose(predictedDisplayTime, TrackedSpace::STAGE, Side::LEFT_HAND) * mPlayerScale;
|
||||
predictedPoses.hands[(int)Side::RIGHT_HAND] = input->getHandPose(predictedDisplayTime, TrackedSpace::STAGE, Side::RIGHT_HAND) * mPlayerScale;
|
||||
auto hmdViews = xr->impl().getPredictedViews(predictedDisplayTime, TrackedSpace::VIEW);
|
||||
predictedPoses.view[(int)Side::LEFT_HAND].pose = fromXR(hmdViews[(int)Side::LEFT_HAND].pose) * mPlayerScale;
|
||||
predictedPoses.view[(int)Side::RIGHT_HAND].pose = fromXR(hmdViews[(int)Side::RIGHT_HAND].pose) * mPlayerScale;
|
||||
|
@ -173,43 +224,34 @@ void VRSession::startFrame()
|
|||
auto stageViews = xr->impl().getPredictedViews(predictedDisplayTime, TrackedSpace::STAGE);
|
||||
predictedPoses.eye[(int)Side::LEFT_HAND] = fromXR(stageViews[(int)Side::LEFT_HAND].pose) * mPlayerScale;
|
||||
predictedPoses.eye[(int)Side::RIGHT_HAND] = fromXR(stageViews[(int)Side::RIGHT_HAND].pose) * mPlayerScale;
|
||||
}
|
||||
else
|
||||
|
||||
auto* input = Environment::get().getInputManager();
|
||||
if (input)
|
||||
{
|
||||
// If session is not running, copy poses from the last frame
|
||||
if (mPostdrawFrame)
|
||||
predictedPoses = mPostdrawFrame->mPredictedPoses;
|
||||
predictedPoses.hands[(int)Side::LEFT_HAND] = input->getHandPose(predictedDisplayTime, TrackedSpace::STAGE, Side::LEFT_HAND) * mPlayerScale;
|
||||
predictedPoses.hands[(int)Side::RIGHT_HAND] = input->getHandPose(predictedDisplayTime, TrackedSpace::STAGE, Side::RIGHT_HAND) * mPlayerScale;
|
||||
}
|
||||
xr->impl().disablePredictions();
|
||||
}
|
||||
|
||||
|
||||
mPredrawFrame.reset(new VRFrame);
|
||||
mPredrawFrame->mPredictedDisplayTime = predictedDisplayTime;
|
||||
mPredrawFrame->mFrameNo = mFrames;
|
||||
mPredrawFrame->mPredictedPoses = predictedPoses;
|
||||
auto& frame = getFrame(FramePhase::Update);
|
||||
frame.reset(new VRFrame);
|
||||
frame->mPredictedDisplayTime = predictedDisplayTime;
|
||||
frame->mFrameNo = mFrames;
|
||||
frame->mPredictedPoses = predictedPoses;
|
||||
frame->mShouldRender = isRunning();
|
||||
}
|
||||
|
||||
const PoseSet& VRSession::predictedPoses(FramePhase phase)
|
||||
{
|
||||
auto& frame = getFrame(phase);
|
||||
|
||||
switch (phase)
|
||||
{
|
||||
case FramePhase::Predraw:
|
||||
if (!mPredrawFrame)
|
||||
startFrame();
|
||||
assert(mPredrawFrame);
|
||||
return mPredrawFrame->mPredictedPoses;
|
||||
if (phase == FramePhase::Update && !frame)
|
||||
beginPhase(FramePhase::Update);
|
||||
|
||||
case FramePhase::Draw:
|
||||
assert(mDrawFrame);
|
||||
return mDrawFrame->mPredictedPoses;
|
||||
|
||||
case FramePhase::Postdraw:
|
||||
assert(mPostdrawFrame);
|
||||
return mPostdrawFrame->mPredictedPoses;
|
||||
}
|
||||
|
||||
assert(0);
|
||||
return mPredrawFrame->mPredictedPoses;
|
||||
if (!frame)
|
||||
throw std::logic_error("Attempted to get poses from a phase with no current pose");
|
||||
return frame->mPredictedPoses;
|
||||
}
|
||||
|
||||
// OSG doesn't provide API to extract euler angles from a quat, but i need it.
|
||||
|
@ -253,7 +295,10 @@ void VRSession::movementAngles(float& yaw, float& pitch)
|
|||
{
|
||||
assert(mPredrawFrame);
|
||||
auto* input = Environment::get().getInputManager();
|
||||
auto lhandquat = input->getHandPose(mPredrawFrame->mPredictedDisplayTime, TrackedSpace::VIEW, Side::LEFT_HAND).orientation;
|
||||
// TODO: This strictly speaking violates the rule of not making predictions outside of prepareFrame()
|
||||
// I should either add VIEW hands to the predicted pose set, or compute this using STAGE poses
|
||||
// It would likely suffice to compute euler angles for STAGE head and hand and return the difference?
|
||||
auto lhandquat = input->getHandPose(getFrame(FramePhase::Update)->mPredictedDisplayTime, TrackedSpace::VIEW, Side::LEFT_HAND).orientation;
|
||||
//predictedPoses(FramePhase::Predraw).hands[(int)TrackedSpace::VIEW][(int)MWVR::Side::LEFT_HAND].orientation;
|
||||
float roll = 0.f;
|
||||
getEulerAngles(lhandquat, yaw, pitch, roll);
|
||||
|
|
|
@ -27,9 +27,11 @@ public:
|
|||
|
||||
enum class FramePhase
|
||||
{
|
||||
Predraw = 0, //!< Get poses predicted for the next frame to be drawn
|
||||
Draw = 1, //!< Get poses predicted for the current rendering frame
|
||||
Postdraw = 2, //!< Get poses predicted for the last rendered frame
|
||||
Update = 0, //!< The frame currently in update traversals
|
||||
Cull, //!< The frame currently in cull
|
||||
Draw, //!< The frame currently in draw
|
||||
Swap, //!< The frame being swapped
|
||||
NumPhases
|
||||
};
|
||||
|
||||
struct VRFrame
|
||||
|
@ -37,6 +39,8 @@ public:
|
|||
long long mFrameNo{ 0 };
|
||||
long long mPredictedDisplayTime{ 0 };
|
||||
PoseSet mPredictedPoses{};
|
||||
bool mShouldRender{ false };
|
||||
bool mHasWaited{ false };
|
||||
};
|
||||
|
||||
public:
|
||||
|
@ -48,12 +52,13 @@ public:
|
|||
const PoseSet& predictedPoses(FramePhase phase);
|
||||
|
||||
//! Starts a new frame
|
||||
void startFrame();
|
||||
void prepareFrame();
|
||||
|
||||
//! Angles to be used for overriding movement direction
|
||||
void movementAngles(float& yaw, float& pitch);
|
||||
|
||||
void advanceFramePhase(void);
|
||||
void beginPhase(FramePhase phase);
|
||||
std::unique_ptr<VRFrame>& getFrame(FramePhase phase);
|
||||
|
||||
bool isRunning() const;
|
||||
|
||||
|
@ -63,9 +68,7 @@ public:
|
|||
osg::Matrix viewMatrix(FramePhase phase, Side side);
|
||||
osg::Matrix projectionMatrix(FramePhase phase, Side side);
|
||||
|
||||
std::unique_ptr<VRFrame> mPredrawFrame{ nullptr };
|
||||
std::unique_ptr<VRFrame> mDrawFrame{ nullptr };
|
||||
std::unique_ptr<VRFrame> mPostdrawFrame{ nullptr };
|
||||
std::array<std::unique_ptr<VRFrame>, (int)FramePhase::NumPhases> mFrame{ nullptr };
|
||||
|
||||
std::mutex mMutex{};
|
||||
std::condition_variable mCondition{};
|
||||
|
@ -74,6 +77,7 @@ public:
|
|||
long long mLastRenderedFrame{ 0 };
|
||||
long long mLastPredictedDisplayTime{ 0 };
|
||||
long long mLastPredictedDisplayPeriod{ 0 };
|
||||
std::chrono::steady_clock::time_point mStart{ std::chrono::steady_clock::now() };
|
||||
std::chrono::nanoseconds mLastFrameInterval{};
|
||||
std::chrono::steady_clock::time_point mLastRenderedFrameTimestamp{std::chrono::steady_clock::now()};
|
||||
|
||||
|
|
|
@ -39,6 +39,17 @@ namespace MWVR {
|
|||
{
|
||||
}
|
||||
|
||||
class CullCallback : public osg::NodeCallback
|
||||
{
|
||||
void operator()(osg::Node* node, osg::NodeVisitor* nv)
|
||||
{
|
||||
const auto& name = node->getName();
|
||||
if (name == "LeftEye")
|
||||
Environment::get().getSession()->beginPhase(VRSession::FramePhase::Cull);
|
||||
traverse(node, nv);
|
||||
}
|
||||
};
|
||||
|
||||
osg::Camera* VRView::createCamera(int eye, const osg::Vec4& clearColor, osg::GraphicsContext* gc)
|
||||
{
|
||||
osg::ref_ptr<osg::Camera> camera = new osg::Camera();
|
||||
|
@ -53,6 +64,7 @@ namespace MWVR {
|
|||
camera->setGraphicsContext(gc);
|
||||
|
||||
camera->setInitialDrawCallback(new VRView::InitialDrawCallback());
|
||||
camera->setCullCallback(new CullCallback);
|
||||
|
||||
return camera.release();
|
||||
}
|
||||
|
@ -69,6 +81,10 @@ namespace MWVR {
|
|||
|
||||
void VRView::InitialDrawCallback::operator()(osg::RenderInfo& renderInfo) const
|
||||
{
|
||||
const auto& name = renderInfo.getCurrentCamera()->getName();
|
||||
if (name == "LeftEye")
|
||||
Environment::get().getSession()->beginPhase(VRSession::FramePhase::Draw);
|
||||
|
||||
osg::GraphicsOperation* graphicsOperation = renderInfo.getCurrentCamera()->getRenderer();
|
||||
osgViewer::Renderer* renderer = dynamic_cast<osgViewer::Renderer*>(graphicsOperation);
|
||||
if (renderer != nullptr)
|
||||
|
@ -76,7 +92,6 @@ namespace MWVR {
|
|||
// Disable normal OSG FBO camera setup
|
||||
renderer->setCameraRequiresSetUp(false);
|
||||
}
|
||||
auto name = renderInfo.getCurrentCamera()->getName();
|
||||
}
|
||||
void VRView::UpdateSlaveCallback::updateSlave(
|
||||
osg::View& view,
|
||||
|
@ -93,8 +108,9 @@ namespace MWVR {
|
|||
|
||||
auto* session = Environment::get().getSession();
|
||||
auto viewMatrix = view.getCamera()->getViewMatrix();
|
||||
auto modifiedViewMatrix = viewMatrix * session->viewMatrix(VRSession::FramePhase::Predraw, side);
|
||||
auto projectionMatrix = session->projectionMatrix(VRSession::FramePhase::Predraw, side);
|
||||
|
||||
auto modifiedViewMatrix = viewMatrix * session->viewMatrix(VRSession::FramePhase::Update, side);
|
||||
auto projectionMatrix = session->projectionMatrix(VRSession::FramePhase::Update, side);
|
||||
|
||||
camera->setViewMatrix(modifiedViewMatrix);
|
||||
camera->setProjectionMatrix(projectionMatrix);
|
||||
|
@ -109,6 +125,6 @@ namespace MWVR {
|
|||
|
||||
void VRView::swapBuffers(osg::GraphicsContext* gc)
|
||||
{
|
||||
swapchain().endFrame(gc);
|
||||
mSwapchain->endFrame(gc);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -151,22 +151,16 @@ namespace MWVR
|
|||
|
||||
void VRViewer::blitEyesToMirrorTexture(osg::GraphicsContext* gc)
|
||||
{
|
||||
//includeMenu = false;
|
||||
mMirrorTextureSwapchain->beginFrame(gc);
|
||||
|
||||
int mirror_width = mMirrorTextureSwapchain->width() / 2;
|
||||
|
||||
mMirrorTextureSwapchain->beginFrame(gc);
|
||||
|
||||
mViews["RightEye"]->swapchain().renderBuffer()->blit(gc, 0, 0, mirror_width, mMirrorTextureSwapchain->height());
|
||||
mViews["LeftEye"]->swapchain().renderBuffer()->blit(gc, mirror_width, 0, 2 * mirror_width, mMirrorTextureSwapchain->height());
|
||||
|
||||
auto* state = gc->getState();
|
||||
auto* gl = osg::GLExtensions::Get(state->getContextID(), false);
|
||||
|
||||
mMirrorTextureSwapchain->endFrame(gc);
|
||||
|
||||
|
||||
|
||||
auto* state = gc->getState();
|
||||
auto* gl = osg::GLExtensions::Get(state->getContextID(), false);
|
||||
gl->glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
|
||||
mMirrorTextureSwapchain->renderBuffer()->blit(gc, 0, 0, mMirrorTextureSwapchain->width(), mMirrorTextureSwapchain->height());
|
||||
|
||||
|
@ -178,24 +172,6 @@ namespace MWVR
|
|||
{
|
||||
auto* session = Environment::get().getSession();
|
||||
session->swapBuffers(gc, *mViewer);
|
||||
gc->swapBuffersImplementation();
|
||||
}
|
||||
|
||||
void VRViewer::swapBuffers(osg::GraphicsContext* gc)
|
||||
{
|
||||
if (!mConfigured)
|
||||
return;
|
||||
|
||||
Timer timer("VRViewer::SwapBuffers");
|
||||
|
||||
for (auto& view : mViews)
|
||||
view.second->swapBuffers(gc);
|
||||
|
||||
timer.checkpoint("Views");
|
||||
|
||||
blitEyesToMirrorTexture(gc);
|
||||
|
||||
gc->swapBuffersImplementation();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -217,12 +193,7 @@ namespace MWVR
|
|||
{
|
||||
auto* camera = info.getCurrentCamera();
|
||||
auto name = camera->getName();
|
||||
auto& view = mViews[name];
|
||||
|
||||
if (name == "LeftEye")
|
||||
Environment::get().getSession()->advanceFramePhase();
|
||||
|
||||
view->prerenderCallback(info);
|
||||
mViews[name]->prerenderCallback(info);
|
||||
}
|
||||
|
||||
void VRViewer::postDrawCallback(osg::RenderInfo& info)
|
||||
|
@ -239,8 +210,5 @@ namespace MWVR
|
|||
camera->setPreDrawCallback(mPreDraw);
|
||||
Log(Debug::Warning) << ("osg overwrote predraw");
|
||||
}
|
||||
|
||||
//if(mDelay && name == "RightEye")
|
||||
// std::this_thread::sleep_for(std::chrono::milliseconds(25));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -77,7 +77,6 @@ namespace MWVR
|
|||
void preDrawCallback(osg::RenderInfo& info);
|
||||
void postDrawCallback(osg::RenderInfo& info);
|
||||
void blitEyesToMirrorTexture(osg::GraphicsContext* gc);
|
||||
void swapBuffers(osg::GraphicsContext* gc);
|
||||
void realize(osg::GraphicsContext* gc);
|
||||
bool realized() { return mConfigured; }
|
||||
|
||||
|
|
Loading…
Reference in a new issue