You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
343 lines
10 KiB
C++
343 lines
10 KiB
C++
#include "vrtracking.hpp"
|
|
#include "vrenvironment.hpp"
|
|
#include "vrsession.hpp"
|
|
#include "openxrmanagerimpl.hpp"
|
|
|
|
#include <components/misc/constants.hpp>
|
|
|
|
#include <mutex>
|
|
|
|
namespace MWVR
|
|
{
|
|
VRTrackingManager::VRTrackingManager()
|
|
{
|
|
mHandDirectedMovement = Settings::Manager::getBool("hand directed movement", "VR");
|
|
mHeadPath = stringToVRPath("/user/head/input/pose");
|
|
mHandPath = stringToVRPath("/user/hand/left/input/aim/pose");
|
|
}
|
|
|
|
VRTrackingManager::~VRTrackingManager()
|
|
{
|
|
}
|
|
|
|
void VRTrackingManager::registerTrackingSource(VRTrackingSource* source, const std::string& name)
|
|
{
|
|
mSources.emplace(name, source);
|
|
notifySourceChanged(name);
|
|
}
|
|
|
|
void VRTrackingManager::unregisterTrackingSource(VRTrackingSource* source)
|
|
{
|
|
std::string name = "";
|
|
{
|
|
auto it = mSources.begin();
|
|
while (it->second != source) it++;
|
|
name = it->first;
|
|
mSources.erase(it);
|
|
}
|
|
notifySourceChanged(name);
|
|
}
|
|
|
|
VRTrackingSource* VRTrackingManager::getSource(const std::string& name)
|
|
{
|
|
auto it = mSources.find(name);
|
|
if (it != mSources.end())
|
|
return it->second;
|
|
return nullptr;
|
|
}
|
|
|
|
void VRTrackingManager::movementAngles(float& yaw, float& pitch)
|
|
{
|
|
yaw = mMovementYaw;
|
|
pitch = mMovementPitch;
|
|
}
|
|
|
|
void VRTrackingManager::processChangedSettings(const std::set<std::pair<std::string, std::string>>& changed)
|
|
{
|
|
mHandDirectedMovement = Settings::Manager::getBool("hand directed movement", "VR");
|
|
}
|
|
|
|
void VRTrackingManager::notifySourceChanged(const std::string& name)
|
|
{
|
|
auto* source = getSource(name);
|
|
for (auto& it : mBindings)
|
|
{
|
|
if (it.second == name)
|
|
{
|
|
if (source)
|
|
it.first->onTrackingAttached(*source);
|
|
else
|
|
it.first->onTrackingDetached();
|
|
}
|
|
}
|
|
}
|
|
|
|
void VRTrackingManager::updateMovementAngles(DisplayTime predictedDisplayTime)
|
|
{
|
|
if (mHandDirectedMovement)
|
|
{
|
|
float headYaw = 0.f;
|
|
float headPitch = 0.f;
|
|
float headsWillRoll = 0.f;
|
|
|
|
float handYaw = 0.f;
|
|
float handPitch = 0.f;
|
|
float handRoll = 0.f;
|
|
|
|
auto pcsource = getSource("pcstage");
|
|
|
|
if (pcsource)
|
|
{
|
|
auto tpHead = pcsource->getTrackingPose(predictedDisplayTime, mHeadPath);
|
|
auto tpHand = pcsource->getTrackingPose(predictedDisplayTime, mHandPath);
|
|
|
|
if (!!tpHead.status && !!tpHand.status)
|
|
{
|
|
getEulerAngles(tpHead.pose.orientation, headYaw, headPitch, headsWillRoll);
|
|
getEulerAngles(tpHand.pose.orientation, handYaw, handPitch, handRoll);
|
|
|
|
mMovementYaw = handYaw - headYaw;
|
|
mMovementPitch = handPitch - headPitch;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
mMovementYaw = 0;
|
|
mMovementPitch = 0;
|
|
}
|
|
}
|
|
|
|
void VRTrackingManager::bind(VRTrackingListener* listener, std::string sourceName)
|
|
{
|
|
unbind(listener);
|
|
mBindings.emplace(listener, sourceName);
|
|
|
|
auto* source = getSource(sourceName);
|
|
if (source)
|
|
listener->onTrackingAttached(*source);
|
|
else
|
|
listener->onTrackingDetached();
|
|
}
|
|
|
|
void VRTrackingManager::unbind(VRTrackingListener* listener)
|
|
{
|
|
auto it = mBindings.find(listener);
|
|
if (it != mBindings.end())
|
|
{
|
|
listener->onTrackingDetached();
|
|
mBindings.erase(listener);
|
|
}
|
|
}
|
|
|
|
VRPath VRTrackingManager::stringToVRPath(const std::string& path)
|
|
{
|
|
// Empty path is invalid
|
|
if (path.empty())
|
|
{
|
|
Log(Debug::Error) << "Empty path";
|
|
return 0;
|
|
}
|
|
|
|
// Return path immediately if it already exists
|
|
auto it = mPathIdentifiers.find(path);
|
|
if (it != mPathIdentifiers.end())
|
|
return it->second;
|
|
|
|
// Add new path and return it
|
|
auto res = mPathIdentifiers.emplace(path, mPathIdentifiers.size() + 1);
|
|
return res.first->second;
|
|
}
|
|
|
|
std::string VRTrackingManager::VRPathToString(VRPath path)
|
|
{
|
|
// Find the identifier in the map and return the corresponding string.
|
|
for (auto& e : mPathIdentifiers)
|
|
if (e.second == path)
|
|
return e.first;
|
|
|
|
// No path found, return empty string
|
|
Log(Debug::Warning) << "No such path identifier (" << path << ")";
|
|
return "";
|
|
}
|
|
|
|
void VRTrackingManager::updateTracking()
|
|
{
|
|
MWVR::Environment::get().getSession()->endFrame();
|
|
MWVR::Environment::get().getSession()->beginFrame();
|
|
auto& frame = Environment::get().getSession()->getFrame(VRSession::FramePhase::Update);
|
|
|
|
if (frame->mFrameInfo.runtimePredictedDisplayTime == 0)
|
|
return;
|
|
|
|
for (auto source : mSources)
|
|
source.second->updateTracking(frame->mFrameInfo.runtimePredictedDisplayTime);
|
|
|
|
updateMovementAngles(frame->mFrameInfo.runtimePredictedDisplayTime);
|
|
|
|
for (auto& binding : mBindings)
|
|
{
|
|
auto* listener = binding.first;
|
|
auto* source = getSource(binding.second);
|
|
if (source)
|
|
{
|
|
if (source->availablePosesChanged())
|
|
listener->onAvailablePosesChanged(*source);
|
|
listener->onTrackingUpdated(*source, frame->mFrameInfo.runtimePredictedDisplayTime);
|
|
}
|
|
}
|
|
|
|
for (auto source : mSources)
|
|
source.second->clearAvailablePosesChanged();
|
|
}
|
|
|
|
VRTrackingSource::VRTrackingSource(const std::string& name)
|
|
{
|
|
Environment::get().getTrackingManager()->registerTrackingSource(this, name);
|
|
}
|
|
|
|
VRTrackingSource::~VRTrackingSource()
|
|
{
|
|
Environment::get().getTrackingManager()->unregisterTrackingSource(this);
|
|
}
|
|
|
|
VRTrackingPose VRTrackingSource::getTrackingPose(DisplayTime predictedDisplayTime, VRPath path, VRPath reference)
|
|
{
|
|
auto it = mCache.find(std::pair(path, reference));
|
|
|
|
if (it == mCache.end())
|
|
{
|
|
mCache[std::pair(path, reference)] = getTrackingPoseImpl(predictedDisplayTime, path, reference);
|
|
mCache[std::pair(path, reference)].time = predictedDisplayTime;
|
|
}
|
|
|
|
if (predictedDisplayTime <= it->second.time)
|
|
return it->second;
|
|
|
|
auto tp = getTrackingPoseImpl(predictedDisplayTime, path, reference);
|
|
tp.time = predictedDisplayTime;
|
|
if (!tp.status)
|
|
tp.pose = it->second.pose;
|
|
it->second = tp;
|
|
|
|
return tp;
|
|
}
|
|
|
|
bool VRTrackingSource::availablePosesChanged() const
|
|
{
|
|
return mAvailablePosesChanged;
|
|
}
|
|
|
|
void VRTrackingSource::clearAvailablePosesChanged()
|
|
{
|
|
mAvailablePosesChanged = false;
|
|
}
|
|
|
|
void VRTrackingSource::clearCache()
|
|
{
|
|
mCache.clear();
|
|
}
|
|
|
|
void VRTrackingSource::notifyAvailablePosesChanged()
|
|
{
|
|
mAvailablePosesChanged = true;
|
|
}
|
|
|
|
VRTrackingListener::~VRTrackingListener()
|
|
{
|
|
Environment::get().getTrackingManager()->unbind(this);
|
|
}
|
|
|
|
VRTrackingToWorldBinding::VRTrackingToWorldBinding(const std::string& name, VRTrackingSource* source, VRPath movementReference)
|
|
: VRTrackingSource(name)
|
|
, mMovementReference(movementReference)
|
|
, mSource(source)
|
|
{
|
|
}
|
|
|
|
|
|
void VRTrackingToWorldBinding::setWorldOrientation(float yaw, bool adjust)
|
|
{
|
|
auto yawQuat = osg::Quat(yaw, osg::Vec3(0, 0, -1));
|
|
if (adjust)
|
|
mOrientation = yawQuat * mOrientation;
|
|
else
|
|
mOrientation = yawQuat;
|
|
}
|
|
|
|
osg::Vec3 VRTrackingToWorldBinding::movement() const
|
|
{
|
|
return mMovement;
|
|
}
|
|
|
|
void VRTrackingToWorldBinding::consumeMovement(const osg::Vec3& movement)
|
|
{
|
|
mMovement.x() -= movement.x();
|
|
mMovement.y() -= movement.y();
|
|
}
|
|
|
|
void VRTrackingToWorldBinding::recenter(bool resetZ)
|
|
{
|
|
mMovement.x() = 0;
|
|
mMovement.y() = 0;
|
|
if (resetZ)
|
|
{
|
|
if (mSeatedPlay)
|
|
mMovement.z() = mEyeLevel;
|
|
else
|
|
mMovement.z() = mLastPose.position.z();
|
|
}
|
|
}
|
|
|
|
VRTrackingPose VRTrackingToWorldBinding::getTrackingPoseImpl(DisplayTime predictedDisplayTime, VRPath path, VRPath reference)
|
|
{
|
|
auto tp = mSource->getTrackingPose(predictedDisplayTime, path, reference);
|
|
tp.pose.position *= Constants::UnitsPerMeter;
|
|
|
|
if (reference == 0 && !!tp.status)
|
|
{
|
|
tp.pose.position -= mLastPose.position;
|
|
tp.pose.position = mOrientation * tp.pose.position;
|
|
tp.pose.position += mMovement;
|
|
tp.pose.orientation = tp.pose.orientation * mOrientation;
|
|
|
|
if(mOrigin)
|
|
tp.pose.position += mOriginWorldPose.position;
|
|
}
|
|
return tp;
|
|
}
|
|
|
|
std::vector<VRPath> VRTrackingToWorldBinding::listSupportedTrackingPosePaths() const
|
|
{
|
|
return mSource->listSupportedTrackingPosePaths();
|
|
}
|
|
|
|
void VRTrackingToWorldBinding::updateTracking(DisplayTime predictedDisplayTime)
|
|
{
|
|
mOriginWorldPose = Pose();
|
|
if (mOrigin)
|
|
{
|
|
auto worldMatrix = osg::computeLocalToWorld(mOrigin->getParentalNodePaths()[0]);
|
|
mOriginWorldPose.position = worldMatrix.getTrans();
|
|
mOriginWorldPose.orientation = worldMatrix.getRotate();
|
|
}
|
|
|
|
auto mtp = mSource->getTrackingPose(predictedDisplayTime, mMovementReference, 0);
|
|
if (!!mtp.status)
|
|
{
|
|
mtp.pose.position *= Constants::UnitsPerMeter;
|
|
osg::Vec3 vrMovement = mtp.pose.position - mLastPose.position;
|
|
mLastPose = mtp.pose;
|
|
if (mHasTrackingData)
|
|
mMovement += mOrientation * vrMovement;
|
|
else
|
|
mMovement.z() = mLastPose.position.z();
|
|
mHasTrackingData = true;
|
|
}
|
|
|
|
mAvailablePosesChanged = mSource->availablePosesChanged();
|
|
}
|
|
}
|
|
|
|
|