Path: blob/master/thirdparty/jolt_physics/Jolt/Physics/Collision/BroadPhase/BroadPhaseBruteForce.cpp
9918 views
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)1// SPDX-FileCopyrightText: 2021 Jorrit Rouwe2// SPDX-License-Identifier: MIT34#include <Jolt/Jolt.h>5#include <Jolt/Physics/Collision/BroadPhase/BroadPhaseBruteForce.h>6#include <Jolt/Physics/Collision/RayCast.h>7#include <Jolt/Physics/Collision/AABoxCast.h>8#include <Jolt/Physics/Collision/CastResult.h>9#include <Jolt/Physics/Body/BodyManager.h>10#include <Jolt/Physics/Body/BodyPair.h>11#include <Jolt/Geometry/RayAABox.h>12#include <Jolt/Geometry/OrientedBox.h>13#include <Jolt/Core/QuickSort.h>1415JPH_NAMESPACE_BEGIN1617void BroadPhaseBruteForce::AddBodiesFinalize(BodyID *ioBodies, int inNumber, AddState inAddState)18{19lock_guard lock(mMutex);2021BodyVector &bodies = mBodyManager->GetBodies();2223// Allocate space24uint32 idx = (uint32)mBodyIDs.size();25mBodyIDs.resize(idx + inNumber);2627// Add bodies28for (const BodyID *b = ioBodies, *b_end = ioBodies + inNumber; b < b_end; ++b)29{30Body &body = *bodies[b->GetIndex()];3132// Validate that body ID is consistent with array index33JPH_ASSERT(body.GetID() == *b);34JPH_ASSERT(!body.IsInBroadPhase());3536// Add it to the list37mBodyIDs[idx] = body.GetID();38++idx;3940// Indicate body is in the broadphase41body.SetInBroadPhaseInternal(true);42}4344// Resort45QuickSort(mBodyIDs.begin(), mBodyIDs.end());46}4748void BroadPhaseBruteForce::RemoveBodies(BodyID *ioBodies, int inNumber)49{50lock_guard lock(mMutex);5152BodyVector &bodies = mBodyManager->GetBodies();5354JPH_ASSERT((int)mBodyIDs.size() >= inNumber);5556// Remove bodies57for (const BodyID *b = ioBodies, *b_end = ioBodies + inNumber; b < b_end; ++b)58{59Body &body = *bodies[b->GetIndex()];6061// Validate that body ID is consistent with array index62JPH_ASSERT(body.GetID() == *b);63JPH_ASSERT(body.IsInBroadPhase());6465// Find body id66Array<BodyID>::const_iterator it = std::lower_bound(mBodyIDs.begin(), mBodyIDs.end(), body.GetID());67JPH_ASSERT(it != mBodyIDs.end());6869// Remove element70mBodyIDs.erase(it);7172// Indicate body is no longer in the broadphase73body.SetInBroadPhaseInternal(false);74}75}7677void BroadPhaseBruteForce::NotifyBodiesAABBChanged(BodyID *ioBodies, int inNumber, bool inTakeLock)78{79// Do nothing, we directly reference the body80}8182void BroadPhaseBruteForce::NotifyBodiesLayerChanged(BodyID * ioBodies, int inNumber)83{84// Do nothing, we directly reference the body85}8687void BroadPhaseBruteForce::CastRay(const RayCast &inRay, RayCastBodyCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter) const88{89shared_lock lock(mMutex);9091// Load ray92Vec3 origin(inRay.mOrigin);93RayInvDirection inv_direction(inRay.mDirection);9495// For all bodies96float early_out_fraction = ioCollector.GetEarlyOutFraction();97for (BodyID b : mBodyIDs)98{99const Body &body = mBodyManager->GetBody(b);100101// Test layer102if (inObjectLayerFilter.ShouldCollide(body.GetObjectLayer()))103{104// Test intersection with ray105const AABox &bounds = body.GetWorldSpaceBounds();106float fraction = RayAABox(origin, inv_direction, bounds.mMin, bounds.mMax);107if (fraction < early_out_fraction)108{109// Store hit110BroadPhaseCastResult result { b, fraction };111ioCollector.AddHit(result);112if (ioCollector.ShouldEarlyOut())113break;114early_out_fraction = ioCollector.GetEarlyOutFraction();115}116}117}118}119120void BroadPhaseBruteForce::CollideAABox(const AABox &inBox, CollideShapeBodyCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter) const121{122shared_lock lock(mMutex);123124// For all bodies125for (BodyID b : mBodyIDs)126{127const Body &body = mBodyManager->GetBody(b);128129// Test layer130if (inObjectLayerFilter.ShouldCollide(body.GetObjectLayer()))131{132// Test intersection with box133const AABox &bounds = body.GetWorldSpaceBounds();134if (bounds.Overlaps(inBox))135{136// Store hit137ioCollector.AddHit(b);138if (ioCollector.ShouldEarlyOut())139break;140}141}142}143}144145void BroadPhaseBruteForce::CollideSphere(Vec3Arg inCenter, float inRadius, CollideShapeBodyCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter) const146{147shared_lock lock(mMutex);148149float radius_sq = Square(inRadius);150151// For all bodies152for (BodyID b : mBodyIDs)153{154const Body &body = mBodyManager->GetBody(b);155156// Test layer157if (inObjectLayerFilter.ShouldCollide(body.GetObjectLayer()))158{159// Test intersection with box160const AABox &bounds = body.GetWorldSpaceBounds();161if (bounds.GetSqDistanceTo(inCenter) <= radius_sq)162{163// Store hit164ioCollector.AddHit(b);165if (ioCollector.ShouldEarlyOut())166break;167}168}169}170}171172void BroadPhaseBruteForce::CollidePoint(Vec3Arg inPoint, CollideShapeBodyCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter) const173{174shared_lock lock(mMutex);175176// For all bodies177for (BodyID b : mBodyIDs)178{179const Body &body = mBodyManager->GetBody(b);180181// Test layer182if (inObjectLayerFilter.ShouldCollide(body.GetObjectLayer()))183{184// Test intersection with box185const AABox &bounds = body.GetWorldSpaceBounds();186if (bounds.Contains(inPoint))187{188// Store hit189ioCollector.AddHit(b);190if (ioCollector.ShouldEarlyOut())191break;192}193}194}195}196197void BroadPhaseBruteForce::CollideOrientedBox(const OrientedBox &inBox, CollideShapeBodyCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter) const198{199shared_lock lock(mMutex);200201// For all bodies202for (BodyID b : mBodyIDs)203{204const Body &body = mBodyManager->GetBody(b);205206// Test layer207if (inObjectLayerFilter.ShouldCollide(body.GetObjectLayer()))208{209// Test intersection with box210const AABox &bounds = body.GetWorldSpaceBounds();211if (inBox.Overlaps(bounds))212{213// Store hit214ioCollector.AddHit(b);215if (ioCollector.ShouldEarlyOut())216break;217}218}219}220}221222void BroadPhaseBruteForce::CastAABoxNoLock(const AABoxCast &inBox, CastShapeBodyCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter) const223{224shared_lock lock(mMutex);225226// Load box227Vec3 origin(inBox.mBox.GetCenter());228Vec3 extent(inBox.mBox.GetExtent());229RayInvDirection inv_direction(inBox.mDirection);230231// For all bodies232float early_out_fraction = ioCollector.GetPositiveEarlyOutFraction();233for (BodyID b : mBodyIDs)234{235const Body &body = mBodyManager->GetBody(b);236237// Test layer238if (inObjectLayerFilter.ShouldCollide(body.GetObjectLayer()))239{240// Test intersection with ray241const AABox &bounds = body.GetWorldSpaceBounds();242float fraction = RayAABox(origin, inv_direction, bounds.mMin - extent, bounds.mMax + extent);243if (fraction < early_out_fraction)244{245// Store hit246BroadPhaseCastResult result { b, fraction };247ioCollector.AddHit(result);248if (ioCollector.ShouldEarlyOut())249break;250early_out_fraction = ioCollector.GetPositiveEarlyOutFraction();251}252}253}254}255256void BroadPhaseBruteForce::CastAABox(const AABoxCast &inBox, CastShapeBodyCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter) const257{258CastAABoxNoLock(inBox, ioCollector, inBroadPhaseLayerFilter, inObjectLayerFilter);259}260261void BroadPhaseBruteForce::FindCollidingPairs(BodyID *ioActiveBodies, int inNumActiveBodies, float inSpeculativeContactDistance, const ObjectVsBroadPhaseLayerFilter &inObjectVsBroadPhaseLayerFilter, const ObjectLayerPairFilter &inObjectLayerPairFilter, BodyPairCollector &ioPairCollector) const262{263shared_lock lock(mMutex);264265// Loop through all active bodies266size_t num_bodies = mBodyIDs.size();267for (int b1 = 0; b1 < inNumActiveBodies; ++b1)268{269BodyID b1_id = ioActiveBodies[b1];270const Body &body1 = mBodyManager->GetBody(b1_id);271const ObjectLayer layer1 = body1.GetObjectLayer();272273// Expand the bounding box by the speculative contact distance274AABox bounds1 = body1.GetWorldSpaceBounds();275bounds1.ExpandBy(Vec3::sReplicate(inSpeculativeContactDistance));276277// For all other bodies278for (size_t b2 = 0; b2 < num_bodies; ++b2)279{280// Check if bodies can collide281BodyID b2_id = mBodyIDs[b2];282const Body &body2 = mBodyManager->GetBody(b2_id);283if (!Body::sFindCollidingPairsCanCollide(body1, body2))284continue;285286// Check if layers can collide287const ObjectLayer layer2 = body2.GetObjectLayer();288if (!inObjectLayerPairFilter.ShouldCollide(layer1, layer2))289continue;290291// Check if bounds overlap292const AABox &bounds2 = body2.GetWorldSpaceBounds();293if (!bounds1.Overlaps(bounds2))294continue;295296// Store overlapping pair297ioPairCollector.AddHit({ b1_id, b2_id });298}299}300}301302AABox BroadPhaseBruteForce::GetBounds() const303{304shared_lock lock(mMutex);305306AABox bounds;307for (BodyID b : mBodyIDs)308bounds.Encapsulate(mBodyManager->GetBody(b).GetWorldSpaceBounds());309return bounds;310}311312JPH_NAMESPACE_END313314315