1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-19 23:53:52 +00:00

Merge remote-tracking branch 'remotes/origin/master' into openxr_vr

This commit is contained in:
Mads Buvik Sandvei 2020-07-22 18:56:25 +02:00
commit 1023ef6e49
13 changed files with 269 additions and 222 deletions

View file

@ -435,6 +435,8 @@ namespace MWBase
virtual void changeVanityModeScale(float factor) = 0; virtual void changeVanityModeScale(float factor) = 0;
virtual bool vanityRotateCamera(float * rot) = 0; virtual bool vanityRotateCamera(float * rot) = 0;
virtual void setCameraDistance(float dist, bool adjust = false, bool override = true)=0; virtual void setCameraDistance(float dist, bool adjust = false, bool override = true)=0;
virtual void applyDeferredPreviewRotationToPlayer(float dt) = 0;
virtual void disableDeferredPreviewRotation() = 0;
virtual void setupPlayer() = 0; virtual void setupPlayer() = 0;
virtual void renderPlayer() = 0; virtual void renderPlayer() = 0;

View file

@ -110,23 +110,21 @@ namespace MWInput
if (MWBase::Environment::get().getInputManager()->getControlSwitch("playerviewswitch")) if (MWBase::Environment::get().getInputManager()->getControlSwitch("playerviewswitch"))
{ {
const float switchLimit = 0.25;
MWBase::World* world = MWBase::Environment::get().getWorld();
if (mBindingsManager->actionIsActive(A_TogglePOV)) if (mBindingsManager->actionIsActive(A_TogglePOV))
{ {
if (mPreviewPOVDelay <= 0.5 && if (world->isFirstPerson() ? mPreviewPOVDelay > switchLimit : mPreviewPOVDelay == 0)
(mPreviewPOVDelay += dt) > 0.5) world->togglePreviewMode(true);
{ mPreviewPOVDelay += dt;
mPreviewPOVDelay = 1.f;
MWBase::Environment::get().getWorld()->togglePreviewMode(true);
}
} }
else else
{ {
//disable preview mode //disable preview mode
MWBase::Environment::get().getWorld()->togglePreviewMode(false); if (mPreviewPOVDelay > 0)
if (mPreviewPOVDelay > 0.f && mPreviewPOVDelay <= 0.5) world->togglePreviewMode(false);
{ if (mPreviewPOVDelay > 0.f && mPreviewPOVDelay <= switchLimit)
MWBase::Environment::get().getWorld()->togglePOV(); world->togglePOV();
}
mPreviewPOVDelay = 0.f; mPreviewPOVDelay = 0.f;
} }
} }

View file

@ -9,6 +9,7 @@
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
#include "../mwworld/esmstore.hpp" #include "../mwworld/esmstore.hpp"
@ -101,6 +102,8 @@ namespace MWInput
mMouseManager->update(dt); mMouseManager->update(dt);
mSensorManager->update(dt); mSensorManager->update(dt);
mActionManager->update(dt, controllerMove); mActionManager->update(dt, controllerMove);
MWBase::Environment::get().getWorld()->applyDeferredPreviewRotationToPlayer(dt);
} }
void InputManager::setDragDrop(bool dragDrop) void InputManager::setDragDrop(bool dragDrop)

View file

@ -108,6 +108,8 @@ namespace MWInput
player.yaw(x); player.yaw(x);
player.pitch(y); player.pitch(y);
} }
else if (!input->getControlSwitch("playerlooking"))
MWBase::Environment::get().getWorld()->disableDeferredPreviewRotation();
if (arg.zrel && input->getControlSwitch("playerviewswitch") && input->getControlSwitch("playercontrols")) //Check to make sure you are allowed to zoomout and there is a change if (arg.zrel && input->getControlSwitch("playerviewswitch") && input->getControlSwitch("playercontrols")) //Check to make sure you are allowed to zoomout and there is a change
{ {
@ -207,17 +209,20 @@ namespace MWInput
return; return;
float rot[3]; float rot[3];
rot[0] = yAxis * dt * 1000.0f * mCameraSensitivity * (mInvertY ? -1 : 1) * mCameraYMultiplier / 256.f; rot[0] = -yAxis * dt * 1000.0f * mCameraSensitivity * (mInvertY ? -1 : 1) * mCameraYMultiplier / 256.f;
rot[1] = 0.0f; rot[1] = 0.0f;
rot[2] = xAxis * dt * 1000.0f * mCameraSensitivity * (mInvertX ? -1 : 1) / 256.f; rot[2] = -xAxis * dt * 1000.0f * mCameraSensitivity * (mInvertX ? -1 : 1) / 256.f;
// Only actually turn player when we're not in vanity mode // Only actually turn player when we're not in vanity mode
if (!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot) && MWBase::Environment::get().getInputManager()->getControlSwitch("playercontrols")) bool controls = MWBase::Environment::get().getInputManager()->getControlSwitch("playercontrols");
if (!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot) && controls)
{ {
MWWorld::Player& player = MWBase::Environment::get().getWorld()->getPlayer(); MWWorld::Player& player = MWBase::Environment::get().getWorld()->getPlayer();
player.yaw(rot[2]); player.yaw(-rot[2]);
player.pitch(rot[0]); player.pitch(-rot[0]);
} }
else if (!controls)
MWBase::Environment::get().getWorld()->disableDeferredPreviewRotation();
MWBase::Environment::get().getInputManager()->resetIdleTime(); MWBase::Environment::get().getInputManager()->resetIdleTime();
} }

