Browse Source

Improved enhanced active edge detection (#1162)

Turning off the cached active edge flags when enhanced active edge detection is on. A collision with an inactive edge will result in its normal being aligned with the face. This means it is not properly filtered out by the enhanced active edge detection algorithm and can cause an incorrect simulation.

See #1155
Jorrit Rouwe 1 year ago
parent
commit
fda5b4aa5a

+ 6 - 1
Jolt/Physics/Character/CharacterVirtual.cpp

@@ -317,7 +317,6 @@ void CharacterVirtual::CheckCollision(RVec3Arg inPosition, QuatArg inRotation, V
 
 	// Settings for collide shape
 	CollideShapeSettings settings;
-	settings.mActiveEdgeMode = EActiveEdgeMode::CollideOnlyWithActive;
 	settings.mBackFaceMode = mBackFaceMode;
 	settings.mActiveEdgeMovementDirection = inMovementDirection;
 	settings.mMaxSeparationDistance = mCharacterPadding + inMaxSeparationDistance;
@@ -326,6 +325,7 @@ void CharacterVirtual::CheckCollision(RVec3Arg inPosition, QuatArg inRotation, V
 	if (mEnhancedInternalEdgeRemoval)
 	{
 		// Version that does additional work to remove internal edges
+		settings.mActiveEdgeMode = EActiveEdgeMode::CollideWithAll;
 		settings.mCollectFacesMode = ECollectFacesMode::CollectFaces;
 
 		// This is a copy of NarrowPhaseQuery::CollideShape with additional logic to wrap the collector in an InternalEdgeRemovingCollector and flushing that collector after every body
@@ -389,7 +389,12 @@ void CharacterVirtual::CheckCollision(RVec3Arg inPosition, QuatArg inRotation, V
 		mSystem->GetBroadPhaseQuery().CollideAABox(bounds, collector, inBroadPhaseLayerFilter, inObjectLayerFilter);
 	}
 	else
+	{
+		// Version that uses the cached active edges
+		settings.mActiveEdgeMode = EActiveEdgeMode::CollideOnlyWithActive;
+
 		mSystem->GetNarrowPhaseQuery().CollideShape(inShape, Vec3::sReplicate(1.0f), transform, settings, inBaseOffset, ioCollector, inBroadPhaseLayerFilter, inObjectLayerFilter, inBodyFilter, inShapeFilter);
+	}
 
 	// Also collide with other characters
 	if (mCharacterVsCharacterCollision != nullptr)

+ 6 - 3
Jolt/Physics/PhysicsSystem.cpp

@@ -999,10 +999,13 @@ void PhysicsSystem::ProcessBodyPair(ContactAllocator &ioContactAllocator, const
 		if (body_pair_handle == nullptr)
 			return; // Out of cache space
 
+		// If we want enhanced active edge detection for this body pair
+		bool enhanced_active_edges = body1->GetEnhancedInternalEdgeRemovalWithBody(*body2);
+
 		// Create the query settings
 		CollideShapeSettings settings;
 		settings.mCollectFacesMode = ECollectFacesMode::CollectFaces;
-		settings.mActiveEdgeMode = mPhysicsSettings.mCheckActiveEdges? EActiveEdgeMode::CollideOnlyWithActive : EActiveEdgeMode::CollideWithAll;
+		settings.mActiveEdgeMode = mPhysicsSettings.mCheckActiveEdges && !enhanced_active_edges? EActiveEdgeMode::CollideOnlyWithActive : EActiveEdgeMode::CollideWithAll;
 		settings.mMaxSeparationDistance = body1->IsSensor() || body2->IsSensor()? 0.0f : mPhysicsSettings.mSpeculativeContactDistance;
 		settings.mActiveEdgeMovementDirection = body1->GetLinearVelocity() - body2->GetLinearVelocity();
 
@@ -1126,7 +1129,7 @@ void PhysicsSystem::ProcessBodyPair(ContactAllocator &ioContactAllocator, const
 
 			// Perform collision detection between the two shapes
 			SubShapeIDCreator part1, part2;
-			auto f = body1->GetEnhancedInternalEdgeRemovalWithBody(*body2)? InternalEdgeRemovingCollector::sCollideShapeVsShape : CollisionDispatch::sCollideShapeVsShape;
+			auto f = enhanced_active_edges? InternalEdgeRemovingCollector::sCollideShapeVsShape : CollisionDispatch::sCollideShapeVsShape;
 			f(body1->GetShape(), body2->GetShape(), Vec3::sReplicate(1.0f), Vec3::sReplicate(1.0f), transform1, transform2, part1, part2, settings, collector, { });
 
 			// Add the contacts
@@ -1227,7 +1230,7 @@ void PhysicsSystem::ProcessBodyPair(ContactAllocator &ioContactAllocator, const
 
 			// Perform collision detection between the two shapes
 			SubShapeIDCreator part1, part2;
-			auto f = body1->GetEnhancedInternalEdgeRemovalWithBody(*body2)? InternalEdgeRemovingCollector::sCollideShapeVsShape : CollisionDispatch::sCollideShapeVsShape;
+			auto f = enhanced_active_edges? InternalEdgeRemovingCollector::sCollideShapeVsShape : CollisionDispatch::sCollideShapeVsShape;
 			f(body1->GetShape(), body2->GetShape(), Vec3::sReplicate(1.0f), Vec3::sReplicate(1.0f), transform1, transform2, part1, part2, settings, collector, { });
 
 			constraint_created = collector.mConstraintCreated;

+ 45 - 0
Samples/Tests/General/EnhancedInternalEdgeRemovalTest.cpp

@@ -111,4 +111,49 @@ void EnhancedInternalEdgeRemovalTest::Initialize()
 			z += 4.0f;
 		}
 	}
+
+	// Create a flat plane
+	MeshShapeSettings plane_mesh({
+		{
+			Float3(-10, 0, -10),
+			Float3(-10, 0, 10),
+			Float3(10, 0, 10)
+		},
+		{
+			Float3(-10, 0, -10),
+			Float3(10, 0, 10),
+			Float3(10, 0, -10)
+		},
+	});
+	plane_mesh.SetEmbedded();
+	BodyCreationSettings level_plane(&plane_mesh, RVec3(-10, 0, 50), Quat::sIdentity(), EMotionType::Static, Layers::NON_MOVING);
+	level_plane.mFriction = 1;
+	mBodyInterface->CreateAndAddBody(level_plane, EActivation::DontActivate);
+
+	// Roll a ball over it
+	BodyCreationSettings level_ball(new SphereShape(0.5f), RVec3(-10, 1, 41), Quat::sIdentity(), EMotionType::Dynamic, Layers::MOVING);
+	level_ball.mEnhancedInternalEdgeRemoval = true;
+	level_ball.mFriction = 1;
+	level_ball.mOverrideMassProperties = EOverrideMassProperties::CalculateInertia;
+	level_ball.mMassPropertiesOverride.mMass = 1;
+	mLevelBall = mBodyInterface->CreateAndAddBody(level_ball, EActivation::Activate);
+
+	// Create a sloped plane
+	BodyCreationSettings slope_plane(&plane_mesh, RVec3(10, 0, 50), Quat::sRotation(Vec3::sAxisX(), DegreesToRadians(45)), EMotionType::Static, Layers::NON_MOVING);
+	slope_plane.mFriction = 1;
+	mBodyInterface->CreateAndAddBody(slope_plane, EActivation::DontActivate);
+
+	// Roll a ball over it
+	BodyCreationSettings slope_ball(new SphereShape(0.5f), RVec3(10, 8, 44), Quat::sIdentity(), EMotionType::Dynamic, Layers::MOVING);
+	slope_ball.mEnhancedInternalEdgeRemoval = true;
+	slope_ball.mFriction = 1;
+	slope_ball.mOverrideMassProperties = EOverrideMassProperties::CalculateInertia;
+	slope_ball.mMassPropertiesOverride.mMass = 1;
+	mBodyInterface->CreateAndAddBody(slope_ball, EActivation::Activate);
+}
+
+void EnhancedInternalEdgeRemovalTest::PrePhysicsUpdate(const PreUpdateParams &inParams)
+{
+	// Increase rotation speed of the ball on the flat plane
+	mBodyInterface->AddTorque(mLevelBall, Vec3(JPH_PI * 4, 0, 0));
 }

+ 3 - 0
Samples/Tests/General/EnhancedInternalEdgeRemovalTest.h

@@ -14,7 +14,10 @@ public:
 
 	// See: Test
 	virtual void	Initialize() override;
+	virtual void	PrePhysicsUpdate(const PreUpdateParams &inParams) override;
 
 private:
 	void			CreateSlidingObjects(RVec3Arg inStart);
+
+	BodyID			mLevelBall;
 };