mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-02-21 19:09:41 +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:
parent
7986def3db
commit
3347cdfe30
17 changed files with 186 additions and 98 deletions
|
@ -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)
|
||||
{
|
||||
auto* session = MWVR::Environment::get().getSession();
|
||||
if (session)
|
||||
if (isPlayer)
|
||||
{
|
||||
float pitch = 0.f;
|
||||
float yaw = 0.f;
|
||||
|
@ -238,81 +238,90 @@ 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;
|
||||
|
||||
auto* inputManager = reinterpret_cast<MWVR::VRCamera*>(MWBase::Environment::get().getWorld()->getRenderingManager().getCamera());
|
||||
|
||||
osg::Vec3 headOffset = inputManager->headOffset();
|
||||
osg::Vec3 trackingOffset = headOffset;
|
||||
// Player's tracking height should not affect character position
|
||||
trackingOffset.z() = 0;
|
||||
|
||||
float remainingTime = time;
|
||||
bool seenGround = physicActor->getOnGround() && !physicActor->getOnSlope() && !actor.mFlying;
|
||||
float remainder = 1.f;
|
||||
|
||||
for (int iterations = 0; iterations < sMaxIterations && remainingTime > 0.01f && remainder > 0.01; ++iterations)
|
||||
if (shouldMove)
|
||||
{
|
||||
osg::Vec3 toMove = trackingOffset * remainder;
|
||||
osg::Vec3 nextpos = newPosition + toMove;
|
||||
auto* inputManager = reinterpret_cast<MWVR::VRCamera*>(MWBase::Environment::get().getWorld()->getRenderingManager().getCamera());
|
||||
|
||||
if ((newPosition - nextpos).length2() > 0.0001)
|
||||
osg::Vec3 headOffset = inputManager->headOffset();
|
||||
osg::Vec3 trackingOffset = headOffset;
|
||||
// Player's tracking height should not affect character position
|
||||
trackingOffset.z() = 0;
|
||||
|
||||
float remainingTime = time;
|
||||
bool seenGround = physicActor->getOnGround() && !physicActor->getOnSlope() && !actor.mFlying;
|
||||
float remainder = 1.f;
|
||||
|
||||
for (int iterations = 0; iterations < sMaxIterations && remainingTime > 0.01f && remainder > 0.01; ++iterations)
|
||||
{
|
||||
// trace to where character would go if there were no obstructions
|
||||
tracer.doTrace(colobj, newPosition, nextpos, collisionWorld);
|
||||
osg::Vec3 toMove = trackingOffset * remainder;
|
||||
osg::Vec3 nextpos = newPosition + toMove;
|
||||
|
||||
// check for obstructions
|
||||
if (tracer.mFraction >= 1.0f)
|
||||
if ((newPosition - nextpos).length2() > 0.0001)
|
||||
{
|
||||
newPosition = tracer.mEndPos; // ok to move, so set newPosition
|
||||
// trace to where character would go if there were no obstructions
|
||||
tracer.doTrace(colobj, newPosition, nextpos, collisionWorld);
|
||||
|
||||
// check for obstructions
|
||||
if (tracer.mFraction >= 1.0f)
|
||||
{
|
||||
newPosition = tracer.mEndPos; // ok to move, so set newPosition
|
||||
remainder = 0.f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// The current position and next position are nearly the same, so just exit.
|
||||
// Note: Bullet can trigger an assert in debug modes if the positions
|
||||
// are the same, since that causes it to attempt to normalize a zero
|
||||
// length vector (which can also happen with nearly identical vectors, since
|
||||
// precision can be lost due to any math Bullet does internally). Since we
|
||||
// aren't performing any collision detection, we want to reject the next
|
||||
// position, so that we don't slowly move inside another object.
|
||||
remainder = 0.f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// The current position and next position are nearly the same, so just exit.
|
||||
// Note: Bullet can trigger an assert in debug modes if the positions
|
||||
// are the same, since that causes it to attempt to normalize a zero
|
||||
// length vector (which can also happen with nearly identical vectors, since
|
||||
// precision can be lost due to any math Bullet does internally). Since we
|
||||
// aren't performing any collision detection, we want to reject the next
|
||||
// position, so that we don't slowly move inside another object.
|
||||
remainder = 0.f;
|
||||
break;
|
||||
|
||||
if (isWalkableSlope(tracer.mPlaneNormal) && !actor.mFlying && newPosition.z() >= swimlevel)
|
||||
seenGround = true;
|
||||
|
||||
// We are touching something.
|
||||
if (tracer.mFraction < 1E-9f)
|
||||
{
|
||||
// Try to separate by backing off slighly to unstuck the solver
|
||||
osg::Vec3f backOff = (newPosition - tracer.mHitPoint) * 1E-2f;
|
||||
newPosition += backOff;
|
||||
}
|
||||
|
||||
// We hit something. Check if we can step up.
|
||||
float hitHeight = tracer.mHitPoint.z() - tracer.mEndPos.z() + halfExtents.z();
|
||||
osg::Vec3f oldPosition = newPosition;
|
||||
bool result = false;
|
||||
if (hitHeight < sStepSizeUp && !isActor(tracer.mHitObject))
|
||||
{
|
||||
// Try to step up onto it.
|
||||
// NOTE: stepMove does not allow stepping over, modifies newPosition if successful
|
||||
result = stepper.step(newPosition, toMove, remainingTime, seenGround, iterations == 0);
|
||||
remainder = remainingTime / time;
|
||||
}
|
||||
}
|
||||
|
||||
if (isWalkableSlope(tracer.mPlaneNormal) && !actor.mFlying && newPosition.z() >= swimlevel)
|
||||
seenGround = true;
|
||||
|
||||
// We are touching something.
|
||||
if (tracer.mFraction < 1E-9f)
|
||||
{
|
||||
// Try to separate by backing off slighly to unstuck the solver
|
||||
osg::Vec3f backOff = (newPosition - tracer.mHitPoint) * 1E-2f;
|
||||
newPosition += backOff;
|
||||
}
|
||||
|
||||
// We hit something. Check if we can step up.
|
||||
float hitHeight = tracer.mHitPoint.z() - tracer.mEndPos.z() + halfExtents.z();
|
||||
osg::Vec3f oldPosition = newPosition;
|
||||
bool result = false;
|
||||
if (hitHeight < sStepSizeUp && !isActor(tracer.mHitObject))
|
||||
{
|
||||
// Try to step up onto it.
|
||||
// NOTE: stepMove does not allow stepping over, modifies newPosition if successful
|
||||
result = stepper.step(newPosition, toMove, remainingTime, seenGround, iterations == 0);
|
||||
remainder = remainingTime / time;
|
||||
}
|
||||
// Try not to lose any tracking
|
||||
osg::Vec3 moved = newPosition - actor.mPosition;
|
||||
headOffset.x() -= moved.x();
|
||||
headOffset.y() -= moved.y();
|
||||
inputManager->setHeadOffset(headOffset);
|
||||
}
|
||||
|
||||
// Try not to lose any tracking
|
||||
osg::Vec3 moved = newPosition - actor.mPosition;
|
||||
headOffset.x() -= moved.x();
|
||||
headOffset.y() -= moved.y();
|
||||
inputManager->setHeadOffset(headOffset);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 };
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
float yaw = 0.f;
|
||||
float pitch = 0.f;
|
||||
float roll = 0.f;
|
||||
getEulerAngles(mHeadPose.orientation, yaw, pitch, roll);
|
||||
mYawOffset = -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 = 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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 };
|
||||
|
|
|
@ -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 };
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
@ -118,7 +125,9 @@ namespace MWVR
|
|||
else if (name == "quickload")
|
||||
onQuickLoad();
|
||||
else if (name == "quicksave")
|
||||
onQuickSave();
|
||||
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)
|
||||
|
|
|
@ -50,6 +50,7 @@ namespace MWVR
|
|||
void onQuickMenu();
|
||||
void onQuickLoad();
|
||||
void onQuickSave();
|
||||
void onRecenter();
|
||||
void close();
|
||||
|
||||
void updateMenu();
|
||||
|
|
|
@ -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()
|
||||
|
@ -71,10 +72,8 @@ namespace MWVR
|
|||
{
|
||||
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");
|
||||
}
|
||||
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;
|
||||
|
|
|
@ -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 };
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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"/>
|
||||
|
|
|
@ -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"/>
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue