Merge branch 'head_bobbing' into 'master'

Add head bobbing in first person mode

Closes #5043

See merge request OpenMW/openmw!320
pull/3019/head
psi29a 4 years ago
commit 9d350ec824

@ -58,6 +58,7 @@
Feature #390: 3rd person look "over the shoulder"
Feature #2386: Distant Statics in the form of Object Paging
Feature #4894: Consider actors as obstacles for pathfinding
Feature #5043: Head Bobbing
Feature #5297: Add a search function to the "Datafiles" tab of the OpenMW launcher
Feature #5362: Show the soul gems' trapped soul in count dialog
Feature #5445: Handle NiLines

@ -136,6 +136,7 @@ bool Launcher::AdvancedPage::loadSettings()
loadSettingBool(autoSwitchShoulderCheckBox, "auto switch shoulder", "Camera");
loadSettingBool(previewIfStandStillCheckBox, "preview if stand still", "Camera");
loadSettingBool(deferredPreviewRotationCheckBox, "deferred preview rotation", "Camera");
loadSettingBool(headBobbingCheckBox, "head bobbing", "Camera");
defaultShoulderComboBox->setCurrentIndex(
mEngineSettings.getVector2("view over shoulder offset", "Camera").x() >= 0 ? 0 : 1);
}
@ -253,6 +254,7 @@ void Launcher::AdvancedPage::saveSettings()
saveSettingBool(autoSwitchShoulderCheckBox, "auto switch shoulder", "Camera");
saveSettingBool(previewIfStandStillCheckBox, "preview if stand still", "Camera");
saveSettingBool(deferredPreviewRotationCheckBox, "deferred preview rotation", "Camera");
saveSettingBool(headBobbingCheckBox, "head bobbing", "Camera");
osg::Vec2f shoulderOffset = mEngineSettings.getVector2("view over shoulder offset", "Camera");
if (defaultShoulderComboBox->currentIndex() != (shoulderOffset.x() >= 0 ? 0 : 1))

