From 173c1fdabb507f0dd204a0219b06d96af33a47fe Mon Sep 17 00:00:00 2001 From: Petr Mikheev Date: Sun, 12 Jul 2020 01:55:20 +0200 Subject: [PATCH] Make transition in 'auto switch shoulder' smoother. --- apps/openmw/mwrender/camera.cpp | 35 +++++++++++++++++++++-- apps/openmw/mwrender/camera.hpp | 12 ++++++-- apps/openmw/mwrender/viewovershoulder.cpp | 27 ++++++++--------- 3 files changed, 53 insertions(+), 21 deletions(-) diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp index 3b3f1aec93..1e6ea2843e 100644 --- a/apps/openmw/mwrender/camera.cpp +++ b/apps/openmw/mwrender/camera.cpp @@ -64,7 +64,8 @@ namespace MWRender mCameraDistance(0.f), mFocalPointCurrentOffset(osg::Vec2d()), mFocalPointTargetOffset(osg::Vec2d()), - mFocalPointTransitionSpeed(1.f), + mFocalPointTransitionSpeedCoef(1.f), + mPreviousTransitionInfluence(0.f), mSmoothedSpeed(0.f), mDynamicCameraDistanceEnabled(false), mShowCrosshairInThirdPersonMode(false) @@ -221,16 +222,44 @@ namespace MWRender mSmoothedSpeed += osg::clampBetween(speed - mSmoothedSpeed, -maxDelta, maxDelta); } + void Camera::setFocalPointTargetOffset(osg::Vec2d v) + { + mFocalPointTargetOffset = v; + mPreviousTransitionSpeed = mFocalPointTransitionSpeed; + mPreviousTransitionInfluence = 1.0f; + } + void Camera::updateFocalPointOffset(float duration) { + if (duration <= 0) + return; + + osg::Vec2d oldOffset = mFocalPointCurrentOffset; + + if (mPreviousTransitionInfluence > 0) + { + mFocalPointCurrentOffset -= mPreviousExtraOffset; + mPreviousExtraOffset = mPreviousExtraOffset / mPreviousTransitionInfluence + mPreviousTransitionSpeed * duration; + mPreviousTransitionInfluence = + std::max(0.f, mPreviousTransitionInfluence - duration * mFocalPointTransitionSpeedCoef); + mPreviousExtraOffset *= mPreviousTransitionInfluence; + mFocalPointCurrentOffset += mPreviousExtraOffset; + } + osg::Vec2d delta = mFocalPointTargetOffset - mFocalPointCurrentOffset; if (delta.length2() > 0) { - float coef = duration * (1.0 + 5.0 / delta.length()) * mFocalPointTransitionSpeed; + float coef = duration * (1.0 + 5.0 / delta.length()) * + mFocalPointTransitionSpeedCoef * (1.0f - mPreviousTransitionInfluence); mFocalPointCurrentOffset += delta * std::min(coef, 1.0f); } else - mFocalPointTransitionSpeed = 1.f; + { + mPreviousExtraOffset = osg::Vec2d(); + mPreviousTransitionInfluence = 0.f; + } + + mFocalPointTransitionSpeed = (mFocalPointCurrentOffset - oldOffset) / duration; } void Camera::toggleViewMode(bool force) diff --git a/apps/openmw/mwrender/camera.hpp b/apps/openmw/mwrender/camera.hpp index 5f3c5d6e49..bd70d6d9a1 100644 --- a/apps/openmw/mwrender/camera.hpp +++ b/apps/openmw/mwrender/camera.hpp @@ -58,7 +58,13 @@ namespace MWRender osg::Vec3d mFocalPointAdjustment; osg::Vec2d mFocalPointCurrentOffset; osg::Vec2d mFocalPointTargetOffset; - float mFocalPointTransitionSpeed; + float mFocalPointTransitionSpeedCoef; + + // This fields are used to make focal point transition smooth if previous transition was not finished. + float mPreviousTransitionInfluence; + osg::Vec2d mFocalPointTransitionSpeed; + osg::Vec2d mPreviousTransitionSpeed; + osg::Vec2d mPreviousExtraOffset; float mSmoothedSpeed; bool mDynamicCameraDistanceEnabled; @@ -75,8 +81,8 @@ namespace MWRender MWWorld::Ptr getTrackingPtr() const; - void setFocalPointTransitionSpeed(float v) { mFocalPointTransitionSpeed = v; } - void setFocalPointTargetOffset(osg::Vec2d v) { mFocalPointTargetOffset = v; } + void setFocalPointTransitionSpeed(float v) { mFocalPointTransitionSpeedCoef = v; } + void setFocalPointTargetOffset(osg::Vec2d v); void enableDynamicCameraDistance(bool v) { mDynamicCameraDistanceEnabled = v; } void enableCrosshairInThirdPersonMode(bool v) { mShowCrosshairInThirdPersonMode = v; } diff --git a/apps/openmw/mwrender/viewovershoulder.cpp b/apps/openmw/mwrender/viewovershoulder.cpp index f908b14302..5d7ec7117a 100644 --- a/apps/openmw/mwrender/viewovershoulder.cpp +++ b/apps/openmw/mwrender/viewovershoulder.cpp @@ -28,6 +28,7 @@ namespace MWRender mCamera->enableDynamicCameraDistance(true); mCamera->enableCrosshairInThirdPersonMode(true); + mCamera->setFocalPointTargetOffset({mOverShoulderHorizontalOffset, mOverShoulderVerticalOffset}); } void ViewOverShoulderController::update() @@ -35,27 +36,23 @@ namespace MWRender if (mCamera->isVanityOrPreviewModeEnabled() || mCamera->isFirstPerson()) return; - Mode newMode = mMode; + Mode oldMode = mMode; auto ptr = mCamera->getTrackingPtr(); if (ptr.getClass().isActor() && ptr.getClass().getCreatureStats(ptr).getDrawState() != MWMechanics::DrawState_Nothing) - newMode = Mode::Combat; + mMode = Mode::Combat; else if (MWBase::Environment::get().getWorld()->isSwimming(ptr)) - newMode = Mode::Swimming; - else if (mMode == Mode::Combat || mMode == Mode::Swimming) - newMode = mDefaultShoulderIsRight ? Mode::RightShoulder : Mode::LeftShoulder; - if (newMode != mMode) - { - if (newMode == Mode::Combat || mMode == Mode::Combat) - mCamera->setFocalPointTransitionSpeed(5.f); - else - mCamera->setFocalPointTransitionSpeed(1.f); - mMode = newMode; - } - + mMode = Mode::Swimming; + else if (oldMode == Mode::Combat || oldMode == Mode::Swimming) + mMode = mDefaultShoulderIsRight ? Mode::RightShoulder : Mode::LeftShoulder; if (mAutoSwitchShoulder && (mMode == Mode::LeftShoulder || mMode == Mode::RightShoulder)) trySwitchShoulder(); + if (oldMode == mMode) return; + + if (oldMode == Mode::Combat || mMode == Mode::Combat) + mCamera->setFocalPointTransitionSpeed(5.f); + else + mCamera->setFocalPointTransitionSpeed(1.f); - osg::Vec2d focalPointTargetOffset; switch (mMode) { case Mode::RightShoulder: