1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-02-15 17:09:46 +00:00

STATIC data variance and asynchronous xrwaitframe.

This commit is contained in:
Mads Buvik Sandvei 2020-05-21 19:52:21 +02:00
parent 288530510d
commit 3e3ed7ecee
4 changed files with 162 additions and 140 deletions

View file

@ -27,155 +27,179 @@
namespace MWVR
{
OpenXRSession::OpenXRSession()
OpenXRSession::OpenXRSession()
{
}
OpenXRSession::~OpenXRSession()
{
}
void OpenXRSession::setLayer(
OpenXRLayerStack::Layer layerType,
OpenXRLayer* layer)
{
mLayerStack.setLayer(layerType, layer);
}
void OpenXRSession::swapBuffers(osg::GraphicsContext* gc)
{
Timer timer("OpenXRSession::SwapBuffers");
auto* xr = Environment::get().getManager();
if (!mShouldRender)
return;
if (mRenderedFrames != mRenderFrame - 1)
{
Log(Debug::Warning) << "swapBuffers called out of order";
waitFrame();
return;
}
OpenXRSession::~OpenXRSession()
{
}
for (auto layer : mLayerStack.layerObjects())
if (layer)
layer->swapBuffers(gc);
void OpenXRSession::setLayer(
OpenXRLayerStack::Layer layerType,
OpenXRLayer* layer)
{
mLayerStack.setLayer(layerType, layer);
}
timer.checkpoint("Rendered");
xr->endFrame(mDrawPredictedDisplayTime, &mLayerStack);
mRenderedFrames++;
}
void OpenXRSession::swapBuffers(osg::GraphicsContext* gc)
const PoseSets& OpenXRSession::predictedPoses(PredictionSlice slice)
{
if (slice == PredictionSlice::Predraw)
waitFrame();
return mPredictedPoses[(int)slice];
}
static std::chrono::steady_clock::time_point gLast{};
void OpenXRSession::waitFrame()
{
if (mPredictedFrames < mPredictionFrame)
{
Timer timer("OpenXRSession::SwapBuffers");
Timer timer("OpenXRSession::waitFrame");
auto* xr = Environment::get().getManager();
if (!mShouldRender)
return;
if (mRenderedFrames != mRenderFrame - 1)
{
Log(Debug::Warning) << "swapBuffers called out of order";
waitFrame();
return;
}
for (auto layer : mLayerStack.layerObjects())
if(layer)
layer->swapBuffers(gc);
timer.checkpoint("Rendered");
xr->endFrame(xr->impl().frameState().predictedDisplayTime, &mLayerStack);
mRenderedFrames++;
}
const PoseSets& OpenXRSession::predictedPoses(PredictionSlice slice)
{
if(slice == PredictionSlice::Predraw)
waitFrame();
return mPredictedPoses[(int)slice];
}
void OpenXRSession::waitFrame()
{
if(mPredictedFrames < mPredictionFrame)
{
Timer timer("OpenXRSession::waitFrame");
auto* xr = Environment::get().getManager();
xr->handleEvents();
mIsRunning = xr->sessionRunning();
if (!mIsRunning)
return;
xr->waitFrame();
timer.checkpoint("waitFrame");
predictNext(0);
mPredictedFrames++;
}
}
// OSG doesn't provide API to extract euler angles from a quat, but i need it.
// Credits goes to Dennis Bunfield, i just copied his formula https://narkive.com/v0re6547.4
void getEulerAngles(const osg::Quat& quat, float& yaw, float& pitch, float& roll)
{
// Now do the computation
osg::Matrixd m2(osg::Matrixd::rotate(quat));
double* mat = (double*)m2.ptr();
double angle_x = 0.0;
double angle_y = 0.0;
double angle_z = 0.0;
double D, C, tr_x, tr_y;
angle_y = D = asin(mat[2]); /* Calculate Y-axis angle */
C = cos(angle_y);
if (fabs(C) > 0.005) /* Test for Gimball lock? */
{
tr_x = mat[10] / C; /* No, so get X-axis angle */
tr_y = -mat[6] / C;
angle_x = atan2(tr_y, tr_x);
tr_x = mat[0] / C; /* Get Z-axis angle */
tr_y = -mat[1] / C;
angle_z = atan2(tr_y, tr_x);
}
else /* Gimball lock has occurred */
{
angle_x = 0; /* Set X-axis angle to zero
*/
tr_x = mat[5]; /* And calculate Z-axis angle
*/
tr_y = mat[4];
angle_z = atan2(tr_y, tr_x);
}
yaw = angle_z;
pitch = angle_x;
roll = angle_y;
}
void OpenXRSession::movementAngles(float& yaw, float& pitch)
{
auto lhandquat = predictedPoses(PredictionSlice::Predraw).hands[(int)TrackedSpace::VIEW][(int)MWVR::Side::LEFT_HAND].orientation;
float roll = 0.f;
getEulerAngles(lhandquat, yaw, pitch, roll);
}
void OpenXRSession::advanceFrame(void)
{
auto* xr = Environment::get().getManager();
mShouldRender = mIsRunning;
xr->handleEvents();
mIsRunning = xr->sessionRunning();
if (!mIsRunning)
return;
if (mPredictedFrames != mPredictionFrame)
// Until OpenXR allows us to get a prediction without waiting
// we make our own (bad) prediction and let openxr wait asynchronously.
auto frameState = xr->impl().frameState();
std::thread waitThread([]{
Environment::get().getManager()->waitFrame();
});
if (mPredrawPredictedDisplayTime == 0)
{
Log(Debug::Warning) << "advanceFrame() called out of order";
return;
// First time
waitThread.join();
mPredrawPredictedDisplayTime = xr->impl().frameState().predictedDisplayTime;
}
else
{
waitThread.detach();
mPredrawPredictedDisplayTime = frameState.predictedDisplayTime + frameState.predictedDisplayPeriod;
}
xr->beginFrame();
mPredictionFrame++;
mRenderFrame++;
mPredictedPoses[(int)PredictionSlice::Draw] = mPredictedPoses[(int)PredictionSlice::Predraw];
timer.checkpoint("waitFrame");
predictNext(0);
mPredictedFrames++;
}
}
void OpenXRSession::predictNext(int extraPeriods)
// OSG doesn't provide API to extract euler angles from a quat, but i need it.
// Credits goes to Dennis Bunfield, i just copied his formula https://narkive.com/v0re6547.4
void getEulerAngles(const osg::Quat& quat, float& yaw, float& pitch, float& roll)
{
// Now do the computation
osg::Matrixd m2(osg::Matrixd::rotate(quat));
double* mat = (double*)m2.ptr();
double angle_x = 0.0;
double angle_y = 0.0;
double angle_z = 0.0;
double D, C, tr_x, tr_y;
angle_y = D = asin(mat[2]); /* Calculate Y-axis angle */
C = cos(angle_y);
if (fabs(C) > 0.005) /* Test for Gimball lock? */
{
auto* xr = Environment::get().getManager();
auto* input = Environment::get().getInputManager();
auto mPredictedDisplayTime = xr->impl().frameState().predictedDisplayTime;
PoseSets newPoses{};
newPoses.head[(int)TrackedSpace::STAGE] = xr->impl().getPredictedLimbPose(mPredictedDisplayTime, TrackedLimb::HEAD, TrackedSpace::STAGE);
newPoses.head[(int)TrackedSpace::VIEW] = xr->impl().getPredictedLimbPose(mPredictedDisplayTime, TrackedLimb::HEAD, TrackedSpace::VIEW);
newPoses.hands[(int)TrackedSpace::STAGE] = input->getHandPoses(mPredictedDisplayTime, TrackedSpace::STAGE);
newPoses.hands[(int)TrackedSpace::VIEW] = input->getHandPoses(mPredictedDisplayTime, TrackedSpace::VIEW);
auto stageViews = xr->impl().getPredictedViews(mPredictedDisplayTime, TrackedSpace::STAGE);
auto hmdViews = xr->impl().getPredictedViews(mPredictedDisplayTime, TrackedSpace::VIEW);
newPoses.eye[(int)TrackedSpace::STAGE][(int)Side::LEFT_HAND] = fromXR(stageViews[(int)Side::LEFT_HAND].pose);
newPoses.eye[(int)TrackedSpace::VIEW][(int)Side::LEFT_HAND] = fromXR(hmdViews[(int)Side::LEFT_HAND].pose);
newPoses.eye[(int)TrackedSpace::STAGE][(int)Side::RIGHT_HAND] = fromXR(stageViews[(int)Side::RIGHT_HAND].pose);
newPoses.eye[(int)TrackedSpace::VIEW][(int)Side::RIGHT_HAND] = fromXR(hmdViews[(int)Side::RIGHT_HAND].pose);
mPredictedPoses[(int)PredictionSlice::Predraw] = newPoses;
tr_x = mat[10] / C; /* No, so get X-axis angle */
tr_y = -mat[6] / C;
angle_x = atan2(tr_y, tr_x);
tr_x = mat[0] / C; /* Get Z-axis angle */
tr_y = -mat[1] / C;
angle_z = atan2(tr_y, tr_x);
}
else /* Gimball lock has occurred */
{
angle_x = 0; /* Set X-axis angle to zero
*/
tr_x = mat[5]; /* And calculate Z-axis angle
*/
tr_y = mat[4];
angle_z = atan2(tr_y, tr_x);
}
yaw = angle_z;
pitch = angle_x;
roll = angle_y;
}
void OpenXRSession::movementAngles(float& yaw, float& pitch)
{
auto lhandquat = predictedPoses(PredictionSlice::Predraw).hands[(int)TrackedSpace::VIEW][(int)MWVR::Side::LEFT_HAND].orientation;
float roll = 0.f;
getEulerAngles(lhandquat, yaw, pitch, roll);
}
void OpenXRSession::advanceFrame(void)
{
auto* xr = Environment::get().getManager();
mShouldRender = mIsRunning;
if (!mIsRunning)
return;
if (mPredictedFrames != mPredictionFrame)
{
Log(Debug::Warning) << "advanceFrame() called out of order";
return;
}
// For the same reason we do waitFrame() asynchronously,
// we do beginFrame async and just blit to the swapchains later.
//std::thread([=] {
xr->beginFrame();
//}).detach();
mPredictionFrame++;
mRenderFrame++;
mPredictedPoses[(int)PredictionSlice::Draw] = mPredictedPoses[(int)PredictionSlice::Predraw];
mDrawPredictedDisplayTime = mPredrawPredictedDisplayTime;
}
void OpenXRSession::predictNext(int extraPeriods)
{
auto* xr = Environment::get().getManager();
auto* input = Environment::get().getInputManager();
PoseSets newPoses{};
newPoses.head[(int)TrackedSpace::STAGE] = xr->impl().getPredictedLimbPose(mPredrawPredictedDisplayTime, TrackedLimb::HEAD, TrackedSpace::STAGE);
newPoses.head[(int)TrackedSpace::VIEW] = xr->impl().getPredictedLimbPose(mPredrawPredictedDisplayTime, TrackedLimb::HEAD, TrackedSpace::VIEW);
newPoses.hands[(int)TrackedSpace::STAGE] = input->getHandPoses(mPredrawPredictedDisplayTime, TrackedSpace::STAGE);
newPoses.hands[(int)TrackedSpace::VIEW] = input->getHandPoses(mPredrawPredictedDisplayTime, TrackedSpace::VIEW);
auto stageViews = xr->impl().getPredictedViews(mPredrawPredictedDisplayTime, TrackedSpace::STAGE);
auto hmdViews = xr->impl().getPredictedViews(mPredrawPredictedDisplayTime, TrackedSpace::VIEW);
newPoses.eye[(int)TrackedSpace::STAGE][(int)Side::LEFT_HAND] = fromXR(stageViews[(int)Side::LEFT_HAND].pose);
newPoses.eye[(int)TrackedSpace::VIEW][(int)Side::LEFT_HAND] = fromXR(hmdViews[(int)Side::LEFT_HAND].pose);
newPoses.eye[(int)TrackedSpace::STAGE][(int)Side::RIGHT_HAND] = fromXR(stageViews[(int)Side::RIGHT_HAND].pose);
newPoses.eye[(int)TrackedSpace::VIEW][(int)Side::RIGHT_HAND] = fromXR(hmdViews[(int)Side::RIGHT_HAND].pose);
mPredictedPoses[(int)PredictionSlice::Predraw] = newPoses;
}
}
std::ostream& operator <<(

View file

@ -64,6 +64,9 @@ public:
int mPredictionFrame{ 1 };
int mPredictedFrames{ 0 };
long long mPredrawPredictedDisplayTime{ 0 };
long long mDrawPredictedDisplayTime{ 0 };
bool mIsRunning{ false };
bool mShouldRender{ false };
};

