Fix #109 also fixes lack of motion controller interaction during main menu and load game.

pull/615/head
madsbuvi 4 years ago
parent fb4a1ebd46
commit abee6ca841

@ -262,7 +262,7 @@ if(BUILD_OPENMW_VR)
add_openmw_dir (mwvr add_openmw_dir (mwvr
openxraction openxractionset openxrdebug openxrinput openxrmanager openxrmanagerimpl openxrplatform openxrswapchain openxrswapchainimage openxrswapchainimpl openxrtracker openxrtypeconversions openxraction openxractionset openxrdebug openxrinput openxrmanager openxrmanagerimpl openxrplatform openxrswapchain openxrswapchainimage openxrswapchainimpl openxrtracker openxrtypeconversions
realisticcombat realisticcombat
vranimation vrcamera vrenvironment vrframebuffer vrgui vrinputmanager vrinput vrlistbox vrmetamenu vrsession vrtracking vrtypes vrviewer vrvirtualkeyboard vranimation vrcamera vrenvironment vrframebuffer vrgui vrinputmanager vrinput vrlistbox vrmetamenu vrpointer vrsession vrtracking vrtypes vrutil vrviewer vrvirtualkeyboard
) )
openmw_add_executable(openmw_vr openmw_add_executable(openmw_vr

@ -698,6 +698,7 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
Settings::Manager::getString("texture mipmap", "General"), Settings::Manager::getString("texture mipmap", "General"),
Settings::Manager::getInt("anisotropy", "General") Settings::Manager::getInt("anisotropy", "General")
); );
mEnvironment.setResourceSystem(mResourceSystem.get());
int numThreads = Settings::Manager::getInt("preload num threads", "Cells"); int numThreads = Settings::Manager::getInt("preload num threads", "Cells");
if (numThreads <= 0) if (numThreads <= 0)
@ -858,7 +859,6 @@ void OMW::Engine::prepareEngine (Settings::Manager & settings)
// Create dialog system // Create dialog system
mEnvironment.setJournal (new MWDialogue::Journal); mEnvironment.setJournal (new MWDialogue::Journal);
mEnvironment.setDialogueManager (new MWDialogue::DialogueManager (mExtensions, mTranslationDataStorage)); mEnvironment.setDialogueManager (new MWDialogue::DialogueManager (mExtensions, mTranslationDataStorage));
mEnvironment.setResourceSystem(mResourceSystem.get());
// scripts // scripts
if (mCompileAll) if (mCompileAll)

@ -91,6 +91,11 @@ namespace MWWorld
typedef std::vector<std::pair<MWWorld::Ptr,MWMechanics::Movement> > PtrMovementList; typedef std::vector<std::pair<MWWorld::Ptr,MWMechanics::Movement> > PtrMovementList;
} }
namespace MWVR
{
class UserPointer;
}
namespace MWBase namespace MWBase
{ {
/// \brief Interface for the World (implemented in MWWorld) /// \brief Interface for the World (implemented in MWWorld)
@ -272,6 +277,8 @@ namespace MWBase
virtual float getMaxActivationDistance() = 0; virtual float getMaxActivationDistance() = 0;
virtual float getActivationDistancePlusTelekinesis() = 0;
/// Returns a pointer to the object the provided object would hit (if within the /// Returns a pointer to the object the provided object would hit (if within the
/// specified distance), and the point where the hit occurs. This will attempt to /// specified distance), and the point where the hit occurs. This will attempt to
/// use the "Head" node, or alternatively the "Bip01 Head" node as a basis. /// use the "Head" node, or alternatively the "Bip01 Head" node as a basis.
@ -667,8 +674,10 @@ namespace MWBase
/// @result pointer to the object and/or node the given node is currently pointing at /// @result pointer to the object and/or node the given node is currently pointing at
/// @Return distance to the target object, or -1 if no object was targeted / in range /// @Return distance to the target object, or -1 if no object was targeted / in range
virtual float getTargetObject(MWRender::RayResult& result, osg::Transform* pointer) = 0; virtual float getTargetObject(MWRender::RayResult& result, const osg::Vec3f& origin, const osg::Quat& orientation, float maxDistance, bool ignorePlayer) = 0;
virtual float getTargetObject(MWRender::RayResult& result, osg::Transform* pointer, float maxDistance, bool ignorePlayer) = 0;
virtual MWVR::UserPointer& getUserPointer() = 0;
virtual MWWorld::Ptr getPointerTarget() = 0;
/// @Return ESM::Weapon::Type enum describing the type of weapon currently drawn by the player. /// @Return ESM::Weapon::Type enum describing the type of weapon currently drawn by the player.
virtual int getActiveWeaponType(void) = 0; virtual int getActiveWeaponType(void) = 0;

@ -604,7 +604,7 @@ namespace MWGui
// VR mode needs to render the 3D gui // VR mode needs to render the 3D gui
if (MWBase::Environment::get().getVrMode()) if (MWBase::Environment::get().getVrMode())
disablemask = MWRender::Mask_3DGUI | MWRender::Mask_PreCompile | MWRender::Mask_RenderToTexture; disablemask = MWRender::Mask_Pointer | MWRender::Mask_3DGUI | MWRender::Mask_PreCompile | MWRender::Mask_RenderToTexture;
if (!enable && mViewer->getCamera()->getCullMask() != disablemask) if (!enable && mViewer->getCamera()->getCullMask() != disablemask)
{ {

@ -53,6 +53,7 @@
#ifdef USE_OPENXR #ifdef USE_OPENXR
#include "../mwvr/vrenvironment.hpp" #include "../mwvr/vrenvironment.hpp"
#include "../mwvr/vranimation.hpp" #include "../mwvr/vranimation.hpp"
#include "../mwvr/vrutil.hpp"
#endif #endif
namespace namespace
@ -1601,8 +1602,7 @@ bool CharacterController::updateWeaponState(CharacterState& idle)
std::string resultMessage, resultSound; std::string resultMessage, resultSound;
// TODO: this will only work for the player, and needs to be fixed if NPCs should ever use lockpicks/probes. // TODO: this will only work for the player, and needs to be fixed if NPCs should ever use lockpicks/probes.
#ifdef USE_OPENXR #ifdef USE_OPENXR
auto* anim = MWVR::Environment::get().getPlayerAnimation(); MWWorld::Ptr target = MWVR::Util::getWeaponTarget().first;
auto target = anim->getTarget("weapon bone");
#else #else
MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getFacedObject(); MWWorld::Ptr target = MWBase::Environment::get().getWorld()->getFacedObject();
#endif #endif

@ -76,6 +76,7 @@
#ifdef USE_OPENXR #ifdef USE_OPENXR
#include "../mwvr/vranimation.hpp" #include "../mwvr/vranimation.hpp"
#include "../mwvr/vrpointer.hpp"
#include "../mwvr/vrviewer.hpp" #include "../mwvr/vrviewer.hpp"
#include "../mwvr/vrenvironment.hpp" #include "../mwvr/vrenvironment.hpp"
#include "../mwvr/vrcamera.hpp" #include "../mwvr/vrcamera.hpp"
@ -206,6 +207,7 @@ namespace MWRender
, mWorkQueue(workQueue) , mWorkQueue(workQueue)
, mUnrefQueue(new SceneUtil::UnrefQueue) , mUnrefQueue(new SceneUtil::UnrefQueue)
, mNavigator(navigator) , mNavigator(navigator)
, mUserPointer(new MWVR::UserPointer(rootNode))
, mMinimumAmbientLuminance(0.f) , mMinimumAmbientLuminance(0.f)
, mNightEyeFactor(0.f) , mNightEyeFactor(0.f)
, mFieldOfViewOverridden(false) , mFieldOfViewOverridden(false)
@ -942,9 +944,9 @@ namespace MWRender
unsigned int mask = ~0u; unsigned int mask = ~0u;
mask &= ~(Mask_RenderToTexture|Mask_Sky|Mask_Debug|Mask_Effect|Mask_Water|Mask_SimpleWater|Mask_Groundcover); mask &= ~(Mask_RenderToTexture|Mask_Sky|Mask_Debug|Mask_Effect|Mask_Water|Mask_SimpleWater|Mask_Groundcover);
if (ignorePlayer) if (ignorePlayer)
mask &= ~(Mask_Player); mask &= ~(Mask_Player|Mask_Pointer);
if (ignoreActors) if (ignoreActors)
mask &= ~(Mask_Actor|Mask_Player); mask &= ~(Mask_Actor|Mask_Player|Mask_Pointer);
mIntersectionVisitor->setTraversalMask(mask); mIntersectionVisitor->setTraversalMask(mask);
return mIntersectionVisitor; return mIntersectionVisitor;
@ -1022,6 +1024,8 @@ namespace MWRender
notifyWorldSpaceChanged(); notifyWorldSpaceChanged();
if (mObjectPaging) if (mObjectPaging)
mObjectPaging->clear(); mObjectPaging->clear();
mUserPointer->setParent(nullptr);
} }
MWRender::Animation* RenderingManager::getAnimation(const MWWorld::Ptr &ptr) MWRender::Animation* RenderingManager::getAnimation(const MWWorld::Ptr &ptr)
@ -1062,7 +1066,7 @@ namespace MWRender
void RenderingManager::renderPlayer(const MWWorld::Ptr &player) void RenderingManager::renderPlayer(const MWWorld::Ptr &player)
{ {
#ifdef USE_OPENXR #ifdef USE_OPENXR
MWVR::Environment::get().setPlayerAnimation(new MWVR::VRAnimation(player, player.getRefData().getBaseNode(), mResourceSystem, false, nullptr)); MWVR::Environment::get().setPlayerAnimation(new MWVR::VRAnimation(player, player.getRefData().getBaseNode(), mResourceSystem, false, mUserPointer));
mPlayerAnimation = MWVR::Environment::get().getPlayerAnimation(); mPlayerAnimation = MWVR::Environment::get().getPlayerAnimation();
#else #else
mPlayerAnimation = new NpcAnimation(player, player.getRefData().getBaseNode(), mResourceSystem, 0, NpcAnimation::VM_Normal, mPlayerAnimation = new NpcAnimation(player, player.getRefData().getBaseNode(), mResourceSystem, 0, NpcAnimation::VM_Normal,
@ -1403,4 +1407,9 @@ namespace MWRender
if (mObjectPaging) if (mObjectPaging)
mObjectPaging->getPagedRefnums(activeGrid, out); mObjectPaging->getPagedRefnums(activeGrid, out);
} }
MWVR::UserPointer& RenderingManager::userPointer()
{
return *mUserPointer;
}
} }

@ -68,6 +68,11 @@ namespace DetourNavigator
struct Settings; struct Settings;
} }
namespace MWVR
{
class UserPointer;
}
namespace MWRender namespace MWRender
{ {
class GroundcoverUpdater; class GroundcoverUpdater;
@ -250,6 +255,8 @@ namespace MWRender
bool pagingUnlockCache(); bool pagingUnlockCache();
void getPagedRefnums(const osg::Vec4i &activeGrid, std::set<ESM::RefNum> &out); void getPagedRefnums(const osg::Vec4i &activeGrid, std::set<ESM::RefNum> &out);
MWVR::UserPointer& userPointer();
private: private:
void updateProjectionMatrix(); void updateProjectionMatrix();
void updateTextureFiltering(); void updateTextureFiltering();
@ -302,6 +309,7 @@ namespace MWRender
std::unique_ptr<Camera> mCamera; std::unique_ptr<Camera> mCamera;
std::unique_ptr<ViewOverShoulderController> mViewOverShoulderController; std::unique_ptr<ViewOverShoulderController> mViewOverShoulderController;
osg::Vec3f mCurrentCameraPos; osg::Vec3f mCurrentCameraPos;
std::shared_ptr<MWVR::UserPointer> mUserPointer;
osg::ref_ptr<StateUpdater> mStateUpdater; osg::ref_ptr<StateUpdater> mStateUpdater;

@ -59,6 +59,7 @@ namespace MWRender
// Vr masks // Vr masks
Mask_3DGUI = (1 << 21), Mask_3DGUI = (1 << 21),
Mask_Pointer = (1 << 22)
}; };
} }