View file

@ -249,17 +249,20 @@ namespace MWInput
if (!mGuiCursorEnabled) if (!mGuiCursorEnabled)
{ {
float rot[3]; float rot[3];
rot[0] = mGyroYSpeed * dt * mGyroVSensitivity * 4 * (mInvertY ? -1 : 1); rot[0] = -mGyroYSpeed * dt * mGyroVSensitivity * 4 * (mInvertY ? -1 : 1);
rot[1] = 0.0f; rot[1] = 0.0f;
rot[2] = mGyroXSpeed * dt * mGyroHSensitivity * 4 * (mInvertX ? -1 : 1); rot[2] = -mGyroXSpeed * dt * mGyroHSensitivity * 4 * (mInvertX ? -1 : 1);
// Only actually turn player when we're not in vanity mode // Only actually turn player when we're not in vanity mode
if (!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot) && MWBase::Environment::get().getInputManager()->getControlSwitch("playerlooking")) bool playerLooking = MWBase::Environment::get().getInputManager()->getControlSwitch("playerlooking");
if (!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot) && playerLooking)
{ {
MWWorld::Player& player = MWBase::Environment::get().getWorld()->getPlayer(); MWWorld::Player& player = MWBase::Environment::get().getWorld()->getPlayer();
player.yaw(rot[2]); player.yaw(-rot[2]);
player.pitch(rot[0]); player.pitch(-rot[0]);
} }
else if (!playerLooking)
MWBase::Environment::get().getWorld()->disableDeferredPreviewRotation();
MWBase::Environment::get().getInputManager()->resetIdleTime(); MWBase::Environment::get().getInputManager()->resetIdleTime();
} }

View file

