diff --git a/apps/openmw/mwphysics/physicssystem.cpp b/apps/openmw/mwphysics/physicssystem.cpp index 7c083ca08f..c0e7a80b9d 100644 --- a/apps/openmw/mwphysics/physicssystem.cpp +++ b/apps/openmw/mwphysics/physicssystem.cpp @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -778,6 +779,30 @@ namespace MWPhysics return result; } + PhysicsSystem::RayResult PhysicsSystem::castSphere(const osg::Vec3f &from, const osg::Vec3f &to, float radius) + { + btCollisionWorld::ClosestConvexResultCallback callback(toBullet(from), toBullet(to)); + callback.m_collisionFilterGroup = 0xff; + callback.m_collisionFilterMask = CollisionType_World|CollisionType_HeightMap; + + btSphereShape shape(radius); + const btQuaternion btrot = btQuaternion::getIdentity(); + + btTransform from_ (btrot, toBullet(from)); + btTransform to_ (btrot, toBullet(to)); + + mCollisionWorld->convexSweepTest(&shape, from_, to_, callback); + + RayResult result; + result.mHit = callback.hasHit(); + if (result.mHit) + { + result.mHitPos = toOsg(callback.m_hitPointWorld); + result.mHitNormal = toOsg(callback.m_hitNormalWorld); + } + return result; + } + bool PhysicsSystem::getLineOfSight(const MWWorld::Ptr &actor1, const MWWorld::Ptr &actor2) { Actor* physactor1 = getActor(actor1); diff --git a/apps/openmw/mwphysics/physicssystem.hpp b/apps/openmw/mwphysics/physicssystem.hpp index 2defd7a507..d4f7e25b10 100644 --- a/apps/openmw/mwphysics/physicssystem.hpp +++ b/apps/openmw/mwphysics/physicssystem.hpp @@ -101,6 +101,8 @@ namespace MWPhysics RayResult castRay(const osg::Vec3f &from, const osg::Vec3f &to, MWWorld::Ptr ignore = MWWorld::Ptr(), int mask = CollisionType_World|CollisionType_HeightMap|CollisionType_Actor); + RayResult castSphere(const osg::Vec3f& from, const osg::Vec3f& to, float radius); + /// Return true if actor1 can see actor2. bool getLineOfSight(const MWWorld::Ptr& actor1, const MWWorld::Ptr& actor2); diff --git a/apps/openmw/mwrender/camera.cpp b/apps/openmw/mwrender/camera.cpp index e28b6befa4..9080d31644 100644 --- a/apps/openmw/mwrender/camera.cpp +++ b/apps/openmw/mwrender/camera.cpp @@ -80,21 +80,28 @@ namespace MWRender return mTrackingPtr; } - void Camera::updateCamera(osg::Camera *cam) + osg::Vec3d Camera::getFocalPoint() { - if (mTrackingPtr.isEmpty()) - return; const osg::Node* trackNode = mTrackingNode; if (!trackNode) - return; + return osg::Vec3d(); osg::MatrixList mats = trackNode->getWorldMatrices(); if (!mats.size()) - return; + return osg::Vec3d(); const osg::Matrix& worldMat = mats[0]; osg::Vec3d position = worldMat.getTrans(); if (!isFirstPerson()) position.z() += mHeight; + return position; + } + + void Camera::updateCamera(osg::Camera *cam) + { + if (mTrackingPtr.isEmpty()) + return; + + osg::Vec3d position = getFocalPoint(); osg::Quat orient = osg::Quat(getPitch(), osg::Vec3d(1,0,0)) * osg::Quat(getYaw(), osg::Vec3d(0,0,1)); @@ -373,12 +380,14 @@ namespace MWRender rotateCamera(getPitch(), getYaw(), false); } - void Camera::getPosition(osg::Vec3 &focal, osg::Vec3 &camera) + void Camera::getPosition(osg::Vec3f &focal, osg::Vec3f &camera) { - //mCamera->getParentSceneNode()->needUpdate(true); + focal = getFocalPoint(); - //camera = mCamera->getRealPosition(); - //focal = mCameraNode->_getDerivedPosition(); + osg::Quat orient = osg::Quat(getPitch(), osg::Vec3d(1,0,0)) * osg::Quat(getYaw(), osg::Vec3d(0,0,1)); + + osg::Vec3d offset = orient * osg::Vec3d(0, -mCameraDistance, 0); + camera = focal + offset; } void Camera::togglePlayerLooking(bool enable) diff --git a/apps/openmw/mwrender/camera.hpp b/apps/openmw/mwrender/camera.hpp index 68f0870d71..a655e1c1f8 100644 --- a/apps/openmw/mwrender/camera.hpp +++ b/apps/openmw/mwrender/camera.hpp @@ -5,6 +5,7 @@ #include #include +#include #include "../mwworld/ptr.hpp" @@ -113,8 +114,10 @@ namespace MWRender void setAnimation(NpcAnimation *anim); + osg::Vec3d getFocalPoint(); + /// Stores focal and camera world positions in passed arguments - void getPosition(osg::Vec3 &focal, osg::Vec3 &camera); + void getPosition(osg::Vec3f &focal, osg::Vec3f &camera); void togglePlayerLooking(bool enable); diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index a067422d46..0218358394 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -514,6 +514,11 @@ namespace MWRender } } + float RenderingManager::getNearClipDistance() const + { + return mNearClip; + } + bool RenderingManager::vanityRotateCamera(const float *rot) { if(!mCamera->isVanityOrPreviewModeEnabled()) diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index e2524b3603..57a2df60e5 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -113,6 +113,8 @@ namespace MWRender void processChangedSettings(const Settings::CategorySettingVector& settings); + float getNearClipDistance() const; + // camera stuff bool vanityRotateCamera(const float *rot); void setCameraDistance(float dist, bool adjust, bool override); diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index aa21ca7fba..2f47c19e60 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1617,6 +1617,19 @@ namespace MWWorld int blind = static_cast(player.getClass().getCreatureStats(player).getMagicEffects().get(ESM::MagicEffect::Blind).getMagnitude()); MWBase::Environment::get().getWindowManager()->setBlindness(std::max(0, std::min(100, blind))); + + + mRendering->getCamera()->setCameraDistance(); + if(!mRendering->getCamera()->isFirstPerson()) + { + osg::Vec3f focal, camera; + mRendering->getCamera()->getPosition(focal, camera); + float radius = mRendering->getNearClipDistance()*2.5f; + MWPhysics::PhysicsSystem::RayResult result = mPhysics->castSphere(focal, camera, radius); + if (result.mHit) + mRendering->getCamera()->setCameraDistance((result.mHitPos - focal).length() - radius, false, false); + } + } void World::updateSoundListener()