Skip to content

Commit

Permalink
Implemented early out for CharacterVsCharacterCollisionSimple::Collid…
Browse files Browse the repository at this point in the history
…e/CastCharacter (#1479)

This increases performance by about 65% in the CharacterVirtual performance test.
  • Loading branch information
jrouwe authored Jan 26, 2025
1 parent 3324d6a commit 6601811
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 9 deletions.
40 changes: 31 additions & 9 deletions Jolt/Physics/Character/CharacterVirtual.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <Jolt/Core/ScopeExit.h>
#include <Jolt/Geometry/ConvexSupport.h>
#include <Jolt/Geometry/GJKClosestPoint.h>
#include <Jolt/Geometry/RayAABox.h>
#ifdef JPH_DEBUG_RENDERER
#include <Jolt/Renderer/DebugRenderer.h>
#endif // JPH_DEBUG_RENDERER
Expand All @@ -35,25 +36,35 @@ void CharacterVsCharacterCollisionSimple::CollideCharacter(const CharacterVirtua
// Make shape 1 relative to inBaseOffset
Mat44 transform1 = inCenterOfMassTransform.PostTranslated(-inBaseOffset).ToMat44();

const Shape *shape = inCharacter->GetShape();
const Shape *shape1 = inCharacter->GetShape();
CollideShapeSettings settings = inCollideShapeSettings;

// Get bounds for character
AABox bounds1 = shape1->GetWorldSpaceBounds(transform1, Vec3::sOne());

// Iterate over all characters
for (const CharacterVirtual *c : mCharacters)
if (c != inCharacter
&& !ioCollector.ShouldEarlyOut())
{
// Collector needs to know which character we're colliding with
ioCollector.SetUserData(reinterpret_cast<uint64>(c));

// Make shape 2 relative to inBaseOffset
Mat44 transform2 = c->GetCenterOfMassTransform().PostTranslated(-inBaseOffset).ToMat44();

// We need to add the padding of character 2 so that we will detect collision with its outer shell
settings.mMaxSeparationDistance = inCollideShapeSettings.mMaxSeparationDistance + c->GetCharacterPadding();

// Check if the bounding boxes of the characters overlap
const Shape *shape2 = c->GetShape();
AABox bounds2 = shape2->GetWorldSpaceBounds(transform2, Vec3::sOne());
bounds2.ExpandBy(Vec3::sReplicate(settings.mMaxSeparationDistance));
if (!bounds1.Overlaps(bounds2))
continue;

// Collector needs to know which character we're colliding with
ioCollector.SetUserData(reinterpret_cast<uint64>(c));

// Note that this collides against the character's shape without padding, this will be corrected for in CharacterVirtual::GetContactsAtPosition
CollisionDispatch::sCollideShapeVsShape(shape, c->GetShape(), Vec3::sOne(), Vec3::sOne(), transform1, transform2, SubShapeIDCreator(), SubShapeIDCreator(), settings, ioCollector);
CollisionDispatch::sCollideShapeVsShape(shape1, shape2, Vec3::sOne(), Vec3::sOne(), transform1, transform2, SubShapeIDCreator(), SubShapeIDCreator(), settings, ioCollector);
}

// Reset the user data
Expand All @@ -66,19 +77,30 @@ void CharacterVsCharacterCollisionSimple::CastCharacter(const CharacterVirtual *
Mat44 transform1 = inCenterOfMassTransform.PostTranslated(-inBaseOffset).ToMat44();
ShapeCast shape_cast(inCharacter->GetShape(), Vec3::sOne(), transform1, inDirection);

// Get world space bounds of the character in the form of center and extent
Vec3 origin = shape_cast.mShapeWorldBounds.GetCenter();
Vec3 extents = shape_cast.mShapeWorldBounds.GetExtent();

// Iterate over all characters
for (const CharacterVirtual *c : mCharacters)
if (c != inCharacter
&& !ioCollector.ShouldEarlyOut())
{
// Collector needs to know which character we're colliding with
ioCollector.SetUserData(reinterpret_cast<uint64>(c));

// Make shape 2 relative to inBaseOffset
Mat44 transform2 = c->GetCenterOfMassTransform().PostTranslated(-inBaseOffset).ToMat44();

// Sweep bounding box of the character against the bounding box of the other character to see if they can collide
const Shape *shape2 = c->GetShape();
AABox bounds2 = shape2->GetWorldSpaceBounds(transform2, Vec3::sOne());
bounds2.ExpandBy(extents);
if (!RayAABoxHits(origin, inDirection, bounds2.mMin, bounds2.mMax))
continue;

// Collector needs to know which character we're colliding with
ioCollector.SetUserData(reinterpret_cast<uint64>(c));

// Note that this collides against the character's shape without padding, this will be corrected for in CharacterVirtual::GetFirstContactForSweep
CollisionDispatch::sCastShapeVsShapeWorldSpace(shape_cast, inShapeCastSettings, c->GetShape(), Vec3::sOne(), { }, transform2, SubShapeIDCreator(), SubShapeIDCreator(), ioCollector);
CollisionDispatch::sCastShapeVsShapeWorldSpace(shape_cast, inShapeCastSettings, shape2, Vec3::sOne(), { }, transform2, SubShapeIDCreator(), SubShapeIDCreator(), ioCollector);
}

// Reset the user data
Expand Down
2 changes: 2 additions & 0 deletions Jolt/Physics/Character/CharacterVirtual.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,8 @@ class JPH_EXPORT CharacterVsCharacterCollision : public NonCopyable
};

/// Simple collision checker that loops over all registered characters.
/// This is a brute force checking algorithm. If you have a lot of characters you may want to store your characters
/// in a hierarchical structure to make this more efficient.
/// Note that this is not thread safe, so make sure that only one CharacterVirtual is checking collision at a time.
class JPH_EXPORT CharacterVsCharacterCollisionSimple : public CharacterVsCharacterCollision
{
Expand Down

0 comments on commit 6601811

Please sign in to comment.