Refactoring. Move all code related to 'view over shoulder' to a separate file.

pull/579/head
Petr Mikheev 5 years ago
parent 5bdf61a886
commit 51173ebcf5

@ -20,7 +20,7 @@ source_group(game FILES ${GAME} ${GAME_HEADER})
add_openmw_dir (mwrender
actors objects renderingmanager animation rotatecontroller sky npcanimation vismask
creatureanimation effectmanager util renderinginterface pathgrid rendermode weaponanimation
bulletdebugdraw globalmap characterpreview camera localmap water terrainstorage ripplesimulation
bulletdebugdraw globalmap characterpreview camera viewovershoulder localmap water terrainstorage ripplesimulation
renderbin actoranimation landmanager navmesh actorspaths recastmesh fogmanager objectpaging
)

@ -7,7 +7,6 @@
#include "../mwbase/environment.hpp"
#include "../mwbase/windowmanager.hpp"
#include "../mwbase/world.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/ptr.hpp"
@ -63,13 +62,12 @@ namespace MWRender
mVanityToggleQueuedValue(false),
mViewModeToggleQueued(false),
mCameraDistance(0.f),
mThirdPersonMode(ThirdPersonViewMode::Standard),
mOverShoulderOffset(osg::Vec2f(30.0f, -10.0f)),
mDefaultShoulderIsRight(true),
mThirdPersionOffsetType(ThirdPersonOffsetType::RightShoulder),
mFocalPointCurrentOffset(osg::Vec2d()),
mFocalPointTargetOffset(osg::Vec2d()),
mFocalPointTransitionSpeed(1.f),
mSmoothedSpeed(0.f)
mSmoothedSpeed(0.f),
mDynamicCameraDistanceEnabled(false),
mShowCrosshairInThirdPersonMode(false)
{
mVanity.enabled = false;
mVanity.allowed = true;
@ -124,7 +122,7 @@ namespace MWRender
osg::Vec3d Camera::getFocalPointOffset() const
{
osg::Vec3d offset(0, 0, 10.f);
if (mThirdPersonMode == ThirdPersonViewMode::OverShoulder && !mPreviewMode && !mVanity.enabled)
if (!mPreviewMode && !mVanity.enabled)
{
offset.x() += mFocalPointCurrentOffset.x() * cos(getYaw());
offset.y() += mFocalPointCurrentOffset.x() * sin(getYaw());
@ -209,7 +207,7 @@ namespace MWRender
// only show the crosshair in game mode
MWBase::WindowManager *wm = MWBase::Environment::get().getWindowManager();
wm->showCrosshair(!wm->isGuiMode() && !mVanity.enabled && !mPreviewMode
&& (mFirstPersonView || mThirdPersonMode != ThirdPersonViewMode::Standard));
&& (mFirstPersonView || mShowCrosshairInThirdPersonMode));
if(mVanity.enabled)
{
@ -223,68 +221,9 @@ namespace MWRender
mSmoothedSpeed += osg::clampBetween(speed - mSmoothedSpeed, -maxDelta, maxDelta);
}
void Camera::setOverShoulderOffset(float horizontal, float vertical)
{
mOverShoulderOffset = osg::Vec2f(std::abs(horizontal), vertical);
mDefaultShoulderIsRight = horizontal >= 0;
}
void Camera::switchToLeftShoulder()
{
if (mThirdPersionOffsetType == ThirdPersonOffsetType::RightShoulder)
mThirdPersionOffsetType = ThirdPersonOffsetType::LeftShoulder;
}
void Camera::switchToRightShoulder()
{
if (mThirdPersionOffsetType == ThirdPersonOffsetType::LeftShoulder)
mThirdPersionOffsetType = ThirdPersonOffsetType::RightShoulder;
}
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;
osg::Vec2d delta = mFocalPointTargetOffset - mFocalPointCurrentOffset;
if (delta.length2() > 0)
{
float coef = duration * (1.0 + 5.0 / delta.length()) * mFocalPointTransitionSpeed;
@ -487,17 +426,15 @@ namespace MWRender
float Camera::getCameraDistanceCorrection() const
{
if (mThirdPersonMode == ThirdPersonViewMode::Standard)
if (!mDynamicCameraDistanceEnabled)
return 0;
else
{
float pitchCorrection = std::max(-getPitch(), 0.f) * 50.f;
float smoothedSpeedSqr = mSmoothedSpeed * mSmoothedSpeed;
float speedCorrection = smoothedSpeedSqr / (smoothedSpeedSqr + 300.f*300.f) * 20.0f;
float pitchCorrection = std::max(-getPitch(), 0.f) * 50.f;
return pitchCorrection + speedCorrection;
}
float smoothedSpeedSqr = mSmoothedSpeed * mSmoothedSpeed;
float speedCorrection = smoothedSpeedSqr / (smoothedSpeedSqr + 300.f*300.f) * 20.0f;
return pitchCorrection + speedCorrection;
}
void Camera::setCameraDistance()

@ -23,12 +23,7 @@ namespace MWRender
/// \brief Camera control
class Camera
{
public:
enum class ThirdPersonViewMode {Standard, OverShoulder};
private:
enum class ThirdPersonOffsetType { RightShoulder, LeftShoulder, Combat, Swimming };
struct CamData {
float pitch, yaw, offset;
};
@ -60,17 +55,14 @@ namespace MWRender
float mCameraDistance;
ThirdPersonViewMode mThirdPersonMode;
osg::Vec2f mOverShoulderOffset;
bool mDefaultShoulderIsRight;
osg::Vec3d mFocalPointAdjustment;
// Makes sense only if mThirdPersonMode is OverShoulder.
ThirdPersonOffsetType mThirdPersionOffsetType;
osg::Vec2d mFocalPointCurrentOffset;
osg::Vec2d mFocalPointTargetOffset;
float mFocalPointTransitionSpeed;
float mSmoothedSpeed;
bool mDynamicCameraDistanceEnabled;
bool mShowCrosshairInThirdPersonMode;
void updateFocalPointOffset(float duration);
float getCameraDistanceCorrection() const;
@ -83,13 +75,10 @@ namespace MWRender
MWWorld::Ptr getTrackingPtr() const;
void setThirdPersonViewMode(ThirdPersonViewMode mode) { mThirdPersonMode = mode; }
ThirdPersonViewMode getThirdPersonViewMode() const { return mThirdPersonMode; }
void setOverShoulderOffset(float horizontal, float vertical);
void switchToLeftShoulder();
void switchToRightShoulder();
void switchToDefaultShoulder();
void setFocalPointTransitionSpeed(float v) { mFocalPointTransitionSpeed = v; }
void setFocalPointTargetOffset(osg::Vec2d v) { mFocalPointTargetOffset = v; }
void enableDynamicCameraDistance(bool v) { mDynamicCameraDistanceEnabled = v; }
void enableCrosshairInThirdPersonMode(bool v) { mShowCrosshairInThirdPersonMode = v; }
/// Update the view matrix of \a cam
void updateCamera(osg::Camera* cam);

@ -65,6 +65,7 @@
#include "vismask.hpp"
#include "pathgrid.hpp"
#include "camera.hpp"
#include "viewovershoulder.hpp"
#include "water.hpp"
#include "terrainstorage.hpp"
#include "util.hpp"
@ -306,6 +307,8 @@ namespace MWRender
mWater.reset(new Water(mRootNode, sceneRoot, mResourceSystem, mViewer->getIncrementalCompileOperation(), resourcePath));
mCamera.reset(new Camera(mViewer->getCamera()));
if (Settings::Manager::getBool("view over shoulder", "Camera"))
mViewOverShoulderController.reset(new ViewOverShoulderController(mCamera.get()));
mViewer->setLightingMode(osgViewer::View::NO_LIGHT);
@ -366,7 +369,6 @@ namespace MWRender
float firstPersonFov = Settings::Manager::getFloat("first person field of view", "Camera");
mFirstPersonFieldOfView = std::min(std::max(1.f, firstPersonFov), 179.f);
mStateUpdater->setFogEnd(mViewDistance);
updateThirdPersonViewMode();
mRootNode->getOrCreateStateSet()->addUniform(new osg::Uniform("near", mNearClip));
mRootNode->getOrCreateStateSet()->addUniform(new osg::Uniform("far", mViewDistance));
@ -382,19 +384,6 @@ namespace MWRender
mWorkQueue = nullptr;
}
void RenderingManager::updateThirdPersonViewMode()
{
if (Settings::Manager::getBool("view over shoulder", "Camera"))
mCamera->setThirdPersonViewMode(Camera::ThirdPersonViewMode::OverShoulder);
else
mCamera->setThirdPersonViewMode(Camera::ThirdPersonViewMode::Standard);
std::stringstream offset(Settings::Manager::getString("view over shoulder offset", "Camera"));
float horizontal = 30.f, vertical = -10.f;
offset >> horizontal >> vertical;
mCamera->setOverShoulderOffset(horizontal, vertical);
}
osgUtil::IncrementalCompileOperation* RenderingManager::getIncrementalCompileOperation()
{
return mViewer->getIncrementalCompileOperation();
@ -630,6 +619,8 @@ namespace MWRender
updateNavMesh();
updateRecastMesh();
if (mViewOverShoulderController)
mViewOverShoulderController->update();
mCamera->update(dt, paused);
osg::Vec3d focal, cameraPos;

@ -79,6 +79,7 @@ namespace MWRender
class NpcAnimation;
class Pathgrid;
class Camera;
class ViewOverShoulderController;
class Water;
class TerrainStorage;
class LandManager;
@ -294,6 +295,7 @@ namespace MWRender
osg::ref_ptr<NpcAnimation> mPlayerAnimation;
osg::ref_ptr<SceneUtil::PositionAttitudeTransform> mPlayerNode;
std::unique_ptr<Camera> mCamera;
std::unique_ptr<ViewOverShoulderController> mViewOverShoulderController;
osg::Vec3f mCurrentCameraPos;
osg::ref_ptr<StateUpdater> mStateUpdater;

@ -0,0 +1,99 @@
#include "viewovershoulder.hpp"
#include <osg/Quat>
#include <components/settings/settings.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/ptr.hpp"
#include "../mwworld/refdata.hpp"
#include "../mwmechanics/drawstate.hpp"
namespace MWRender
{
ViewOverShoulderController::ViewOverShoulderController(Camera* camera) :
mCamera(camera), mMode(Mode::RightShoulder),
mAutoSwitchShoulder(Settings::Manager::getBool("auto switch shoulder", "Camera")),
mOverShoulderHorizontalOffset(30.f), mOverShoulderVerticalOffset(-10.f)
{
std::stringstream offset(Settings::Manager::getString("view over shoulder offset", "Camera"));
offset >> mOverShoulderHorizontalOffset >> mOverShoulderVerticalOffset;
mDefaultShoulderIsRight = mOverShoulderHorizontalOffset >= 0;
mOverShoulderHorizontalOffset = std::abs(mOverShoulderHorizontalOffset);
mCamera->enableDynamicCameraDistance(true);
mCamera->enableCrosshairInThirdPersonMode(true);
}
void ViewOverShoulderController::update()
{
if (mCamera->isVanityOrPreviewModeEnabled() || mCamera->isFirstPerson())
return;
Mode newMode = mMode;
auto ptr = mCamera->getTrackingPtr();
if (ptr.getClass().isActor() && ptr.getClass().getCreatureStats(ptr).getDrawState() != MWMechanics::DrawState_Nothing)
newMode = 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;
}
if (mAutoSwitchShoulder && (mMode == Mode::LeftShoulder || mMode == Mode::RightShoulder))
trySwitchShoulder();
osg::Vec2d focalPointTargetOffset;
switch (mMode)
{
case Mode::RightShoulder:
mCamera->setFocalPointTargetOffset({mOverShoulderHorizontalOffset, mOverShoulderVerticalOffset});
break;
case Mode::LeftShoulder:
mCamera->setFocalPointTargetOffset({-mOverShoulderHorizontalOffset, mOverShoulderVerticalOffset});
break;
case Mode::Combat:
case Mode::Swimming:
default:
mCamera->setFocalPointTargetOffset({0, 15});
}
}
void ViewOverShoulderController::trySwitchShoulder()
{
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
auto orient = osg::Quat(mCamera->getYaw(), osg::Vec3d(0,0,1));
osg::Vec3d playerPos = mCamera->getFocalPoint() - mCamera->getFocalPointOffset();
MWBase::World* world = MWBase::Environment::get().getWorld();
osg::Vec3d sideOffset = orient * osg::Vec3d(world->getHalfExtents(mCamera->getTrackingPtr()).x() - 1, 0, 0);
float rayRight = world->getDistToNearestRayHit(
playerPos + sideOffset, orient * osg::Vec3d(1, 1, 0), limitToSwitchBack + 1);
float rayLeft = world->getDistToNearestRayHit(
playerPos - sideOffset, orient * osg::Vec3d(-1, 1, 0), limitToSwitchBack + 1);
float rayForward = world->getDistToNearestRayHit(
playerPos, orient * osg::Vec3d(0, 1, 0), limitToSwitchBack + 1);
if (rayLeft < limitToSwitch && rayRight > limitToSwitchBack)
mMode = Mode::RightShoulder;
else if (rayRight < limitToSwitch && rayLeft > limitToSwitchBack)
mMode = Mode::LeftShoulder;
else if (rayLeft > limitToSwitchBack && rayRight > limitToSwitchBack && rayForward > limitToSwitchBack)
mMode = mDefaultShoulderIsRight ? Mode::RightShoulder : Mode::LeftShoulder;
}
}

@ -0,0 +1,30 @@
#ifndef VIEWOVERSHOULDER_H
#define VIEWOVERSHOULDER_H
#include "camera.hpp"
namespace MWRender
{
class ViewOverShoulderController
{
public:
ViewOverShoulderController(Camera* camera);
void update();
private:
void trySwitchShoulder();
enum class Mode { RightShoulder, LeftShoulder, Combat, Swimming };
Camera* mCamera;
Mode mMode;
bool mAutoSwitchShoulder;
float mOverShoulderHorizontalOffset;
float mOverShoulderVerticalOffset;
bool mDefaultShoulderIsRight;
};
}
#endif // VIEWOVERSHOULDER_H

@ -1869,44 +1869,13 @@ namespace MWWorld
float cameraObstacleLimit = mRendering->getNearClipDistance() * 2.5f;
float focalObstacleLimit = std::max(cameraObstacleLimit, 10.0f);
// Adjust focal point.
osg::Vec3d focal = camera->getFocalPoint();
osg::Vec3d focalOffset = camera->getFocalPointOffset();
osg::Vec3d playerPos = focal - focalOffset;
static const bool autoSwitchShoulder = Settings::Manager::getBool("auto switch shoulder", "Camera");
if (camera->getThirdPersonViewMode() == MWRender::Camera::ThirdPersonViewMode::OverShoulder
&& autoSwitchShoulder && !camera->isVanityOrPreviewModeEnabled())
{
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
auto orient = osg::Quat(camera->getYaw(), osg::Vec3d(0,0,1));
int mask = MWPhysics::CollisionType_World | MWPhysics::CollisionType_Door | MWPhysics::CollisionType_HeightMap;
MWPhysics::PhysicsSystem::RayResult rayRight = mPhysics->castRay(
playerPos + orient * osg::Vec3d(28, 0, 0),
playerPos + orient * osg::Vec3d(limitToSwitchBack, limitToSwitchBack, 0),
{}, {}, mask);
MWPhysics::PhysicsSystem::RayResult rayLeft = mPhysics->castRay(
playerPos + orient * osg::Vec3d(-28, 0, 0),
playerPos + orient * osg::Vec3d(-limitToSwitchBack, limitToSwitchBack, 0),
{}, {}, mask);
MWPhysics::PhysicsSystem::RayResult rayForward = mPhysics->castRay(
playerPos, playerPos + orient * osg::Vec3d(0, limitToSwitchBack, 0),
{}, {}, mask);
bool rightTooClose = rayRight.mHit && (rayRight.mHitPos - playerPos).length2() < limitToSwitch * limitToSwitch;
bool leftTooClose = rayLeft.mHit && (rayLeft.mHitPos - playerPos).length2() < limitToSwitch * limitToSwitch;
if (!rayRight.mHit && leftTooClose)
camera->switchToRightShoulder();
else if (!rayLeft.mHit && rightTooClose)
camera->switchToLeftShoulder();
else if (!rayRight.mHit && !rayLeft.mHit && !rayForward.mHit)
camera->switchToDefaultShoulder();
}
// Adjust focal point.
float offsetLen = focalOffset.length();
if (offsetLen > 0)
{
MWPhysics::PhysicsSystem::RayResult result = mPhysics->castSphere(playerPos, focal, focalObstacleLimit);
MWPhysics::PhysicsSystem::RayResult result = mPhysics->castSphere(focal - focalOffset, focal, focalObstacleLimit);
if (result.mHit)
{
double adjustmentCoef = -(result.mHitPos + result.mHitNormal * focalObstacleLimit - focal).length() / offsetLen;

Loading…
Cancel
Save