Browse Source

Bugfix: Character reports to be on ground for one more frame after jumping against a wall (#674)

The wall will report a sliding contact and if we're not supported but have a sliding contact, we will attempt to move downwards to see if we're not actually supported by multiple steep slopes that form a bowl. We should skip this check if we're actually moving away from the ground as we'll not be supported then.
Jorrit Rouwe 2 years ago
parent
commit
39a76bb048
1 changed files with 30 additions and 22 deletions
  1. 30 22
      Jolt/Physics/Character/CharacterVirtual.cpp

+ 30 - 22
Jolt/Physics/Character/CharacterVirtual.cpp

@@ -202,7 +202,7 @@ void CharacterVirtual::ContactCastCollector::AddHit(const ShapeCastResult &inRes
 			// Convert the hit result into a contact
 			sFillContactProperties(mCharacter, contact, body, mUp, mBaseOffset, *this, inResult);
 		}
-			
+
 		contact.mFraction = inResult.mFraction;
 
 		// Check if the contact that will make us penetrate more than the allowed tolerance
@@ -397,7 +397,7 @@ void CharacterVirtual::DetermineConstraints(TempContactList &inContacts, float i
 		// Next check if the angle is too steep and if it is add an additional constraint that holds the character back
 		if (IsSlopeTooSteep(c.mSurfaceNormal))
 		{
-			// Only take planes that point up. 
+			// Only take planes that point up.
 			// Note that we use the contact normal to allow for better sliding as the surface normal may be in the opposite direction of movement.
 			float dot = c.mContactNormal.Dot(mUp);
 			if (dot > 1.0e-3f) // Add a little slack, if the normal is perfectly horizontal we already have our vertical plane.
@@ -863,27 +863,35 @@ void CharacterVirtual::UpdateSupportingContact(bool inSkipContactVelocityCheck,
 	}
 	else if (num_sliding > 0)
 	{
-		// If we're sliding we may actually be standing on multiple sliding contacts in such a way that we can't slide off, in this case we're also supported
-
-		// Convert the contacts into constraints
-		TempContactList contacts(mActiveContacts.begin(), mActiveContacts.end(), inAllocator);
-		ConstraintList constraints(inAllocator);
-		constraints.reserve(contacts.size() * 2);
-		DetermineConstraints(contacts, mLastDeltaTime, constraints);
-
-		// Solve the displacement using these constraints, this is used to check if we didn't move at all because we are supported
-		Vec3 displacement;
-		float time_simulated;
-		IgnoredContactList ignored_contacts(inAllocator);
-		ignored_contacts.reserve(contacts.size());
-		SolveConstraints(-mUp, 1.0f, 1.0f, constraints, ignored_contacts, time_simulated, displacement, inAllocator);
-
-		// If we're blocked then we're supported, otherwise we're sliding
-		float min_required_displacement_sq = Square(0.6f * mLastDeltaTime);
-		if (time_simulated < 0.001f || displacement.LengthSq() < min_required_displacement_sq)
-			mGroundState = EGroundState::OnGround;
-		else
+		if ((mLinearVelocity - deepest_contact->mLinearVelocity).Dot(mUp) > 1.0e-4f)
+		{
+			// We cannot be on ground if we're moving upwards relative to the ground
 			mGroundState = EGroundState::OnSteepGround;
+		}
+		else
+		{
+			// If we're sliding down, we may actually be standing on multiple sliding contacts in such a way that we can't slide off, in this case we're also supported
+
+			// Convert the contacts into constraints
+			TempContactList contacts(mActiveContacts.begin(), mActiveContacts.end(), inAllocator);
+			ConstraintList constraints(inAllocator);
+			constraints.reserve(contacts.size() * 2);
+			DetermineConstraints(contacts, mLastDeltaTime, constraints);
+
+			// Solve the displacement using these constraints, this is used to check if we didn't move at all because we are supported
+			Vec3 displacement;
+			float time_simulated;
+			IgnoredContactList ignored_contacts(inAllocator);
+			ignored_contacts.reserve(contacts.size());
+			SolveConstraints(-mUp, 1.0f, 1.0f, constraints, ignored_contacts, time_simulated, displacement, inAllocator);
+
+			// If we're blocked then we're supported, otherwise we're sliding
+			float min_required_displacement_sq = Square(0.6f * mLastDeltaTime);
+			if (time_simulated < 0.001f || displacement.LengthSq() < min_required_displacement_sq)
+				mGroundState = EGroundState::OnGround;
+			else
+				mGroundState = EGroundState::OnSteepGround;
+		}
 	}
 	else
 	{