View file

@ -603,9 +603,7 @@ osg::ref_ptr<osg::Geometry> VRAnimation::createPointerGeometry(void)
geometry->setVertexArray(vertexArray);
geometry->setColorArray(colorArray, osg::Array::BIND_PER_VERTEX);
geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES, 0, numVertices));
geometry->setDataVariance(osg::Object::DYNAMIC);
geometry->setSupportsDisplayList(false);
geometry->setCullingActive(false);
geometry->setDataVariance(osg::Object::STATIC);
auto stateset = geometry->getOrCreateStateSet();
stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF);

View file

@ -172,8 +172,7 @@ VRGUILayer::VRGUILayer(
(*normals)[0].set(0.0f, -1.0f, 0.0f);
mGeometry->setNormalArray(normals, osg::Array::BIND_OVERALL);
mGeometry->addPrimitiveSet(new osg::DrawArrays(GL_QUADS, 0, 4));
mGeometry->setDataVariance(osg::Object::DYNAMIC);
mGeometry->setSupportsDisplayList(false);
mGeometry->setDataVariance(osg::Object::STATIC);
mGeometry->setName("VRGUILayer");
// Create the camera that will render the menu texture
@ -183,8 +182,6 @@ VRGUILayer::VRGUILayer(
mGUICamera = new GUICamera(config.pixelResolution.x(), config.pixelResolution.y(), config.backgroundColor);
osgMyGUI::RenderManager& renderManager = static_cast<osgMyGUI::RenderManager&>(MyGUI::RenderManager::getInstance());
mMyGUICamera = renderManager.createGUICamera(osg::Camera::NESTED_RENDER, filter);
//myGUICamera->setViewport(0, 0, 256, 256);
//mMyGUICamera->setProjectionMatrixAsOrtho2D(-1, 1, -1, 1);
mGUICamera->setScene(mMyGUICamera);
// Define state set that allows rendering with transparency