Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/jolt_physics/Jolt/Physics/Collision/BroadPhase/BroadPhaseBruteForce.cpp
9918 views
1
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
2
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
3
// SPDX-License-Identifier: MIT
4
5
#include <Jolt/Jolt.h>
6
#include <Jolt/Physics/Collision/BroadPhase/BroadPhaseBruteForce.h>
7
#include <Jolt/Physics/Collision/RayCast.h>
8
#include <Jolt/Physics/Collision/AABoxCast.h>
9
#include <Jolt/Physics/Collision/CastResult.h>
10
#include <Jolt/Physics/Body/BodyManager.h>
11
#include <Jolt/Physics/Body/BodyPair.h>
12
#include <Jolt/Geometry/RayAABox.h>
13
#include <Jolt/Geometry/OrientedBox.h>
14
#include <Jolt/Core/QuickSort.h>
15
16
JPH_NAMESPACE_BEGIN
17
18
void BroadPhaseBruteForce::AddBodiesFinalize(BodyID *ioBodies, int inNumber, AddState inAddState)
19
{
20
lock_guard lock(mMutex);
21
22
BodyVector &bodies = mBodyManager->GetBodies();
23
24
// Allocate space
25
uint32 idx = (uint32)mBodyIDs.size();
26
mBodyIDs.resize(idx + inNumber);
27
28
// Add bodies
29
for (const BodyID *b = ioBodies, *b_end = ioBodies + inNumber; b < b_end; ++b)
30
{
31
Body &body = *bodies[b->GetIndex()];
32
33
// Validate that body ID is consistent with array index
34
JPH_ASSERT(body.GetID() == *b);
35
JPH_ASSERT(!body.IsInBroadPhase());
36
37
// Add it to the list
38
mBodyIDs[idx] = body.GetID();
39
++idx;
40
41
// Indicate body is in the broadphase
42
body.SetInBroadPhaseInternal(true);
43
}
44
45
// Resort
46
QuickSort(mBodyIDs.begin(), mBodyIDs.end());
47
}
48
49
void BroadPhaseBruteForce::RemoveBodies(BodyID *ioBodies, int inNumber)
50
{
51
lock_guard lock(mMutex);
52
53
BodyVector &bodies = mBodyManager->GetBodies();
54
55
JPH_ASSERT((int)mBodyIDs.size() >= inNumber);
56
57
// Remove bodies
58
for (const BodyID *b = ioBodies, *b_end = ioBodies + inNumber; b < b_end; ++b)
59
{
60
Body &body = *bodies[b->GetIndex()];
61
62
// Validate that body ID is consistent with array index
63
JPH_ASSERT(body.GetID() == *b);
64
JPH_ASSERT(body.IsInBroadPhase());
65
66
// Find body id
67
Array<BodyID>::const_iterator it = std::lower_bound(mBodyIDs.begin(), mBodyIDs.end(), body.GetID());
68
JPH_ASSERT(it != mBodyIDs.end());
69
70
// Remove element
71
mBodyIDs.erase(it);
72
73
// Indicate body is no longer in the broadphase
74
body.SetInBroadPhaseInternal(false);
75
}
76
}
77
78
void BroadPhaseBruteForce::NotifyBodiesAABBChanged(BodyID *ioBodies, int inNumber, bool inTakeLock)
79
{
80
// Do nothing, we directly reference the body
81
}
82
83
void BroadPhaseBruteForce::NotifyBodiesLayerChanged(BodyID * ioBodies, int inNumber)
84
{
85
// Do nothing, we directly reference the body
86
}
87
88
void BroadPhaseBruteForce::CastRay(const RayCast &inRay, RayCastBodyCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter) const
89
{
90
shared_lock lock(mMutex);
91
92
// Load ray
93
Vec3 origin(inRay.mOrigin);
94
RayInvDirection inv_direction(inRay.mDirection);
95
96
// For all bodies
97
float early_out_fraction = ioCollector.GetEarlyOutFraction();
98
for (BodyID b : mBodyIDs)
99
{
100
const Body &body = mBodyManager->GetBody(b);
101
102
// Test layer
103
if (inObjectLayerFilter.ShouldCollide(body.GetObjectLayer()))
104
{
105
// Test intersection with ray
106
const AABox &bounds = body.GetWorldSpaceBounds();
107
float fraction = RayAABox(origin, inv_direction, bounds.mMin, bounds.mMax);
108
if (fraction < early_out_fraction)
109
{
110
// Store hit
111
BroadPhaseCastResult result { b, fraction };
112
ioCollector.AddHit(result);
113
if (ioCollector.ShouldEarlyOut())
114
break;
115
early_out_fraction = ioCollector.GetEarlyOutFraction();
116
}
117
}
118
}
119
}
120
121
void BroadPhaseBruteForce::CollideAABox(const AABox &inBox, CollideShapeBodyCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter) const
122
{
123
shared_lock lock(mMutex);
124
125
// For all bodies
126
for (BodyID b : mBodyIDs)
127
{
128
const Body &body = mBodyManager->GetBody(b);
129
130
// Test layer
131
if (inObjectLayerFilter.ShouldCollide(body.GetObjectLayer()))
132
{
133
// Test intersection with box
134
const AABox &bounds = body.GetWorldSpaceBounds();
135
if (bounds.Overlaps(inBox))
136
{
137
// Store hit
138
ioCollector.AddHit(b);
139
if (ioCollector.ShouldEarlyOut())
140
break;
141
}
142
}
143
}
144
}
145
146
void BroadPhaseBruteForce::CollideSphere(Vec3Arg inCenter, float inRadius, CollideShapeBodyCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter) const
147
{
148
shared_lock lock(mMutex);
149
150
float radius_sq = Square(inRadius);
151
152
// For all bodies
153
for (BodyID b : mBodyIDs)
154
{
155
const Body &body = mBodyManager->GetBody(b);
156
157
// Test layer
158
if (inObjectLayerFilter.ShouldCollide(body.GetObjectLayer()))
159
{
160
// Test intersection with box
161
const AABox &bounds = body.GetWorldSpaceBounds();
162
if (bounds.GetSqDistanceTo(inCenter) <= radius_sq)
163
{
164
// Store hit
165
ioCollector.AddHit(b);
166
if (ioCollector.ShouldEarlyOut())
167
break;
168
}
169
}
170
}
171
}
172
173
void BroadPhaseBruteForce::CollidePoint(Vec3Arg inPoint, CollideShapeBodyCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter) const
174
{
175
shared_lock lock(mMutex);
176
177
// For all bodies
178
for (BodyID b : mBodyIDs)
179
{
180
const Body &body = mBodyManager->GetBody(b);
181
182
// Test layer
183
if (inObjectLayerFilter.ShouldCollide(body.GetObjectLayer()))
184
{
185
// Test intersection with box
186
const AABox &bounds = body.GetWorldSpaceBounds();
187
if (bounds.Contains(inPoint))
188
{
189
// Store hit
190
ioCollector.AddHit(b);
191
if (ioCollector.ShouldEarlyOut())
192
break;
193
}
194
}
195
}
196
}
197
198
void BroadPhaseBruteForce::CollideOrientedBox(const OrientedBox &inBox, CollideShapeBodyCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter) const
199
{
200
shared_lock lock(mMutex);
201
202
// For all bodies
203
for (BodyID b : mBodyIDs)
204
{
205
const Body &body = mBodyManager->GetBody(b);
206
207
// Test layer
208
if (inObjectLayerFilter.ShouldCollide(body.GetObjectLayer()))
209
{
210
// Test intersection with box
211
const AABox &bounds = body.GetWorldSpaceBounds();
212
if (inBox.Overlaps(bounds))
213
{
214
// Store hit
215
ioCollector.AddHit(b);
216
if (ioCollector.ShouldEarlyOut())
217
break;
218
}
219
}
220
}
221
}
222
223
void BroadPhaseBruteForce::CastAABoxNoLock(const AABoxCast &inBox, CastShapeBodyCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter) const
224
{
225
shared_lock lock(mMutex);
226
227
// Load box
228
Vec3 origin(inBox.mBox.GetCenter());
229
Vec3 extent(inBox.mBox.GetExtent());
230
RayInvDirection inv_direction(inBox.mDirection);
231
232
// For all bodies
233
float early_out_fraction = ioCollector.GetPositiveEarlyOutFraction();
234
for (BodyID b : mBodyIDs)
235
{
236
const Body &body = mBodyManager->GetBody(b);
237
238
// Test layer
239
if (inObjectLayerFilter.ShouldCollide(body.GetObjectLayer()))
240
{
241
// Test intersection with ray
242
const AABox &bounds = body.GetWorldSpaceBounds();
243
float fraction = RayAABox(origin, inv_direction, bounds.mMin - extent, bounds.mMax + extent);
244
if (fraction < early_out_fraction)
245
{
246
// Store hit
247
BroadPhaseCastResult result { b, fraction };
248
ioCollector.AddHit(result);
249
if (ioCollector.ShouldEarlyOut())
250
break;
251
early_out_fraction = ioCollector.GetPositiveEarlyOutFraction();
252
}
253
}
254
}
255
}
256
257
void BroadPhaseBruteForce::CastAABox(const AABoxCast &inBox, CastShapeBodyCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter) const
258
{
259
CastAABoxNoLock(inBox, ioCollector, inBroadPhaseLayerFilter, inObjectLayerFilter);
260
}
261
262
void BroadPhaseBruteForce::FindCollidingPairs(BodyID *ioActiveBodies, int inNumActiveBodies, float inSpeculativeContactDistance, const ObjectVsBroadPhaseLayerFilter &inObjectVsBroadPhaseLayerFilter, const ObjectLayerPairFilter &inObjectLayerPairFilter, BodyPairCollector &ioPairCollector) const
263
{
264
shared_lock lock(mMutex);
265
266
// Loop through all active bodies
267
size_t num_bodies = mBodyIDs.size();
268
for (int b1 = 0; b1 < inNumActiveBodies; ++b1)
269
{
270
BodyID b1_id = ioActiveBodies[b1];
271
const Body &body1 = mBodyManager->GetBody(b1_id);
272
const ObjectLayer layer1 = body1.GetObjectLayer();
273
274
// Expand the bounding box by the speculative contact distance
275
AABox bounds1 = body1.GetWorldSpaceBounds();
276
bounds1.ExpandBy(Vec3::sReplicate(inSpeculativeContactDistance));
277
278
// For all other bodies
279
for (size_t b2 = 0; b2 < num_bodies; ++b2)
280
{
281
// Check if bodies can collide
282
BodyID b2_id = mBodyIDs[b2];
283
const Body &body2 = mBodyManager->GetBody(b2_id);
284
if (!Body::sFindCollidingPairsCanCollide(body1, body2))
285
continue;
286
287
// Check if layers can collide
288
const ObjectLayer layer2 = body2.GetObjectLayer();
289
if (!inObjectLayerPairFilter.ShouldCollide(layer1, layer2))
290
continue;
291
292
// Check if bounds overlap
293
const AABox &bounds2 = body2.GetWorldSpaceBounds();
294
if (!bounds1.Overlaps(bounds2))
295
continue;
296
297
// Store overlapping pair
298
ioPairCollector.AddHit({ b1_id, b2_id });
299
}
300
}
301
}
302
303
AABox BroadPhaseBruteForce::GetBounds() const
304
{
305
shared_lock lock(mMutex);
306
307
AABox bounds;
308
for (BodyID b : mBodyIDs)
309
bounds.Encapsulate(mBodyManager->GetBody(b).GetWorldSpaceBounds());
310
return bounds;
311
}
312
313
JPH_NAMESPACE_END
314
315