@ -67,7 +67,7 @@ namespace MWVR
return 0; return 0;
} }
VRTrackingPose OpenXRTracker::getTrackingPose(DisplayTime predictedDisplayTime, VRPath path, VRPath reference) VRTrackingPose OpenXRTracker::getTrackingPoseImpl(DisplayTime predictedDisplayTime, VRPath path, VRPath reference)
{ {
VRTrackingPose pose; VRTrackingPose pose;
pose.status = TrackingStatus::Good; pose.status = TrackingStatus::Good;

@ -22,11 +22,12 @@ namespace MWVR
//! The base space used to reference everything else. //! The base space used to reference everything else.
void setReferenceSpace(XrSpace referenceSpace); void setReferenceSpace(XrSpace referenceSpace);
VRTrackingPose getTrackingPose(DisplayTime predictedDisplayTime, VRPath path, VRPath reference = 0) override;
std::vector<VRPath> listSupportedTrackingPosePaths() const override; std::vector<VRPath> listSupportedTrackingPosePaths() const override;
void updateTracking(DisplayTime predictedDisplayTime) override; void updateTracking(DisplayTime predictedDisplayTime) override;
protected:
VRTrackingPose getTrackingPoseImpl(DisplayTime predictedDisplayTime, VRPath path, VRPath reference = 0) override;
private: private:
std::array<View, 2> locateViews(DisplayTime predictedDisplayTime, XrSpace reference); std::array<View, 2> locateViews(DisplayTime predictedDisplayTime, XrSpace reference);
void locate(VRTrackingPose& pose, XrSpace space, XrSpace reference, DisplayTime predictedDisplayTime); void locate(VRTrackingPose& pose, XrSpace space, XrSpace reference, DisplayTime predictedDisplayTime);

@ -3,6 +3,8 @@
#include "vrviewer.hpp" #include "vrviewer.hpp"
#include "vrinputmanager.hpp" #include "vrinputmanager.hpp"
#include "vrcamera.hpp" #include "vrcamera.hpp"
#include "vrutil.hpp"
#include "vrpointer.hpp"
#include <osg/MatrixTransform> #include <osg/MatrixTransform>
#include <osg/PositionAttitudeTransform> #include <osg/PositionAttitudeTransform>
@ -38,6 +40,7 @@
#include "../mwrender/camera.hpp" #include "../mwrender/camera.hpp"
#include "../mwrender/renderingmanager.hpp" #include "../mwrender/renderingmanager.hpp"
#include "../mwrender/vismask.hpp"
namespace MWVR namespace MWVR
{ {
@ -323,15 +326,15 @@ namespace MWVR
VRAnimation::VRAnimation( VRAnimation::VRAnimation(
const MWWorld::Ptr& ptr, osg::ref_ptr<osg::Group> parentNode, Resource::ResourceSystem* resourceSystem, const MWWorld::Ptr& ptr, osg::ref_ptr<osg::Group> parentNode, Resource::ResourceSystem* resourceSystem,
bool disableSounds, std::shared_ptr<VRSession> xrSession) bool disableSounds, std::shared_ptr<UserPointer> userPointer)
// Note that i let it construct as 3rd person and then later update it to VM_VRFirstPerson // Note that i let it construct as 3rd person and then later update it to VM_VRFirstPerson
// when the character controller updates // when the character controller updates
: MWRender::NpcAnimation(ptr, parentNode, resourceSystem, disableSounds, VM_Normal, 55.f) : MWRender::NpcAnimation(ptr, parentNode, resourceSystem, disableSounds, VM_Normal, 55.f)
, mSession(xrSession)
, mIndexFingerControllers{ nullptr, nullptr } , mIndexFingerControllers{ nullptr, nullptr }
// The player model needs to be pushed back a little to make sure the player's view point is naturally protruding // The player model needs to be pushed back a little to make sure the player's view point is naturally protruding
// Pushing the camera forward instead would produce an unnatural extra movement when rotating the player model. // Pushing the camera forward instead would produce an unnatural extra movement when rotating the player model.
, mModelOffset(new osg::MatrixTransform(osg::Matrix::translate(osg::Vec3(0, -15, 0)))) , mModelOffset(new osg::MatrixTransform(osg::Matrix::translate(osg::Vec3(0, -15, 0))))
, mUserPointer(userPointer)
{ {
for (int i = 0; i < 2; i++) for (int i = 0; i < 2; i++)
{ {
@ -344,17 +347,8 @@ namespace MWVR
mWeaponDirectionTransform->setUpdateCallback(new WeaponDirectionController); mWeaponDirectionTransform->setUpdateCallback(new WeaponDirectionController);
mModelOffset->setName("ModelOffset"); mModelOffset->setName("ModelOffset");
mPointerGeometry = createPointerGeometry();
mPointerRescale = new osg::MatrixTransform();
mPointerRescale->addChild(mPointerGeometry);
mPointerTransform = new osg::MatrixTransform();
mPointerTransform->addChild(mPointerRescale);
mPointerTransform->setName("Pointer Transform");
// Morrowind's hands don't actually point forward, so we have to reorient the pointer.
mPointerTransform->setMatrix(osg::Matrix::rotate(osg::Quat(-osg::PI_2, osg::Vec3f(0, 0, 1))));
mWeaponPointerTransform = new osg::MatrixTransform(); mWeaponPointerTransform = new osg::MatrixTransform();
mWeaponPointerTransform->addChild(mPointerGeometry);
mWeaponPointerTransform->setMatrix( mWeaponPointerTransform->setMatrix(
osg::Matrix::scale(0.f, 0.f, 0.f) osg::Matrix::scale(0.f, 0.f, 0.f)
); );
@ -408,7 +402,7 @@ namespace MWVR
if (mViewMode == VM_VRFirstPerson) if (mViewMode == VM_VRFirstPerson)
{ {
// Hide everything other than the hands and feet. // Hide everything other than hands
removeIndividualPart(ESM::PartReferenceType::PRT_Hair); removeIndividualPart(ESM::PartReferenceType::PRT_Hair);
removeIndividualPart(ESM::PartReferenceType::PRT_Head); removeIndividualPart(ESM::PartReferenceType::PRT_Head);
removeIndividualPart(ESM::PartReferenceType::PRT_LForearm); removeIndividualPart(ESM::PartReferenceType::PRT_LForearm);
@ -478,97 +472,11 @@ namespace MWVR
} }
} }
mPointerTransform->removeChild(mPointerRescale); mUserPointer->setEnabled(enabled);
if (enabled)
{
mPointerTransform->addChild(mPointerRescale);
}
else
{
mPointerTarget = MWRender::RayResult{};
}
mFingerPointingMode = enabled; mFingerPointingMode = enabled;
} }
osg::ref_ptr<osg::Geometry> VRAnimation::createPointerGeometry(void)
{
osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry();
// Create pointer geometry, which will point from the tip of the player's finger.
// The geometry will be a Four sided pyramid, with the top at the player's fingers
osg::Vec3 vertices[]{
{0, 0, 0}, // origin
{-1, 1, -1}, // A
{-1, 1, 1}, // B
{1, 1, 1}, // C
{1, 1, -1}, // D
};
osg::Vec4 colors[]{
osg::Vec4(1.0f, 0.0f, 0.0f, 0.0f),
osg::Vec4(1.0f, 0.0f, 0.0f, 1.0f),
osg::Vec4(1.0f, 0.0f, 0.0f, 1.0f),
osg::Vec4(1.0f, 0.0f, 0.0f, 1.0f),
osg::Vec4(1.0f, 0.0f, 0.0f, 1.0f),
};
const int O = 0;
const int A = 1;
const int B = 2;
const int C = 3;
const int D = 4;
const int triangles[] =
{
A,D,B,
B,D,C,
O,D,A,
O,C,D,
O,B,C,
O,A,B,
};
int numVertices = sizeof(triangles) / sizeof(*triangles);
osg::ref_ptr<osg::Vec3Array> vertexArray = new osg::Vec3Array(numVertices);
osg::ref_ptr<osg::Vec4Array> colorArray = new osg::Vec4Array(numVertices);
for (int i = 0; i < numVertices; i++)
{
(*vertexArray)[i] = vertices[triangles[i]];
(*colorArray)[i] = colors[triangles[i]];
}
geometry->setVertexArray(vertexArray);
geometry->setColorArray(colorArray, osg::Array::BIND_PER_VERTEX);
geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES, 0, numVertices));
geometry->setSupportsDisplayList(false);
geometry->setDataVariance(osg::Object::STATIC);
auto stateset = geometry->getOrCreateStateSet();
stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
stateset->setMode(GL_BLEND, osg::StateAttribute::ON);
stateset->setAttributeAndModes(new osg::BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
osg::ref_ptr<osg::Fog> fog(new osg::Fog);
fog->setStart(10000000);
fog->setEnd(10000000);
stateset->setAttributeAndModes(fog, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE);
osg::ref_ptr<osg::LightModel> lightmodel = new osg::LightModel;
lightmodel->setAmbientIntensity(osg::Vec4(1.0, 1.0, 1.0, 1.0));
stateset->setAttributeAndModes(lightmodel, osg::StateAttribute::ON);
SceneUtil::ShadowManager::disableShadowsForStateSet(stateset);
osg::ref_ptr<osg::Material> material = new osg::Material;
material->setColorMode(osg::Material::ColorMode::AMBIENT_AND_DIFFUSE);
stateset->setAttributeAndModes(material, osg::StateAttribute::ON);
mResourceSystem->getSceneManager()->recreateShaders(geometry);
mSkeleton->setIsTracked(true);
return geometry;
}
float VRAnimation::getVelocity(const std::string& groupname) const float VRAnimation::getVelocity(const std::string& groupname) const
{ {
return 0.0f; return 0.0f;
@ -582,7 +490,7 @@ namespace MWVR
if (mSkeleton) if (mSkeleton)
mSkeleton->markBoneMatriceDirty(); mSkeleton->markBoneMatriceDirty();
updatePointerTarget(); mUserPointer->updatePointerTarget();
} }
osg::Vec3f VRAnimation::runAnimation(float timepassed) osg::Vec3f VRAnimation::runAnimation(float timepassed)
@ -624,8 +532,7 @@ namespace MWVR
auto finger = mNodeMap.find("bip01 r finger11"); auto finger = mNodeMap.find("bip01 r finger11");
if (finger != mNodeMap.end()) if (finger != mNodeMap.end())
{ {
finger->second->removeChild(mPointerTransform); mUserPointer->setParent(finger->second);
finger->second->addChild(mPointerTransform);
} }
mSkeleton->setIsTracked(true); mSkeleton->setIsTracked(true);
} }
@ -638,56 +545,8 @@ namespace MWVR
NpcAnimation::setAccurateAiming(false); NpcAnimation::setAccurateAiming(false);
} }
bool VRAnimation::canPlaceObject()
{
const float maxDist = 200.f;
if (mPointerTarget.mHit)
{
// check if the wanted position is on a flat surface, and not e.g. against a vertical wall
if (std::acos((mPointerTarget.mHitNormalWorld / mPointerTarget.mHitNormalWorld.length()) * osg::Vec3f(0, 0, 1)) >= osg::DegreesToRadians(30.f))
return false;
return true;
}
return false;
}
const MWRender::RayResult& VRAnimation::getPointerTarget() const
{
return mPointerTarget;
}
MWWorld::Ptr VRAnimation::getTarget(const std::string& directorNode)
{
auto node = mNodeMap.find(directorNode);
auto* world = MWBase::Environment::get().getWorld();
MWRender::RayResult result{};
if (node != mNodeMap.end())
if (world)
world->getTargetObject(result, node->second);
return result.mHitObject;
}
osg::Matrix VRAnimation::getWeaponTransformMatrix() const osg::Matrix VRAnimation::getWeaponTransformMatrix() const
{ {
return osg::computeLocalToWorld(mWeaponDirectionTransform->getParentalNodePaths()[0]); return osg::computeLocalToWorld(mWeaponDirectionTransform->getParentalNodePaths()[0]);
} }
void VRAnimation::updatePointerTarget()
{
auto* world = MWBase::Environment::get().getWorld();
if (world)
{
mPointerRescale->setMatrix(osg::Matrix::scale(1, 1, 1));
mDistanceToPointerTarget = world->getTargetObject(mPointerTarget, mPointerTransform);
if (mDistanceToPointerTarget >= 0)
mPointerRescale->setMatrix(osg::Matrix::scale(0.25f, mDistanceToPointerTarget, 0.25f));
else
mPointerRescale->setMatrix(osg::Matrix::scale(0.25f, 10000.f, 0.25f));
}
}
} }

