Browse Source

Added function to do a collision check at an arbitrary position for both Character and CharacterVirtual with a similar interface (#155)

Jorrit Rouwe 3 years ago
parent
commit
3ee7c8a3f5

+ 24 - 11
Jolt/Physics/Character/Character.cpp

@@ -68,7 +68,7 @@ void Character::Activate(bool inLockBodies)
 	sGetBodyInterface(mSystem, inLockBodies).ActivateBody(mBodyID);
 }
 
-void Character::CheckCollision(const Shape *inShape, float inMaxSeparationDistance, CollideShapeCollector &ioCollector, bool inLockBodies) const
+void Character::CheckCollision(Mat44Arg inCenterOfMassTransform, Vec3Arg inMovementDirection, float inMaxSeparationDistance, const Shape *inShape, CollideShapeCollector &ioCollector, bool inLockBodies) const
 {
 	// Create query broadphase layer filter
 	DefaultBroadPhaseLayerFilter broadphase_layer_filter = mSystem->GetDefaultBroadPhaseLayerFilter(mLayer);
@@ -79,6 +79,26 @@ void Character::CheckCollision(const Shape *inShape, float inMaxSeparationDistan
 	// Ignore my own body
 	IgnoreSingleBodyFilter body_filter(mBodyID);
 
+	// Settings for collide shape
+	CollideShapeSettings settings;
+	settings.mMaxSeparationDistance = inMaxSeparationDistance;
+	settings.mActiveEdgeMode = EActiveEdgeMode::CollideOnlyWithActive;
+	settings.mActiveEdgeMovementDirection = inMovementDirection;
+	settings.mBackFaceMode = EBackFaceMode::IgnoreBackFaces;
+
+	sGetNarrowPhaseQuery(mSystem, inLockBodies).CollideShape(inShape, Vec3::sReplicate(1.0f), inCenterOfMassTransform, settings, ioCollector, broadphase_layer_filter, object_layer_filter, body_filter);
+}
+
+void Character::CheckCollision(Vec3Arg inPosition, QuatArg inRotation, Vec3Arg inMovementDirection, float inMaxSeparationDistance, const Shape *inShape, CollideShapeCollector &ioCollector, bool inLockBodies) const
+{
+	// Calculate center of mass transform
+	Mat44 center_of_mass = Mat44::sRotationTranslation(inRotation, inPosition).PreTranslated(inShape->GetCenterOfMass());
+
+	CheckCollision(center_of_mass, inMovementDirection, inMaxSeparationDistance, inShape, ioCollector, inLockBodies);
+}
+
+void Character::CheckCollision(const Shape *inShape, float inMaxSeparationDistance, CollideShapeCollector &ioCollector, bool inLockBodies) const
+{
 	// Determine position and velocity of body
 	Mat44 query_transform;
 	Vec3 velocity;
@@ -94,14 +114,7 @@ void Character::CheckCollision(const Shape *inShape, float inMaxSeparationDistan
 		velocity = body.GetLinearVelocity();
 	}
 
-	// Settings for collide shape
-	CollideShapeSettings settings;
-	settings.mMaxSeparationDistance = inMaxSeparationDistance;
-	settings.mActiveEdgeMode = EActiveEdgeMode::CollideOnlyWithActive;
-	settings.mActiveEdgeMovementDirection = velocity;
-	settings.mBackFaceMode = EBackFaceMode::IgnoreBackFaces;
-
-	sGetNarrowPhaseQuery(mSystem, inLockBodies).CollideShape(inShape, Vec3::sReplicate(1.0f), query_transform, settings, ioCollector, broadphase_layer_filter, object_layer_filter, body_filter);
+	CheckCollision(query_transform, velocity, inMaxSeparationDistance, inShape, ioCollector, inLockBodies);
 }
 
 void Character::PostSimulation(float inMaxSeparationDistance, bool inLockBodies)
@@ -140,7 +153,7 @@ void Character::PostSimulation(float inMaxSeparationDistance, bool inLockBodies)
 
 	// Collide shape
 	MyCollector collector(mSystem->GetGravity());
-	CheckCollision(mShape, inMaxSeparationDistance, collector);
+	CheckCollision(mShape, inMaxSeparationDistance, collector, inLockBodies);
 
 	// Copy results
 	mGroundBodyID = collector.mGroundBodyID;
@@ -274,7 +287,7 @@ bool Character::SetShape(const Shape *inShape, float inMaxPenetrationDepth, bool
 
 		// Test if anything is in the way of switching
 		MyCollector collector(inMaxPenetrationDepth);
-		CheckCollision(inShape, 0.0f, collector);
+		CheckCollision(inShape, 0.0f, collector, inLockBodies);
 		if (collector.mHadCollision)
 			return false;
 	}

+ 15 - 2
Jolt/Physics/Character/Character.h

@@ -106,9 +106,22 @@ public:
 	/// if the new shape collides before switching shape. Returns true if the switch succeeded.
 	bool								SetShape(const Shape *inShape, float inMaxPenetrationDepth, bool inLockBodies = true);
 
+	/// @brief Get all contacts for the character at a particular location
+	/// @param inPosition Position to test.
+	/// @param inRotation Rotation at which to test the shape.
+	/// @param inMovementDirection A hint in which direction the character is moving, will be used to calculate a proper normal.
+	/// @param inMaxSeparationDistance How much distance around the character you want to report contacts in (can be 0 to match the character exactly).
+	/// @param inShape Shape to test collision with.
+	/// @param ioCollector Collision collector that receives the collision results.
+	/// @param inLockBodies If the collision query should use the locking body interface (true) or the non locking body interface (false)
+	void								CheckCollision(Vec3Arg inPosition, QuatArg inRotation, Vec3Arg inMovementDirection, float inMaxSeparationDistance, const Shape *inShape, CollideShapeCollector &ioCollector, bool inLockBodies = true) const;
+
 private:
-	/// Check collisions between inShape and the world
-	void								CheckCollision(const Shape *inShape, float inMaxSeparationDistance, CollideShapeCollector &ioCollector, bool inLockBodies = true) const;
+	/// Check collisions between inShape and the world using the center of mass transform
+	void								CheckCollision(Mat44Arg inCenterOfMassTransform, Vec3Arg inMovementDirection, float inMaxSeparationDistance, const Shape *inShape, CollideShapeCollector &ioCollector, bool inLockBodies) const;
+
+	/// Check collisions between inShape and the world using the current position / rotation of the character
+	void								CheckCollision(const Shape *inShape, float inMaxSeparationDistance, CollideShapeCollector &ioCollector, bool inLockBodies) const;
 
 	/// The body of this character
 	BodyID								mBodyID;

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

@@ -89,24 +89,30 @@ void CharacterVirtual::ContactCastCollector::AddHit(const ShapeCastResult &inRes
 	}
 }
 
