Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/jolt_physics/Jolt/Physics/Collision/NarrowPhaseQuery.cpp
21212 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
7
#include <Jolt/Physics/Collision/NarrowPhaseQuery.h>
8
#include <Jolt/Physics/Collision/CollisionDispatch.h>
9
#include <Jolt/Physics/Collision/RayCast.h>
10
#include <Jolt/Physics/Collision/AABoxCast.h>
11
#include <Jolt/Physics/Collision/ShapeCast.h>
12
#include <Jolt/Physics/Collision/CollideShape.h>
13
#include <Jolt/Physics/Collision/CollisionCollectorImpl.h>
14
#include <Jolt/Physics/Collision/CastResult.h>
15
#include <Jolt/Physics/Collision/InternalEdgeRemovingCollector.h>
16
17
JPH_NAMESPACE_BEGIN
18
19
bool NarrowPhaseQuery::CastRay(const RRayCast &inRay, RayCastResult &ioHit, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter) const
20
{
21
JPH_PROFILE_FUNCTION();
22
23
class MyCollector : public RayCastBodyCollector
24
{
25
public:
26
MyCollector(const RRayCast &inRay, RayCastResult &ioHit, const BodyLockInterface &inBodyLockInterface, const BodyFilter &inBodyFilter) :
27
mRay(inRay),
28
mHit(ioHit),
29
mBodyLockInterface(inBodyLockInterface),
30
mBodyFilter(inBodyFilter)
31
{
32
ResetEarlyOutFraction(ioHit.mFraction);
33
}
34
35
virtual void AddHit(const ResultType &inResult) override
36
{
37
JPH_ASSERT(inResult.mFraction < mHit.mFraction, "This hit should not have been passed on to the collector");
38
39
// Only test shape if it passes the body filter
40
if (mBodyFilter.ShouldCollide(inResult.mBodyID))
41
{
42
// Lock the body
43
BodyLockRead lock(mBodyLockInterface, inResult.mBodyID);
44
if (lock.SucceededAndIsInBroadPhase()) // Race condition: body could have been removed since it has been found in the broadphase, ensures body is in the broadphase while we call the callbacks
45
{
46
const Body &body = lock.GetBody();
47
48
// Check body filter again now that we've locked the body
49
if (mBodyFilter.ShouldCollideLocked(body))
50
{
51
// Collect the transformed shape
52
TransformedShape ts = body.GetTransformedShape();
53
54
// Release the lock now, we have all the info we need in the transformed shape
55
lock.ReleaseLock();
56
57
// Do narrow phase collision check
58
if (ts.CastRay(mRay, mHit))
59
{
60
// Test that we didn't find a further hit by accident
61
JPH_ASSERT(mHit.mFraction >= 0.0f && mHit.mFraction < GetEarlyOutFraction());
62
63
// Update early out fraction based on narrow phase collector
64
UpdateEarlyOutFraction(mHit.mFraction);
65
}
66
}
67
}
68
}
69
}
70
71
RRayCast mRay;
72
RayCastResult & mHit;
73
const BodyLockInterface & mBodyLockInterface;
74
const BodyFilter & mBodyFilter;
75
};
76
77
// Do broadphase test, note that the broadphase uses floats so we drop precision here
78
MyCollector collector(inRay, ioHit, *mBodyLockInterface, inBodyFilter);
79
mBroadPhaseQuery->CastRay(RayCast(inRay), collector, inBroadPhaseLayerFilter, inObjectLayerFilter);
80
return ioHit.mFraction <= 1.0f;
81
}
82
83
void NarrowPhaseQuery::CastRay(const RRayCast &inRay, const RayCastSettings &inRayCastSettings, CastRayCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter) const
84
{
85
JPH_PROFILE_FUNCTION();
86
87
class MyCollector : public RayCastBodyCollector
88
{
89
public:
90
MyCollector(const RRayCast &inRay, const RayCastSettings &inRayCastSettings, CastRayCollector &ioCollector, const BodyLockInterface &inBodyLockInterface, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter) :
91
RayCastBodyCollector(ioCollector),
92
mRay(inRay),
93
mRayCastSettings(inRayCastSettings),
94
mCollector(ioCollector),
95
mBodyLockInterface(inBodyLockInterface),
96
mBodyFilter(inBodyFilter),
97
mShapeFilter(inShapeFilter)
98
{
99
}
100
101
virtual void AddHit(const ResultType &inResult) override
102
{
103
JPH_ASSERT(inResult.mFraction < mCollector.GetEarlyOutFraction(), "This hit should not have been passed on to the collector");
104
105
// Only test shape if it passes the body filter
106
if (mBodyFilter.ShouldCollide(inResult.mBodyID))
107
{
108
// Lock the body
109
BodyLockRead lock(mBodyLockInterface, inResult.mBodyID);
110
if (lock.SucceededAndIsInBroadPhase()) // Race condition: body could have been removed since it has been found in the broadphase, ensures body is in the broadphase while we call the callbacks
111
{
112
const Body &body = lock.GetBody();
113
114
// Check body filter again now that we've locked the body
115
if (mBodyFilter.ShouldCollideLocked(body))
116
{
117
// Collect the transformed shape
118
TransformedShape ts = body.GetTransformedShape();
119
120
// Notify collector of new body
121
mCollector.OnBody(body);
122
123
// Release the lock now, we have all the info we need in the transformed shape
124
lock.ReleaseLock();
125
126
// Do narrow phase collision check
127
ts.CastRay(mRay, mRayCastSettings, mCollector, mShapeFilter);
128
129
// Notify collector of the end of this body
130
// We do this before updating the early out fraction so that the collector can still modify it
131
mCollector.OnBodyEnd();
132
133
// Update early out fraction based on narrow phase collector
134
UpdateEarlyOutFraction(mCollector.GetEarlyOutFraction());
135
}
136
}
137
}
138
}
139
140
RRayCast mRay;
141
RayCastSettings mRayCastSettings;
142
CastRayCollector & mCollector;
143
const BodyLockInterface & mBodyLockInterface;
144
const BodyFilter & mBodyFilter;
145
const ShapeFilter & mShapeFilter;
146
};
147
148
// Do broadphase test, note that the broadphase uses floats so we drop precision here
149
MyCollector collector(inRay, inRayCastSettings, ioCollector, *mBodyLockInterface, inBodyFilter, inShapeFilter);
150
mBroadPhaseQuery->CastRay(RayCast(inRay), collector, inBroadPhaseLayerFilter, inObjectLayerFilter);
151
}
152
153
void NarrowPhaseQuery::CollidePoint(RVec3Arg inPoint, CollidePointCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter) const
154
{
155
JPH_PROFILE_FUNCTION();
156
157
class MyCollector : public CollideShapeBodyCollector
158
{
159
public:
160
MyCollector(RVec3Arg inPoint, CollidePointCollector &ioCollector, const BodyLockInterface &inBodyLockInterface, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter) :
161
CollideShapeBodyCollector(ioCollector),
162
mPoint(inPoint),
163
mCollector(ioCollector),
164
mBodyLockInterface(inBodyLockInterface),
165
mBodyFilter(inBodyFilter),
166
mShapeFilter(inShapeFilter)
167
{
168
}
169
170
virtual void AddHit(const ResultType &inResult) override
171
{
172
// Only test shape if it passes the body filter
173
if (mBodyFilter.ShouldCollide(inResult))
174
{
175
// Lock the body
176
BodyLockRead lock(mBodyLockInterface, inResult);
177
if (lock.SucceededAndIsInBroadPhase()) // Race condition: body could have been removed since it has been found in the broadphase, ensures body is in the broadphase while we call the callbacks
178
{
179
const Body &body = lock.GetBody();
180
181
// Check body filter again now that we've locked the body
182
if (mBodyFilter.ShouldCollideLocked(body))
183
{
184
// Collect the transformed shape
185
TransformedShape ts = body.GetTransformedShape();
186
187
// Notify collector of new body
188
mCollector.OnBody(body);
189
190
// Release the lock now, we have all the info we need in the transformed shape
191
lock.ReleaseLock();
192
193
// Do narrow phase collision check
194
ts.CollidePoint(mPoint, mCollector, mShapeFilter);
195
196
// Notify collector of the end of this body
197
// We do this before updating the early out fraction so that the collector can still modify it
198
mCollector.OnBodyEnd();
199
200
// Update early out fraction based on narrow phase collector
201
UpdateEarlyOutFraction(mCollector.GetEarlyOutFraction());
202
}
203
}
204
}
205
}
206
207
RVec3 mPoint;
208
CollidePointCollector & mCollector;
209
const BodyLockInterface & mBodyLockInterface;
210
const BodyFilter & mBodyFilter;
211
const ShapeFilter & mShapeFilter;
212
};
213
214
// Do broadphase test (note: truncates double to single precision since the broadphase uses single precision)
215
MyCollector collector(inPoint, ioCollector, *mBodyLockInterface, inBodyFilter, inShapeFilter);
216
mBroadPhaseQuery->CollidePoint(Vec3(inPoint), collector, inBroadPhaseLayerFilter, inObjectLayerFilter);
217
}
218
219
void NarrowPhaseQuery::CollideShape(const Shape *inShape, Vec3Arg inShapeScale, RMat44Arg inCenterOfMassTransform, const CollideShapeSettings &inCollideShapeSettings, RVec3Arg inBaseOffset, CollideShapeCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter) const
220
{
221
JPH_PROFILE_FUNCTION();
222
223
class MyCollector : public CollideShapeBodyCollector
224
{
225
public:
226
MyCollector(const Shape *inShape, Vec3Arg inShapeScale, RMat44Arg inCenterOfMassTransform, const CollideShapeSettings &inCollideShapeSettings, RVec3Arg inBaseOffset, CollideShapeCollector &ioCollector, const BodyLockInterface &inBodyLockInterface, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter) :
227
CollideShapeBodyCollector(ioCollector),
228
mShape(inShape),
229
mShapeScale(inShapeScale),
230
mCenterOfMassTransform(inCenterOfMassTransform),
231
mCollideShapeSettings(inCollideShapeSettings),
232
mBaseOffset(inBaseOffset),
233
mCollector(ioCollector),
234
mBodyLockInterface(inBodyLockInterface),
235
mBodyFilter(inBodyFilter),
236
mShapeFilter(inShapeFilter)
237
{
238
}
239
240
virtual void AddHit(const ResultType &inResult) override
241
{
242
// Only test shape if it passes the body filter
243
if (mBodyFilter.ShouldCollide(inResult))
244
{
245
// Lock the body
246
BodyLockRead lock(mBodyLockInterface, inResult);
247
if (lock.SucceededAndIsInBroadPhase()) // Race condition: body could have been removed since it has been found in the broadphase, ensures body is in the broadphase while we call the callbacks
248
{
249
const Body &body = lock.GetBody();
250
251
// Check body filter again now that we've locked the body
252
if (mBodyFilter.ShouldCollideLocked(body))
253
{
254
// Collect the transformed shape
255
TransformedShape ts = body.GetTransformedShape();
256
257
// Notify collector of new body
258
mCollector.OnBody(body);
259
260
// Release the lock now, we have all the info we need in the transformed shape
261
lock.ReleaseLock();
262
263
// Do narrow phase collision check
264
ts.CollideShape(mShape, mShapeScale, mCenterOfMassTransform, mCollideShapeSettings, mBaseOffset, mCollector, mShapeFilter);
265
266
// Notify collector of the end of this body
267
// We do this before updating the early out fraction so that the collector can still modify it
268
mCollector.OnBodyEnd();
269
270
// Update early out fraction based on narrow phase collector
271
UpdateEarlyOutFraction(mCollector.GetEarlyOutFraction());
272
}
273
}
274
}
275
}
276
277
const Shape * mShape;
278
Vec3 mShapeScale;
279
RMat44 mCenterOfMassTransform;
280
const CollideShapeSettings & mCollideShapeSettings;
281
RVec3 mBaseOffset;
282
CollideShapeCollector & mCollector;
283
const BodyLockInterface & mBodyLockInterface;
284
const BodyFilter & mBodyFilter;
285
const ShapeFilter & mShapeFilter;
286
};
287
288
// Calculate bounds for shape and expand by max separation distance
289
AABox bounds = inShape->GetWorldSpaceBounds(inCenterOfMassTransform, inShapeScale);
290
bounds.ExpandBy(Vec3::sReplicate(inCollideShapeSettings.mMaxSeparationDistance));
291
292
// Do broadphase test
293
MyCollector collector(inShape, inShapeScale, inCenterOfMassTransform, inCollideShapeSettings, inBaseOffset, ioCollector, *mBodyLockInterface, inBodyFilter, inShapeFilter);
294
mBroadPhaseQuery->CollideAABox(bounds, collector, inBroadPhaseLayerFilter, inObjectLayerFilter);
295
}
296
297
void NarrowPhaseQuery::CollideShapeWithInternalEdgeRemoval(const Shape *inShape, Vec3Arg inShapeScale, RMat44Arg inCenterOfMassTransform, const CollideShapeSettings &inCollideShapeSettings, RVec3Arg inBaseOffset, CollideShapeCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter) const
298
{
299
// We require these settings for internal edge removal to work
300
CollideShapeSettings settings = inCollideShapeSettings;
301
settings.mActiveEdgeMode = EActiveEdgeMode::CollideWithAll;
302
settings.mCollectFacesMode = ECollectFacesMode::CollectFaces;
303
304
InternalEdgeRemovingCollector wrapper(ioCollector
305
#ifdef JPH_INTERNAL_EDGE_REMOVING_COLLECTOR_DEBUG
306
, inBaseOffset
307
#endif // JPH_INTERNAL_EDGE_REMOVING_COLLECTOR_DEBUG
308
);
309
CollideShape(inShape, inShapeScale, inCenterOfMassTransform, settings, inBaseOffset, wrapper, inBroadPhaseLayerFilter, inObjectLayerFilter, inBodyFilter, inShapeFilter);
310
}
311
312
void NarrowPhaseQuery::CastShape(const RShapeCast &inShapeCast, const ShapeCastSettings &inShapeCastSettings, RVec3Arg inBaseOffset, CastShapeCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter) const
313
{
314
JPH_PROFILE_FUNCTION();
315
316
class MyCollector : public CastShapeBodyCollector
317
{
318
public:
319
MyCollector(const RShapeCast &inShapeCast, const ShapeCastSettings &inShapeCastSettings, RVec3Arg inBaseOffset, CastShapeCollector &ioCollector, const BodyLockInterface &inBodyLockInterface, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter) :
320
CastShapeBodyCollector(ioCollector),
321
mShapeCast(inShapeCast),
322
mShapeCastSettings(inShapeCastSettings),
323
mBaseOffset(inBaseOffset),
324
mCollector(ioCollector),
325
mBodyLockInterface(inBodyLockInterface),
326
mBodyFilter(inBodyFilter),
327
mShapeFilter(inShapeFilter)
328
{
329
}
330
331
virtual void AddHit(const ResultType &inResult) override
332
{
333
JPH_ASSERT(inResult.mFraction <= max(0.0f, mCollector.GetEarlyOutFraction()), "This hit should not have been passed on to the collector");
334
335
// Only test shape if it passes the body filter
336
if (mBodyFilter.ShouldCollide(inResult.mBodyID))
337
{
338
// Lock the body
339
BodyLockRead lock(mBodyLockInterface, inResult.mBodyID);
340
if (lock.SucceededAndIsInBroadPhase()) // Race condition: body could have been removed since it has been found in the broadphase, ensures body is in the broadphase while we call the callbacks
341
{
342
const Body &body = lock.GetBody();
343
344
// Check body filter again now that we've locked the body
345
if (mBodyFilter.ShouldCollideLocked(body))
346
{
347
// Collect the transformed shape
348
TransformedShape ts = body.GetTransformedShape();
349
350
// Notify collector of new body
351
mCollector.OnBody(body);
352
353
// Release the lock now, we have all the info we need in the transformed shape
354
lock.ReleaseLock();
355
356
// Do narrow phase collision check
357
ts.CastShape(mShapeCast, mShapeCastSettings, mBaseOffset, mCollector, mShapeFilter);
358
359
// Notify collector of the end of this body
360
// We do this before updating the early out fraction so that the collector can still modify it
361
mCollector.OnBodyEnd();
362
363
// Update early out fraction based on narrow phase collector
364
UpdateEarlyOutFraction(mCollector.GetEarlyOutFraction());
365
}
366
}
367
}
368
}
369
370
RShapeCast mShapeCast;
371
const ShapeCastSettings & mShapeCastSettings;
372
RVec3 mBaseOffset;
373
CastShapeCollector & mCollector;
374
const BodyLockInterface & mBodyLockInterface;
375
const BodyFilter & mBodyFilter;
376
const ShapeFilter & mShapeFilter;
377
};
378
379
// Do broadphase test
380
MyCollector collector(inShapeCast, inShapeCastSettings, inBaseOffset, ioCollector, *mBodyLockInterface, inBodyFilter, inShapeFilter);
381
mBroadPhaseQuery->CastAABox({ inShapeCast.mShapeWorldBounds, inShapeCast.mDirection }, collector, inBroadPhaseLayerFilter, inObjectLayerFilter);
382
}
383
384
void NarrowPhaseQuery::CollectTransformedShapes(const AABox &inBox, TransformedShapeCollector &ioCollector, const BroadPhaseLayerFilter &inBroadPhaseLayerFilter, const ObjectLayerFilter &inObjectLayerFilter, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter) const
385
{
386
class MyCollector : public CollideShapeBodyCollector
387
{
388
public:
389
MyCollector(const AABox &inBox, TransformedShapeCollector &ioCollector, const BodyLockInterface &inBodyLockInterface, const BodyFilter &inBodyFilter, const ShapeFilter &inShapeFilter) :
390
CollideShapeBodyCollector(ioCollector),
391
mBox(inBox),
392
mCollector(ioCollector),
393
mBodyLockInterface(inBodyLockInterface),
394
mBodyFilter(inBodyFilter),
395
mShapeFilter(inShapeFilter)
396
{
397
}
398
399
virtual void AddHit(const ResultType &inResult) override
400
{
401
// Only test shape if it passes the body filter
402
if (mBodyFilter.ShouldCollide(inResult))
403
{
404
// Lock the body
405
BodyLockRead lock(mBodyLockInterface, inResult);
406
if (lock.SucceededAndIsInBroadPhase()) // Race condition: body could have been removed since it has been found in the broadphase, ensures body is in the broadphase while we call the callbacks
407
{
408
const Body &body = lock.GetBody();
409
410
// Check body filter again now that we've locked the body
411
if (mBodyFilter.ShouldCollideLocked(body))
412
{
413
// Collect the transformed shape
414
TransformedShape ts = body.GetTransformedShape();
415
416
// Notify collector of new body
417
mCollector.OnBody(body);
418
419
// Release the lock now, we have all the info we need in the transformed shape
420
lock.ReleaseLock();
421
422
// Do narrow phase collision check
423
ts.CollectTransformedShapes(mBox, mCollector, mShapeFilter);
424
425
// Notify collector of the end of this body
426
// We do this before updating the early out fraction so that the collector can still modify it
427
mCollector.OnBodyEnd();
428
429
// Update early out fraction based on narrow phase collector
430
UpdateEarlyOutFraction(mCollector.GetEarlyOutFraction());
431
}
432
}
433
}
434
}
435
436
const AABox & mBox;
437
TransformedShapeCollector & mCollector;
438
const BodyLockInterface & mBodyLockInterface;
439
const BodyFilter & mBodyFilter;
440
const ShapeFilter & mShapeFilter;
441
};
442
443
// Do broadphase test
444
MyCollector collector(inBox, ioCollector, *mBodyLockInterface, inBodyFilter, inShapeFilter);
445
mBroadPhaseQuery->CollideAABox(inBox, collector, inBroadPhaseLayerFilter, inObjectLayerFilter);
446
}
447
448
JPH_NAMESPACE_END
449
450