@ -9,10 +9,10 @@
namespace MWVR namespace MWVR
{ {
class HandController; class HandController;
class FingerController; class FingerController;
class TrackingController; class TrackingController;
class UserPointer;
/// Subclassing NpcAnimation to implement VR related behaviour /// Subclassing NpcAnimation to implement VR related behaviour
class VRAnimation : public MWRender::NpcAnimation, public VRTrackingListener class VRAnimation : public MWRender::NpcAnimation, public VRTrackingListener
@ -31,7 +31,7 @@ namespace MWVR
* @param xrSession The XR session that shall be used to track limbs * @param xrSession The XR session that shall be used to track limbs
*/ */
VRAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr<osg::Group> parentNode, Resource::ResourceSystem* resourceSystem, VRAnimation(const MWWorld::Ptr& ptr, osg::ref_ptr<osg::Group> parentNode, Resource::ResourceSystem* resourceSystem,
bool disableSounds, std::shared_ptr<VRSession> xrSession); bool disableSounds, std::shared_ptr<UserPointer> userPointer);
virtual ~VRAnimation(); virtual ~VRAnimation();
/// Overridden to always be false /// Overridden to always be false
@ -55,23 +55,10 @@ namespace MWVR
/// @return Whether animation is currently in finger pointing mode /// @return Whether animation is currently in finger pointing mode
bool fingerPointingMode() const { return mFingerPointingMode; } bool fingerPointingMode() const { return mFingerPointingMode; }
/// @return true if it is possible to place on object where the player is currently pointing
bool canPlaceObject();
/// @return pointer to the object the player's melee weapon is currently intersecting.
const MWRender::RayResult& getPointerTarget() const;
/// Update what object this vr animation is currently pointing at.
void updatePointerTarget();
/// @return whatever ref is the current pointer target, if any
MWWorld::Ptr getTarget(const std::string& directorNode);
/// @return world transform that yields the position and orientation of the current weapon /// @return world transform that yields the position and orientation of the current weapon
osg::Matrix getWeaponTransformMatrix() const; osg::Matrix getWeaponTransformMatrix() const;
protected: protected:
osg::ref_ptr<osg::Geometry> createPointerGeometry(void);
float getVelocity(const std::string& groupname) const override; float getVelocity(const std::string& groupname) const override;
@ -85,13 +72,9 @@ namespace MWVR
osg::ref_ptr<osg::MatrixTransform> mModelOffset; osg::ref_ptr<osg::MatrixTransform> mModelOffset;
bool mFingerPointingMode{ false }; bool mFingerPointingMode{ false };
osg::ref_ptr<osg::Geometry> mPointerGeometry{ nullptr }; std::shared_ptr<UserPointer> mUserPointer;
osg::ref_ptr<osg::MatrixTransform> mPointerRescale{ nullptr };
osg::ref_ptr<osg::MatrixTransform> mPointerTransform{ nullptr };
osg::ref_ptr<osg::MatrixTransform> mWeaponDirectionTransform{ nullptr }; osg::ref_ptr<osg::MatrixTransform> mWeaponDirectionTransform{ nullptr };
osg::ref_ptr<osg::MatrixTransform> mWeaponPointerTransform{ nullptr }; osg::ref_ptr<osg::MatrixTransform> mWeaponPointerTransform{ nullptr };
MWRender::RayResult mPointerTarget{};
float mDistanceToPointerTarget{ -1.f };
}; };
} }

