Browse Source

Attempt to remove jitter in virtual character when moving towards steep slope (#696)

This can be seen in CharacterVirtualTest by walking towards the area that has varying slope angles and trying to slide against the base of the steep slopes. Due to numerical accuracy, you could randomly hit the vertical wall constraint or the slope constraint first. If you hit the constraint first it was possibler that you accumulated a small vertical velocity which caused the character to leave the floor a little bit. This was visible as a jitter in movement. Now we cancel the velocity towards the slope also in the steep slope so that we don't get this vertical velocity.
Jorrit Rouwe 1 year ago
parent
commit
60e16e44e8

+ 17 - 0
Jolt/Physics/Character/CharacterVirtual.cpp

@@ -402,6 +402,9 @@ void CharacterVirtual::DetermineConstraints(TempContactList &inContacts, float i
 			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.
 			{
+				// Mark the slope constraint as steep
+				constraint.mIsSteepSlope = true;
+
 				// Make horizontal normal
 				Vec3 normal = (c.mContactNormal - dot * mUp).Normalized();
 
@@ -628,6 +631,20 @@ void CharacterVirtual::SolveConstraints(Vec3Arg inVelocity, float inDeltaTime, f
 		// Get the normal of the plane we're hitting
 		Vec3 plane_normal = constraint->mPlane.GetNormal();
 
+		// If we're hitting a steep slope we cancel the velocity towards the slope first so that we don't end up slidinng up the slope
+		// (we may hit the slope before the vertical wall constraint we added which will result in a small movement up causing jitter in the character movement)
+		if (constraint->mIsSteepSlope)
+		{
+			// We're hitting a steep slope, create a vertical plane that blocks any further movement up the slope (note: not normalized)
+			Vec3 vertical_plane_normal = plane_normal - plane_normal.Dot(mUp) * mUp;
+
+			// Get the relative velocity between the character and the constraint
+			Vec3 relative_velocity = velocity - constraint->mLinearVelocity;
+
+			// Remove velocity towards the slope
+			velocity = velocity - min(0.0f, relative_velocity.Dot(vertical_plane_normal)) * vertical_plane_normal / vertical_plane_normal.LengthSq();
+		}
+
 		// Get the relative velocity between the character and the constraint
 		Vec3 relative_velocity = velocity - constraint->mLinearVelocity;
 

+ 1 - 0
Jolt/Physics/Character/CharacterVirtual.h

@@ -333,6 +333,7 @@ private:
 		float							mProjectedVelocity;										///< Velocity of the contact projected on the contact normal (negative if separating)
 		Vec3							mLinearVelocity;										///< Velocity of the contact (can contain a corrective velocity to resolve penetration)
 		Plane							mPlane;													///< Plane around the origin that describes how far we can displace (from the origin)
+		bool							mIsSteepSlope = false;									///< If this constraint belongs to a steep slope
 	};
 
 	using ConstraintList = std::vector<Constraint, STLTempAllocator<Constraint>>;