mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-19 22:23:51 +00:00
Fix #109 also fixes lack of motion controller interaction during main menu and load game.
This commit is contained in:
parent
fb4a1ebd46
commit
abee6ca841
23 changed files with 520 additions and 263 deletions
|
@ -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 "vrenvironment.hpp"
|
|
||||||
#include "vrsession.hpp"
|
|
||||||
#include "openxrmanagerimpl.hpp"
|
|
||||||
#include "openxrinput.hpp"
|
|
||||||
#include "vranimation.hpp"
|
#include "vranimation.hpp"
|
||||||
|
#include "vrenvironment.hpp"
|
||||||
|
#include "vrpointer.hpp"
|
||||||
|
#include "vrsession.hpp"
|
||||||
|
#include "openxrinput.hpp"
|
||||||
|
#include "openxrmanagerimpl.hpp"
|
||||||
|
|
||||||
#include <osg/Texture2D>
|
#include <osg/Texture2D>
|
||||||
#include <osg/ClipNode>
|
#include <osg/ClipNode>
|
||||||
|
@ -760,11 +761,14 @@ 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)
|
||||||
|
{
|
||||||
|
auto& pointer = world->getUserPointer();
|
||||||
|
if (pointer.getPointerTarget().mHit)
|
||||||
{
|
{
|
||||||
std::shared_ptr<VRGUILayer> newFocusLayer = nullptr;
|
std::shared_ptr<VRGUILayer> newFocusLayer = nullptr;
|
||||||
auto* node = anim->getPointerTarget().mHitNode;
|
auto* node = pointer.getPointerTarget().mHitNode;
|
||||||
if (node->getName() == "VRGUILayer")
|
if (node->getName() == "VRGUILayer")
|
||||||
{
|
{
|
||||||
VRGUILayerUserData* userData = static_cast<VRGUILayerUserData*>(node->getUserData());
|
VRGUILayerUserData* userData = static_cast<VRGUILayerUserData*>(node->getUserData());
|
||||||
|
@ -774,10 +778,11 @@ namespace MWVR
|
||||||
if (newFocusLayer && newFocusLayer->mLayerName != "Notification")
|
if (newFocusLayer && newFocusLayer->mLayerName != "Notification")
|
||||||
{
|
{
|
||||||
setFocusLayer(newFocusLayer.get());
|
setFocusLayer(newFocusLayer.get());
|
||||||
computeGuiCursor(anim->getPointerTarget().mHitPointLocal);
|
computeGuiCursor(pointer.getPointerTarget().mHitPointLocal);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -801,10 +806,13 @@ namespace MWVR
|
||||||
}
|
}
|
||||||
mFocusLayer = layer;
|
mFocusLayer = layer;
|
||||||
if (mFocusLayer)
|
if (mFocusLayer)
|
||||||
|
{
|
||||||
|
if (!mFocusLayer->mWidgets.empty())
|
||||||
{
|
{
|
||||||
Log(Debug::Verbose) << "Set focus layer to " << mFocusLayer->mWidgets.front()->mMainWidget->getLayer()->getName();
|
Log(Debug::Verbose) << "Set focus layer to " << mFocusLayer->mWidgets.front()->mMainWidget->getLayer()->getName();
|
||||||
setPick(mFocusLayer->mWidgets.front(), true);
|
setPick(mFocusLayer->mWidgets.front(), true);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Log(Debug::Verbose) << "Set focus layer to null";
|
Log(Debug::Verbose) << "Set focus layer to null";
|
||||||
|
@ -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 "vrcamera.hpp"
|
|
||||||
#include "vrgui.hpp"
|
|
||||||
#include "vranimation.hpp"
|
#include "vranimation.hpp"
|
||||||
#include "openxrinput.hpp"
|
#include "vrcamera.hpp"
|
||||||
#include "vrenvironment.hpp"
|
#include "vrenvironment.hpp"
|
||||||
|
#include "vrgui.hpp"
|
||||||
|
#include "vrpointer.hpp"
|
||||||
|
#include "vrviewer.hpp"
|
||||||
|
#include "openxrinput.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();
|
||||||
|
|
||||||
|
|
203
apps/openmw/mwvr/vrpointer.cpp
Normal file
203
apps/openmw/mwvr/vrpointer.cpp
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
45
apps/openmw/mwvr/vrpointer.hpp
Normal file
45
apps/openmw/mwvr/vrpointer.hpp
Normal file
|
@ -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;
|
||||||
|
|
80
apps/openmw/mwvr/vrutil.cpp
Normal file
80
apps/openmw/mwvr/vrutil.cpp
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
24
apps/openmw/mwvr/vrutil.hpp
Normal file
24
apps/openmw/mwvr/vrutil.hpp
Normal file
|
@ -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 = {};
|
osg::Vec3f direction = orientation * osg::Vec3f(0, 1, 0);
|
||||||
result.mHit = false;
|
direction.normalize();
|
||||||
|
osg::Vec3f end = origin + direction * maxDistance;
|
||||||
auto* windowManager = MWBase::Environment::get().getWindowManager();
|
result = mRendering->castRay(origin, end, ignorePlayer);
|
||||||
|
if(!result.mHit)
|
||||||
if (windowManager->isGuiMode() && windowManager->isConsoleMode())
|
return 0.f;
|
||||||
{
|
|
||||||
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);
|
|
||||||
|
|
||||||
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…
Reference in a new issue