Skip to content

Commit

Permalink
An empty MutableCompoundShape now returns the same local bounding box…
Browse files Browse the repository at this point in the history
… as EmptyShape (a point at (0, 0, 0)). (#1461)

This prevents floating point overflow exceptions.
  • Loading branch information
jrouwe authored Jan 17, 2025
1 parent 8c81aa5 commit 2c1864d
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 3 deletions.
1 change: 1 addition & 0 deletions Docs/ReleaseNotes.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ For breaking API changes see [this document](https://github.com/jrouwe/JoltPhysi
* Fixed CharacterVirtual::Contact::mHadContact not being true for collisions with sensors. They will still be marked as mWasDiscarded to prevent any further interaction.
* Fixed numerical inaccuracy in penetration depth calculation when CollideShapeSettings::mMaxSeparationDistance was set to a really high value (e.g. 1000).
* Bugfix in Semaphore::Acquire for non-windows platform. The count was updated before waiting, meaning that the counter would become -(number of waiting threads) and the semaphore would not wake up until at least the same amount of releases was done. In practice this meant that the main thread had to do the last (number of threads) jobs, slowing down the simulation a bit.
* An empty MutableCompoundShape now returns the same local bounding box as EmptyShape (a point at (0, 0, 0)). This prevents floating point overflow exceptions.

## v5.2.0

Expand Down
4 changes: 2 additions & 2 deletions Jolt/Physics/Collision/Shape/MutableCompoundShape.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,8 @@ void MutableCompoundShape::CalculateLocalBounds()
}
else
{
// There are no subshapes, set the bounding box to invalid
mLocalBounds.SetEmpty();
// There are no subshapes, make the bounding box empty
mLocalBounds.mMin = mLocalBounds.mMax = Vec3::sZero();
}

// Cache the inner radius as it can take a while to recursively iterate over all sub shapes
Expand Down
38 changes: 37 additions & 1 deletion UnitTests/Physics/MutableCompoundShapeTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <Jolt/Physics/Collision/Shape/MutableCompoundShape.h>
#include <Jolt/Physics/Collision/CollisionCollectorImpl.h>
#include <Jolt/Physics/Collision/CollidePointResult.h>
#include <Jolt/Physics/Collision/CollideShape.h>

TEST_SUITE("MutableCompoundShapeTests")
{
Expand Down Expand Up @@ -117,7 +118,7 @@ TEST_SUITE("MutableCompoundShapeTests")

shape->RemoveShape(0);
CHECK(shape->GetNumSubShapes() == 0);
CHECK(!shape->GetLocalBounds().IsValid());
CHECK(shape->GetLocalBounds() == AABox(Vec3::sZero(), Vec3::sZero()));
CHECK(check_shape_hit(Vec3::sZero()) == nullptr);
CHECK(check_shape_hit(Vec3(10, 0, 0)) == nullptr);
CHECK(check_shape_hit(Vec3(15, 0, 0)) == nullptr);
Expand Down Expand Up @@ -170,4 +171,39 @@ TEST_SUITE("MutableCompoundShapeTests")
CHECK((collector.mHits.size() == 1 && shape->GetSubShapeUserData(collector.mHits[0].mSubShapeID2) == 2));
collector.Reset();
}

TEST_CASE("TestEmptyMutableCompoundShape")
{
// Create an empty compound shape
PhysicsTestContext c;
MutableCompoundShapeSettings settings;
Ref<MutableCompoundShape> shape = StaticCast<MutableCompoundShape>(settings.Create().Get());
BodyCreationSettings bcs(shape, RVec3::sZero(), Quat::sIdentity(), EMotionType::Dynamic, Layers::MOVING);
bcs.mLinearDamping = 0.0f;
bcs.mOverrideMassProperties = EOverrideMassProperties::MassAndInertiaProvided;
bcs.mMassPropertiesOverride.mMass = 1.0f;
bcs.mMassPropertiesOverride.mInertia = Mat44::sIdentity();
BodyID body_id = c.GetBodyInterface().CreateAndAddBody(bcs, EActivation::Activate);

// Simulate with empty shape
c.Simulate(1.0f);
RVec3 expected_pos = c.PredictPosition(RVec3::sZero(), Vec3::sZero(), c.GetSystem()->GetGravity(), 1.0f);
CHECK_APPROX_EQUAL(c.GetBodyInterface().GetPosition(body_id), expected_pos);

// Check that we can't hit the shape
Ref<Shape> box_shape = new BoxShape(Vec3::sReplicate(10000));
AllHitCollisionCollector<CollideShapeCollector> collector;
c.GetSystem()->GetNarrowPhaseQuery().CollideShape(box_shape, Vec3::sOne(), RMat44::sIdentity(), CollideShapeSettings(), RVec3::sZero(), collector);
CHECK(collector.mHits.empty());

// Add a box to the compound shape
Vec3 com = shape->GetCenterOfMass();
shape->AddShape(Vec3::sZero(), Quat::sIdentity(), new BoxShape(Vec3::sOne()));
c.GetBodyInterface().NotifyShapeChanged(body_id, com, false, EActivation::DontActivate);

// Check that we can now hit the shape
c.GetSystem()->GetNarrowPhaseQuery().CollideShape(box_shape, Vec3::sOne(), RMat44::sIdentity(), CollideShapeSettings(), RVec3::sZero(), collector);
CHECK(collector.mHits.size() == 1);
CHECK(collector.mHits[0].mBodyID2 == body_id);
}
}

0 comments on commit 2c1864d

Please sign in to comment.