@ -19,6 +19,7 @@
#endif #endif
#include "../mwmechanics/drawstate.hpp" #include "../mwmechanics/drawstate.hpp"
#include "../mwmechanics/movement.hpp"
#include "../mwmechanics/npcstats.hpp" #include "../mwmechanics/npcstats.hpp"
#include "npcanimation.hpp" #include "npcanimation.hpp"
@ -59,7 +60,10 @@ namespace MWRender
mCamera(camera), mCamera(camera),
mAnimation(nullptr), mAnimation(nullptr),
mFirstPersonView(true), mFirstPersonView(true),
mPreviewMode(false), mMode(Mode::Normal),
mVanityAllowed(true),
mStandingPreviewAllowed(Settings::Manager::getBool("preview if stand still", "Camera")),
mDeferredRotationAllowed(Settings::Manager::getBool("deferred preview rotation", "Camera")),
mNearest(30.f), mNearest(30.f),
mFurthest(800.f), mFurthest(800.f),
mIsNearest(false), mIsNearest(false),
@ -78,20 +82,10 @@ namespace MWRender
mSmoothedSpeed(0.f), mSmoothedSpeed(0.f),
mZoomOutWhenMoveCoef(Settings::Manager::getFloat("zoom out when move coef", "Camera")), mZoomOutWhenMoveCoef(Settings::Manager::getFloat("zoom out when move coef", "Camera")),
mDynamicCameraDistanceEnabled(false), mDynamicCameraDistanceEnabled(false),
mShowCrosshairInThirdPersonMode(false) mShowCrosshairInThirdPersonMode(false),
mDeferredRotation(osg::Vec3f()),
mDeferredRotationDisabled(false)
{ {
mVanity.enabled = false;
mVanity.allowed = true;
mPreviewCam.roll = 0.f;
mPreviewCam.pitch = 0.f;
mPreviewCam.yaw = 0.f;
mPreviewCam.offset = 400.f;
mMainCam.roll = 0.f;
mMainCam.pitch = 0.f;
mMainCam.yaw = 0.f;
mMainCam.offset = 400.f;
mCameraDistance = mBaseCameraDistance; mCameraDistance = mBaseCameraDistance;
mUpdateCallback = new UpdateRenderCameraCallback(this); mUpdateCallback = new UpdateRenderCameraCallback(this);
@ -103,19 +97,14 @@ namespace MWRender
mCamera->removeUpdateCallback(mUpdateCallback); mCamera->removeUpdateCallback(mUpdateCallback);
} }
MWWorld::Ptr Camera::getTrackingPtr() const
{
return mTrackingPtr;
}
osg::Vec3d Camera::getFocalPoint() const osg::Vec3d Camera::getFocalPoint() const
{ {
const osg::Node* trackNode = mTrackingNode; if (!mTrackingNode)
if (!trackNode)
{ {
return osg::Vec3d(); return osg::Vec3d();
} }
osg::NodePathList nodepaths = trackNode->getParentalNodePaths();
osg::NodePathList nodepaths = mTrackingNode->getParentalNodePaths();
if (nodepaths.empty()) if (nodepaths.empty())
return osg::Vec3d(); return osg::Vec3d();
osg::Matrix worldMat = osg::computeLocalToWorld(nodepaths[0]); osg::Matrix worldMat = osg::computeLocalToWorld(nodepaths[0]);
@ -147,12 +136,9 @@ namespace MWRender
osg::Vec3d Camera::getFocalPointOffset() const osg::Vec3d Camera::getFocalPointOffset() const
{ {
osg::Vec3d offset(0, 0, 10.f); osg::Vec3d offset(0, 0, 10.f);
if (!mPreviewMode && !mVanity.enabled) offset.x() += mFocalPointCurrentOffset.x() * cos(getYaw());
{ offset.y() += mFocalPointCurrentOffset.x() * sin(getYaw());
offset.x() += mFocalPointCurrentOffset.x() * cos(getYaw()); offset.z() += mFocalPointCurrentOffset.y();
offset.y() += mFocalPointCurrentOffset.x() * sin(getYaw());
offset.z() += mFocalPointCurrentOffset.y();
}
return offset; return offset;
} }
@ -170,9 +156,6 @@ namespace MWRender
void Camera::updateCamera(osg::Camera *cam) void Camera::updateCamera(osg::Camera *cam)
{ {
if (mTrackingPtr.isEmpty())
return;
osg::Quat orient = osg::Quat(getPitch(), osg::Vec3d(1,0,0)) * osg::Quat(getRoll(), osg::Vec3d(0, 1, 0)) * osg::Quat(getYaw(), osg::Vec3d(0,0,1)); osg::Quat orient = osg::Quat(getPitch(), osg::Vec3d(1,0,0)) * osg::Quat(getRoll(), osg::Vec3d(0, 1, 0)) * osg::Quat(getYaw(), osg::Vec3d(0,0,1));
osg::Vec3d focal, position; osg::Vec3d focal, position;
getPosition(focal, position); getPosition(focal, position);
@ -183,7 +166,6 @@ namespace MWRender
{ {
position += inputManager->headOffset(); position += inputManager->headOffset();
} }
#else
#endif #endif
osg::Vec3d forward = orient * osg::Vec3d(0,1,0); osg::Vec3d forward = orient * osg::Vec3d(0,1,0);
@ -213,11 +195,6 @@ namespace MWRender
setRoll(roll); setRoll(roll);
} }
void Camera::attachTo(const MWWorld::Ptr &ptr)
{
mTrackingPtr = ptr;
}
void Camera::update(float duration, bool paused) void Camera::update(float duration, bool paused)
{ {
if (mAnimation->upperBodyReady()) if (mAnimation->upperBodyReady())
@ -230,7 +207,6 @@ namespace MWRender
} }
if (mViewModeToggleQueued) if (mViewModeToggleQueued)
{ {
togglePreviewMode(false); togglePreviewMode(false);
toggleViewMode(); toggleViewMode();
mViewModeToggleQueued = false; mViewModeToggleQueued = false;
@ -242,13 +218,11 @@ namespace MWRender
// only show the crosshair in game mode // only show the crosshair in game mode
MWBase::WindowManager *wm = MWBase::Environment::get().getWindowManager(); MWBase::WindowManager *wm = MWBase::Environment::get().getWindowManager();
wm->showCrosshair(!wm->isGuiMode() && !mVanity.enabled && !mPreviewMode wm->showCrosshair(!wm->isGuiMode() && mMode != Mode::Preview && mMode != Mode::Vanity
&& (mFirstPersonView || mShowCrosshairInThirdPersonMode)); && (mFirstPersonView || mShowCrosshairInThirdPersonMode));
if(mVanity.enabled) if(mMode == Mode::Vanity)
{
rotateCamera(0.f, 0.f, osg::DegreesToRadians(3.f * duration), true); rotateCamera(0.f, 0.f, osg::DegreesToRadians(3.f * duration), true);
}
updateFocalPointOffset(duration); updateFocalPointOffset(duration);
@ -258,6 +232,24 @@ namespace MWRender
mSmoothedSpeed += osg::clampBetween(speed - mSmoothedSpeed, -maxDelta, maxDelta); mSmoothedSpeed += osg::clampBetween(speed - mSmoothedSpeed, -maxDelta, maxDelta);
mMaxNextCameraDistance = mCameraDistance + duration * (100.f + mBaseCameraDistance); mMaxNextCameraDistance = mCameraDistance + duration * (100.f + mBaseCameraDistance);
updateStandingPreviewMode();
}
void Camera::updateStandingPreviewMode()
{
if (!mStandingPreviewAllowed)
return;
float speed = mTrackingPtr.getClass().getSpeed(mTrackingPtr);
bool combat = mTrackingPtr.getClass().isActor() &&
mTrackingPtr.getClass().getCreatureStats(mTrackingPtr).getDrawState() != MWMechanics::DrawState_Nothing;
bool standingStill = speed == 0 && !combat && !mFirstPersonView;
if (!standingStill && mMode == Mode::StandingPreview)
{
mMode = Mode::Normal;
calculateDeferredRotation();
}
else if (standingStill && mMode == Mode::Normal)
mMode = Mode::StandingPreview;
} }
void Camera::setFocalPointTargetOffset(osg::Vec2d v) void Camera::setFocalPointTargetOffset(osg::Vec2d v)
@ -324,14 +316,19 @@ namespace MWRender
mTrackingPtr.getClass().getCreatureStats(mTrackingPtr).setSideMovementAngle(0); mTrackingPtr.getClass().getCreatureStats(mTrackingPtr).setSideMovementAngle(0);
mFirstPersonView = !mFirstPersonView; mFirstPersonView = !mFirstPersonView;
updateStandingPreviewMode();
instantTransition();
processViewChange(); processViewChange();
} }
void Camera::allowVanityMode(bool allow) void Camera::allowVanityMode(bool allow)
{ {
if (!allow && mVanity.enabled) if (!allow && mMode == Mode::Vanity)
{
disableDeferredPreviewRotation();
toggleVanityMode(false); toggleVanityMode(false);
mVanity.allowed = allow; }
mVanityAllowed = allow;
} }
bool Camera::toggleVanityMode(bool enable) bool Camera::toggleVanityMode(bool enable)
@ -349,26 +346,18 @@ namespace MWRender
return false; return false;
} }
if(!mVanity.allowed && enable) if (!mVanityAllowed && enable)
return false; return false;
if(mVanity.enabled == enable) if ((mMode == Mode::Vanity) == enable)
return true; return true;
mVanity.enabled = enable; mMode = enable ? Mode::Vanity : Mode::Normal;
if (!mDeferredRotationAllowed)
disableDeferredPreviewRotation();
if (!enable)
calculateDeferredRotation();
processViewChange(); processViewChange();
float offset = mPreviewCam.offset;
if (mVanity.enabled) {
setPitch(osg::DegreesToRadians(-30.f));
mMainCam.offset = mCameraDistance;
} else {
offset = mMainCam.offset;
}
mCameraDistance = offset;
return true; return true;
} }
@ -377,22 +366,21 @@ namespace MWRender
if (mFirstPersonView && !mAnimation->upperBodyReady()) if (mFirstPersonView && !mAnimation->upperBodyReady())
return; return;
if(mPreviewMode == enable) if((mMode == Mode::Preview) == enable)
return; return;
mPreviewMode = enable; mMode = enable ? Mode::Preview : Mode::Normal;
processViewChange(); if (mMode == Mode::Normal)
updateStandingPreviewMode();
float offset = mCameraDistance; else if (mFirstPersonView)
if (mPreviewMode) { instantTransition();
mMainCam.offset = offset; if (mMode == Mode::Normal)
offset = mPreviewCam.offset; {
} else { if (!mDeferredRotationAllowed)
mPreviewCam.offset = offset; disableDeferredPreviewRotation();
offset = mMainCam.offset; calculateDeferredRotation();
} }
processViewChange();
mCameraDistance = offset;
} }
void Camera::setSneakOffset(float offset) void Camera::setSneakOffset(float offset)
@ -400,13 +388,6 @@ namespace MWRender
mAnimation->setFirstPersonOffset(osg::Vec3f(0,0,-offset)); mAnimation->setFirstPersonOffset(osg::Vec3f(0,0,-offset));
} }
float Camera::getYaw() const
{
if(mVanity.enabled || mPreviewMode)
return mPreviewCam.yaw;
return mMainCam.yaw;
}
void Camera::setYaw(float angle) void Camera::setYaw(float angle)
{ {
if (angle > osg::PI) { if (angle > osg::PI) {
@ -414,18 +395,7 @@ namespace MWRender
} else if (angle < -osg::PI) { } else if (angle < -osg::PI) {
angle += osg::PI*2; angle += osg::PI*2;
} }
if (mVanity.enabled || mPreviewMode) { mYaw = angle;
mPreviewCam.yaw = angle;
} else {
mMainCam.yaw = angle;
}
}
float Camera::getRoll()
{
if (mVanity.enabled || mPreviewMode)
return mPreviewCam.roll;
return mMainCam.roll;
} }
void Camera::setRoll(float angle) void Camera::setRoll(float angle)
@ -437,46 +407,19 @@ namespace MWRender
else if (angle < -osg::PI) { else if (angle < -osg::PI) {
angle += osg::PI * 2; angle += osg::PI * 2;
} }
if (mVanity.enabled || mPreviewMode) { mRoll = angle;
mPreviewCam.roll = angle;
}
else {
mMainCam.roll = angle;
}
#else #else
// It seems OpenMW saves roll data, causing the camera to get tilted // It seems OpenMW saves roll data, causing the camera to get tilted
// when loading a VR save in non-VR. // when loading a VR save in non-VR.
mMainCam.roll = mPreviewCam.roll = 0.f; mRoll = 0.f;
#endif #endif
} }
float Camera::getPitch() const
{
if (mVanity.enabled || mPreviewMode) {
return mPreviewCam.pitch;
}
return mMainCam.pitch;
}
void Camera::setPitch(float angle) void Camera::setPitch(float angle)
{ {
const float epsilon = 0.000001f; const float epsilon = 0.000001f;
float limit = osg::PI_2 - epsilon; float limit = osg::PI_2 - epsilon;
if(mPreviewMode) mPitch = osg::clampBetween(angle, -limit, limit);
limit /= 2;
#ifndef USE_OPENXR
if(angle > limit)
angle = limit;
else if(angle < -limit)
angle = -limit;
#endif
if (mVanity.enabled || mPreviewMode) {
mPreviewCam.pitch = angle;
} else {
mMainCam.pitch = angle;
}
} }
float Camera::getCameraDistance() const float Camera::getCameraDistance() const
@ -488,50 +431,25 @@ namespace MWRender
void Camera::updateBaseCameraDistance(float dist, bool adjust) void Camera::updateBaseCameraDistance(float dist, bool adjust)
{ {
if(mFirstPersonView && !mPreviewMode && !mVanity.enabled) if (isFirstPerson())
return; return;
mIsNearest = false;
if (adjust) if (adjust)
{ dist += std::min(mCameraDistance - getCameraDistanceCorrection(), mBaseCameraDistance);
if (mVanity.enabled || mPreviewMode)
dist += mCameraDistance;
else
dist += std::min(mCameraDistance - getCameraDistanceCorrection(), mBaseCameraDistance);
}
mIsNearest = dist <= mNearest;
if (dist >= mFurthest) mBaseCameraDistance = osg::clampBetween(dist, mNearest, mFurthest);
dist = mFurthest; Settings::Manager::setFloat("third person camera distance", "Camera", mBaseCameraDistance);
else if (dist <= mNearest)
{
dist = mNearest;
mIsNearest = true;
}
if (mVanity.enabled || mPreviewMode)
mPreviewCam.offset = dist;
else if (!mFirstPersonView)
{
mBaseCameraDistance = dist;
Settings::Manager::setFloat("third person camera distance", "Camera", dist);
}
setCameraDistance(); setCameraDistance();
} }
void Camera::setCameraDistance(float dist, bool adjust) void Camera::setCameraDistance(float dist, bool adjust)
{ {
if(mFirstPersonView && !mPreviewMode && !mVanity.enabled) if (isFirstPerson())
return; return;
if (adjust)
if (adjust) dist += mCameraDistance; dist += mCameraDistance;
mCameraDistance = osg::clampBetween(dist, 10.f, mFurthest);
if (dist >= mFurthest)
dist = mFurthest;
else if (dist < 10.f)
dist = 10.f;
mCameraDistance = dist;
} }
float Camera::getCameraDistanceCorrection() const float Camera::getCameraDistanceCorrection() const
@ -549,21 +467,17 @@ namespace MWRender
void Camera::setCameraDistance() void Camera::setCameraDistance()
{ {
if (mVanity.enabled || mPreviewMode)
mCameraDistance = mPreviewCam.offset;
else if (!mFirstPersonView)
{
mCameraDistance = mBaseCameraDistance + getCameraDistanceCorrection();
if (mDynamicCameraDistanceEnabled)
mCameraDistance = std::min(mCameraDistance, mMaxNextCameraDistance);
}
mFocalPointAdjustment = osg::Vec3d(); mFocalPointAdjustment = osg::Vec3d();
if (isFirstPerson())
return;
mCameraDistance = mBaseCameraDistance + getCameraDistanceCorrection();
if (mDynamicCameraDistanceEnabled)
mCameraDistance = std::min(mCameraDistance, mMaxNextCameraDistance);
} }
void Camera::setAnimation(NpcAnimation *anim) void Camera::setAnimation(NpcAnimation *anim)
{ {
mAnimation = anim; mAnimation = anim;
processViewChange(); processViewChange();
} }
@ -602,13 +516,74 @@ namespace MWRender
#endif #endif
} }
bool Camera::isVanityOrPreviewModeEnabled() const void Camera::applyDeferredPreviewRotationToPlayer(float dt)
{ {
return mPreviewMode || mVanity.enabled; if (isVanityOrPreviewModeEnabled() || mTrackingPtr.isEmpty())
return;
osg::Vec3f rot = mDeferredRotation;
float delta = rot.normalize();
delta = std::min(delta, (delta + 1.f) * 3 * dt);
rot *= delta;
mDeferredRotation -= rot;
if (mDeferredRotationDisabled)
{
mDeferredRotationDisabled = delta > 0.0001;
rotateCameraToTrackingPtr();
return;
}
auto& movement = mTrackingPtr.getClass().getMovementSettings(mTrackingPtr);
movement.mRotation[0] += rot.x();
movement.mRotation[1] += rot.y();
movement.mRotation[2] += rot.z();
if (std::abs(mDeferredRotation.z()) > 0.0001)
{
float s = std::sin(mDeferredRotation.z());
float c = std::cos(mDeferredRotation.z());
float x = movement.mPosition[0];
float y = movement.mPosition[1];
movement.mPosition[0] = x * c + y * s;
movement.mPosition[1] = x * -s + y * c;
}
} }
bool Camera::isNearest() const void Camera::rotateCameraToTrackingPtr()
{ {
return mIsNearest; setPitch(-mTrackingPtr.getRefData().getPosition().rot[0] - mDeferredRotation.x());
setYaw(-mTrackingPtr.getRefData().getPosition().rot[2] - mDeferredRotation.z());
} }
void Camera::instantTransition()
{
mSkipFocalPointTransition = true;
mDeferredRotationDisabled = false;
mDeferredRotation = osg::Vec3f();
rotateCameraToTrackingPtr();
}
void Camera::calculateDeferredRotation()
{
MWWorld::Ptr ptr = mTrackingPtr;
if (isVanityOrPreviewModeEnabled() || ptr.isEmpty())
return;
if (mFirstPersonView)
{
instantTransition();
return;
}
mDeferredRotation.x() = -ptr.getRefData().getPosition().rot[0] - mPitch;
mDeferredRotation.z() = -ptr.getRefData().getPosition().rot[2] - mYaw;
if (mDeferredRotation.x() > osg::PI)
mDeferredRotation.x() -= 2 * osg::PI;
if (mDeferredRotation.x() < -osg::PI)
mDeferredRotation.x() += 2 * osg::PI;
if (mDeferredRotation.z() > osg::PI)
mDeferredRotation.z() -= 2 * osg::PI;
if (mDeferredRotation.z() < -osg::PI)
mDeferredRotation.z() += 2 * osg::PI;
}
} }

