1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-02-22 14:09:40 +00:00

Fixed recentering adjusting the player's orientation. Cell changes should now retain the proper orientation. Added support for seated play.

This commit is contained in:
madsbuvi 2021-02-28 16:01:03 +01:00
parent 7986def3db
commit 3347cdfe30
17 changed files with 186 additions and 98 deletions

View file

@ -158,10 +158,10 @@ namespace MWPhysics
// But 2. is not so obvious. I guess it's doable if i compute the direction between current position and the player's
// position in the VR stage, and just let it catch up at the character's own move speed, but it still needs to reach the position as exactly as possible.
if (isPlayer)
{
auto* session = MWVR::Environment::get().getSession();
if (session)
{
if (isPlayer)
{
float pitch = 0.f;
float yaw = 0.f;
@ -238,10 +238,18 @@ namespace MWPhysics
#ifdef USE_OPENXR
// Catch the player character up to the real world position of the player.
// But only if play is not seated.
// TODO: Hack.
if (isPlayer && !world->getPlayer().isDisabled())
if (isPlayer)
{
bool shouldMove = true;
if (session && session->seatedPlay())
shouldMove = false;
if (world->getPlayer().isDisabled())
shouldMove = false;
if (shouldMove)
{
auto* inputManager = reinterpret_cast<MWVR::VRCamera*>(MWBase::Environment::get().getWorld()->getRenderingManager().getCamera());
osg::Vec3 headOffset = inputManager->headOffset();
@ -314,6 +322,7 @@ namespace MWPhysics
headOffset.y() -= moved.y();
inputManager->setHeadOffset(headOffset);
}
}
#endif
/*

View file

@ -90,8 +90,13 @@ namespace MWVR
CHECK_XRCMD(xrCreateReferenceSpace(mSession, &createInfo, &mReferenceSpaceView));
createInfo.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_STAGE;
CHECK_XRCMD(xrCreateReferenceSpace(mSession, &createInfo, &mReferenceSpaceStage));
createInfo.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_LOCAL;
CHECK_XRCMD(xrCreateReferenceSpace(mSession, &createInfo, &mReferenceSpaceLocal));
}
// Default to using the stage
mReferenceSpace = mReferenceSpaceStage;
{ // Read and log graphics properties for the swapchain
xrGetSystemProperties(mInstance, mSystemId, &mSystemProperties);
@ -302,7 +307,7 @@ namespace MWVR
compositionLayerProjectionViews[(int)Side::LEFT_SIDE] = toXR((*layerStack)[(int)Side::LEFT_SIDE]);
compositionLayerProjectionViews[(int)Side::RIGHT_SIDE] = toXR((*layerStack)[(int)Side::RIGHT_SIDE]);
layer.type = XR_TYPE_COMPOSITION_LAYER_PROJECTION;
layer.space = getReferenceSpace(ReferenceSpace::STAGE);
layer.space = getReferenceSpace();
layer.viewCount = 2;
layer.views = compositionLayerProjectionViews.data();
auto* xrLayerStack = reinterpret_cast<XrCompositionLayerBaseHeader*>(&layer);
@ -591,14 +596,9 @@ namespace MWVR
return XrFovf{ fov.angleLeft, fov.angleRight, fov.angleUp, fov.angleDown };
}
XrSpace OpenXRManagerImpl::getReferenceSpace(ReferenceSpace space)
XrSpace OpenXRManagerImpl::getReferenceSpace()
{
XrSpace referenceSpace = XR_NULL_HANDLE;
if (space == ReferenceSpace::STAGE)
referenceSpace = mReferenceSpaceStage;
if (space == ReferenceSpace::VIEW)
referenceSpace = mReferenceSpaceView;
return referenceSpace;
return mReferenceSpace;
}
bool OpenXRManagerImpl::xrExtensionIsEnabled(const char* extensionName) const

View file

@ -56,7 +56,7 @@ namespace MWVR
long long getLastPredictedDisplayTime();
long long getLastPredictedDisplayPeriod();
std::array<SwapchainConfig, 2> getRecommendedSwapchainConfig() const;
XrSpace getReferenceSpace(ReferenceSpace space);
XrSpace getReferenceSpace();
XrSession xrSession() const { return mSession; };
XrInstance xrInstance() const { return mInstance; };
bool xrExtensionIsEnabled(const char* extensionName) const;
@ -69,6 +69,7 @@ namespace MWVR
void eraseFormat(int64_t format);
OpenXRPlatform& platform() { return mPlatform; };
protected:
void setupExtensionsAndLayers();
void setupDebugMessenger(void);
@ -97,6 +98,8 @@ namespace MWVR
std::array<XrViewConfigurationView, 2> mConfigViews{ { {XR_TYPE_VIEW_CONFIGURATION_VIEW}, {XR_TYPE_VIEW_CONFIGURATION_VIEW} } };
XrSpace mReferenceSpaceView = XR_NULL_HANDLE;
XrSpace mReferenceSpaceStage = XR_NULL_HANDLE;
XrSpace mReferenceSpaceLocal = XR_NULL_HANDLE;
XrSpace mReferenceSpace = XR_NULL_HANDLE;
XrFrameState mFrameState{};
XrSessionState mSessionState = XR_SESSION_STATE_UNKNOWN;
XrDebugUtilsMessengerEXT mDebugMessenger{ nullptr };

View file

@ -469,6 +469,7 @@ namespace MWVR
float realHeight = Settings::Manager::getFloat("real height", "VR");
float sizeFactor = charHeight / realHeight;
Environment::get().getSession()->setPlayerScale(sizeFactor);
Environment::get().getSession()->setEyeLevel(charHeightBase - 0.15f); // approximation
}
void VRAnimation::setFingerPointingMode(bool enabled)

View file

@ -12,6 +12,9 @@
#include "../mwbase/world.hpp"
#include "../mwworld/player.hpp"
#include "../mwworld/class.hpp"
#include "../mwmechanics/movement.hpp"
#include <osg/Quat>
@ -45,16 +48,35 @@ namespace MWVR
// Move position of head to center of character
// Z should not be affected
mHeadOffset = osg::Vec3(0, 0, 0);
mHeadOffset.z() = mHeadPose.position.z();
mHeadOffset.x() = 0;
mHeadOffset.y() = 0;
// Adjust orientation to zero yaw
auto* session = Environment::get().getSession();
if (session->seatedPlay() && mShouldResetZ)
{
// Adjust offset to place the current pose roughly at eye level
mHeadOffset.z() = session->eyeLevel() * Constants::UnitsPerMeter;
}
else
{
mHeadOffset.z() = mHeadPose.position.z();
}
mShouldResetZ = false;
// When the cell changes, the game rotates the character appropriately.
// To respect this, reset yaw offset to make our yaw match the character.
MWBase::World* world = MWBase::Environment::get().getWorld();
if (world)
{
auto& player = world->getPlayer();
auto playerPtr = player.getPlayer();
const auto& data = playerPtr.getRefData();
float yaw = 0.f;
float pitch = 0.f;
float roll = 0.f;
getEulerAngles(mHeadPose.orientation, yaw, pitch, roll);
mYawOffset = -yaw;
mYawOffset = data.getPosition().rot[2] - yaw;
}
mShouldRecenter = false;
Log(Debug::Verbose) << "Recentered";
}
@ -194,4 +216,12 @@ namespace MWVR
{
return osg::Quat(mYawOffset, osg::Vec3(0, 0, -1));
}
void VRCamera::requestRecenter(bool resetZ)
{
mShouldRecenter = true;
// Use OR so we don't a pending reset of Z.
mShouldResetZ |= resetZ;
}
}

View file

@ -57,7 +57,7 @@ namespace MWVR
void rotateStage(float yaw) { mYawOffset += yaw; }
void requestRecenter() { mShouldRecenter = true; }
void requestRecenter(bool resetZ);
const osg::Vec3& headOffset() const { return mHeadOffset; }
@ -75,6 +75,7 @@ namespace MWVR
Pose mHeadPose{};
osg::Vec3 mHeadOffset{ 0,0,0 };
bool mShouldRecenter{ true };
bool mShouldResetZ{ true };
bool mHasTrackingData{ false };
float mYawOffset{ 0.f };
bool mShouldTrackPlayerCharacter{ false };

View file

@ -42,7 +42,7 @@ namespace MWVR
mPrevious = mValue;
auto* xr = Environment::get().getManager();
XrSpace referenceSpace = xr->impl().getReferenceSpace(ReferenceSpace::STAGE);
XrSpace referenceSpace = xr->impl().getReferenceSpace();
XrSpaceLocation location{ XR_TYPE_SPACE_LOCATION };
XrSpaceVelocity velocity{ XR_TYPE_SPACE_VELOCITY };

View file

@ -280,10 +280,10 @@ namespace MWVR
mAxisDeadzone->setDeadzoneRadius(deadzoneRadius);
}
void VRInputManager::requestRecenter()
void VRInputManager::requestRecenter(bool resetZ)
{
// TODO: Hack, should have a cleaner way of accessing this
reinterpret_cast<VRCamera*>(MWBase::Environment::get().getWorld()->getRenderingManager().getCamera())->requestRecenter();
reinterpret_cast<VRCamera*>(MWBase::Environment::get().getWorld()->getRenderingManager().getCamera())->requestRecenter(resetZ);
}
VRInputManager::VRInputManager(
@ -723,7 +723,7 @@ namespace MWVR
case A_Recenter:
vrGuiManager->updateTracking();
if (!MWBase::Environment::get().getWindowManager()->isGuiMode())
requestRecenter();
requestRecenter(true);
break;
case MWInput::A_Use:
if (mActivationIndication || MWBase::Environment::get().getWindowManager()->isGuiMode())

View file

@ -46,7 +46,7 @@ namespace MWVR
void update(float dt, bool disableControls = false, bool disableEvents = false) override;
/// Set current offset to 0 and re-align VR stage.
void requestRecenter();
void requestRecenter(bool resetZ);
/// Tracking pose of the given limb at the given predicted time
Pose getLimbPose(int64_t time, TrackedLimb limb);

View file

@ -6,7 +6,9 @@
#include "../mwbase/windowmanager.hpp"
#include "../mwbase/world.hpp"
#include "../mwbase/statemanager.hpp"
#include "vrmetamenu.hpp"
#include "vrenvironment.hpp"
#include "vrinputmanager.hpp"
namespace MWVR
{
@ -94,6 +96,11 @@ namespace MWVR
MWBase::Environment::get().getStateManager()->quickSave();
}
void VrMetaMenu::onRecenter()
{
Environment::get().getInputManager()->requestRecenter(true);
}
void VrMetaMenu::close()
{
MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_VrMetaMenu);
@ -119,6 +126,8 @@ namespace MWVR
onQuickLoad();
else if (name == "quicksave")
onQuickSave();
else if (name == "recenter")
onRecenter();
}
bool VrMetaMenu::exit()
@ -128,7 +137,7 @@ namespace MWVR
void VrMetaMenu::updateMenu()
{
static std::vector<std::string> buttons{ "return", "quicksave", "quickload", "console", "inventory", "journal", "rest", "quickmenu", "gamemenu" };
static std::vector<std::string> buttons{ "return", "recenter", "quicksave", "quickload", "console", "inventory", "journal", "rest", "quickmenu", "gamemenu" };
if(mButtons.empty())
for (std::string& buttonId : buttons)

View file

@ -50,6 +50,7 @@ namespace MWVR
void onQuickMenu();
void onQuickLoad();
void onQuickSave();
void onRecenter();
void close();
void updateMenu();

View file

@ -52,6 +52,7 @@ namespace MWVR
VRSession::VRSession()
{
mHandDirectedMovement = Settings::Manager::getBool("hand directed movement", "VR");
mSeatedPlay = Settings::Manager::getBool("seated play", "VR");
}
VRSession::~VRSession()
@ -70,11 +71,9 @@ namespace MWVR
void VRSession::processChangedSettings(const std::set<std::pair<std::string, std::string>>& changed)
{
for (Settings::CategorySettingVector::const_iterator it = changed.begin(); it != changed.end(); ++it)
{
if (it->first == "VR" && it->second == "hand directed movement")
{
mHandDirectedMovement = Settings::Manager::getBool("hand directed movement", "VR");
}
setSeatedPlay(Settings::Manager::getBool("seated play", "VR"));
}
}
@ -98,6 +97,15 @@ namespace MWVR
}
}
void VRSession::setSeatedPlay(bool seatedPlay)
{
std::swap(mSeatedPlay, seatedPlay);
if (mSeatedPlay != seatedPlay)
{
Environment::get().getInputManager()->requestRecenter(true);
}
}
osg::Matrix VRSession::viewMatrix(osg::Vec3 position, osg::Quat orientation)
{
position = position * Constants::UnitsPerMeter;

View file

@ -66,9 +66,13 @@ namespace MWVR
void beginPhase(FramePhase phase);
std::unique_ptr<VRFrameMeta>& getFrame(FramePhase phase);
bool seatedPlay() const { return mSeatedPlay; }
float playerScale() const { return mPlayerScale; }
float setPlayerScale(float scale) { return mPlayerScale = scale; }
void setPlayerScale(float scale) { mPlayerScale = scale; }
float eyeLevel() const { return mEyeLevel; }
void setEyeLevel(float eyeLevel) { mEyeLevel = eyeLevel; }
osg::Matrix viewMatrix(osg::Vec3 position, osg::Quat orientation);
osg::Matrix viewMatrix(FramePhase phase, Side side, bool offset, bool glConvention);
@ -81,11 +85,15 @@ namespace MWVR
void beginFrame();
void endFrame();
protected:
void setSeatedPlay(bool seatedPlay);
private:
std::mutex mMutex{};
std::condition_variable mCondition{};
bool mHandDirectedMovement{ false };
bool mSeatedPlay{ false };
long long mFrames{ 0 };
long long mLastRenderedFrame{ 0 };
long long mLastPredictedDisplayTime{ 0 };
@ -95,6 +103,7 @@ namespace MWVR
std::chrono::steady_clock::time_point mLastRenderedFrameTimestamp{ std::chrono::steady_clock::now() };
float mPlayerScale{ 1.f };
float mEyeLevel{ 1.f };
};
}

View file

@ -964,7 +964,7 @@ namespace MWWorld
#ifdef USE_OPENXR
auto* xrInput = MWVR::Environment::get().getInputManager();
if (xrInput)
xrInput->requestRecenter();
xrInput->requestRecenter(false);
#endif
}
@ -987,7 +987,7 @@ namespace MWWorld
#ifdef USE_OPENXR
auto* xrInput = MWVR::Environment::get().getInputManager();
if (xrInput)
xrInput->requestRecenter();
xrInput->requestRecenter(false);
#endif
}

View file

@ -595,7 +595,17 @@
<Property key="Caption" value="Hand directed movement"/>
</Widget>
</Widget>
<Widget type="HBox" skin="" position="4 154 350 24">
<Widget type="HBox" skin="" position="4 154 260 24">
<Widget type="AutoSizedButton" skin="MW_Button" position="0 0 24 24" align="Left Top">
<UserString key="SettingCategory" value="VR"/>
<UserString key="SettingName" value="seated play"/>
<UserString key="SettingType" value="CheckButton"/>
</Widget>
<Widget type="AutoSizedTextBox" skin="SandText" position="28 4 71 16" align="Left Top">
<Property key="Caption" value="Seated play"/>
</Widget>
</Widget>
<Widget type="HBox" skin="" position="4 184 350 24">
<Widget type="ComboBox" skin="MW_ComboBox" position="0 0 85 24" align="Left Top" name="VRLeftHudPosition">
<Property key="AddItem" value="Wrist"/>
<Property key="AddItem" value="Top"/>

View file

@ -12,6 +12,11 @@
<Property key="FontHeight" value="32"/>
</Widget>
<Widget type="AutoSizedButton" skin="MW_Button" name="recenter" align="HCenter">
<Property key="Caption" value="Recenter"/>
<Property key="FontHeight" value="32"/>
</Widget>
<Widget type="Spacer"/>
<Widget type="Widget" skin="IB_T" align="HCenter" position="0 0 125 4">
<Widget type="Widget"/>

View file

@ -1023,6 +1023,8 @@ left hand hud position = wrist
# As the general quality of OpenXR DirectX runtimes is better than OpenGL runtimes, i default this to true.
Prefer DirectX swapchains = true
seated play = false
[VR Debug]
# If true, OpenMW-VR will enable gamma postprocessing
gamma postprocessing = true