summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpsi29a <psi29a@gmail.com>2022-01-17 07:32:19 +0000
committerpsi29a <psi29a@gmail.com>2022-01-17 07:32:19 +0000
commit78e8fb5cf9e235fae78e22a6eebb52caae014171 (patch)
treeaffb532526dc86c2551d12cc3f2571be5be21eab
parentfd7e0b74cc640c42d7b121da5fba0d7ec1c240f0 (diff)
parent20cbf941fbe054bc24ff24feb3ef01f6b13c1842 (diff)
Merge branch 'movement_tweaks' into 'master'
Movement solver tweaks See merge request OpenMW/openmw!1352
-rw-r--r--apps/openmw/mwphysics/actor.cpp1
-rw-r--r--apps/openmw/mwphysics/constants.hpp2
-rw-r--r--apps/openmw/mwphysics/movementsolver.cpp38
3 files changed, 29 insertions, 12 deletions
diff --git a/apps/openmw/mwphysics/actor.cpp b/apps/openmw/mwphysics/actor.cpp
index 16501c432d..568da999bc 100644
--- a/apps/openmw/mwphysics/actor.cpp
+++ b/apps/openmw/mwphysics/actor.cpp
@@ -59,6 +59,7 @@ Actor::Actor(const MWWorld::Ptr& ptr, const Resource::BulletShape* shape, Physic
mRotationallyInvariant = (mMeshTranslation.x() == 0.0 && mMeshTranslation.y() == 0.0) && std::fabs(mOriginalHalfExtents.x() - mOriginalHalfExtents.y()) < 2.2;
mConvexShape = static_cast<btConvexShape*>(mShape.get());
+ mConvexShape->setMargin(0.001); // make sure bullet isn't using the huge default convex shape margin of 0.04
mCollisionObject = std::make_unique<btCollisionObject>();
mCollisionObject->setCollisionFlags(btCollisionObject::CF_KINEMATIC_OBJECT);
diff --git a/apps/openmw/mwphysics/constants.hpp b/apps/openmw/mwphysics/constants.hpp
index c275b63c7b..b2d189e874 100644
--- a/apps/openmw/mwphysics/constants.hpp
+++ b/apps/openmw/mwphysics/constants.hpp
@@ -15,7 +15,7 @@ namespace MWPhysics
// Arbitrary number. To prevent infinite loops. They shouldn't happen but it's good to be prepared.
static constexpr int sMaxIterations = 8;
// Allows for more precise movement solving without getting stuck or snagging too easily.
- static constexpr float sCollisionMargin = 0.1f;
+ static constexpr float sCollisionMargin = 0.2f;
// Allow for a small amount of penetration to prevent numerical precision issues from causing the "unstuck"ing code to run unnecessarily
// Currently set to 0 because having the "unstuck"ing code run whenever possible prevents some glitchy snagging issues
static constexpr float sAllowedPenetration = 0.0f;
diff --git a/apps/openmw/mwphysics/movementsolver.cpp b/apps/openmw/mwphysics/movementsolver.cpp
index fc2ea57b40..2f2abca487 100644
--- a/apps/openmw/mwphysics/movementsolver.cpp
+++ b/apps/openmw/mwphysics/movementsolver.cpp
@@ -252,6 +252,8 @@ namespace MWPhysics
remainingTime *= (1.0f-tracer.mFraction);
auto planeNormal = tracer.mPlaneNormal;
+ // need to know the unadjusted normal to handle certain types of seams properly
+ const auto origPlaneNormal = planeNormal;
// If we touched the ground this frame, and whatever we ran into is a wall of some sort,
// pretend that its collision normal is pointing horizontally
@@ -275,10 +277,11 @@ namespace MWPhysics
bool usedSeamLogic = false;
// check for the current and previous collision planes forming an acute angle; slide along the seam if they do
+ // for this, we want to use the original plane normal, or else certain types of geometry will snag
if(numTimesSlid > 0)
{
- auto dotA = lastSlideNormal * planeNormal;
- auto dotB = lastSlideNormalFallback * planeNormal;
+ auto dotA = lastSlideNormal * origPlaneNormal;
+ auto dotB = lastSlideNormalFallback * origPlaneNormal;
if(numTimesSlid <= 1) // ignore fallback normal if this is only the first or second slide
dotB = 1.0;
if(dotA <= 0.0 || dotB <= 0.0)
@@ -291,14 +294,14 @@ namespace MWPhysics
lastSlideNormal = lastSlideNormalFallback;
}
- auto constraintVector = bestNormal ^ planeNormal; // cross product
+ auto constraintVector = bestNormal ^ origPlaneNormal; // cross product
if(constraintVector.length2() > 0) // only if it's not zero length
{
constraintVector.normalize();
newVelocity = project(velocity, constraintVector);
// version of surface rejection for acute crevices/seams
- auto averageNormal = bestNormal + planeNormal;
+ auto averageNormal = bestNormal + origPlaneNormal;
averageNormal.normalize();
tracer.doTrace(actor.mCollisionObject, newPosition, newPosition + averageNormal*(sCollisionMargin*2.0), collisionWorld);
newPosition = (newPosition + tracer.mEndPos)/2.0;
@@ -309,27 +312,40 @@ namespace MWPhysics
}
// otherwise just keep the normal vector rejection
- // if this isn't the first iteration, or if the first iteration is also the last iteration,
// move away from the collision plane slightly, if possible
// this reduces getting stuck in some concave geometry, like the gaps above the railings in some ald'ruhn buildings
// this is different from the normal collision margin, because the normal collision margin is along the movement path,
// but this is along the collision normal
- if(!usedSeamLogic && (iterations > 0 || remainingTime < 0.01f))
+ if(!usedSeamLogic)
{
tracer.doTrace(actor.mCollisionObject, newPosition, newPosition + planeNormal*(sCollisionMargin*2.0), collisionWorld);
newPosition = (newPosition + tracer.mEndPos)/2.0;
}
+ // short circuit if we went backwards, but only if it was mostly horizontal and we're on the ground
+ if (seenGround && newVelocity * origVelocity <= 0.0f)
+ {
+ auto perpendicular = newVelocity ^ origVelocity;
+ if (perpendicular.length2() > 0.0f)
+ {
+ perpendicular.normalize();
+ if (std::abs(perpendicular.z()) > 0.7071f)
+ break;
+ }
+ }
+
// Do not allow sliding up steep slopes if there is gravity.
- if (newPosition.z() >= swimlevel && !actor.mFlying && !isWalkableSlope(planeNormal))
+ // The purpose of this is to prevent air control from letting you slide up tall, unwalkable slopes.
+ // For that purpose, it is not necessary to do it when trying to slide along acute seams/crevices (i.e. usedSeamLogic)
+ // and doing so would actually break air control in some situations where vanilla allows air control.
+ // Vanilla actually allows you to slide up slopes as long as you're in the "walking" animation, which can be true even
+ // in the air, so allowing this for seams isn't a compatibility break.
+ if (newPosition.z() >= swimlevel && !actor.mFlying && !isWalkableSlope(planeNormal) && !usedSeamLogic)
newVelocity.z() = std::min(newVelocity.z(), velocity.z());
- if (newVelocity * origVelocity <= 0.0f)
- break;
-
numTimesSlid += 1;
lastSlideNormalFallback = lastSlideNormal;
- lastSlideNormal = planeNormal;
+ lastSlideNormal = origPlaneNormal;
velocity = newVelocity;
}
}