View file

@ -23,11 +23,10 @@ namespace MWRender
/// \brief Camera control /// \brief Camera control
class Camera class Camera
{ {
private: public:
struct CamData { enum class Mode { Normal, Vanity, Preview, StandingPreview };
float roll, pitch, yaw, offset;
};
private:
MWWorld::Ptr mTrackingPtr; MWWorld::Ptr mTrackingPtr;
osg::ref_ptr<const osg::Node> mTrackingNode; osg::ref_ptr<const osg::Node> mTrackingNode;
float mHeightScale; float mHeightScale;
@ -37,17 +36,17 @@ namespace MWRender
NpcAnimation *mAnimation; NpcAnimation *mAnimation;
bool mFirstPersonView; bool mFirstPersonView;
bool mPreviewMode; Mode mMode;
bool mVanityAllowed;
bool mStandingPreviewAllowed;
bool mDeferredRotationAllowed;
float mNearest; float mNearest;
float mFurthest; float mFurthest;
bool mIsNearest; bool mIsNearest;
struct {
bool enabled, allowed;
} mVanity;
float mHeight, mBaseCameraDistance; float mHeight, mBaseCameraDistance;
CamData mMainCam, mPreviewCam; float mPitch, mYaw, mRoll;
bool mVanityToggleQueued; bool mVanityToggleQueued;
bool mVanityToggleQueuedValue; bool mVanityToggleQueuedValue;
@ -78,15 +77,23 @@ namespace MWRender
osg::ref_ptr<osg::NodeCallback> mUpdateCallback; osg::ref_ptr<osg::NodeCallback> mUpdateCallback;
// Used to rotate player to the direction of view after exiting preview or vanity mode.
osg::Vec3f mDeferredRotation;
bool mDeferredRotationDisabled;
void calculateDeferredRotation();
void updateStandingPreviewMode();
public: public:
Camera(osg::Camera* camera); Camera(osg::Camera* camera);
~Camera(); ~Camera();
MWWorld::Ptr getTrackingPtr() const; /// Attach camera to object
void attachTo(const MWWorld::Ptr &ptr) { mTrackingPtr = ptr; }
MWWorld::Ptr getTrackingPtr() const { return mTrackingPtr; }
void setFocalPointTransitionSpeed(float v) { mFocalPointTransitionSpeedCoef = v; } void setFocalPointTransitionSpeed(float v) { mFocalPointTransitionSpeedCoef = v; }
void setFocalPointTargetOffset(osg::Vec2d v); void setFocalPointTargetOffset(osg::Vec2d v);
void skipFocalPointTransition() { mSkipFocalPointTransition = true; } void instantTransition();
void enableDynamicCameraDistance(bool v) { mDynamicCameraDistanceEnabled = v; } void enableDynamicCameraDistance(bool v) { mDynamicCameraDistanceEnabled = v; }
void enableCrosshairInThirdPersonMode(bool v) { mShowCrosshairInThirdPersonMode = v; } void enableCrosshairInThirdPersonMode(bool v) { mShowCrosshairInThirdPersonMode = v; }
@ -102,18 +109,16 @@ namespace MWRender
/// Set where the camera is looking at. Uses Morrowind (euler) angles /// Set where the camera is looking at. Uses Morrowind (euler) angles
/// \param rot Rotation angles in radians /// \param rot Rotation angles in radians
void rotateCamera(float pitch, float roll, float yaw, bool adjust); void rotateCamera(float pitch, float roll, float yaw, bool adjust);
void rotateCameraToTrackingPtr();
float getYaw() const; float getYaw() const { return mYaw; }
void setYaw(float angle); void setYaw(float angle);
float getRoll(); float getPitch() const { return mPitch; }
void setRoll(float angle);
float getPitch() const;
void setPitch(float angle); void setPitch(float angle);
/// Attach camera to object float getRoll() { return mRoll; }
void attachTo(const MWWorld::Ptr &); void setRoll(float angle);
/// @param Force view mode switch, even if currently not allowed by the animation. /// @param Force view mode switch, even if currently not allowed by the animation.
void toggleViewMode(bool force=false); void toggleViewMode(bool force=false);
@ -124,11 +129,13 @@ namespace MWRender
/// @note this may be ignored if an important animation is currently playing /// @note this may be ignored if an important animation is currently playing
void togglePreviewMode(bool enable); void togglePreviewMode(bool enable);
void applyDeferredPreviewRotationToPlayer(float dt);
void disableDeferredPreviewRotation() { mDeferredRotationDisabled = true; }
/// \brief Lowers the camera for sneak. /// \brief Lowers the camera for sneak.
void setSneakOffset(float offset); void setSneakOffset(float offset);
bool isFirstPerson() const bool isFirstPerson() const { return mFirstPersonView && mMode == Mode::Normal; }
{ return !(mVanity.enabled || mPreviewMode || !mFirstPersonView); }
void processViewChange(); void processViewChange();
@ -159,9 +166,10 @@ namespace MWRender
/// Stores focal and camera world positions in passed arguments /// Stores focal and camera world positions in passed arguments
void getPosition(osg::Vec3d &focal, osg::Vec3d &camera) const; void getPosition(osg::Vec3d &focal, osg::Vec3d &camera) const;
bool isVanityOrPreviewModeEnabled() const; bool isVanityOrPreviewModeEnabled() const { return mMode != Mode::Normal; }
Mode getMode() const { return mMode; }
bool isNearest() const; bool isNearest() const { return mIsNearest; }
}; };
} }

