1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-02-21 18:39:40 +00:00

Generalize calculation of focal point offset for 3rd person camera.

When player swim, the view slowly switches from "over shoulder" to "above head".
New functions to switch shoulder.
This commit is contained in:
Petr Mikheev 2020-06-19 22:03:11 +02:00
parent f12123a172
commit 5675d6ce81
2 changed files with 85 additions and 25 deletions

View file

@ -7,6 +7,7 @@
#include "../mwbase/environment.hpp" #include "../mwbase/environment.hpp"
#include "../mwbase/windowmanager.hpp" #include "../mwbase/windowmanager.hpp"
#include "../mwbase/world.hpp"
#include "../mwworld/class.hpp" #include "../mwworld/class.hpp"
#include "../mwworld/ptr.hpp" #include "../mwworld/ptr.hpp"
@ -64,7 +65,10 @@ namespace MWRender
mCameraDistance(0.f), mCameraDistance(0.f),
mThirdPersonMode(ThirdPersonViewMode::Standard), mThirdPersonMode(ThirdPersonViewMode::Standard),
mOverShoulderOffset(osg::Vec2f(30.0f, -10.0f)), mOverShoulderOffset(osg::Vec2f(30.0f, -10.0f)),
mSmoothTransitionToCombatMode(0.f) mDefaultShoulderIsRight(true),
mThirdPersionOffsetType(ThirdPersonOffsetType::RightShoulder),
mFocalPointCurrentOffset(osg::Vec2d()),
mFocalPointTransitionSpeed(1.f)
{ {
mVanity.enabled = false; mVanity.enabled = false;
mVanity.allowed = true; mVanity.allowed = true;
@ -121,12 +125,9 @@ namespace MWRender
osg::Vec3d offset(0, 0, 10.f); osg::Vec3d offset(0, 0, 10.f);
if (mThirdPersonMode == ThirdPersonViewMode::OverShoulder && !mPreviewMode && !mVanity.enabled) if (mThirdPersonMode == ThirdPersonViewMode::OverShoulder && !mPreviewMode && !mVanity.enabled)
{ {
float horizontalOffset = mOverShoulderOffset.x() * (1.f - mSmoothTransitionToCombatMode); offset.x() += mFocalPointCurrentOffset.x() * cos(getYaw());
float verticalOffset = mSmoothTransitionToCombatMode * 15.f + (1.f - mSmoothTransitionToCombatMode) * mOverShoulderOffset.y(); offset.y() += mFocalPointCurrentOffset.x() * sin(getYaw());
offset.z() += mFocalPointCurrentOffset.y();
offset.x() += horizontalOffset * cos(getYaw());
offset.y() += horizontalOffset * sin(getYaw());
offset.z() += verticalOffset;
} }
return offset; return offset;
} }
@ -214,28 +215,78 @@ namespace MWRender
rotateCamera(0.f, osg::DegreesToRadians(3.f * duration), true); rotateCamera(0.f, osg::DegreesToRadians(3.f * duration), true);
} }
updateSmoothTransitionToCombatMode(duration); updateFocalPointOffset(duration);
} }
void Camera::setOverShoulderOffset(float horizontal, float vertical) void Camera::setOverShoulderOffset(float horizontal, float vertical)
{ {
mOverShoulderOffset = osg::Vec2f(horizontal, vertical); mOverShoulderOffset = osg::Vec2f(std::abs(horizontal), vertical);
mDefaultShoulderIsRight = horizontal >= 0;
} }
void Camera::updateSmoothTransitionToCombatMode(float duration) void Camera::switchToLeftShoulder()
{ {
bool combatMode = true; if (mThirdPersionOffsetType == ThirdPersonOffsetType::RightShoulder)
if (mTrackingPtr.getClass().isActor()) mThirdPersionOffsetType = ThirdPersonOffsetType::LeftShoulder;
combatMode = mTrackingPtr.getClass().getCreatureStats(mTrackingPtr).getDrawState() != MWMechanics::DrawState_Nothing; }
float speed = ((combatMode ? 1.f : 0.f) - mSmoothTransitionToCombatMode) * 5;
if (speed != 0)
speed += speed > 0 ? 1 : -1;
mSmoothTransitionToCombatMode += speed * duration; void Camera::switchToRightShoulder()
if (mSmoothTransitionToCombatMode > 1) {
mSmoothTransitionToCombatMode = 1; if (mThirdPersionOffsetType == ThirdPersonOffsetType::LeftShoulder)
if (mSmoothTransitionToCombatMode < 0) mThirdPersionOffsetType = ThirdPersonOffsetType::RightShoulder;
mSmoothTransitionToCombatMode = 0; }
void Camera::switchToDefaultShoulder()
{
if (mThirdPersionOffsetType == ThirdPersonOffsetType::LeftShoulder || mThirdPersionOffsetType == ThirdPersonOffsetType::RightShoulder)
mThirdPersionOffsetType = mDefaultShoulderIsRight ? ThirdPersonOffsetType::RightShoulder : ThirdPersonOffsetType::LeftShoulder;
}
void Camera::updateFocalPointOffset(float duration)
{
if (mThirdPersonMode == ThirdPersonViewMode::Standard)
return; // In Standard mode there is no focal point offset.
ThirdPersonOffsetType newOffsetType = mThirdPersionOffsetType;
if (mTrackingPtr.getClass().isActor() && mTrackingPtr.getClass().getCreatureStats(mTrackingPtr).getDrawState() != MWMechanics::DrawState_Nothing)
newOffsetType = ThirdPersonOffsetType::Combat;
else if (MWBase::Environment::get().getWorld()->isSwimming(mTrackingPtr))
newOffsetType = ThirdPersonOffsetType::Swimming;
else if (mThirdPersionOffsetType == ThirdPersonOffsetType::Combat || mThirdPersionOffsetType == ThirdPersonOffsetType::Swimming)
newOffsetType = mDefaultShoulderIsRight ? ThirdPersonOffsetType::RightShoulder : ThirdPersonOffsetType::LeftShoulder;
if (newOffsetType != mThirdPersionOffsetType)
{
if (newOffsetType == ThirdPersonOffsetType::Combat || mThirdPersionOffsetType == ThirdPersonOffsetType::Combat)
mFocalPointTransitionSpeed = 5;
else
mFocalPointTransitionSpeed = 1;
mThirdPersionOffsetType = newOffsetType;
}
osg::Vec2d focalPointTargetOffset;
switch (mThirdPersionOffsetType)
{
case ThirdPersonOffsetType::RightShoulder:
focalPointTargetOffset = mOverShoulderOffset;
break;
case ThirdPersonOffsetType::LeftShoulder:
focalPointTargetOffset = mOverShoulderOffset
focalPointTargetOffset.x() *= -1;
break;
case ThirdPersonOffsetType::Combat:
case ThirdPersonOffsetType::Swimming:
default:
focalPointTargetOffset = osg::Vec2d(0, 15);
}
osg::Vec2d delta = focalPointTargetOffset - mFocalPointCurrentOffset;
if (delta.length2() > 0)
{
float coef = duration * (1.0 + 5.0 / delta.length()) * mFocalPointTransitionSpeed;
mFocalPointCurrentOffset += delta * std::min(coef, 1.0f);
}
else
mFocalPointTransitionSpeed = 1.f;
} }
void Camera::toggleViewMode(bool force) void Camera::toggleViewMode(bool force)