@ -2,11 +2,12 @@
#include <cmath> #include <cmath>
#include "vranimation.hpp"
#include "vrenvironment.hpp" #include "vrenvironment.hpp"
#include "vrpointer.hpp"
#include "vrsession.hpp" #include "vrsession.hpp"
#include "openxrmanagerimpl.hpp"
#include "openxrinput.hpp" #include "openxrinput.hpp"
#include "vranimation.hpp" #include "openxrmanagerimpl.hpp"
#include <osg/Texture2D> #include <osg/Texture2D>
#include <osg/ClipNode> #include <osg/ClipNode>
@ -760,22 +761,26 @@ namespace MWVR
bool VRGUIManager::updateFocus() bool VRGUIManager::updateFocus()
{ {
auto* anim = MWVR::Environment::get().getPlayerAnimation(); auto* world = MWBase::Environment::get().getWorld();
if (anim && anim->getPointerTarget().mHit) if (world)
{ {
std::shared_ptr<VRGUILayer> newFocusLayer = nullptr; auto& pointer = world->getUserPointer();
auto* node = anim->getPointerTarget().mHitNode; if (pointer.getPointerTarget().mHit)
if (node->getName() == "VRGUILayer")
{
VRGUILayerUserData* userData = static_cast<VRGUILayerUserData*>(node->getUserData());
newFocusLayer = userData->mLayer.lock();
}
if (newFocusLayer && newFocusLayer->mLayerName != "Notification")
{ {
setFocusLayer(newFocusLayer.get()); std::shared_ptr<VRGUILayer> newFocusLayer = nullptr;
computeGuiCursor(anim->getPointerTarget().mHitPointLocal); auto* node = pointer.getPointerTarget().mHitNode;
return true; if (node->getName() == "VRGUILayer")
{
VRGUILayerUserData* userData = static_cast<VRGUILayerUserData*>(node->getUserData());
newFocusLayer = userData->mLayer.lock();
}
if (newFocusLayer && newFocusLayer->mLayerName != "Notification")
{
setFocusLayer(newFocusLayer.get());
computeGuiCursor(pointer.getPointerTarget().mHitPointLocal);
return true;
}
} }
} }
return false; return false;
@ -802,8 +807,11 @@ namespace MWVR
mFocusLayer = layer; mFocusLayer = layer;
if (mFocusLayer) if (mFocusLayer)
{ {
Log(Debug::Verbose) << "Set focus layer to " << mFocusLayer->mWidgets.front()->mMainWidget->getLayer()->getName(); if (!mFocusLayer->mWidgets.empty())
setPick(mFocusLayer->mWidgets.front(), true); {
Log(Debug::Verbose) << "Set focus layer to " << mFocusLayer->mWidgets.front()->mMainWidget->getLayer()->getName();
setPick(mFocusLayer->mWidgets.front(), true);
}
} }
else else
{ {
@ -977,7 +985,7 @@ namespace MWVR
mStationaryPath = tm->stringToVRPath("/ui/input/stationary/pose"); mStationaryPath = tm->stringToVRPath("/ui/input/stationary/pose");
} }
VRTrackingPose VRGUITracking::getTrackingPose(DisplayTime predictedDisplayTime, VRPath path, VRPath reference) VRTrackingPose VRGUITracking::getTrackingPoseImpl(DisplayTime predictedDisplayTime, VRPath path, VRPath reference)
{ {
if (path == mStationaryPath) if (path == mStationaryPath)
return mStationaryPose; return mStationaryPose;

@ -72,11 +72,13 @@ namespace MWVR
public: public:
VRGUITracking(const std::string& source); VRGUITracking(const std::string& source);
virtual VRTrackingPose getTrackingPose(DisplayTime predictedDisplayTime, VRPath path, VRPath reference = 0) override;
virtual std::vector<VRPath> listSupportedTrackingPosePaths() const override; virtual std::vector<VRPath> listSupportedTrackingPosePaths() const override;
virtual void updateTracking(DisplayTime predictedDisplayTime) override; virtual void updateTracking(DisplayTime predictedDisplayTime) override;
void resetStationaryPose(); void resetStationaryPose();
protected:
virtual VRTrackingPose getTrackingPoseImpl(DisplayTime predictedDisplayTime, VRPath path, VRPath reference = 0) override;
private: private:
VRPath mStationaryPath = 0; VRPath mStationaryPath = 0;
VRPath mHeadPath = 0; VRPath mHeadPath = 0;

@ -1,11 +1,12 @@
#include "vrinputmanager.hpp" #include "vrinputmanager.hpp"
#include "vrviewer.hpp" #include "vranimation.hpp"
#include "vrcamera.hpp" #include "vrcamera.hpp"
#include "vrenvironment.hpp"
#include "vrgui.hpp" #include "vrgui.hpp"
#include "vranimation.hpp" #include "vrpointer.hpp"
#include "vrviewer.hpp"
#include "openxrinput.hpp" #include "openxrinput.hpp"
#include "vrenvironment.hpp"
#include "openxrmanager.hpp" #include "openxrmanager.hpp"
#include "openxrmanagerimpl.hpp" #include "openxrmanagerimpl.hpp"
#include "openxraction.hpp" #include "openxraction.hpp"
@ -86,11 +87,11 @@ namespace MWVR
virtual MWWorld::Ptr copyItem(const MWGui::ItemStack& item, size_t count, bool /*allowAutoEquip*/) virtual MWWorld::Ptr copyItem(const MWGui::ItemStack& item, size_t count, bool /*allowAutoEquip*/)
{ {
MWBase::World* world = MWBase::Environment::get().getWorld(); MWBase::World* world = MWBase::Environment::get().getWorld();
MWVR::VRAnimation* anim = MWVR::Environment::get().getPlayerAnimation(); auto& pointer = world->getUserPointer();
MWWorld::Ptr dropped; MWWorld::Ptr dropped;
if (anim->canPlaceObject()) if (pointer.canPlaceObject())
dropped = world->placeObject(item.mBase, anim->getPointerTarget(), count); dropped = world->placeObject(item.mBase, pointer.getPointerTarget(), count);
else else
dropped = world->dropObjectOnGround(world->getPlayerPtr(), item.mBase, count); dropped = world->dropObjectOnGround(world->getPlayerPtr(), item.mBase, count);
dropped.getCellRef().setOwner(""); dropped.getCellRef().setOwner("");
@ -112,11 +113,11 @@ namespace MWVR
void VRInputManager::pointActivation(bool onPress) void VRInputManager::pointActivation(bool onPress)
{ {
auto* world = MWBase::Environment::get().getWorld(); auto* world = MWBase::Environment::get().getWorld();
auto* anim = MWVR::Environment::get().getPlayerAnimation(); auto& pointer = world->getUserPointer();
if (world && anim && anim->getPointerTarget().mHit) if (world && pointer.getPointerTarget().mHit)
{ {
auto* node = anim->getPointerTarget().mHitNode; auto* node = pointer.getPointerTarget().mHitNode;
MWWorld::Ptr ptr = anim->getPointerTarget().mHitObject; MWWorld::Ptr ptr = pointer.getPointerTarget().mHitObject;
auto wm = MWBase::Environment::get().getWindowManager(); auto wm = MWBase::Environment::get().getWindowManager();
auto& dnd = wm->getDragAndDrop(); auto& dnd = wm->getDragAndDrop();

@ -0,0 +1,203 @@
#include "vrpointer.hpp"
#include "vrutil.hpp"
#include "vrenvironment.hpp"
#include <osg/MatrixTransform>
#include <osg/Drawable>
#include <osg/BlendFunc>
#include <osg/Fog>
#include <osg/LightModel>
#include <components/resource/resourcesystem.hpp>
#include <components/resource/scenemanager.hpp>
#include <components/sceneutil/shadow.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
#include "../mwrender/renderingmanager.hpp"
#include "../mwrender/vismask.hpp"
namespace MWVR
{
UserPointer::UserPointer(osg::Group* root)
: mRoot(root)
{
mPointerGeometry = createPointerGeometry();
mPointerRescale = new osg::MatrixTransform();
mPointerRescale->addChild(mPointerGeometry);
mPointerTransform = new osg::MatrixTransform();
mPointerTransform->addChild(mPointerRescale);
mPointerTransform->setName("Pointer Transform");
mPointerTransform->setNodeMask(MWRender::VisMask::Mask_Pointer);
auto tm = MWVR::Environment::get().getTrackingManager();
tm->bind(this, "pcworld");
mHandPath = tm->stringToVRPath("/user/hand/right/input/aim/pose");
setEnabled(true);
}
UserPointer::~UserPointer()
{
}
void UserPointer::setParent(osg::Group* group)
{
bool enabled = mEnabled;
setEnabled(false);
mParent = group;
setEnabled(enabled);
}
void UserPointer::setEnabled(bool enabled)
{
mRoot->removeChild(mPointerTransform);
if (mParent)
{
mParent->removeChild(mPointerTransform);
if (enabled)
{
mParent->addChild(mPointerTransform);
// Morrowind's hands don't actually point forward, so we have to reorient the pointer.
mPointerTransform->setMatrix(osg::Matrix::rotate(osg::Quat(-osg::PI_2, osg::Vec3f(0, 0, 1))));
}
}
else if(enabled)
{
mRoot->addChild(mPointerTransform);
}
mEnabled = enabled;
}
void UserPointer::onTrackingUpdated(VRTrackingSource& source, DisplayTime predictedDisplayTime)
{
// If no parent is set, then the actor is currently unloaded
// And we need to point directly from tracking data and the root
if (!mParent)
{
auto tp = source.getTrackingPose(predictedDisplayTime, mHandPath, 0);
osg::Matrix worldReference = osg::Matrix::identity();
worldReference.preMultTranslate(tp.pose.position);
worldReference.preMultRotate(tp.pose.orientation);
mPointerTransform->setMatrix(worldReference);
updatePointerTarget();
MWBase::Environment::get().getResourceSystem()->getSceneManager()->recreateShaders(mPointerGeometry);
}
}
const MWRender::RayResult& UserPointer::getPointerTarget() const
{
return mPointerTarget;
}
bool UserPointer::canPlaceObject() const
{
return mCanPlaceObject;
}
void UserPointer::updatePointerTarget()
{
auto* world = MWBase::Environment::get().getWorld();
if (world)
{
mPointerRescale->setMatrix(osg::Matrix::scale(1, 1, 1));
//mDistanceToPointerTarget = world->getTargetObject(mPointerTarget, mPointerTransform);
//osg::computeLocalToWorld(mPointerTransform->getParentalNodePaths()[0]);
mDistanceToPointerTarget = Util::getPoseTarget(mPointerTarget, Util::getNodePose(mPointerTransform), true);
mCanPlaceObject = false;
if (mPointerTarget.mHit)
{
// check if the wanted position is on a flat surface, and not e.g. against a vertical wall
mCanPlaceObject = !(std::acos((mPointerTarget.mHitNormalWorld / mPointerTarget.mHitNormalWorld.length()) * osg::Vec3f(0, 0, 1)) >= osg::DegreesToRadians(30.f));
}
if (mDistanceToPointerTarget > 0.f)
mPointerRescale->setMatrix(osg::Matrix::scale(0.25f, mDistanceToPointerTarget, 0.25f));
else
mPointerRescale->setMatrix(osg::Matrix::scale(0.25f, 10000.f, 0.25f));
}
}
osg::ref_ptr<osg::Geometry> UserPointer::createPointerGeometry()
{
osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry();
// Create pointer geometry, which will point from the tip of the player's finger.
// The geometry will be a Four sided pyramid, with the top at the player's fingers
osg::Vec3 vertices[]{
{0, 0, 0}, // origin
{-1, 1, -1}, // A
{-1, 1, 1}, // B
{1, 1, 1}, // C
{1, 1, -1}, // D
};
osg::Vec4 colors[]{
osg::Vec4(1.0f, 0.0f, 0.0f, 0.0f),
osg::Vec4(1.0f, 0.0f, 0.0f, 1.0f),
osg::Vec4(1.0f, 0.0f, 0.0f, 1.0f),
osg::Vec4(1.0f, 0.0f, 0.0f, 1.0f),
osg::Vec4(1.0f, 0.0f, 0.0f, 1.0f),
};
const int O = 0;
const int A = 1;
const int B = 2;
const int C = 3;
const int D = 4;
const int triangles[] =
{
A,D,B,
B,D,C,
O,D,A,
O,C,D,
O,B,C,
O,A,B,
};
int numVertices = sizeof(triangles) / sizeof(*triangles);
osg::ref_ptr<osg::Vec3Array> vertexArray = new osg::Vec3Array(numVertices);
osg::ref_ptr<osg::Vec4Array> colorArray = new osg::Vec4Array(numVertices);
for (int i = 0; i < numVertices; i++)
{
(*vertexArray)[i] = vertices[triangles[i]];
(*colorArray)[i] = colors[triangles[i]];
}
geometry->setVertexArray(vertexArray);
geometry->setColorArray(colorArray, osg::Array::BIND_PER_VERTEX);
geometry->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES, 0, numVertices));
geometry->setSupportsDisplayList(false);
geometry->setDataVariance(osg::Object::STATIC);
auto stateset = geometry->getOrCreateStateSet();
stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
stateset->setMode(GL_BLEND, osg::StateAttribute::ON);
stateset->setAttributeAndModes(new osg::BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
osg::ref_ptr<osg::Fog> fog(new osg::Fog);
fog->setStart(10000000);
fog->setEnd(10000000);
stateset->setAttributeAndModes(fog, osg::StateAttribute::OFF | osg::StateAttribute::OVERRIDE);
osg::ref_ptr<osg::LightModel> lightmodel = new osg::LightModel;
lightmodel->setAmbientIntensity(osg::Vec4(1.0, 1.0, 1.0, 1.0));
stateset->setAttributeAndModes(lightmodel, osg::StateAttribute::ON);
SceneUtil::ShadowManager::disableShadowsForStateSet(stateset);
osg::ref_ptr<osg::Material> material = new osg::Material;
material->setColorMode(osg::Material::ColorMode::AMBIENT_AND_DIFFUSE);
stateset->setAttributeAndModes(material, osg::StateAttribute::ON);
MWBase::Environment::get().getResourceSystem()->getSceneManager()->recreateShaders(geometry);
return geometry;
}
}

@ -0,0 +1,45 @@
#ifndef MWVR_POINTER_H
#define MWVR_POINTER_H
#include "../mwrender/npcanimation.hpp"
#include "../mwrender/renderingmanager.hpp"
#include "openxrmanager.hpp"
#include "vrsession.hpp"
#include "vrtracking.hpp"
namespace MWVR
{
//! Controls the beam used to target/select objects.
class UserPointer : public VRTrackingListener
{
public:
UserPointer(osg::Group* root);
~UserPointer();
void updatePointerTarget();
const MWRender::RayResult& getPointerTarget() const;
bool canPlaceObject() const;
void setParent(osg::Group* group);
void setEnabled(bool enabled);
protected:
void onTrackingUpdated(VRTrackingSource& source, DisplayTime predictedDisplayTime) override;
private:
osg::ref_ptr<osg::Geometry> createPointerGeometry();
osg::ref_ptr<osg::Geometry> mPointerGeometry{ nullptr };
osg::ref_ptr<osg::MatrixTransform> mPointerRescale{ nullptr };
osg::ref_ptr<osg::MatrixTransform> mPointerTransform{ nullptr };
osg::ref_ptr<osg::Group> mParent{ nullptr };
osg::ref_ptr<osg::Group> mRoot{ nullptr };
VRPath mHandPath;
bool mEnabled;
MWRender::RayResult mPointerTarget{};
float mDistanceToPointerTarget{ -1.f };
bool mCanPlaceObject{ false };
};
}
#endif

@ -201,6 +201,28 @@ namespace MWVR
Environment::get().getTrackingManager()->unregisterTrackingSource(this); 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 bool VRTrackingSource::availablePosesChanged() const
{ {
return mAvailablePosesChanged; return mAvailablePosesChanged;
@ -211,6 +233,11 @@ namespace MWVR
mAvailablePosesChanged = false; mAvailablePosesChanged = false;
} }
void VRTrackingSource::clearCache()
{
mCache.clear();
}
void VRTrackingSource::notifyAvailablePosesChanged() void VRTrackingSource::notifyAvailablePosesChanged()
{ {
mAvailablePosesChanged = true; mAvailablePosesChanged = true;
@ -262,7 +289,7 @@ namespace MWVR
} }
} }
VRTrackingPose VRTrackingToWorldBinding::getTrackingPose(DisplayTime predictedDisplayTime, VRPath path, VRPath reference) VRTrackingPose VRTrackingToWorldBinding::getTrackingPoseImpl(DisplayTime predictedDisplayTime, VRPath path, VRPath reference)
{ {
auto tp = mSource->getTrackingPose(predictedDisplayTime, path, reference); auto tp = mSource->getTrackingPose(predictedDisplayTime, path, reference);
tp.pose.position *= Constants::UnitsPerMeter; tp.pose.position *= Constants::UnitsPerMeter;

@ -39,6 +39,7 @@ namespace MWVR
{ {
TrackingStatus status = TrackingStatus::Unknown; //!< State of the prediction. TrackingStatus status = TrackingStatus::Unknown; //!< State of the prediction.
Pose pose = {}; //!< The predicted pose. Pose pose = {}; //!< The predicted pose.
DisplayTime time; //!< The time for which the pose was predicted.
}; };
//! Source for tracking data. Converts paths to poses at predicted times. //! Source for tracking data. Converts paths to poses at predicted times.
@ -59,12 +60,12 @@ namespace MWVR
//! @brief Predicted pose of the given path at the predicted time //! @brief Predicted pose of the given path at the predicted time
//! //!
//! \arg predictedDisplayTime[in] Time to predict. This is normally the predicted display time. //! \arg predictedDisplayTime[in] Time to predict. This is normally the predicted display time. If time is 0, the last pose that was predicted is returned.
//! \arg path[in] path of the pose requested. Should match an available pose path. //! \arg path[in] path of the pose requested. Should match an available pose path.
//! \arg reference[in] path of the pose to use as reference. If 0, pose is referenced to the VR stage. //! \arg reference[in] path of the pose to use as reference. If 0, pose is referenced to the VR stage.
//! //!
//! \return A structure describing a pose and the tracking status. //! \return A structure describing a pose and the tracking status.
virtual VRTrackingPose getTrackingPose(DisplayTime predictedDisplayTime, VRPath path, VRPath reference = 0) = 0; VRTrackingPose getTrackingPose(DisplayTime predictedDisplayTime, VRPath path, VRPath reference = 0);
//! List currently supported tracking paths. //! List currently supported tracking paths.
virtual std::vector<VRPath> listSupportedTrackingPosePaths() const = 0; virtual std::vector<VRPath> listSupportedTrackingPosePaths() const = 0;
@ -79,7 +80,13 @@ namespace MWVR
//! \arg predictedDisplayTime [in] the predicted display time. The pose shall be predicted for this time based on current tracking data. //! \arg predictedDisplayTime [in] the predicted display time. The pose shall be predicted for this time based on current tracking data.
virtual void updateTracking(DisplayTime predictedDisplayTime) = 0; virtual void updateTracking(DisplayTime predictedDisplayTime) = 0;
void clearCache();
protected: protected:
virtual VRTrackingPose getTrackingPoseImpl(DisplayTime predictedDisplayTime, VRPath path, VRPath reference = 0) = 0;
std::map<std::pair<VRPath, VRPath>, VRTrackingPose> mCache;
void notifyAvailablePosesChanged(); void notifyAvailablePosesChanged();
bool mAvailablePosesChanged = true; bool mAvailablePosesChanged = true;
@ -119,7 +126,7 @@ namespace MWVR
protected: protected:
//! Fetches a pose from the source, and then aligns it with the game world if the reference is 0 (stage). //! Fetches a pose from the source, and then aligns it with the game world if the reference is 0 (stage).
VRTrackingPose getTrackingPose(DisplayTime predictedDisplayTime, VRPath path, VRPath movementReference = 0) override; VRTrackingPose getTrackingPoseImpl(DisplayTime predictedDisplayTime, VRPath path, VRPath movementReference = 0) override;
//! List currently supported tracking paths. //! List currently supported tracking paths.
std::vector<VRPath> listSupportedTrackingPosePaths() const override; std::vector<VRPath> listSupportedTrackingPosePaths() const override;

@ -0,0 +1,80 @@
#include "vrutil.hpp"
#include "vrenvironment.hpp"
#include "vrtracking.hpp"
#include "vranimation.hpp"
#include "../mwbase/environment.hpp"
#include "../mwbase/windowmanager.hpp"
#include "../mwbase/world.hpp"
#include "../mwworld/class.hpp"
#include "../mwrender/renderingmanager.hpp"
#include "osg/Transform"
namespace MWVR
{
namespace Util
{
std::pair<MWWorld::Ptr, osg::Vec3f> getHitContact(float distance, std::vector<MWWorld::Ptr>& targets)
{
return std::pair<MWWorld::Ptr, osg::Vec3f>();
}
std::pair<MWWorld::Ptr, float> getTouchTarget()
{
MWRender::RayResult result;
auto* tm = Environment::get().getTrackingManager();
VRPath rightHandPath = tm->stringToVRPath("/user/hand/right/input/aim/pose");
auto* source = tm->getSource("pcworld");
auto distance = getPoseTarget(result, source->getTrackingPose(0, rightHandPath).pose, true);
return std::pair<MWWorld::Ptr, float>(result.mHitObject, distance);
}
std::pair<MWWorld::Ptr, float> getWeaponTarget()
{
auto* anim = MWVR::Environment::get().getPlayerAnimation();
MWRender::RayResult result;
auto distance = getPoseTarget(result, getNodePose(anim->getNode("weapon bone")), false);
return std::pair<MWWorld::Ptr, float>(result.mHitObject, distance);
}
float getPoseTarget(MWRender::RayResult& result, const Pose& pose, bool allowTelekinesis)
{
auto* wm = MWBase::Environment::get().getWindowManager();
auto* world = MWBase::Environment::get().getWorld();
if (wm->isGuiMode() && wm->isConsoleMode())
return world->getTargetObject(result, pose.position, pose.orientation, world->getMaxActivationDistance() * 50, true);
else
{
float activationDistance = 0.f;
if (allowTelekinesis)
activationDistance = world->getActivationDistancePlusTelekinesis();
else
activationDistance = world->getMaxActivationDistance();
auto distance = world->getTargetObject(result, pose.position, pose.orientation, world->getMaxActivationDistance(), true);
if (!result.mHitObject.isEmpty() && !result.mHitObject.getClass().allowTelekinesis(result.mHitObject)
&& distance > world->getMaxActivationDistance() && !MWBase::Environment::get().getWindowManager()->isGuiMode())
{
result.mHit = false;
result.mHitObject = nullptr;
distance = 0.f;
};
return distance;
}
}
Pose getNodePose(const osg::Node* node)
{
osg::Matrix worldMatrix = osg::computeLocalToWorld(node->getParentalNodePaths()[0]);
Pose pose;
pose.position = worldMatrix.getTrans();
pose.orientation = worldMatrix.getRotate();
return pose;
}
}
}

@ -0,0 +1,24 @@
#ifndef VR_UTIL_HPP
#define VR_UTIL_HPP
#include "../mwworld/ptr.hpp"
#include "vrtypes.hpp"
namespace MWRender
{
struct RayResult;
}
namespace MWVR
{
namespace Util {
std::pair<MWWorld::Ptr, float> getTouchTarget();
std::pair<MWWorld::Ptr, float> getWeaponTarget();
float getPoseTarget(MWRender::RayResult& result, const Pose& pose, bool allowTelekinesis);
Pose getNodePose(const osg::Node* node);
}
}
#endif

@ -76,9 +76,11 @@
#include "esmloader.hpp" #include "esmloader.hpp"
#ifdef USE_OPENXR #ifdef USE_OPENXR
#include "../mwvr/vrenvironment.hpp"
#include "../mwvr/vranimation.hpp" #include "../mwvr/vranimation.hpp"
#include "../mwvr/vrenvironment.hpp"
#include "../mwvr/vrinputmanager.hpp" #include "../mwvr/vrinputmanager.hpp"
#include "../mwvr/vrpointer.hpp"
#include "../mwvr/vrutil.hpp"
#endif #endif
namespace namespace
@ -1027,13 +1029,7 @@ namespace MWWorld
MWWorld::Ptr World::getFacedObject() MWWorld::Ptr World::getFacedObject()
{ {
#ifdef USE_OPENXR #ifdef USE_OPENXR
// TODO: Rename this method to getTargetObject? return getPointerTarget();
// "getFacedObject" doesn't make sense with finger pointing.
auto* anim = MWVR::Environment::get().getPlayerAnimation();
if (anim && anim->getPointerTarget().mHit)
return anim->getPointerTarget().mHitObject;
else
return MWWorld::Ptr();
#endif #endif
MWWorld::Ptr facedObject; MWWorld::Ptr facedObject;
@ -3105,7 +3101,10 @@ namespace MWWorld
// for player we can take faced object first // for player we can take faced object first
MWWorld::Ptr target; MWWorld::Ptr target;
#ifndef USE_OPENXR #ifdef USE_OPENXR
if (actor == MWMechanics::getPlayer())
target = MWVR::Util::getTouchTarget().first;
#else
// Does not apply to VR // Does not apply to VR
if (actor == MWMechanics::getPlayer()) if (actor == MWMechanics::getPlayer())
target = getFacedObject(); target = getFacedObject();
@ -3154,6 +3153,8 @@ namespace MWWorld
orient = worldMatrix.getRotate(); orient = worldMatrix.getRotate();
} }
#endif #endif
Log(Debug::Verbose) << "Origin: " << origin;
Log(Debug::Verbose) << "Orient: " << orient;
osg::Vec3f direction = orient * osg::Vec3f(0,1,0); osg::Vec3f direction = orient * osg::Vec3f(0,1,0);
float distance = getMaxActivationDistance(); float distance = getMaxActivationDistance();
@ -4030,35 +4031,14 @@ namespace MWWorld
return btRayAabb(localFrom, localTo, aabbMin, aabbMax, hitDistance, hitNormal); return btRayAabb(localFrom, localTo, aabbMin, aabbMax, hitDistance, hitNormal);
} }
float World::getTargetObject(MWRender::RayResult& result, osg::Transform* pointer) float World::getTargetObject(MWRender::RayResult& result, const osg::Vec3f& origin, const osg::Quat& orientation, float maxDistance, bool ignorePlayer)
{
result = {};
result.mHit = false;
auto* windowManager = MWBase::Environment::get().getWindowManager();
if (windowManager->isGuiMode() && windowManager->isConsoleMode())
{
return getTargetObject(result, pointer, getMaxActivationDistance() * 50, true);
}
else
{
float maxDistance = getActivationDistancePlusTelekinesis();
MWRender::RayResult rayToObject{};
float distance = getTargetObject(rayToObject, pointer, maxDistance, true);
auto ptr = rayToObject.mHitObject;
if (!ptr.isEmpty() && !ptr.getClass().allowTelekinesis(ptr)
&& distance > getMaxActivationDistance() && !MWBase::Environment::get().getWindowManager()->isGuiMode())
return -1.f;
result = rayToObject;
return distance;
}
return -1.f;
}
float World::getTargetObject(MWRender::RayResult& result, osg::Transform* pointer, float maxDistance, bool ignorePlayer)
{ {
result = mRendering->castRay(pointer, maxDistance, ignorePlayer, false); osg::Vec3f direction = orientation * osg::Vec3f(0, 1, 0);
direction.normalize();
osg::Vec3f end = origin + direction * maxDistance;
result = mRendering->castRay(origin, end, ignorePlayer);
if(!result.mHit)
return 0.f;
MWWorld::Ptr facedObject = result.mHitObject; MWWorld::Ptr facedObject = result.mHitObject;
if (facedObject.isEmpty() && result.mHitRefnum.hasContentFile()) if (facedObject.isEmpty() && result.mHitRefnum.hasContentFile())
@ -4071,9 +4051,17 @@ namespace MWWorld
} }
result.mHitObject = facedObject; result.mHitObject = facedObject;
if(result.mHit) return result.mRatio * maxDistance;
return result.mRatio * maxDistance; }
return -1.f;
MWVR::UserPointer& World::getUserPointer()
{
return mRendering->userPointer();
}
MWWorld::Ptr World::getPointerTarget()
{
return getUserPointer().getPointerTarget().mHitObject;
} }
MWWorld::Ptr World::placeObject(const MWWorld::ConstPtr& object, const MWRender::RayResult& ray, int amount) MWWorld::Ptr World::placeObject(const MWWorld::ConstPtr& object, const MWRender::RayResult& ray, int amount)

@ -177,7 +177,7 @@ namespace MWWorld
const std::vector<std::string>& content, const std::vector<std::string>& groundcover, ContentLoader& contentLoader); const std::vector<std::string>& content, const std::vector<std::string>& groundcover, ContentLoader& contentLoader);
float feetToGameUnits(float feet); float feetToGameUnits(float feet);
float getActivationDistancePlusTelekinesis(); float getActivationDistancePlusTelekinesis() override;
MWWorld::ConstPtr getClosestMarker( const MWWorld::Ptr &ptr, const std::string &id ); MWWorld::ConstPtr getClosestMarker( const MWWorld::Ptr &ptr, const std::string &id );
MWWorld::ConstPtr getClosestMarkerFromExteriorPosition( const osg::Vec3f& worldPos, const std::string &id ); MWWorld::ConstPtr getClosestMarkerFromExteriorPosition( const osg::Vec3f& worldPos, const std::string &id );
@ -742,10 +742,12 @@ namespace MWWorld
bool hasCollisionWithDoor(const MWWorld::ConstPtr& door, const osg::Vec3f& position, const osg::Vec3f& destination) const override; bool hasCollisionWithDoor(const MWWorld::ConstPtr& door, const osg::Vec3f& position, const osg::Vec3f& destination) const override;
/// @result pointer to the object and/or node the given node is currently pointing at /// Intersects the scene from the origin, in the specified orientation and distance, storing the %result in the result structure.
/// @Return distance to the target object, or -1 if no object was targeted / in range /// @Return distance to the target object, or -1 if no object was targeted / in range
float getTargetObject(MWRender::RayResult& result, osg::Transform* pointer) override; float getTargetObject(MWRender::RayResult& result, const osg::Vec3f& origin, const osg::Quat& orientation, float maxDistance, bool ignorePlayer) override;
float getTargetObject(MWRender::RayResult& result, osg::Transform* pointer, float maxDistance, bool ignorePlayer) override;
MWVR::UserPointer& getUserPointer() override;
MWWorld::Ptr getPointerTarget() override;
MWWorld::Ptr placeObject(const MWWorld::ConstPtr& object, const MWRender::RayResult& ray, int amount) override; MWWorld::Ptr placeObject(const MWWorld::ConstPtr& object, const MWRender::RayResult& ray, int amount) override;
///< copy and place an object into the gameworld based on the given intersection ///< copy and place an object into the gameworld based on the given intersection

Loading…
Cancel
Save