View file

@ -660,7 +660,7 @@ namespace MWRender
if(ptr == mCamera->getTrackingPtr() && if(ptr == mCamera->getTrackingPtr() &&
!mCamera->isVanityOrPreviewModeEnabled()) !mCamera->isVanityOrPreviewModeEnabled())
{ {
mCamera->rotateCamera(-ptr.getRefData().getPosition().rot[0], -ptr.getRefData().getPosition().rot[1], -ptr.getRefData().getPosition().rot[2], false); mCamera->rotateCameraToTrackingPtr();
} }
ptr.getRefData().getBaseNode()->setAttitude(rot); ptr.getRefData().getBaseNode()->setAttitude(rot);

View file

@ -33,12 +33,13 @@ namespace MWRender
void ViewOverShoulderController::update() void ViewOverShoulderController::update()
{ {
if (mCamera->isVanityOrPreviewModeEnabled() || mCamera->isFirstPerson()) if (mCamera->isFirstPerson())
return; return;
Mode oldMode = mMode; Mode oldMode = mMode;
auto ptr = mCamera->getTrackingPtr(); auto ptr = mCamera->getTrackingPtr();
if (ptr.getClass().isActor() && ptr.getClass().getCreatureStats(ptr).getDrawState() != MWMechanics::DrawState_Nothing) bool combat = ptr.getClass().isActor() && ptr.getClass().getCreatureStats(ptr).getDrawState() != MWMechanics::DrawState_Nothing;
if (combat && !mCamera->isVanityOrPreviewModeEnabled())
mMode = Mode::Combat; mMode = Mode::Combat;
else if (MWBase::Environment::get().getWorld()->isSwimming(ptr)) else if (MWBase::Environment::get().getWorld()->isSwimming(ptr))
mMode = Mode::Swimming; mMode = Mode::Swimming;
@ -46,12 +47,18 @@ namespace MWRender
mMode = mDefaultShoulderIsRight ? Mode::RightShoulder : Mode::LeftShoulder; mMode = mDefaultShoulderIsRight ? Mode::RightShoulder : Mode::LeftShoulder;
if (mAutoSwitchShoulder && (mMode == Mode::LeftShoulder || mMode == Mode::RightShoulder)) if (mAutoSwitchShoulder && (mMode == Mode::LeftShoulder || mMode == Mode::RightShoulder))
trySwitchShoulder(); trySwitchShoulder();
if (oldMode == mMode) return;
if (oldMode == Mode::Combat || mMode == Mode::Combat) if (oldMode == mMode)
return;
if (mCamera->getMode() == Camera::Mode::Vanity)
// Player doesn't touch controls for a long time. Transition should be very slow.
mCamera->setFocalPointTransitionSpeed(0.2f);
else if ((oldMode == Mode::Combat || mMode == Mode::Combat) && mCamera->getMode() == Camera::Mode::Normal)
// Transition to/from combat mode and we are not it preview mode. Should be fast.
mCamera->setFocalPointTransitionSpeed(5.f); mCamera->setFocalPointTransitionSpeed(5.f);
else else
mCamera->setFocalPointTransitionSpeed(1.f); mCamera->setFocalPointTransitionSpeed(1.f); // Default transition speed.
switch (mMode) switch (mMode)
{ {
@ -70,6 +77,9 @@ namespace MWRender
void ViewOverShoulderController::trySwitchShoulder() void ViewOverShoulderController::trySwitchShoulder()
{ {
if (mCamera->getMode() != Camera::Mode::Normal)
return;
const float limitToSwitch = 120; // switch to other shoulder if wall is closer than this limit const float limitToSwitch = 120; // switch to other shoulder if wall is closer than this limit
const float limitToSwitchBack = 300; // switch back to default shoulder if there is no walls at this distance const float limitToSwitchBack = 300; // switch back to default shoulder if there is no walls at this distance
@ -93,4 +103,4 @@ namespace MWRender
mMode = mDefaultShoulderIsRight ? Mode::RightShoulder : Mode::LeftShoulder; mMode = mDefaultShoulderIsRight ? Mode::RightShoulder : Mode::LeftShoulder;
} }
} }

View file

@ -954,7 +954,7 @@ namespace MWWorld
removeContainerScripts(getPlayerPtr()); removeContainerScripts(getPlayerPtr());
mWorldScene->changeToInteriorCell(cellName, position, adjustPlayerPos, changeEvent); mWorldScene->changeToInteriorCell(cellName, position, adjustPlayerPos, changeEvent);
addContainerScripts(getPlayerPtr(), getPlayerPtr().getCell()); addContainerScripts(getPlayerPtr(), getPlayerPtr().getCell());
mRendering->getCamera()->skipFocalPointTransition(); mRendering->getCamera()->instantTransition();
#ifdef USE_OPENXR #ifdef USE_OPENXR
auto* xrInput = MWVR::Environment::get().getInputManager(); auto* xrInput = MWVR::Environment::get().getInputManager();
@ -976,7 +976,7 @@ namespace MWWorld
removeContainerScripts(getPlayerPtr()); removeContainerScripts(getPlayerPtr());
mWorldScene->changeToExteriorCell(position, adjustPlayerPos, changeEvent); mWorldScene->changeToExteriorCell(position, adjustPlayerPos, changeEvent);
addContainerScripts(getPlayerPtr(), getPlayerPtr().getCell()); addContainerScripts(getPlayerPtr(), getPlayerPtr().getCell());
mRendering->getCamera()->skipFocalPointTransition(); mRendering->getCamera()->instantTransition();
#ifdef USE_OPENXR #ifdef USE_OPENXR
auto* xrInput = MWVR::Environment::get().getInputManager(); auto* xrInput = MWVR::Environment::get().getInputManager();
@ -2446,6 +2446,16 @@ namespace MWWorld
return mRendering->toggleVanityMode(enable); return mRendering->toggleVanityMode(enable);
} }
void World::disableDeferredPreviewRotation()
{
mRendering->getCamera()->disableDeferredPreviewRotation();
}
void World::applyDeferredPreviewRotationToPlayer(float dt)
{
mRendering->getCamera()->applyDeferredPreviewRotationToPlayer(dt);
}
void World::allowVanityMode(bool allow) void World::allowVanityMode(bool allow)
{ {
mRendering->allowVanityMode(allow); mRendering->allowVanityMode(allow);

View file

@ -540,6 +540,9 @@ namespace MWWorld
bool vanityRotateCamera(float * rot) override; bool vanityRotateCamera(float * rot) override;
void setCameraDistance(float dist, bool adjust = false, bool override = true) override; void setCameraDistance(float dist, bool adjust = false, bool override = true) override;
void applyDeferredPreviewRotationToPlayer(float dt) override;
void disableDeferredPreviewRotation() override;
void setupPlayer() override; void setupPlayer() override;
void renderPlayer() override; void renderPlayer() override;

View file

@ -174,3 +174,27 @@ Slightly pulls camera away (or closer in case of negative value) when the charac
This setting can only be configured by editing the settings configuration file. This setting can only be configured by editing the settings configuration file.
preview if stand still
----------------------
:Type: boolean
:Range: True/False
:Default: False
If enabled then the character rotation is not synchonized with the camera rotation while the character doesn't move and not in combat mode.
This setting can only be configured by editing the settings configuration file.
deferred preview rotation
-------------------------
:Type: boolean
:Range: True/False
:Default: True
Makes difference only in third person mode.
If enabled then the character smoothly rotates to the view direction after exiting preview or vanity mode.
If disabled then the camera rotates rather than the character.
This setting can only be configured by editing the settings configuration file.

View file

@ -48,6 +48,12 @@ auto switch shoulder = true
# Slightly pulls camera away when the character moves. Works only in 'view over shoulder' mode. Set to 0 to disable. # Slightly pulls camera away when the character moves. Works only in 'view over shoulder' mode. Set to 0 to disable.
zoom out when move coef = 20 zoom out when move coef = 20
# Automatically enable preview mode when player doesn't move.
preview if stand still = false
# Rotate the character to the view direction after exiting preview mode.
deferred preview rotation = true
[Cells] [Cells]
# Preload cells in a background thread. All settings starting with 'preload' have no effect unless this is enabled. # Preload cells in a background thread. All settings starting with 'preload' have no effect unless this is enabled.