View file

@ -27,6 +27,8 @@ namespace MWRender
enum class ThirdPersonViewMode {Standard, OverShoulder}; enum class ThirdPersonViewMode {Standard, OverShoulder};
private: private:
enum class ThirdPersonOffsetType { RightShoulder, LeftShoulder, Combat, Swimming };
struct CamData { struct CamData {
float pitch, yaw, offset; float pitch, yaw, offset;
}; };
@ -60,12 +62,15 @@ namespace MWRender
ThirdPersonViewMode mThirdPersonMode; ThirdPersonViewMode mThirdPersonMode;
osg::Vec2f mOverShoulderOffset; osg::Vec2f mOverShoulderOffset;
bool mDefaultShoulderIsRight;
osg::Vec3d mFocalPointAdjustment; osg::Vec3d mFocalPointAdjustment;
// Makes sense only if mThirdPersonMode is OverShoulder. Can be in range [0, 1]. // Makes sense only if mThirdPersonMode is OverShoulder.
// Used for smooth transition from non-combat camera position (0) to combat camera position (1). ThirdPersonOffsetType mThirdPersionOffsetType;
float mSmoothTransitionToCombatMode; osg::Vec2d mFocalPointCurrentOffset;
void updateSmoothTransitionToCombatMode(float duration); float mFocalPointTransitionSpeed;
void updateFocalPointOffset(float duration);
float getCameraDistanceCorrection() const; float getCameraDistanceCorrection() const;
osg::ref_ptr<osg::NodeCallback> mUpdateCallback; osg::ref_ptr<osg::NodeCallback> mUpdateCallback;
@ -79,6 +84,10 @@ namespace MWRender
void setThirdPersonViewMode(ThirdPersonViewMode mode) { mThirdPersonMode = mode; } void setThirdPersonViewMode(ThirdPersonViewMode mode) { mThirdPersonMode = mode; }
void setOverShoulderOffset(float horizontal, float vertical); void setOverShoulderOffset(float horizontal, float vertical);
void switchToLeftShoulder();
void switchToRightShoulder();
void switchToDefaultShoulder();
/// Update the view matrix of \a cam /// Update the view matrix of \a cam
void updateCamera(osg::Camera* cam); void updateCamera(osg::Camera* cam);