From 4d206d2c678a56c98ebfdd812a1216681fe3714a Mon Sep 17 00:00:00 2001 From: Petr Mikheev Date: Sat, 27 Jun 2020 00:58:33 +0200 Subject: [PATCH 1/7] Improved preview mode --- apps/openmw/mwbase/world.hpp | 2 + apps/openmw/mwinput/actionmanager.cpp | 24 ++++++--- apps/openmw/mwinput/inputmanagerimp.cpp | 3 ++ apps/openmw/mwinput/mousemanager.cpp | 7 ++- apps/openmw/mwinput/sensormanager.cpp | 5 +- apps/openmw/mwrender/camera.cpp | 66 ++++++++++++----------- apps/openmw/mwrender/camera.hpp | 5 ++ apps/openmw/mwrender/renderingmanager.cpp | 55 ++++++++++++++++++- apps/openmw/mwrender/renderingmanager.hpp | 8 +++ apps/openmw/mwrender/viewovershoulder.cpp | 13 +++-- apps/openmw/mwworld/worldimp.cpp | 10 ++++ apps/openmw/mwworld/worldimp.hpp | 3 ++ files/settings-default.cfg | 4 ++ 13 files changed, 157 insertions(+), 48 deletions(-) diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 627e2f2b7..17e233053 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -422,6 +422,8 @@ namespace MWBase virtual void changeVanityModeScale(float factor) = 0; virtual bool vanityRotateCamera(float * rot) = 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 renderPlayer() = 0; diff --git a/apps/openmw/mwinput/actionmanager.cpp b/apps/openmw/mwinput/actionmanager.cpp index f2af3089d..bbfad1fdd 100644 --- a/apps/openmw/mwinput/actionmanager.cpp +++ b/apps/openmw/mwinput/actionmanager.cpp @@ -110,23 +110,31 @@ namespace MWInput if (MWBase::Environment::get().getInputManager()->getControlSwitch("playerviewswitch")) { + static const bool separatePreviewCamera = Settings::Manager::getBool("separate preview camera", "Camera"); if (mBindingsManager->actionIsActive(A_TogglePOV)) { - if (mPreviewPOVDelay <= 0.5 && - (mPreviewPOVDelay += dt) > 0.5) + if (separatePreviewCamera) { - mPreviewPOVDelay = 1.f; - MWBase::Environment::get().getWorld()->togglePreviewMode(true); + if (mPreviewPOVDelay <= 0.5 && (mPreviewPOVDelay += dt) > 0.5) + { + mPreviewPOVDelay = 1.f; + MWBase::Environment::get().getWorld()->togglePreviewMode(true); + } + } + else + { + if (mPreviewPOVDelay == 0) + MWBase::Environment::get().getWorld()->togglePreviewMode(true); + mPreviewPOVDelay += dt; } } else { //disable preview mode - MWBase::Environment::get().getWorld()->togglePreviewMode(false); - if (mPreviewPOVDelay > 0.f && mPreviewPOVDelay <= 0.5) - { + if (mPreviewPOVDelay > 0 || separatePreviewCamera) + MWBase::Environment::get().getWorld()->togglePreviewMode(false); + if (mPreviewPOVDelay > 0.f && mPreviewPOVDelay <= (separatePreviewCamera ? 0.5 : 0.25)) MWBase::Environment::get().getWorld()->togglePOV(); - } mPreviewPOVDelay = 0.f; } } diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 79541fbe4..690183c57 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -9,6 +9,7 @@ #include "../mwbase/windowmanager.hpp" #include "../mwbase/environment.hpp" +#include "../mwbase/world.hpp" #include "../mwworld/esmstore.hpp" @@ -101,6 +102,8 @@ namespace MWInput mMouseManager->update(dt); mSensorManager->update(dt); mActionManager->update(dt, controllerMove); + + MWBase::Environment::get().getWorld()->applyDeferredPreviewRotationToPlayer(dt); } void InputManager::setDragDrop(bool dragDrop) diff --git a/apps/openmw/mwinput/mousemanager.cpp b/apps/openmw/mwinput/mousemanager.cpp index 3fef62345..5a0446093 100644 --- a/apps/openmw/mwinput/mousemanager.cpp +++ b/apps/openmw/mwinput/mousemanager.cpp @@ -108,6 +108,8 @@ namespace MWInput player.yaw(x); 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 { @@ -212,12 +214,15 @@ namespace MWInput rot[2] = xAxis * dt * 1000.0f * mCameraSensitivity * (mInvertX ? -1 : 1) / 256.f; // 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(); player.yaw(rot[2]); player.pitch(rot[0]); } + else if (!controls) + MWBase::Environment::get().getWorld()->disableDeferredPreviewRotation(); MWBase::Environment::get().getInputManager()->resetIdleTime(); } diff --git a/apps/openmw/mwinput/sensormanager.cpp b/apps/openmw/mwinput/sensormanager.cpp index f3c2c2305..5a3d8847b 100644 --- a/apps/openmw/mwinput/sensormanager.cpp +++ b/apps/openmw/mwinput/sensormanager.cpp @@ -254,12 +254,15 @@ namespace MWInput rot[2] = mGyroXSpeed * dt * mGyroHSensitivity * 4 * (mInvertX ? -1 : 1); // 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(); player.yaw(rot[2]); player.pitch(rot[0]); } + else if (!playerLooking) + MWBase::Environment::get().getWorld()->disableDeferredPreviewRotation(); MWBase::Environment::get().getInputManager()->resetIdleTime(); } diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp index 7c43a522c..787e016ef 100644 --- a/apps/openmw/mwrender/camera.cpp +++ b/apps/openmw/mwrender/camera.cpp @@ -58,6 +58,7 @@ namespace MWRender mIsNearest(false), mHeight(124.f), mBaseCameraDistance(Settings::Manager::getFloat("third person camera distance", "Camera")), + mUseSeparatePreviewCam(Settings::Manager::getBool("separate preview camera", "Camera")), mVanityToggleQueued(false), mVanityToggleQueuedValue(false), mViewModeToggleQueued(false), @@ -126,7 +127,7 @@ namespace MWRender osg::Vec3d Camera::getFocalPointOffset() const { osg::Vec3d offset(0, 0, 10.f); - if (!mPreviewMode && !mVanity.enabled) + if (!mUseSeparatePreviewCam || (!mPreviewMode && !mVanity.enabled)) { offset.x() += mFocalPointCurrentOffset.x() * cos(getYaw()); offset.y() += mFocalPointCurrentOffset.x() * sin(getYaw()); @@ -322,17 +323,19 @@ namespace MWRender processViewChange(); - float offset = mPreviewCam.offset; - - if (mVanity.enabled) { - setPitch(osg::DegreesToRadians(-30.f)); - mMainCam.offset = mCameraDistance; - } else { - offset = mMainCam.offset; + if (mUseSeparatePreviewCam) + { + float offset = mPreviewCam.offset; + if (mVanity.enabled) + { + setPitch(osg::DegreesToRadians(-30.f)); + mMainCam.offset = mCameraDistance; + } + else + offset = mMainCam.offset; + mCameraDistance = offset; } - mCameraDistance = offset; - return true; } @@ -347,16 +350,18 @@ namespace MWRender mPreviewMode = enable; processViewChange(); - float offset = mCameraDistance; - if (mPreviewMode) { - mMainCam.offset = offset; - offset = mPreviewCam.offset; - } else { - mPreviewCam.offset = offset; - offset = mMainCam.offset; + if (mUseSeparatePreviewCam) + { + float offset = mCameraDistance; + if (mPreviewMode) { + mMainCam.offset = offset; + offset = mPreviewCam.offset; + } else { + mPreviewCam.offset = offset; + offset = mMainCam.offset; + } + mCameraDistance = offset; } - - mCameraDistance = offset; } void Camera::setSneakOffset(float offset) @@ -366,7 +371,7 @@ namespace MWRender float Camera::getYaw() const { - if(mVanity.enabled || mPreviewMode) + if (mUseSeparatePreviewCam && (mVanity.enabled || mPreviewMode)) return mPreviewCam.yaw; return mMainCam.yaw; } @@ -378,18 +383,16 @@ namespace MWRender } else if (angle < -osg::PI) { angle += osg::PI*2; } - if (mVanity.enabled || mPreviewMode) { + if (mUseSeparatePreviewCam && (mVanity.enabled || mPreviewMode)) mPreviewCam.yaw = angle; - } else { + else mMainCam.yaw = angle; - } } float Camera::getPitch() const { - if (mVanity.enabled || mPreviewMode) { + if (mUseSeparatePreviewCam && (mVanity.enabled || mPreviewMode)) return mPreviewCam.pitch; - } return mMainCam.pitch; } @@ -397,7 +400,7 @@ namespace MWRender { const float epsilon = 0.000001f; float limit = osg::PI_2 - epsilon; - if(mPreviewMode) + if(mUseSeparatePreviewCam && mPreviewMode) limit /= 2; if(angle > limit) @@ -405,11 +408,10 @@ namespace MWRender else if(angle < -limit) angle = -limit; - if (mVanity.enabled || mPreviewMode) { + if (mUseSeparatePreviewCam && (mVanity.enabled || mPreviewMode)) mPreviewCam.pitch = angle; - } else { + else mMainCam.pitch = angle; - } } float Camera::getCameraDistance() const @@ -428,7 +430,7 @@ namespace MWRender if (adjust) { - if (mVanity.enabled || mPreviewMode) + if (mUseSeparatePreviewCam && (mVanity.enabled || mPreviewMode)) dist += mCameraDistance; else dist += std::min(mCameraDistance - getCameraDistanceCorrection(), mBaseCameraDistance); @@ -443,7 +445,7 @@ namespace MWRender mIsNearest = true; } - if (mVanity.enabled || mPreviewMode) + if (mUseSeparatePreviewCam && (mVanity.enabled || mPreviewMode)) mPreviewCam.offset = dist; else if (!mFirstPersonView) { @@ -482,7 +484,7 @@ namespace MWRender void Camera::setCameraDistance() { - if (mVanity.enabled || mPreviewMode) + if (mUseSeparatePreviewCam && (mVanity.enabled || mPreviewMode)) mCameraDistance = mPreviewCam.offset; else if (!mFirstPersonView) { diff --git a/apps/openmw/mwrender/camera.hpp b/apps/openmw/mwrender/camera.hpp index d1acb814c..fb83cf4d3 100644 --- a/apps/openmw/mwrender/camera.hpp +++ b/apps/openmw/mwrender/camera.hpp @@ -48,6 +48,7 @@ namespace MWRender float mHeight, mBaseCameraDistance; CamData mMainCam, mPreviewCam; + bool mUseSeparatePreviewCam; bool mVanityToggleQueued; bool mVanityToggleQueuedValue; @@ -115,6 +116,9 @@ namespace MWRender bool toggleVanityMode(bool enable); void allowVanityMode(bool allow); + void useSeparatePreviewCamera(bool v) { mUseSeparatePreviewCam = v; } + bool isUsingSeparatePreviewCamera() const { return mUseSeparatePreviewCam; } + /// @note this may be ignored if an important animation is currently playing void togglePreviewMode(bool enable); @@ -152,6 +156,7 @@ namespace MWRender void getPosition(osg::Vec3d &focal, osg::Vec3d &camera) const; bool isVanityOrPreviewModeEnabled() const; + bool isVanityModeEnabled() const { return mVanity.enabled; } bool isNearest() const; }; diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index d91da5a08..46b573b2e 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -58,6 +58,7 @@ #include "../mwgui/loadingscreen.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwmechanics/movement.hpp" #include "sky.hpp" #include "effectmanager.hpp" @@ -203,6 +204,8 @@ namespace MWRender , mNightEyeFactor(0.f) , mFieldOfViewOverridden(false) , mFieldOfViewOverride(0.f) + , mDeferredRotation(osg::Vec3f()) + , mDeferredRotationDisabled(false) { resourceSystem->getSceneManager()->setParticleSystemMask(MWRender::Mask_ParticleSystem); resourceSystem->getSceneManager()->setShaderPath(resourcePath + "/shaders"); @@ -653,7 +656,8 @@ namespace MWRender if(ptr == mCamera->getTrackingPtr() && !mCamera->isVanityOrPreviewModeEnabled()) { - mCamera->rotateCamera(-ptr.getRefData().getPosition().rot[0], -ptr.getRefData().getPosition().rot[2], false); + mCamera->rotateCamera(-ptr.getRefData().getPosition().rot[0] - mDeferredRotation.x(), + -ptr.getRefData().getPosition().rot[2] - mDeferredRotation.z(), false); } ptr.getRefData().getBaseNode()->setAttitude(rot); @@ -1324,6 +1328,50 @@ namespace MWRender return true; } + void RenderingManager::applyDeferredPreviewRotationToPlayer(float dt) + { + MWWorld::Ptr ptr = mCamera->getTrackingPtr(); + if (mCamera->isVanityOrPreviewModeEnabled() || ptr.isEmpty()) + return; + + osg::Vec3f rot = mDeferredRotation; + float delta = rot.normalize(); + delta = std::min(delta, (delta + 1.f) * 3 * dt); + rot *= delta; + mDeferredRotation -= rot; + + auto& movement = ptr.getClass().getMovementSettings(ptr); + movement.mRotation[0] += rot.x(); + movement.mRotation[1] += rot.y(); + movement.mRotation[2] += rot.z(); + } + + void RenderingManager::calculateDeferredRotation() + { + MWWorld::Ptr ptr = mCamera->getTrackingPtr(); + if (mCamera->isVanityOrPreviewModeEnabled() || mCamera->isUsingSeparatePreviewCamera() || ptr.isEmpty()) + return; + if (mCamera->isFirstPerson() || mDeferredRotationDisabled) + { + mDeferredRotationDisabled = false; + mDeferredRotation = osg::Vec3f(); + mCamera->rotateCamera(-ptr.getRefData().getPosition().rot[0], + -ptr.getRefData().getPosition().rot[2], false); + return; + } + + mDeferredRotation.x() = -ptr.getRefData().getPosition().rot[0] - mCamera->getPitch(); + mDeferredRotation.z() = -ptr.getRefData().getPosition().rot[2] - mCamera->getYaw(); + 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; + } + void RenderingManager::setCameraDistance(float dist, bool adjust, bool override) { if(!mCamera->isVanityOrPreviewModeEnabled() && !mCamera->isFirstPerson()) @@ -1373,11 +1421,14 @@ namespace MWRender void RenderingManager::togglePreviewMode(bool enable) { mCamera->togglePreviewMode(enable); + calculateDeferredRotation(); } bool RenderingManager::toggleVanityMode(bool enable) { - return mCamera->toggleVanityMode(enable); + bool res = mCamera->toggleVanityMode(enable); + calculateDeferredRotation(); + return res; } void RenderingManager::allowVanityMode(bool allow) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index d6a0f89c3..000826caa 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -221,6 +221,9 @@ namespace MWRender void allowVanityMode(bool allow); void changeVanityModeScale(float factor); + void applyDeferredPreviewRotationToPlayer(float dt); + void disableDeferredPreviewRotation() { mDeferredRotationDisabled = true; } + /// temporarily override the field of view with given value. void overrideFieldOfView(float val); /// reset a previous overrideFieldOfView() call, i.e. revert to field of view specified in the settings file. @@ -310,6 +313,11 @@ namespace MWRender float mFieldOfView; float mFirstPersonFieldOfView; + // Used to rotate player to the direction of view after exiting preview or vanity mode. + osg::Vec3f mDeferredRotation; + bool mDeferredRotationDisabled; + void calculateDeferredRotation(); + void operator = (const RenderingManager&); RenderingManager(const RenderingManager&); }; diff --git a/apps/openmw/mwrender/viewovershoulder.cpp b/apps/openmw/mwrender/viewovershoulder.cpp index 5d7ec7117..12f47b5f7 100644 --- a/apps/openmw/mwrender/viewovershoulder.cpp +++ b/apps/openmw/mwrender/viewovershoulder.cpp @@ -33,12 +33,13 @@ namespace MWRender void ViewOverShoulderController::update() { - if (mCamera->isVanityOrPreviewModeEnabled() || mCamera->isFirstPerson()) + if (mCamera->isFirstPerson()) return; Mode oldMode = mMode; 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; else if (MWBase::Environment::get().getWorld()->isSwimming(ptr)) mMode = Mode::Swimming; @@ -46,9 +47,13 @@ namespace MWRender 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) + if (oldMode == mMode) + return; + + if (mCamera->isVanityOrPreviewModeEnabled()) + mCamera->setFocalPointTransitionSpeed(mCamera->isVanityModeEnabled() ? 0.2 : 1); + else if (oldMode == Mode::Combat || mMode == Mode::Combat) mCamera->setFocalPointTransitionSpeed(5.f); else mCamera->setFocalPointTransitionSpeed(1.f); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 6e459d5e2..423c55732 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2405,6 +2405,16 @@ namespace MWWorld return mRendering->toggleVanityMode(enable); } + void World::disableDeferredPreviewRotation() + { + mRendering->disableDeferredPreviewRotation(); + } + + void World::applyDeferredPreviewRotationToPlayer(float dt) + { + mRendering->applyDeferredPreviewRotationToPlayer(dt); + } + void World::allowVanityMode(bool allow) { mRendering->allowVanityMode(allow); diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index aeb6bbae4..c08206600 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -536,6 +536,9 @@ namespace MWWorld bool vanityRotateCamera(float * rot) override; void setCameraDistance(float dist, bool adjust = false, bool override = true) override; + void applyDeferredPreviewRotationToPlayer(float dt) override; + void disableDeferredPreviewRotation() override; + void setupPlayer() override; void renderPlayer() override; diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 35be128a8..e4ef28f02 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -33,6 +33,10 @@ field of view = 60.0 # Best to leave this at the default since vanilla assets are not complete enough to adapt to high FoV's. Too low FoV would clip the hands off screen. first person field of view = 60.0 +# true - standard bahaviour of preview and vanity camera +# false - smooth preview mode +separate preview camera = true + # Distance from the camera to the character in third person mode. third person camera distance = 192 From 8ac7ffc32bef80cfa424f3d4f94f480ef647ee1a Mon Sep 17 00:00:00 2001 From: Petr Mikheev Date: Fri, 17 Jul 2020 01:11:09 +0200 Subject: [PATCH 2/7] Remove 'separate preview camera' and make the new behavior the default one. Also minor refactoring in camera.cpp --- apps/openmw/mwinput/actionmanager.cpp | 22 +--- apps/openmw/mwrender/camera.cpp | 146 +++------------------- apps/openmw/mwrender/camera.hpp | 20 +-- apps/openmw/mwrender/renderingmanager.cpp | 2 +- files/settings-default.cfg | 4 - 5 files changed, 32 insertions(+), 162 deletions(-) diff --git a/apps/openmw/mwinput/actionmanager.cpp b/apps/openmw/mwinput/actionmanager.cpp index bbfad1fdd..ddde7a11e 100644 --- a/apps/openmw/mwinput/actionmanager.cpp +++ b/apps/openmw/mwinput/actionmanager.cpp @@ -110,30 +110,18 @@ namespace MWInput if (MWBase::Environment::get().getInputManager()->getControlSwitch("playerviewswitch")) { - static const bool separatePreviewCamera = Settings::Manager::getBool("separate preview camera", "Camera"); if (mBindingsManager->actionIsActive(A_TogglePOV)) { - if (separatePreviewCamera) - { - if (mPreviewPOVDelay <= 0.5 && (mPreviewPOVDelay += dt) > 0.5) - { - mPreviewPOVDelay = 1.f; - MWBase::Environment::get().getWorld()->togglePreviewMode(true); - } - } - else - { - if (mPreviewPOVDelay == 0) - MWBase::Environment::get().getWorld()->togglePreviewMode(true); - mPreviewPOVDelay += dt; - } + if (mPreviewPOVDelay == 0) + MWBase::Environment::get().getWorld()->togglePreviewMode(true); + mPreviewPOVDelay += dt; } else { //disable preview mode - if (mPreviewPOVDelay > 0 || separatePreviewCamera) + if (mPreviewPOVDelay > 0) MWBase::Environment::get().getWorld()->togglePreviewMode(false); - if (mPreviewPOVDelay > 0.f && mPreviewPOVDelay <= (separatePreviewCamera ? 0.5 : 0.25)) + if (mPreviewPOVDelay > 0.f && mPreviewPOVDelay <= 0.25) MWBase::Environment::get().getWorld()->togglePOV(); mPreviewPOVDelay = 0.f; } diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp index 787e016ef..a674643d8 100644 --- a/apps/openmw/mwrender/camera.cpp +++ b/apps/openmw/mwrender/camera.cpp @@ -58,7 +58,6 @@ namespace MWRender mIsNearest(false), mHeight(124.f), mBaseCameraDistance(Settings::Manager::getFloat("third person camera distance", "Camera")), - mUseSeparatePreviewCam(Settings::Manager::getBool("separate preview camera", "Camera")), mVanityToggleQueued(false), mVanityToggleQueuedValue(false), mViewModeToggleQueued(false), @@ -77,13 +76,6 @@ namespace MWRender mVanity.enabled = false; mVanity.allowed = true; - mPreviewCam.pitch = 0.f; - mPreviewCam.yaw = 0.f; - mPreviewCam.offset = 400.f; - mMainCam.pitch = 0.f; - mMainCam.yaw = 0.f; - mMainCam.offset = 400.f; - mCameraDistance = mBaseCameraDistance; mUpdateCallback = new UpdateRenderCameraCallback(this); @@ -95,17 +87,11 @@ namespace MWRender mCamera->removeUpdateCallback(mUpdateCallback); } - MWWorld::Ptr Camera::getTrackingPtr() const - { - return mTrackingPtr; - } - osg::Vec3d Camera::getFocalPoint() const { - const osg::Node* trackNode = mTrackingNode; - if (!trackNode) + if (!mTrackingNode) return osg::Vec3d(); - osg::NodePathList nodepaths = trackNode->getParentalNodePaths(); + osg::NodePathList nodepaths = mTrackingNode->getParentalNodePaths(); if (nodepaths.empty()) return osg::Vec3d(); osg::Matrix worldMat = osg::computeLocalToWorld(nodepaths[0]); @@ -127,12 +113,9 @@ namespace MWRender osg::Vec3d Camera::getFocalPointOffset() const { osg::Vec3d offset(0, 0, 10.f); - if (!mUseSeparatePreviewCam || (!mPreviewMode && !mVanity.enabled)) - { - offset.x() += mFocalPointCurrentOffset.x() * cos(getYaw()); - offset.y() += mFocalPointCurrentOffset.x() * sin(getYaw()); - offset.z() += mFocalPointCurrentOffset.y(); - } + offset.x() += mFocalPointCurrentOffset.x() * cos(getYaw()); + offset.y() += mFocalPointCurrentOffset.x() * sin(getYaw()); + offset.z() += mFocalPointCurrentOffset.y(); return offset; } @@ -199,7 +182,6 @@ namespace MWRender } if (mViewModeToggleQueued) { - togglePreviewMode(false); toggleViewMode(); mViewModeToggleQueued = false; @@ -295,7 +277,7 @@ namespace MWRender mFirstPersonView = !mFirstPersonView; processViewChange(); } - + void Camera::allowVanityMode(bool allow) { if (!allow && mVanity.enabled) @@ -322,20 +304,6 @@ namespace MWRender mVanity.enabled = enable; processViewChange(); - - if (mUseSeparatePreviewCam) - { - float offset = mPreviewCam.offset; - if (mVanity.enabled) - { - setPitch(osg::DegreesToRadians(-30.f)); - mMainCam.offset = mCameraDistance; - } - else - offset = mMainCam.offset; - mCameraDistance = offset; - } - return true; } @@ -349,19 +317,6 @@ namespace MWRender mPreviewMode = enable; processViewChange(); - - if (mUseSeparatePreviewCam) - { - float offset = mCameraDistance; - if (mPreviewMode) { - mMainCam.offset = offset; - offset = mPreviewCam.offset; - } else { - mPreviewCam.offset = offset; - offset = mMainCam.offset; - } - mCameraDistance = offset; - } } void Camera::setSneakOffset(float offset) @@ -369,13 +324,6 @@ namespace MWRender mAnimation->setFirstPersonOffset(osg::Vec3f(0,0,-offset)); } - float Camera::getYaw() const - { - if (mUseSeparatePreviewCam && (mVanity.enabled || mPreviewMode)) - return mPreviewCam.yaw; - return mMainCam.yaw; - } - void Camera::setYaw(float angle) { if (angle > osg::PI) { @@ -383,35 +331,14 @@ namespace MWRender } else if (angle < -osg::PI) { angle += osg::PI*2; } - if (mUseSeparatePreviewCam && (mVanity.enabled || mPreviewMode)) - mPreviewCam.yaw = angle; - else - mMainCam.yaw = angle; - } - - float Camera::getPitch() const - { - if (mUseSeparatePreviewCam && (mVanity.enabled || mPreviewMode)) - return mPreviewCam.pitch; - return mMainCam.pitch; + mYaw = angle; } void Camera::setPitch(float angle) { const float epsilon = 0.000001f; float limit = osg::PI_2 - epsilon; - if(mUseSeparatePreviewCam && mPreviewMode) - limit /= 2; - - if(angle > limit) - angle = limit; - else if(angle < -limit) - angle = -limit; - - if (mUseSeparatePreviewCam && (mVanity.enabled || mPreviewMode)) - mPreviewCam.pitch = angle; - else - mMainCam.pitch = angle; + mPitch = osg::clampBetween(angle, -limit, limit); } float Camera::getCameraDistance() const @@ -426,28 +353,13 @@ namespace MWRender if(mFirstPersonView && !mPreviewMode && !mVanity.enabled) return; - mIsNearest = false; - if (adjust) - { - if (mUseSeparatePreviewCam && (mVanity.enabled || mPreviewMode)) - dist += mCameraDistance; - else - dist += std::min(mCameraDistance - getCameraDistanceCorrection(), mBaseCameraDistance); - } - + dist += std::min(mCameraDistance - getCameraDistanceCorrection(), mBaseCameraDistance); - if (dist >= mFurthest) - dist = mFurthest; - else if (dist <= mNearest) - { - dist = mNearest; - mIsNearest = true; - } + mIsNearest = dist <= mNearest; + dist = osg::clampBetween(dist, mNearest, mFurthest); - if (mUseSeparatePreviewCam && (mVanity.enabled || mPreviewMode)) - mPreviewCam.offset = dist; - else if (!mFirstPersonView) + if (!mFirstPersonView) { mBaseCameraDistance = dist; Settings::Manager::setFloat("third person camera distance", "Camera", dist); @@ -459,14 +371,9 @@ namespace MWRender { if(mFirstPersonView && !mPreviewMode && !mVanity.enabled) return; - - if (adjust) dist += mCameraDistance; - - if (dist >= mFurthest) - dist = mFurthest; - else if (dist < 10.f) - dist = 10.f; - mCameraDistance = dist; + if (adjust) + dist += mCameraDistance; + mCameraDistance = osg::clampBetween(dist, 10.f, mFurthest); } float Camera::getCameraDistanceCorrection() const @@ -484,21 +391,17 @@ namespace MWRender void Camera::setCameraDistance() { - if (mUseSeparatePreviewCam && (mVanity.enabled || mPreviewMode)) - mCameraDistance = mPreviewCam.offset; - else if (!mFirstPersonView) - { - mCameraDistance = mBaseCameraDistance + getCameraDistanceCorrection(); - if (mDynamicCameraDistanceEnabled) - mCameraDistance = std::min(mCameraDistance, mMaxNextCameraDistance); - } mFocalPointAdjustment = osg::Vec3d(); + if (mFirstPersonView) + return; + mCameraDistance = mBaseCameraDistance + getCameraDistanceCorrection(); + if (mDynamicCameraDistanceEnabled) + mCameraDistance = std::min(mCameraDistance, mMaxNextCameraDistance); } void Camera::setAnimation(NpcAnimation *anim) { mAnimation = anim; - processViewChange(); } @@ -525,13 +428,4 @@ namespace MWRender rotateCamera(getPitch(), getYaw(), false); } - bool Camera::isVanityOrPreviewModeEnabled() const - { - return mPreviewMode || mVanity.enabled; - } - - bool Camera::isNearest() const - { - return mIsNearest; - } } diff --git a/apps/openmw/mwrender/camera.hpp b/apps/openmw/mwrender/camera.hpp index fb83cf4d3..1701be375 100644 --- a/apps/openmw/mwrender/camera.hpp +++ b/apps/openmw/mwrender/camera.hpp @@ -24,10 +24,6 @@ namespace MWRender class Camera { private: - struct CamData { - float pitch, yaw, offset; - }; - MWWorld::Ptr mTrackingPtr; osg::ref_ptr mTrackingNode; float mHeightScale; @@ -47,8 +43,7 @@ namespace MWRender } mVanity; float mHeight, mBaseCameraDistance; - CamData mMainCam, mPreviewCam; - bool mUseSeparatePreviewCam; + float mPitch, mYaw; bool mVanityToggleQueued; bool mVanityToggleQueuedValue; @@ -83,7 +78,7 @@ namespace MWRender Camera(osg::Camera* camera); ~Camera(); - MWWorld::Ptr getTrackingPtr() const; + MWWorld::Ptr getTrackingPtr() const { return mTrackingPtr; } void setFocalPointTransitionSpeed(float v) { mFocalPointTransitionSpeedCoef = v; } void setFocalPointTargetOffset(osg::Vec2d v); @@ -101,10 +96,10 @@ namespace MWRender /// \param rot Rotation angles in radians void rotateCamera(float pitch, float yaw, bool adjust); - float getYaw() const; + float getYaw() const { return mYaw; } void setYaw(float angle); - float getPitch() const; + float getPitch() const { return mPitch; } void setPitch(float angle); /// Attach camera to object @@ -116,9 +111,6 @@ namespace MWRender bool toggleVanityMode(bool enable); void allowVanityMode(bool allow); - void useSeparatePreviewCamera(bool v) { mUseSeparatePreviewCam = v; } - bool isUsingSeparatePreviewCamera() const { return mUseSeparatePreviewCam; } - /// @note this may be ignored if an important animation is currently playing void togglePreviewMode(bool enable); @@ -155,10 +147,10 @@ namespace MWRender /// Stores focal and camera world positions in passed arguments void getPosition(osg::Vec3d &focal, osg::Vec3d &camera) const; - bool isVanityOrPreviewModeEnabled() const; + bool isVanityOrPreviewModeEnabled() const { return mPreviewMode || mVanity.enabled; } bool isVanityModeEnabled() const { return mVanity.enabled; } - bool isNearest() const; + bool isNearest() const { return mIsNearest; } }; } diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 46b573b2e..e4150eebc 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -1349,7 +1349,7 @@ namespace MWRender void RenderingManager::calculateDeferredRotation() { MWWorld::Ptr ptr = mCamera->getTrackingPtr(); - if (mCamera->isVanityOrPreviewModeEnabled() || mCamera->isUsingSeparatePreviewCamera() || ptr.isEmpty()) + if (mCamera->isVanityOrPreviewModeEnabled() || ptr.isEmpty()) return; if (mCamera->isFirstPerson() || mDeferredRotationDisabled) { diff --git a/files/settings-default.cfg b/files/settings-default.cfg index e4ef28f02..35be128a8 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -33,10 +33,6 @@ field of view = 60.0 # Best to leave this at the default since vanilla assets are not complete enough to adapt to high FoV's. Too low FoV would clip the hands off screen. first person field of view = 60.0 -# true - standard bahaviour of preview and vanity camera -# false - smooth preview mode -separate preview camera = true - # Distance from the camera to the character in third person mode. third person camera distance = 192 From 63cab4052d370bf099d43494fc3136f6b2b5c9ab Mon Sep 17 00:00:00 2001 From: Petr Mikheev Date: Sat, 18 Jul 2020 10:27:13 +0200 Subject: [PATCH 3/7] Refactoring in mwrender::Camera. enum for normal/preview/vanity mode. --- apps/openmw/mwrender/camera.cpp | 49 ++++++++--------------- apps/openmw/mwrender/camera.hpp | 23 +++++------ apps/openmw/mwrender/viewovershoulder.cpp | 12 +++--- 3 files changed, 34 insertions(+), 50 deletions(-) diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp index a674643d8..16deed878 100644 --- a/apps/openmw/mwrender/camera.cpp +++ b/apps/openmw/mwrender/camera.cpp @@ -52,7 +52,8 @@ namespace MWRender mCamera(camera), mAnimation(nullptr), mFirstPersonView(true), - mPreviewMode(false), + mMode(Mode::Normal), + mVanityAllowed(true), mNearest(30.f), mFurthest(800.f), mIsNearest(false), @@ -73,9 +74,6 @@ namespace MWRender mDynamicCameraDistanceEnabled(false), mShowCrosshairInThirdPersonMode(false) { - mVanity.enabled = false; - mVanity.allowed = true; - mCameraDistance = mBaseCameraDistance; mUpdateCallback = new UpdateRenderCameraCallback(this); @@ -133,9 +131,6 @@ namespace MWRender void Camera::updateCamera(osg::Camera *cam) { - if (mTrackingPtr.isEmpty()) - return; - osg::Vec3d focal, position; getPosition(focal, position); @@ -165,11 +160,6 @@ namespace MWRender setPitch(pitch); } - void Camera::attachTo(const MWWorld::Ptr &ptr) - { - mTrackingPtr = ptr; - } - void Camera::update(float duration, bool paused) { if (mAnimation->upperBodyReady()) @@ -193,13 +183,11 @@ namespace MWRender // only show the crosshair in game mode 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)); - if(mVanity.enabled) - { + if(mMode == Mode::Vanity) rotateCamera(0.f, osg::DegreesToRadians(3.f * duration), true); - } updateFocalPointOffset(duration); @@ -280,9 +268,9 @@ namespace MWRender void Camera::allowVanityMode(bool allow) { - if (!allow && mVanity.enabled) + if (!allow && mMode == Mode::Vanity) toggleVanityMode(false); - mVanity.allowed = allow; + mVanityAllowed = allow; } bool Camera::toggleVanityMode(bool enable) @@ -296,12 +284,12 @@ namespace MWRender return false; } - if(!mVanity.allowed && enable) + if (!mVanityAllowed && enable) return false; - if(mVanity.enabled == enable) + if ((mMode == Mode::Vanity) == enable) return true; - mVanity.enabled = enable; + mMode = enable ? Mode::Vanity : Mode::Normal; processViewChange(); return true; @@ -312,10 +300,10 @@ namespace MWRender if (mFirstPersonView && !mAnimation->upperBodyReady()) return; - if(mPreviewMode == enable) + if((mMode == Mode::Preview) == enable) return; - mPreviewMode = enable; + mMode = enable ? Mode::Preview : Mode::Normal; processViewChange(); } @@ -350,26 +338,21 @@ namespace MWRender void Camera::updateBaseCameraDistance(float dist, bool adjust) { - if(mFirstPersonView && !mPreviewMode && !mVanity.enabled) + if (isFirstPerson()) return; if (adjust) dist += std::min(mCameraDistance - getCameraDistanceCorrection(), mBaseCameraDistance); mIsNearest = dist <= mNearest; - dist = osg::clampBetween(dist, mNearest, mFurthest); - - if (!mFirstPersonView) - { - mBaseCameraDistance = dist; - Settings::Manager::setFloat("third person camera distance", "Camera", dist); - } + mBaseCameraDistance = osg::clampBetween(dist, mNearest, mFurthest); + Settings::Manager::setFloat("third person camera distance", "Camera", mBaseCameraDistance); setCameraDistance(); } void Camera::setCameraDistance(float dist, bool adjust) { - if(mFirstPersonView && !mPreviewMode && !mVanity.enabled) + if (isFirstPerson()) return; if (adjust) dist += mCameraDistance; @@ -392,7 +375,7 @@ namespace MWRender void Camera::setCameraDistance() { mFocalPointAdjustment = osg::Vec3d(); - if (mFirstPersonView) + if (isFirstPerson()) return; mCameraDistance = mBaseCameraDistance + getCameraDistanceCorrection(); if (mDynamicCameraDistanceEnabled) diff --git a/apps/openmw/mwrender/camera.hpp b/apps/openmw/mwrender/camera.hpp index 1701be375..4c5523974 100644 --- a/apps/openmw/mwrender/camera.hpp +++ b/apps/openmw/mwrender/camera.hpp @@ -23,6 +23,9 @@ namespace MWRender /// \brief Camera control class Camera { + public: + enum class Mode { Normal, Vanity, Preview }; + private: MWWorld::Ptr mTrackingPtr; osg::ref_ptr mTrackingNode; @@ -33,15 +36,13 @@ namespace MWRender NpcAnimation *mAnimation; bool mFirstPersonView; - bool mPreviewMode; + Mode mMode; + bool mVanityAllowed; + float mNearest; float mFurthest; bool mIsNearest; - struct { - bool enabled, allowed; - } mVanity; - float mHeight, mBaseCameraDistance; float mPitch, mYaw; @@ -78,6 +79,8 @@ namespace MWRender Camera(osg::Camera* camera); ~Camera(); + /// Attach camera to object + void attachTo(const MWWorld::Ptr &ptr) { mTrackingPtr = ptr; } MWWorld::Ptr getTrackingPtr() const { return mTrackingPtr; } void setFocalPointTransitionSpeed(float v) { mFocalPointTransitionSpeedCoef = v; } @@ -102,9 +105,6 @@ namespace MWRender float getPitch() const { return mPitch; } void setPitch(float angle); - /// Attach camera to object - void attachTo(const MWWorld::Ptr &); - /// @param Force view mode switch, even if currently not allowed by the animation. void toggleViewMode(bool force=false); @@ -117,8 +117,7 @@ namespace MWRender /// \brief Lowers the camera for sneak. void setSneakOffset(float offset); - bool isFirstPerson() const - { return !(mVanity.enabled || mPreviewMode || !mFirstPersonView); } + bool isFirstPerson() const { return mFirstPersonView && mMode == Mode::Normal; } void processViewChange(); @@ -147,8 +146,8 @@ namespace MWRender /// Stores focal and camera world positions in passed arguments void getPosition(osg::Vec3d &focal, osg::Vec3d &camera) const; - bool isVanityOrPreviewModeEnabled() const { return mPreviewMode || mVanity.enabled; } - bool isVanityModeEnabled() const { return mVanity.enabled; } + bool isVanityOrPreviewModeEnabled() const { return mMode != Mode::Normal; } + Mode getMode() const { return mMode; } bool isNearest() const { return mIsNearest; } }; diff --git a/apps/openmw/mwrender/viewovershoulder.cpp b/apps/openmw/mwrender/viewovershoulder.cpp index 12f47b5f7..ceb9407a1 100644 --- a/apps/openmw/mwrender/viewovershoulder.cpp +++ b/apps/openmw/mwrender/viewovershoulder.cpp @@ -51,12 +51,14 @@ namespace MWRender if (oldMode == mMode) return; - if (mCamera->isVanityOrPreviewModeEnabled()) - mCamera->setFocalPointTransitionSpeed(mCamera->isVanityModeEnabled() ? 0.2 : 1); - else if (oldMode == Mode::Combat || mMode == Mode::Combat) + 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); else - mCamera->setFocalPointTransitionSpeed(1.f); + mCamera->setFocalPointTransitionSpeed(1.f); // Default transition speed. switch (mMode) { @@ -98,4 +100,4 @@ namespace MWRender mMode = mDefaultShoulderIsRight ? Mode::RightShoulder : Mode::LeftShoulder; } -} \ No newline at end of file +} From 9f850b6ffcedaa946251a5551cca16992e7731f3 Mon Sep 17 00:00:00 2001 From: Petr Mikheev Date: Sat, 18 Jul 2020 11:48:46 +0200 Subject: [PATCH 4/7] Move deferred rotation logic from renderingmanager.cpp to camera.cpp --- apps/openmw/mwrender/camera.cpp | 69 ++++++++++++++++++++++- apps/openmw/mwrender/camera.hpp | 9 +++ apps/openmw/mwrender/renderingmanager.cpp | 55 +----------------- apps/openmw/mwrender/renderingmanager.hpp | 8 --- apps/openmw/mwworld/worldimp.cpp | 4 +- 5 files changed, 81 insertions(+), 64 deletions(-) diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp index 16deed878..877cb7570 100644 --- a/apps/openmw/mwrender/camera.cpp +++ b/apps/openmw/mwrender/camera.cpp @@ -13,6 +13,7 @@ #include "../mwworld/refdata.hpp" #include "../mwmechanics/drawstate.hpp" +#include "../mwmechanics/movement.hpp" #include "../mwmechanics/npcstats.hpp" #include "npcanimation.hpp" @@ -72,7 +73,9 @@ namespace MWRender mSmoothedSpeed(0.f), mZoomOutWhenMoveCoef(Settings::Manager::getFloat("zoom out when move coef", "Camera")), mDynamicCameraDistanceEnabled(false), - mShowCrosshairInThirdPersonMode(false) + mShowCrosshairInThirdPersonMode(false), + mDeferredRotation(osg::Vec3f()), + mDeferredRotationDisabled(false) { mCameraDistance = mBaseCameraDistance; @@ -269,7 +272,10 @@ namespace MWRender void Camera::allowVanityMode(bool allow) { if (!allow && mMode == Mode::Vanity) + { + disableDeferredPreviewRotation(); toggleVanityMode(false); + } mVanityAllowed = allow; } @@ -290,6 +296,8 @@ namespace MWRender if ((mMode == Mode::Vanity) == enable) return true; mMode = enable ? Mode::Vanity : Mode::Normal; + if (!enable) + calculateDeferredRotation(); processViewChange(); return true; @@ -304,6 +312,8 @@ namespace MWRender return; mMode = enable ? Mode::Preview : Mode::Normal; + if (!enable) + calculateDeferredRotation(); processViewChange(); } @@ -411,4 +421,61 @@ namespace MWRender rotateCamera(getPitch(), getYaw(), false); } + void Camera::applyDeferredPreviewRotationToPlayer(float dt) + { + 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; + + 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; + } + } + + void Camera::rotateCameraToTrackingPtr() + { + setPitch(-mTrackingPtr.getRefData().getPosition().rot[0] - mDeferredRotation.x()); + setYaw(-mTrackingPtr.getRefData().getPosition().rot[2] - mDeferredRotation.z()); + } + + void Camera::calculateDeferredRotation() + { + MWWorld::Ptr ptr = mTrackingPtr; + if (isVanityOrPreviewModeEnabled() || ptr.isEmpty()) + return; + if (isFirstPerson() || mDeferredRotationDisabled) + { + mDeferredRotationDisabled = false; + mDeferredRotation = osg::Vec3f(); + rotateCameraToTrackingPtr(); + 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; + } + } diff --git a/apps/openmw/mwrender/camera.hpp b/apps/openmw/mwrender/camera.hpp index 4c5523974..c5f7ec2b2 100644 --- a/apps/openmw/mwrender/camera.hpp +++ b/apps/openmw/mwrender/camera.hpp @@ -75,6 +75,11 @@ namespace MWRender osg::ref_ptr mUpdateCallback; + // Used to rotate player to the direction of view after exiting preview or vanity mode. + osg::Vec3f mDeferredRotation; + bool mDeferredRotationDisabled; + void calculateDeferredRotation(); + public: Camera(osg::Camera* camera); ~Camera(); @@ -98,6 +103,7 @@ namespace MWRender /// Set where the camera is looking at. Uses Morrowind (euler) angles /// \param rot Rotation angles in radians void rotateCamera(float pitch, float yaw, bool adjust); + void rotateCameraToTrackingPtr(); float getYaw() const { return mYaw; } void setYaw(float angle); @@ -114,6 +120,9 @@ namespace MWRender /// @note this may be ignored if an important animation is currently playing void togglePreviewMode(bool enable); + void applyDeferredPreviewRotationToPlayer(float dt); + void disableDeferredPreviewRotation() { mDeferredRotationDisabled = true; } + /// \brief Lowers the camera for sneak. void setSneakOffset(float offset); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index e4150eebc..d9739e844 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -58,7 +58,6 @@ #include "../mwgui/loadingscreen.hpp" #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" -#include "../mwmechanics/movement.hpp" #include "sky.hpp" #include "effectmanager.hpp" @@ -204,8 +203,6 @@ namespace MWRender , mNightEyeFactor(0.f) , mFieldOfViewOverridden(false) , mFieldOfViewOverride(0.f) - , mDeferredRotation(osg::Vec3f()) - , mDeferredRotationDisabled(false) { resourceSystem->getSceneManager()->setParticleSystemMask(MWRender::Mask_ParticleSystem); resourceSystem->getSceneManager()->setShaderPath(resourcePath + "/shaders"); @@ -656,8 +653,7 @@ namespace MWRender if(ptr == mCamera->getTrackingPtr() && !mCamera->isVanityOrPreviewModeEnabled()) { - mCamera->rotateCamera(-ptr.getRefData().getPosition().rot[0] - mDeferredRotation.x(), - -ptr.getRefData().getPosition().rot[2] - mDeferredRotation.z(), false); + mCamera->rotateCameraToTrackingPtr(); } ptr.getRefData().getBaseNode()->setAttitude(rot); @@ -1328,50 +1324,6 @@ namespace MWRender return true; } - void RenderingManager::applyDeferredPreviewRotationToPlayer(float dt) - { - MWWorld::Ptr ptr = mCamera->getTrackingPtr(); - if (mCamera->isVanityOrPreviewModeEnabled() || ptr.isEmpty()) - return; - - osg::Vec3f rot = mDeferredRotation; - float delta = rot.normalize(); - delta = std::min(delta, (delta + 1.f) * 3 * dt); - rot *= delta; - mDeferredRotation -= rot; - - auto& movement = ptr.getClass().getMovementSettings(ptr); - movement.mRotation[0] += rot.x(); - movement.mRotation[1] += rot.y(); - movement.mRotation[2] += rot.z(); - } - - void RenderingManager::calculateDeferredRotation() - { - MWWorld::Ptr ptr = mCamera->getTrackingPtr(); - if (mCamera->isVanityOrPreviewModeEnabled() || ptr.isEmpty()) - return; - if (mCamera->isFirstPerson() || mDeferredRotationDisabled) - { - mDeferredRotationDisabled = false; - mDeferredRotation = osg::Vec3f(); - mCamera->rotateCamera(-ptr.getRefData().getPosition().rot[0], - -ptr.getRefData().getPosition().rot[2], false); - return; - } - - mDeferredRotation.x() = -ptr.getRefData().getPosition().rot[0] - mCamera->getPitch(); - mDeferredRotation.z() = -ptr.getRefData().getPosition().rot[2] - mCamera->getYaw(); - 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; - } - void RenderingManager::setCameraDistance(float dist, bool adjust, bool override) { if(!mCamera->isVanityOrPreviewModeEnabled() && !mCamera->isFirstPerson()) @@ -1421,14 +1373,11 @@ namespace MWRender void RenderingManager::togglePreviewMode(bool enable) { mCamera->togglePreviewMode(enable); - calculateDeferredRotation(); } bool RenderingManager::toggleVanityMode(bool enable) { - bool res = mCamera->toggleVanityMode(enable); - calculateDeferredRotation(); - return res; + return mCamera->toggleVanityMode(enable); } void RenderingManager::allowVanityMode(bool allow) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index 000826caa..d6a0f89c3 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -221,9 +221,6 @@ namespace MWRender void allowVanityMode(bool allow); void changeVanityModeScale(float factor); - void applyDeferredPreviewRotationToPlayer(float dt); - void disableDeferredPreviewRotation() { mDeferredRotationDisabled = true; } - /// temporarily override the field of view with given value. void overrideFieldOfView(float val); /// reset a previous overrideFieldOfView() call, i.e. revert to field of view specified in the settings file. @@ -313,11 +310,6 @@ namespace MWRender float mFieldOfView; float mFirstPersonFieldOfView; - // Used to rotate player to the direction of view after exiting preview or vanity mode. - osg::Vec3f mDeferredRotation; - bool mDeferredRotationDisabled; - void calculateDeferredRotation(); - void operator = (const RenderingManager&); RenderingManager(const RenderingManager&); }; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 423c55732..ca451601b 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2407,12 +2407,12 @@ namespace MWWorld void World::disableDeferredPreviewRotation() { - mRendering->disableDeferredPreviewRotation(); + mRendering->getCamera()->disableDeferredPreviewRotation(); } void World::applyDeferredPreviewRotationToPlayer(float dt) { - mRendering->applyDeferredPreviewRotationToPlayer(dt); + mRendering->getCamera()->applyDeferredPreviewRotationToPlayer(dt); } void World::allowVanityMode(bool allow) From 2e6aa155a35a8c271b8935f4b95fe65d69afad2d Mon Sep 17 00:00:00 2001 From: Petr Mikheev Date: Sat, 18 Jul 2020 13:27:53 +0200 Subject: [PATCH 5/7] New settings 'preview if stand still' and 'deferred preview rotation'. --- apps/openmw/mwrender/camera.cpp | 52 +++++++++++++++++-- apps/openmw/mwrender/camera.hpp | 7 ++- apps/openmw/mwrender/viewovershoulder.cpp | 3 ++ apps/openmw/mwworld/worldimp.cpp | 4 +- .../reference/modding/settings/camera.rst | 24 +++++++++ files/settings-default.cfg | 6 +++ 6 files changed, 87 insertions(+), 9 deletions(-) diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp index 877cb7570..54bc581ef 100644 --- a/apps/openmw/mwrender/camera.cpp +++ b/apps/openmw/mwrender/camera.cpp @@ -55,6 +55,8 @@ namespace MWRender mFirstPersonView(true), 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), mFurthest(800.f), mIsNearest(false), @@ -200,6 +202,24 @@ namespace MWRender mSmoothedSpeed += osg::clampBetween(speed - mSmoothedSpeed, -maxDelta, maxDelta); 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) @@ -266,6 +286,7 @@ namespace MWRender mTrackingPtr.getClass().getCreatureStats(mTrackingPtr).setSideMovementAngle(0); mFirstPersonView = !mFirstPersonView; + updateStandingPreviewMode(); processViewChange(); } @@ -296,6 +317,8 @@ namespace MWRender if ((mMode == Mode::Vanity) == enable) return true; mMode = enable ? Mode::Vanity : Mode::Normal; + if (!mDeferredRotationAllowed) + disableDeferredPreviewRotation(); if (!enable) calculateDeferredRotation(); @@ -312,8 +335,14 @@ namespace MWRender return; mMode = enable ? Mode::Preview : Mode::Normal; - if (!enable) + if (mMode == Mode::Normal) + updateStandingPreviewMode(); + if (mMode == Mode::Normal) + { + if (!mDeferredRotationAllowed) + disableDeferredPreviewRotation(); calculateDeferredRotation(); + } processViewChange(); } @@ -432,6 +461,13 @@ namespace MWRender 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(); @@ -453,16 +489,22 @@ namespace MWRender 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 (isFirstPerson() || mDeferredRotationDisabled) + if (mFirstPersonView) { - mDeferredRotationDisabled = false; - mDeferredRotation = osg::Vec3f(); - rotateCameraToTrackingPtr(); + instantTransition(); return; } diff --git a/apps/openmw/mwrender/camera.hpp b/apps/openmw/mwrender/camera.hpp index c5f7ec2b2..f2e5c390d 100644 --- a/apps/openmw/mwrender/camera.hpp +++ b/apps/openmw/mwrender/camera.hpp @@ -24,7 +24,7 @@ namespace MWRender class Camera { public: - enum class Mode { Normal, Vanity, Preview }; + enum class Mode { Normal, Vanity, Preview, StandingPreview }; private: MWWorld::Ptr mTrackingPtr; @@ -38,6 +38,8 @@ namespace MWRender bool mFirstPersonView; Mode mMode; bool mVanityAllowed; + bool mStandingPreviewAllowed; + bool mDeferredRotationAllowed; float mNearest; float mFurthest; @@ -79,6 +81,7 @@ namespace MWRender osg::Vec3f mDeferredRotation; bool mDeferredRotationDisabled; void calculateDeferredRotation(); + void updateStandingPreviewMode(); public: Camera(osg::Camera* camera); @@ -90,7 +93,7 @@ namespace MWRender void setFocalPointTransitionSpeed(float v) { mFocalPointTransitionSpeedCoef = v; } void setFocalPointTargetOffset(osg::Vec2d v); - void skipFocalPointTransition() { mSkipFocalPointTransition = true; } + void instantTransition(); 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 ceb9407a1..4d708afe0 100644 --- a/apps/openmw/mwrender/viewovershoulder.cpp +++ b/apps/openmw/mwrender/viewovershoulder.cpp @@ -77,6 +77,9 @@ namespace MWRender 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 limitToSwitchBack = 300; // switch back to default shoulder if there is no walls at this distance diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index ca451601b..84f50cdef 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -945,7 +945,7 @@ namespace MWWorld removeContainerScripts(getPlayerPtr()); mWorldScene->changeToInteriorCell(cellName, position, adjustPlayerPos, changeEvent); addContainerScripts(getPlayerPtr(), getPlayerPtr().getCell()); - mRendering->getCamera()->skipFocalPointTransition(); + mRendering->getCamera()->instantTransition(); } void World::changeToExteriorCell (const ESM::Position& position, bool adjustPlayerPos, bool changeEvent) @@ -961,7 +961,7 @@ namespace MWWorld removeContainerScripts(getPlayerPtr()); mWorldScene->changeToExteriorCell(position, adjustPlayerPos, changeEvent); addContainerScripts(getPlayerPtr(), getPlayerPtr().getCell()); - mRendering->getCamera()->skipFocalPointTransition(); + mRendering->getCamera()->instantTransition(); } void World::changeToCell (const ESM::CellId& cellId, const ESM::Position& position, bool adjustPlayerPos, bool changeEvent) diff --git a/docs/source/reference/modding/settings/camera.rst b/docs/source/reference/modding/settings/camera.rst index be636cef4..18b6754a7 100644 --- a/docs/source/reference/modding/settings/camera.rst +++ b/docs/source/reference/modding/settings/camera.rst @@ -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. +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. + diff --git a/files/settings-default.cfg b/files/settings-default.cfg index 35be128a8..a9777fc42 100644 --- a/files/settings-default.cfg +++ b/files/settings-default.cfg @@ -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. 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] # Preload cells in a background thread. All settings starting with 'preload' have no effect unless this is enabled. From d78b22767053073d71bda9e6c229c8c8cf050dde Mon Sep 17 00:00:00 2001 From: Petr Mikheev Date: Sun, 19 Jul 2020 11:53:39 +0200 Subject: [PATCH 6/7] Fix inverted preview rotation when using controller --- apps/openmw/mwinput/mousemanager.cpp | 8 ++++---- apps/openmw/mwinput/sensormanager.cpp | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/apps/openmw/mwinput/mousemanager.cpp b/apps/openmw/mwinput/mousemanager.cpp index 5a0446093..84ab091c5 100644 --- a/apps/openmw/mwinput/mousemanager.cpp +++ b/apps/openmw/mwinput/mousemanager.cpp @@ -209,17 +209,17 @@ namespace MWInput return; 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[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 bool controls = MWBase::Environment::get().getInputManager()->getControlSwitch("playercontrols"); if (!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot) && controls) { MWWorld::Player& player = MWBase::Environment::get().getWorld()->getPlayer(); - player.yaw(rot[2]); - player.pitch(rot[0]); + player.yaw(-rot[2]); + player.pitch(-rot[0]); } else if (!controls) MWBase::Environment::get().getWorld()->disableDeferredPreviewRotation(); diff --git a/apps/openmw/mwinput/sensormanager.cpp b/apps/openmw/mwinput/sensormanager.cpp index 5a3d8847b..3e8e70aef 100644 --- a/apps/openmw/mwinput/sensormanager.cpp +++ b/apps/openmw/mwinput/sensormanager.cpp @@ -249,17 +249,17 @@ namespace MWInput if (!mGuiCursorEnabled) { 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[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 bool playerLooking = MWBase::Environment::get().getInputManager()->getControlSwitch("playerlooking"); if (!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot) && playerLooking) { MWWorld::Player& player = MWBase::Environment::get().getWorld()->getPlayer(); - player.yaw(rot[2]); - player.pitch(rot[0]); + player.yaw(-rot[2]); + player.pitch(-rot[0]); } else if (!playerLooking) MWBase::Environment::get().getWorld()->disableDeferredPreviewRotation(); From 62c8ea373bc55503f996c735ce8796dd0e0f7c75 Mon Sep 17 00:00:00 2001 From: Petr Mikheev Date: Sun, 19 Jul 2020 22:12:17 +0200 Subject: [PATCH 7/7] Fix not completely correct camera transition when switching from 1st person to 3rd person if armed. --- apps/openmw/mwinput/actionmanager.cpp | 12 +++++++----- apps/openmw/mwrender/camera.cpp | 3 +++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/apps/openmw/mwinput/actionmanager.cpp b/apps/openmw/mwinput/actionmanager.cpp index ddde7a11e..ec6c5cf7f 100644 --- a/apps/openmw/mwinput/actionmanager.cpp +++ b/apps/openmw/mwinput/actionmanager.cpp @@ -110,19 +110,21 @@ namespace MWInput 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 (mPreviewPOVDelay == 0) - MWBase::Environment::get().getWorld()->togglePreviewMode(true); + if (world->isFirstPerson() ? mPreviewPOVDelay > switchLimit : mPreviewPOVDelay == 0) + world->togglePreviewMode(true); mPreviewPOVDelay += dt; } else { //disable preview mode if (mPreviewPOVDelay > 0) - MWBase::Environment::get().getWorld()->togglePreviewMode(false); - if (mPreviewPOVDelay > 0.f && mPreviewPOVDelay <= 0.25) - MWBase::Environment::get().getWorld()->togglePOV(); + world->togglePreviewMode(false); + if (mPreviewPOVDelay > 0.f && mPreviewPOVDelay <= switchLimit) + world->togglePOV(); mPreviewPOVDelay = 0.f; } } diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp index 54bc581ef..328e53a79 100644 --- a/apps/openmw/mwrender/camera.cpp +++ b/apps/openmw/mwrender/camera.cpp @@ -287,6 +287,7 @@ namespace MWRender mFirstPersonView = !mFirstPersonView; updateStandingPreviewMode(); + instantTransition(); processViewChange(); } @@ -337,6 +338,8 @@ namespace MWRender mMode = enable ? Mode::Preview : Mode::Normal; if (mMode == Mode::Normal) updateStandingPreviewMode(); + else if (mFirstPersonView) + instantTransition(); if (mMode == Mode::Normal) { if (!mDeferredRotationAllowed)