-void CharacterVirtual::GetContactsAtPosition(Vec3Arg inPosition, Vec3Arg inMovementDirection, const Shape *inShape, TempContactList &outContacts, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter) const
+void CharacterVirtual::CheckCollision(Vec3Arg inPosition, QuatArg inRotation, Vec3Arg inMovementDirection, float inMaxSeparationDistance, const Shape *inShape, CollideShapeCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter) const
 {
-	// Remove previous results
-	outContacts.clear();
-
 	// Query shape transform
-	Mat44 transform = GetCenterOfMassTransform(inPosition);
+	Mat44 transform = GetCenterOfMassTransform(inPosition, inRotation, inShape);
 
 	// Settings for collide shape
 	CollideShapeSettings settings;
 	settings.mActiveEdgeMode = EActiveEdgeMode::CollideOnlyWithActive;
 	settings.mBackFaceMode = EBackFaceMode::CollideWithBackFaces;
 	settings.mActiveEdgeMovementDirection = inMovementDirection;
-	settings.mMaxSeparationDistance = mCharacterPadding + mPredictiveContactDistance;
+	settings.mMaxSeparationDistance = mCharacterPadding + inMaxSeparationDistance;
+
+	// Collide shape
+	mSystem->GetNarrowPhaseQuery().CollideShape(inShape, Vec3::sReplicate(1.0f), transform, settings, ioCollector, inBroadPhaseLayerFilter, inObjectLayerFilter, inBodyFilter);
+}
+
+void CharacterVirtual::GetContactsAtPosition(Vec3Arg inPosition, Vec3Arg inMovementDirection, const Shape *inShape, TempContactList &outContacts, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter) const
+{
+	// Remove previous results
+	outContacts.clear();
 
 	// Collide shape
 	ContactCollector collector(mSystem, mMaxNumHits, outContacts);
-	mSystem->GetNarrowPhaseQuery().CollideShape(inShape, Vec3::sReplicate(1.0f), transform, settings, collector, inBroadPhaseLayerFilter, inObjectLayerFilter, inBodyFilter);
+	CheckCollision(inPosition, mRotation, inMovementDirection, mPredictiveContactDistance, inShape, collector, inBroadPhaseLayerFilter, inObjectLayerFilter, inBodyFilter);
 
 	// Reduce distance to contact by padding to ensure we stay away from the object by a little margin
 	// (this will make collision detection cheaper - especially for sweep tests as they won't hit the surface if we're properly sliding)
@@ -168,7 +174,7 @@ bool CharacterVirtual::GetFirstContactForSweep(Vec3Arg inPosition, Vec3Arg inDis
 		return false;
 
 	// Calculate start transform
-	Mat44 start = GetCenterOfMassTransform(inPosition);
+	Mat44 start = GetCenterOfMassTransform(inPosition, mRotation, mShape);
 
 	// Settings for the cast
 	ShapeCastSettings settings;
@@ -792,10 +798,6 @@ bool CharacterVirtual::SetShape(const Shape *inShape, float inMaxPenetrationDept
 
 	if (inShape != mShape && inShape != nullptr)
 	{
-		// Tentatively set new shape
-		RefConst<Shape> old_shape = mShape;
-		mShape = inShape;
-
 		if (inMaxPenetrationDepth < FLT_MAX)
 		{
 			// Check collision around the new shape
@@ -806,13 +808,13 @@ bool CharacterVirtual::SetShape(const Shape *inShape, float inMaxPenetrationDept
 			// Test if this results in penetration, if so cancel the transition
 			for (const Contact &c : contacts)
 				if (c.mDistance < -inMaxPenetrationDepth)
-				{
-					mShape = old_shape;
 					return false;
-				}
 
 			StoreActiveContacts(contacts, inAllocator);
 		}
+
+		// Set new shape
+		mShape = inShape;
 	}
 
 	return mShape == inShape;

+ 17 - 2
Jolt/Physics/Character/CharacterVirtual.h

@@ -103,7 +103,7 @@ public:
 	Mat44								GetWorldTransform() const								{ return Mat44::sRotationTranslation(mRotation, mPosition); }
 
 	/// Calculates the transform for this character's center of mass
-	Mat44								GetCenterOfMassTransform() const						{ return GetCenterOfMassTransform(mPosition); }
+	Mat44								GetCenterOfMassTransform() const						{ return GetCenterOfMassTransform(mPosition, mRotation, mShape); }
 
 	/// Character mass (kg)
 	void								SetMass(float inMass)									{ mMass = inMass; }
@@ -136,6 +136,18 @@ public:
 	/// @return Returns true if the switch succeeded.
 	bool								SetShape(const Shape *inShape, float inMaxPenetrationDepth, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter, TempAllocator &inAllocator);
 
+	/// @brief Get all contacts for the character at a particular location
+	/// @param inPosition Position to test, note that this position will be corrected for the character padding.
+	/// @param inRotation Rotation at which to test the shape.
+	/// @param inMovementDirection A hint in which direction the character is moving, will be used to calculate a proper normal.
+	/// @param inMaxSeparationDistance How much distance around the character you want to report contacts in (can be 0 to match the character exactly).
+	/// @param inShape Shape to test collision with.
+	/// @param ioCollector Collision collector that receives the collision results.
+	/// @param inBroadPhaseLayerFilter Filter that is used to check if the character collides with something in the broadphase.
+	/// @param inObjectLayerFilter Filter that is used to check if a character collides with a layer.
+	/// @param inBodyFilter Filter that is used to check if a character collides with a body.
+	void								CheckCollision(Vec3Arg inPosition, QuatArg inRotation, Vec3Arg inMovementDirection, float inMaxSeparationDistance, const Shape *inShape, CollideShapeCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter) const;
+
 	// Saving / restoring state for replay
 	virtual void						SaveState(StateRecorder &inStream) const override;
 	virtual void						RestoreState(StateRecorder &inStream) override;
@@ -253,7 +265,10 @@ private:
 	void								UpdateSupportingContact(TempAllocator &inAllocator);
 
 	// This function returns the actual center of mass of the shape, not corrected for the character padding
-	inline Mat44						GetCenterOfMassTransform(Vec3Arg inPosition) const		{ return Mat44::sRotationTranslation(mRotation, inPosition).PreTranslated(mShape->GetCenterOfMass()).PostTranslated(mCharacterPadding * mUp); }
+	inline Mat44						GetCenterOfMassTransform(Vec3Arg inPosition, QuatArg inRotation, const Shape *inShape) const
+	{
+		return Mat44::sRotationTranslation(inRotation, inPosition).PreTranslated(inShape->GetCenterOfMass()).PostTranslated(mCharacterPadding * mUp);
+	}
 
 	// Our main listener for contacts
 	CharacterContactListener *			mListener = nullptr;