@ -80,6 +80,7 @@ namespace MWRender
mZoomOutWhenMoveCoef(Settings::Manager::getFloat("zoom out when move coef", "Camera")),
mDynamicCameraDistanceEnabled(false),
mShowCrosshairInThirdPersonMode(false),
mHeadBobbingEnabled(Settings::Manager::getBool("head bobbing", "Camera")),
mDeferredRotation(osg::Vec3f()),
mDeferredRotationDisabled(false)
{
@ -104,7 +105,9 @@ namespace MWRender
osg::Matrix worldMat = osg::computeLocalToWorld(nodepaths[0]);
osg::Vec3d position = worldMat.getTrans();
if (!isFirstPerson())
if (isFirstPerson())
position.z() += mHeadBobbingOffset;
else
{
position.z() += mHeight * mHeightScale;
@ -143,13 +146,31 @@ namespace MWRender
osg::Vec3d focal, position;
getPosition(focal, position);
osg::Quat orient = osg::Quat(getPitch(), osg::Vec3d(1,0,0)) * osg::Quat(getYaw(), osg::Vec3d(0,0,1));
osg::Quat orient = osg::Quat(mRoll, osg::Vec3d(0, 1, 0)) * osg::Quat(mPitch, osg::Vec3d(1, 0, 0)) * osg::Quat(mYaw, osg::Vec3d(0, 0, 1));
osg::Vec3d forward = orient * osg::Vec3d(0,1,0);
osg::Vec3d up = orient * osg::Vec3d(0,0,1);
cam->setViewMatrixAsLookAt(position, position + forward, up);
}
void Camera::updateHeadBobbing(float duration) {
static const float doubleStepLength = Settings::Manager::getFloat("head bobbing step", "Camera") * 2;
static const float stepHeight = Settings::Manager::getFloat("head bobbing height", "Camera");
static const float maxRoll = osg::DegreesToRadians(Settings::Manager::getFloat("head bobbing roll", "Camera"));
if (MWBase::Environment::get().getWorld()->isOnGround(mTrackingPtr))
mHeadBobbingWeight = std::min(mHeadBobbingWeight + duration * 5, 1.f);
else
mHeadBobbingWeight = std::max(mHeadBobbingWeight - duration * 5, 0.f);
float doubleStepState = mTotalMovement / doubleStepLength - std::floor(mTotalMovement / doubleStepLength); // from 0 to 1 during 2 steps
float stepState = std::abs(doubleStepState * 4 - 2) - 1; // from -1 to 1 on even steps and from 1 to -1 on odd steps
float effect = (1 - std::cos(stepState * osg::DegreesToRadians(30.f))) * 7.5f; // range from 0 to 1
float coef = std::min(mSmoothedSpeed / 300.f, 1.f) * mHeadBobbingWeight;
mHeadBobbingOffset = (0.5f - effect) * coef * stepHeight; // range from -stepHeight/2 to stepHeight/2
mRoll = osg::sign(stepState) * effect * coef * maxRoll; // range from -maxRoll to maxRoll
}
void Camera::reset()
{
togglePreviewMode(false);
@ -198,10 +219,16 @@ namespace MWRender
if(mMode == Mode::Vanity)
rotateCamera(0.f, osg::DegreesToRadians(3.f * duration), true);
if (isFirstPerson() && mHeadBobbingEnabled)
updateHeadBobbing(duration);
else
mRoll = mHeadBobbingOffset = 0;
updateFocalPointOffset(duration);
updatePosition();
float speed = mTrackingPtr.getClass().getCurrentSpeed(mTrackingPtr);
mTotalMovement += speed * duration;
speed /= (1.f + speed / 500.f);
float maxDelta = 300.f * duration;
mSmoothedSpeed += osg::clampBetween(speed - mSmoothedSpeed, -maxDelta, maxDelta);

@ -46,7 +46,7 @@ namespace MWRender
bool mIsNearest;
float mHeight, mBaseCameraDistance;
float mPitch, mYaw;
float mPitch, mYaw, mRoll;
bool mVanityToggleQueued;
bool mVanityToggleQueuedValue;
@ -72,6 +72,12 @@ namespace MWRender
bool mDynamicCameraDistanceEnabled;
bool mShowCrosshairInThirdPersonMode;
bool mHeadBobbingEnabled;
float mHeadBobbingOffset;
float mHeadBobbingWeight = 0; // Value from 0 to 1 for smooth enabling/disabling.
float mTotalMovement = 0; // Needed for head bobbing.
void updateHeadBobbing(float duration);
void updateFocalPointOffset(float duration);
void updatePosition();
float getCameraDistanceCorrection() const;

@ -199,3 +199,50 @@ If disabled then the camera rotates rather than the character.
This setting can be controlled in Advanced tab of the launcher.
head bobbing
------------
:Type: boolean
:Range: True/False
:Default: False
Enables head bobbing when move in first person mode.
This setting can be controlled in Advanced tab of the launcher.
head bobbing step
-----------------
:Type: floating point
:Range: >0
:Default: 90.0
Makes diffence only in first person mode if 'head bobbing' is enabled.
Length of each step.
This setting can only be configured by editing the settings configuration file.
head bobbing height
-------------------
:Type: floating point
:Range: Any
:Default: 3.0
Makes diffence only in first person mode if 'head bobbing' is enabled.
Amplitude of the head bobbing.
This setting can only be configured by editing the settings configuration file.
head bobbing roll
-----------------
:Type: floating point
:Range: 0-90
:Default: 0.2
Makes diffence only in first person mode if 'head bobbing' is enabled.
Maximum roll angle in degrees.
This setting can only be configured by editing the settings configuration file.

@ -54,6 +54,18 @@ preview if stand still = false
# Rotate the character to the view direction after exiting preview mode.
deferred preview rotation = true
# Enables head bobbing in first person mode
head bobbing = false
# Length of each step
head bobbing step = 90.0
# Amplitude of the bobbing effect
head bobbing height = 3.0
# Maximum camera roll angle (degrees)
head bobbing roll = 0.2
[Cells]
# Preload cells in a background thread. All settings starting with 'preload' have no effect unless this is enabled.

@ -583,6 +583,16 @@ True: In non-combat mode camera is positioned behind the character's shoulder. C
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="headBobbingCheckBox">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enables head bobbing when move in first person mode.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Head bobbing in 1st person mode</string>
</property>
</widget>
</item>
<item>
<spacer>
<property name="orientation">

Loading…
Cancel
Save