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:
parent
288530510d
commit
3e3ed7ecee
4 changed files with 162 additions and 140 deletions
|
@ -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 <<(
|
||||
|
|
|
@ -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 };
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue