diff --git a/apps/openmw/mwbase/world.hpp b/apps/openmw/mwbase/world.hpp index 9709df362..f5a8ae5b5 100644 --- a/apps/openmw/mwbase/world.hpp +++ b/apps/openmw/mwbase/world.hpp @@ -51,6 +51,11 @@ namespace ESM struct TimeStamp; } +namespace MWPhysics +{ + class PhysicsSystem; +} + namespace MWRender { class Animation; @@ -115,6 +120,8 @@ namespace MWBase virtual void readRecord (ESM::ESMReader& reader, uint32_t type, const std::map& contentFileMap) = 0; + virtual const MWPhysics::PhysicsSystem* getPhysics() const = 0; + virtual MWWorld::CellStore *getExterior (int x, int y) = 0; virtual MWWorld::CellStore *getInterior (const std::string& name) = 0; diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index d423830b1..133e0aeb0 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -311,7 +311,7 @@ namespace MWPhysics return result; } - PhysicsSystem::RayResult PhysicsSystem::castSphere(const osg::Vec3f &from, const osg::Vec3f &to, float radius) + PhysicsSystem::RayResult PhysicsSystem::castSphere(const osg::Vec3f &from, const osg::Vec3f &to, float radius) const { btCollisionWorld::ClosestConvexResultCallback callback(Misc::Convert::toBullet(from), Misc::Convert::toBullet(to)); callback.m_collisionFilterGroup = 0xff; diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 32d460b1d..c2a74cbd8 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -123,7 +123,7 @@ namespace MWPhysics std::vector targets = std::vector(), int mask = CollisionType_World|CollisionType_HeightMap|CollisionType_Actor|CollisionType_Door, int group=0xff) const; - RayResult castSphere(const osg::Vec3f& from, const osg::Vec3f& to, float radius); + RayResult castSphere(const osg::Vec3f& from, const osg::Vec3f& to, float radius) const; /// Return true if actor1 can see actor2. bool getLineOfSight(const MWWorld::ConstPtr& actor1, const MWWorld::ConstPtr& actor2) const; diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp index 328e53a79..47ef1f299 100644 --- a/apps/openmw/mwrender/camera.cpp +++ b/apps/openmw/mwrender/camera.cpp @@ -7,6 +7,7 @@ #include "../mwbase/environment.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/world.hpp" #include "../mwworld/class.hpp" #include "../mwworld/ptr.hpp" @@ -16,6 +17,8 @@ #include "../mwmechanics/movement.hpp" #include "../mwmechanics/npcstats.hpp" +#include "../mwphysics/physicssystem.hpp" + #include "npcanimation.hpp" namespace @@ -195,6 +198,7 @@ namespace MWRender rotateCamera(0.f, osg::DegreesToRadians(3.f * duration), true); updateFocalPointOffset(duration); + updatePosition(); float speed = mTrackingPtr.getClass().getSpeed(mTrackingPtr); speed /= (1.f + speed / 500.f); @@ -205,6 +209,42 @@ namespace MWRender updateStandingPreviewMode(); } + void Camera::updatePosition() + { + mFocalPointAdjustment = osg::Vec3d(); + if (isFirstPerson()) + return; + + const float cameraObstacleLimit = 5.0f; + const float focalObstacleLimit = 10.f; + + const MWPhysics::PhysicsSystem* physics = MWBase::Environment::get().getWorld()->getPhysics(); + + // Adjust focal point to prevent clipping. + osg::Vec3d focal = getFocalPoint(); + osg::Vec3d focalOffset = getFocalPointOffset(); + float offsetLen = focalOffset.length(); + if (offsetLen > 0) + { + MWPhysics::PhysicsSystem::RayResult result = physics->castSphere(focal - focalOffset, focal, focalObstacleLimit); + if (result.mHit) + { + double adjustmentCoef = -(result.mHitPos + result.mHitNormal * focalObstacleLimit - focal).length() / offsetLen; + mFocalPointAdjustment = focalOffset * std::max(-1.0, adjustmentCoef); + } + } + + // Calculate camera distance. + mCameraDistance = mBaseCameraDistance + getCameraDistanceCorrection(); + if (mDynamicCameraDistanceEnabled) + mCameraDistance = std::min(mCameraDistance, mMaxNextCameraDistance); + osg::Vec3d cameraPos; + getPosition(focal, cameraPos); + MWPhysics::PhysicsSystem::RayResult result = physics->castSphere(focal, cameraPos, cameraObstacleLimit); + if (result.mHit) + mCameraDistance = (result.mHitPos + result.mHitNormal * cameraObstacleLimit - focal).length(); + } + void Camera::updateStandingPreviewMode() { if (!mStandingPreviewAllowed) @@ -389,7 +429,6 @@ namespace MWRender mIsNearest = dist <= mNearest; mBaseCameraDistance = osg::clampBetween(dist, mNearest, mFurthest); Settings::Manager::setFloat("third person camera distance", "Camera", mBaseCameraDistance); - setCameraDistance(); } void Camera::setCameraDistance(float dist, bool adjust) @@ -414,16 +453,6 @@ namespace MWRender return pitchCorrection + speedCorrection; } - void Camera::setCameraDistance() - { - mFocalPointAdjustment = osg::Vec3d(); - if (isFirstPerson()) - return; - mCameraDistance = mBaseCameraDistance + getCameraDistanceCorrection(); - if (mDynamicCameraDistanceEnabled) - mCameraDistance = std::min(mCameraDistance, mMaxNextCameraDistance); - } - void Camera::setAnimation(NpcAnimation *anim) { mAnimation = anim; diff --git a/apps/openmw/mwrender/camera.hpp b/apps/openmw/mwrender/camera.hpp index f2e5c390d..bf54be715 100644 --- a/apps/openmw/mwrender/camera.hpp +++ b/apps/openmw/mwrender/camera.hpp @@ -73,6 +73,7 @@ namespace MWRender bool mShowCrosshairInThirdPersonMode; void updateFocalPointOffset(float duration); + void updatePosition(); float getCameraDistanceCorrection() const; osg::ref_ptr mUpdateCallback; @@ -144,16 +145,12 @@ namespace MWRender /// Default distance can be restored with setCameraDistance(). void setCameraDistance(float dist, bool adjust = false); - /// Restore default camera distance and offset for current mode. - void setCameraDistance(); - float getCameraDistance() const; void setAnimation(NpcAnimation *anim); osg::Vec3d getFocalPoint() const; osg::Vec3d getFocalPointOffset() const; - void adjustFocalPoint(osg::Vec3d adjustment) { mFocalPointAdjustment = adjustment; } /// Stores focal and camera world positions in passed arguments void getPosition(osg::Vec3d &focal, osg::Vec3d &camera) const; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 2eec9bf0e..c111abc43 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1863,37 +1863,6 @@ namespace MWWorld int nightEye = static_cast(player.getClass().getCreatureStats(player).getMagicEffects().get(ESM::MagicEffect::NightEye).getMagnitude()); mRendering->setNightEyeFactor(std::min(1.f, (nightEye/100.f))); - - auto* camera = mRendering->getCamera(); - camera->setCameraDistance(); - if(!mRendering->getCamera()->isFirstPerson()) - { - 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(); - float offsetLen = focalOffset.length(); - if (offsetLen > 0) - { - MWPhysics::PhysicsSystem::RayResult result = mPhysics->castSphere(focal - focalOffset, focal, focalObstacleLimit); - if (result.mHit) - { - double adjustmentCoef = -(result.mHitPos + result.mHitNormal * focalObstacleLimit - focal).length() / offsetLen; - if (adjustmentCoef < -1) - adjustmentCoef = -1; - camera->adjustFocalPoint(focalOffset * adjustmentCoef); - } - } - - // Adjust camera position. - osg::Vec3d cameraPos; - camera->getPosition(focal, cameraPos); - MWPhysics::PhysicsSystem::RayResult result = mPhysics->castSphere(focal, cameraPos, cameraObstacleLimit); - if (result.mHit) - mRendering->getCamera()->setCameraDistance((result.mHitPos + result.mHitNormal * cameraObstacleLimit - focal).length(), false); - } } void World::preloadSpells() diff --git a/apps/openmw/mwworld/worldimp.hpp b/apps/openmw/mwworld/worldimp.hpp index 5eae9608e..ade6c4a62 100644 --- a/apps/openmw/mwworld/worldimp.hpp +++ b/apps/openmw/mwworld/worldimp.hpp @@ -214,6 +214,8 @@ namespace MWWorld void readRecord (ESM::ESMReader& reader, uint32_t type, const std::map& contentFileMap) override; + const MWPhysics::PhysicsSystem* getPhysics() const override { return mPhysics.get(); } + CellStore *getExterior (int x, int y) override; CellStore *getInterior (const std::string& name) override;