Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/jolt_physics/Jolt/Physics/Collision/Shape/PlaneShape.cpp
9913 views
1
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
2
// SPDX-FileCopyrightText: 2024 Jorrit Rouwe
3
// SPDX-License-Identifier: MIT
4
5
#include <Jolt/Jolt.h>
6
7
#include <Jolt/Physics/Collision/Shape/PlaneShape.h>
8
#include <Jolt/Physics/Collision/Shape/ConvexShape.h>
9
#include <Jolt/Physics/Collision/Shape/ScaleHelpers.h>
10
#include <Jolt/Physics/Collision/RayCast.h>
11
#include <Jolt/Physics/Collision/ShapeCast.h>
12
#include <Jolt/Physics/Collision/ShapeFilter.h>
13
#include <Jolt/Physics/Collision/CastResult.h>
14
#include <Jolt/Physics/Collision/CollisionDispatch.h>
15
#include <Jolt/Physics/Collision/TransformedShape.h>
16
#include <Jolt/Physics/Collision/CollidePointResult.h>
17
#include <Jolt/Physics/Collision/CollideSoftBodyVertexIterator.h>
18
#include <Jolt/Core/Profiler.h>
19
#include <Jolt/Core/StreamIn.h>
20
#include <Jolt/Core/StreamOut.h>
21
#include <Jolt/Geometry/Plane.h>
22
#include <Jolt/ObjectStream/TypeDeclarations.h>
23
#ifdef JPH_DEBUG_RENDERER
24
#include <Jolt/Renderer/DebugRenderer.h>
25
#endif // JPH_DEBUG_RENDERER
26
27
JPH_NAMESPACE_BEGIN
28
29
JPH_IMPLEMENT_SERIALIZABLE_VIRTUAL(PlaneShapeSettings)
30
{
31
JPH_ADD_BASE_CLASS(PlaneShapeSettings, ShapeSettings)
32
33
JPH_ADD_ATTRIBUTE(PlaneShapeSettings, mPlane)
34
JPH_ADD_ATTRIBUTE(PlaneShapeSettings, mMaterial)
35
JPH_ADD_ATTRIBUTE(PlaneShapeSettings, mHalfExtent)
36
}
37
38
ShapeSettings::ShapeResult PlaneShapeSettings::Create() const
39
{
40
if (mCachedResult.IsEmpty())
41
Ref<Shape> shape = new PlaneShape(*this, mCachedResult);
42
return mCachedResult;
43
}
44
45
inline static void sPlaneGetOrthogonalBasis(Vec3Arg inNormal, Vec3 &outPerp1, Vec3 &outPerp2)
46
{
47
outPerp1 = inNormal.Cross(Vec3::sAxisY()).NormalizedOr(Vec3::sAxisX());
48
outPerp2 = outPerp1.Cross(inNormal).Normalized();
49
outPerp1 = inNormal.Cross(outPerp2);
50
}
51
52
void PlaneShape::GetVertices(Vec3 *outVertices) const
53
{
54
// Create orthogonal basis
55
Vec3 normal = mPlane.GetNormal();
56
Vec3 perp1, perp2;
57
sPlaneGetOrthogonalBasis(normal, perp1, perp2);
58
59
// Scale basis
60
perp1 *= mHalfExtent;
61
perp2 *= mHalfExtent;
62
63
// Calculate corners
64
Vec3 point = -normal * mPlane.GetConstant();
65
outVertices[0] = point + perp1 + perp2;
66
outVertices[1] = point + perp1 - perp2;
67
outVertices[2] = point - perp1 - perp2;
68
outVertices[3] = point - perp1 + perp2;
69
}
70
71
void PlaneShape::CalculateLocalBounds()
72
{
73
// Get the vertices of the plane
74
Vec3 vertices[4];
75
GetVertices(vertices);
76
77
// Encapsulate the vertices and a point mHalfExtent behind the plane
78
mLocalBounds = AABox();
79
Vec3 normal = mPlane.GetNormal();
80
for (const Vec3 &v : vertices)
81
{
82
mLocalBounds.Encapsulate(v);
83
mLocalBounds.Encapsulate(v - mHalfExtent * normal);
84
}
85
}
86
87
PlaneShape::PlaneShape(const PlaneShapeSettings &inSettings, ShapeResult &outResult) :
88
Shape(EShapeType::Plane, EShapeSubType::Plane, inSettings, outResult),
89
mPlane(inSettings.mPlane),
90
mMaterial(inSettings.mMaterial),
91
mHalfExtent(inSettings.mHalfExtent)
92
{
93
if (!mPlane.GetNormal().IsNormalized())
94
{
95
outResult.SetError("Plane normal needs to be normalized!");
96
return;
97
}
98
99
CalculateLocalBounds();
100
101
outResult.Set(this);
102
}
103
104
MassProperties PlaneShape::GetMassProperties() const
105
{
106
// Object should always be static, return default mass properties
107
return MassProperties();
108
}
109
110
void PlaneShape::GetSupportingFace(const SubShapeID &inSubShapeID, Vec3Arg inDirection, Vec3Arg inScale, Mat44Arg inCenterOfMassTransform, SupportingFace &outVertices) const
111
{
112
// Get the vertices of the plane
113
Vec3 vertices[4];
114
GetVertices(vertices);
115
116
// Reverse if scale is inside out
117
if (ScaleHelpers::IsInsideOut(inScale))
118
{
119
std::swap(vertices[0], vertices[3]);
120
std::swap(vertices[1], vertices[2]);
121
}
122
123
// Transform them to world space
124
outVertices.clear();
125
Mat44 com = inCenterOfMassTransform.PreScaled(inScale);
126
for (const Vec3 &v : vertices)
127
outVertices.push_back(com * v);
128
}
129
130
#ifdef JPH_DEBUG_RENDERER
131
void PlaneShape::Draw(DebugRenderer *inRenderer, RMat44Arg inCenterOfMassTransform, Vec3Arg inScale, ColorArg inColor, bool inUseMaterialColors, bool inDrawWireframe) const
132
{
133
// Get the vertices of the plane
134
Vec3 local_vertices[4];
135
GetVertices(local_vertices);
136
137
// Reverse if scale is inside out
138
if (ScaleHelpers::IsInsideOut(inScale))
139
{
140
std::swap(local_vertices[0], local_vertices[3]);
141
std::swap(local_vertices[1], local_vertices[2]);
142
}
143
144
// Transform them to world space
145
RMat44 com = inCenterOfMassTransform.PreScaled(inScale);
146
RVec3 vertices[4];
147
for (uint i = 0; i < 4; ++i)
148
vertices[i] = com * local_vertices[i];
149
150
// Determine the color
151
Color color = inUseMaterialColors? GetMaterial(SubShapeID())->GetDebugColor() : inColor;
152
153
// Draw the plane
154
if (inDrawWireframe)
155
{
156
inRenderer->DrawWireTriangle(vertices[0], vertices[1], vertices[2], color);
157
inRenderer->DrawWireTriangle(vertices[0], vertices[2], vertices[3], color);
158
}
159
else
160
{
161
inRenderer->DrawTriangle(vertices[0], vertices[1], vertices[2], color, DebugRenderer::ECastShadow::On);
162
inRenderer->DrawTriangle(vertices[0], vertices[2], vertices[3], color, DebugRenderer::ECastShadow::On);
163
}
164
}
165
#endif // JPH_DEBUG_RENDERER
166
167
bool PlaneShape::CastRay(const RayCast &inRay, const SubShapeIDCreator &inSubShapeIDCreator, RayCastResult &ioHit) const
168
{
169
JPH_PROFILE_FUNCTION();
170
171
// Test starting inside of negative half space
172
float distance = mPlane.SignedDistance(inRay.mOrigin);
173
if (distance <= 0.0f)
174
{
175
ioHit.mFraction = 0.0f;
176
ioHit.mSubShapeID2 = inSubShapeIDCreator.GetID();
177
return true;
178
}
179
180
// Test ray parallel to plane
181
float dot = inRay.mDirection.Dot(mPlane.GetNormal());
182
if (dot == 0.0f)
183
return false;
184
185
// Calculate hit fraction
186
float fraction = -distance / dot;
187
if (fraction >= 0.0f && fraction < ioHit.mFraction)
188
{
189
ioHit.mFraction = fraction;
190
ioHit.mSubShapeID2 = inSubShapeIDCreator.GetID();
191
return true;
192
}
193
194
return false;
195
}
196
197
void PlaneShape::CastRay(const RayCast &inRay, const RayCastSettings &inRayCastSettings, const SubShapeIDCreator &inSubShapeIDCreator, CastRayCollector &ioCollector, const ShapeFilter &inShapeFilter) const
198
{
199
JPH_PROFILE_FUNCTION();
200
201
// Test shape filter
202
if (!inShapeFilter.ShouldCollide(this, inSubShapeIDCreator.GetID()))
203
return;
204
205
// Inside solid half space?
206
float distance = mPlane.SignedDistance(inRay.mOrigin);
207
if (inRayCastSettings.mTreatConvexAsSolid
208
&& distance <= 0.0f // Inside plane
209
&& ioCollector.GetEarlyOutFraction() > 0.0f) // Willing to accept hits at fraction 0
210
{
211
// Hit at fraction 0
212
RayCastResult hit;
213
hit.mBodyID = TransformedShape::sGetBodyID(ioCollector.GetContext());
214
hit.mFraction = 0.0f;
215
hit.mSubShapeID2 = inSubShapeIDCreator.GetID();
216
ioCollector.AddHit(hit);
217
}
218
219
float dot = inRay.mDirection.Dot(mPlane.GetNormal());
220
if (dot != 0.0f // Parallel ray will not hit plane
221
&& (inRayCastSettings.mBackFaceModeConvex == EBackFaceMode::CollideWithBackFaces || dot < 0.0f)) // Back face culling
222
{
223
// Calculate hit with plane
224
float fraction = -distance / dot;
225
if (fraction >= 0.0f && fraction < ioCollector.GetEarlyOutFraction())
226
{
227
RayCastResult hit;
228
hit.mBodyID = TransformedShape::sGetBodyID(ioCollector.GetContext());
229
hit.mFraction = fraction;
230
hit.mSubShapeID2 = inSubShapeIDCreator.GetID();
231
ioCollector.AddHit(hit);
232
}
233
}
234
}
235
236
void PlaneShape::CollidePoint(Vec3Arg inPoint, const SubShapeIDCreator &inSubShapeIDCreator, CollidePointCollector &ioCollector, const ShapeFilter &inShapeFilter) const
237
{
238
JPH_PROFILE_FUNCTION();
239
240
// Test shape filter
241
if (!inShapeFilter.ShouldCollide(this, inSubShapeIDCreator.GetID()))
242
return;
243
244
// Check if the point is inside the plane
245
if (mPlane.SignedDistance(inPoint) < 0.0f)
246
ioCollector.AddHit({ TransformedShape::sGetBodyID(ioCollector.GetContext()), inSubShapeIDCreator.GetID() });
247
}
248
249
void PlaneShape::CollideSoftBodyVertices(Mat44Arg inCenterOfMassTransform, Vec3Arg inScale, const CollideSoftBodyVertexIterator &inVertices, uint inNumVertices, int inCollidingShapeIndex) const
250
{
251
JPH_PROFILE_FUNCTION();
252
253
// Convert plane to world space
254
Plane plane = mPlane.Scaled(inScale).GetTransformed(inCenterOfMassTransform);
255
256
for (CollideSoftBodyVertexIterator v = inVertices, sbv_end = inVertices + inNumVertices; v != sbv_end; ++v)
257
if (v.GetInvMass() > 0.0f)
258
{
259
// Calculate penetration
260
float penetration = -plane.SignedDistance(v.GetPosition());
261
if (v.UpdatePenetration(penetration))
262
v.SetCollision(plane, inCollidingShapeIndex);
263
}
264
}
265
266
// This is a version of GetSupportingFace that returns a face that is large enough to cover the shape we're colliding with but not as large as the regular GetSupportedFace to avoid numerical precision issues
267
inline static void sGetSupportingFace(const ConvexShape *inShape, Vec3Arg inShapeCOM, const Plane &inPlane, Mat44Arg inPlaneToWorld, ConvexShape::SupportingFace &outPlaneFace)
268
{
269
// Project COM of shape onto plane
270
Plane world_plane = inPlane.GetTransformed(inPlaneToWorld);
271
Vec3 center = world_plane.ProjectPointOnPlane(inShapeCOM);
272
273
// Create orthogonal basis for the plane
274
Vec3 normal = world_plane.GetNormal();
275
Vec3 perp1, perp2;
276
sPlaneGetOrthogonalBasis(normal, perp1, perp2);
277
278
// Base the size of the face on the bounding box of the shape, ensuring that it is large enough to cover the entire shape
279
float size = inShape->GetLocalBounds().GetSize().Length();
280
perp1 *= size;
281
perp2 *= size;
282
283
// Emit the vertices
284
outPlaneFace.resize(4);
285
outPlaneFace[0] = center + perp1 + perp2;
286
outPlaneFace[1] = center + perp1 - perp2;
287
outPlaneFace[2] = center - perp1 - perp2;
288
outPlaneFace[3] = center - perp1 + perp2;
289
}
290
291
void PlaneShape::sCastConvexVsPlane(const ShapeCast &inShapeCast, const ShapeCastSettings &inShapeCastSettings, const Shape *inShape, Vec3Arg inScale, [[maybe_unused]] const ShapeFilter &inShapeFilter, Mat44Arg inCenterOfMassTransform2, const SubShapeIDCreator &inSubShapeIDCreator1, const SubShapeIDCreator &inSubShapeIDCreator2, CastShapeCollector &ioCollector)
292
{
293
JPH_PROFILE_FUNCTION();
294
295
// Get the shapes
296
JPH_ASSERT(inShapeCast.mShape->GetType() == EShapeType::Convex);
297
JPH_ASSERT(inShape->GetType() == EShapeType::Plane);
298
const ConvexShape *convex_shape = static_cast<const ConvexShape *>(inShapeCast.mShape);
299
const PlaneShape *plane_shape = static_cast<const PlaneShape *>(inShape);
300
301
// Shape cast is provided relative to COM of inShape, so all we need to do is transform our plane with inScale
302
Plane plane = plane_shape->mPlane.Scaled(inScale);
303
Vec3 normal = plane.GetNormal();
304
305
// Get support function
306
ConvexShape::SupportBuffer shape1_support_buffer;
307
const ConvexShape::Support *shape1_support = convex_shape->GetSupportFunction(ConvexShape::ESupportMode::Default, shape1_support_buffer, inShapeCast.mScale);
308
309
// Get the support point of the convex shape in the opposite direction of the plane normal in our local space
310
Vec3 normal_in_convex_shape_space = inShapeCast.mCenterOfMassStart.Multiply3x3Transposed(normal);
311
Vec3 support_point = inShapeCast.mCenterOfMassStart * shape1_support->GetSupport(-normal_in_convex_shape_space);
312
float signed_distance = plane.SignedDistance(support_point);
313
float convex_radius = shape1_support->GetConvexRadius();
314
float penetration_depth = -signed_distance + convex_radius;
315
float dot = inShapeCast.mDirection.Dot(normal);
316
317
// Collision output
318
Mat44 com_hit;
319
Vec3 point1, point2;
320
float fraction;
321
322
// Do we start in collision?
323
if (penetration_depth > 0.0f)
324
{
325
// Back face culling?
326
if (inShapeCastSettings.mBackFaceModeConvex == EBackFaceMode::IgnoreBackFaces && dot > 0.0f)
327
return;
328
329
// Shallower hit?
330
if (penetration_depth <= -ioCollector.GetEarlyOutFraction())
331
return;
332
333
// We're hitting at fraction 0
334
fraction = 0.0f;
335
336
// Get contact point
337
com_hit = inCenterOfMassTransform2;
338
point1 = inCenterOfMassTransform2 * (support_point - normal * convex_radius);
339
point2 = inCenterOfMassTransform2 * (support_point - normal * signed_distance);
340
}
341
else if (dot < 0.0f) // Moving towards the plane?
342
{
343
// Calculate hit fraction
344
fraction = penetration_depth / dot;
345
JPH_ASSERT(fraction >= 0.0f);
346
347
// Further than early out fraction?
348
if (fraction >= ioCollector.GetEarlyOutFraction())
349
return;
350
351
// Get contact point
352
com_hit = inCenterOfMassTransform2.PostTranslated(fraction * inShapeCast.mDirection);
353
point1 = point2 = com_hit * (support_point - normal * convex_radius);
354
}
355
else
356
{
357
// Moving away from the plane
358
return;
359
}
360
361
// Create cast result
362
Vec3 penetration_axis_world = com_hit.Multiply3x3(-normal);
363
bool back_facing = dot > 0.0f;
364
ShapeCastResult result(fraction, point1, point2, penetration_axis_world, back_facing, inSubShapeIDCreator1.GetID(), inSubShapeIDCreator2.GetID(), TransformedShape::sGetBodyID(ioCollector.GetContext()));
365
366
// Gather faces
367
if (inShapeCastSettings.mCollectFacesMode == ECollectFacesMode::CollectFaces)
368
{
369
// Get supporting face of convex shape
370
Mat44 shape_to_world = com_hit * inShapeCast.mCenterOfMassStart;
371
convex_shape->GetSupportingFace(SubShapeID(), normal_in_convex_shape_space, inShapeCast.mScale, shape_to_world, result.mShape1Face);
372
373
// Get supporting face of plane
374
if (!result.mShape1Face.empty())
375
sGetSupportingFace(convex_shape, shape_to_world.GetTranslation(), plane, inCenterOfMassTransform2, result.mShape2Face);
376
}
377
378
// Notify the collector
379
JPH_IF_TRACK_NARROWPHASE_STATS(TrackNarrowPhaseCollector track;)
380
ioCollector.AddHit(result);
381
}
382
383
struct PlaneShape::PSGetTrianglesContext
384
{
385
Float3 mVertices[4];
386
bool mDone = false;
387
};
388
389
void PlaneShape::GetTrianglesStart(GetTrianglesContext &ioContext, const AABox &inBox, Vec3Arg inPositionCOM, QuatArg inRotation, Vec3Arg inScale) const
390
{
391
static_assert(sizeof(PSGetTrianglesContext) <= sizeof(GetTrianglesContext), "GetTrianglesContext too small");
392
JPH_ASSERT(IsAligned(&ioContext, alignof(PSGetTrianglesContext)));
393
394
PSGetTrianglesContext *context = new (&ioContext) PSGetTrianglesContext();
395
396
// Get the vertices of the plane
397
Vec3 vertices[4];
398
GetVertices(vertices);
399
400
// Reverse if scale is inside out
401
if (ScaleHelpers::IsInsideOut(inScale))
402
{
403
std::swap(vertices[0], vertices[3]);
404
std::swap(vertices[1], vertices[2]);
405
}
406
407
// Transform them to world space
408
Mat44 com = Mat44::sRotationTranslation(inRotation, inPositionCOM).PreScaled(inScale);
409
for (uint i = 0; i < 4; ++i)
410
(com * vertices[i]).StoreFloat3(&context->mVertices[i]);
411
}
412
413
int PlaneShape::GetTrianglesNext(GetTrianglesContext &ioContext, int inMaxTrianglesRequested, Float3 *outTriangleVertices, const PhysicsMaterial **outMaterials) const
414
{
415
static_assert(cGetTrianglesMinTrianglesRequested >= 2, "cGetTrianglesMinTrianglesRequested is too small");
416
JPH_ASSERT(inMaxTrianglesRequested >= cGetTrianglesMinTrianglesRequested);
417
418
// Check if we're done
419
PSGetTrianglesContext &context = (PSGetTrianglesContext &)ioContext;
420
if (context.mDone)
421
return 0;
422
context.mDone = true;
423
424
// 1st triangle
425
outTriangleVertices[0] = context.mVertices[0];
426
outTriangleVertices[1] = context.mVertices[1];
427
outTriangleVertices[2] = context.mVertices[2];
428
429
// 2nd triangle
430
outTriangleVertices[3] = context.mVertices[0];
431
outTriangleVertices[4] = context.mVertices[2];
432
outTriangleVertices[5] = context.mVertices[3];
433
434
if (outMaterials != nullptr)
435
{
436
// Get material
437
const PhysicsMaterial *material = GetMaterial(SubShapeID());
438
outMaterials[0] = material;
439
outMaterials[1] = material;
440
}
441
442
return 2;
443
}
444
445
void PlaneShape::sCollideConvexVsPlane(const Shape *inShape1, const Shape *inShape2, Vec3Arg inScale1, Vec3Arg inScale2, Mat44Arg inCenterOfMassTransform1, Mat44Arg inCenterOfMassTransform2, const SubShapeIDCreator &inSubShapeIDCreator1, const SubShapeIDCreator &inSubShapeIDCreator2, const CollideShapeSettings &inCollideShapeSettings, CollideShapeCollector &ioCollector, [[maybe_unused]] const ShapeFilter &inShapeFilter)
446
{
447
JPH_PROFILE_FUNCTION();
448
449
// Get the shapes
450
JPH_ASSERT(inShape1->GetType() == EShapeType::Convex);
451
JPH_ASSERT(inShape2->GetType() == EShapeType::Plane);
452
const ConvexShape *shape1 = static_cast<const ConvexShape *>(inShape1);
453
const PlaneShape *shape2 = static_cast<const PlaneShape *>(inShape2);
454
455
// Transform the plane to the space of the convex shape
456
Plane scaled_plane = shape2->mPlane.Scaled(inScale2);
457
Plane plane = scaled_plane.GetTransformed(inCenterOfMassTransform1.InversedRotationTranslation() * inCenterOfMassTransform2);
458
Vec3 normal = plane.GetNormal();
459
460
// Get support function
461
ConvexShape::SupportBuffer shape1_support_buffer;
462
const ConvexShape::Support *shape1_support = shape1->GetSupportFunction(ConvexShape::ESupportMode::Default, shape1_support_buffer, inScale1);
463
464
// Get the support point of the convex shape in the opposite direction of the plane normal
465
Vec3 support_point = shape1_support->GetSupport(-normal);
466
float signed_distance = plane.SignedDistance(support_point);
467
float convex_radius = shape1_support->GetConvexRadius();
468
float penetration_depth = -signed_distance + convex_radius;
469
if (penetration_depth > -inCollideShapeSettings.mMaxSeparationDistance)
470
{
471
// Get contact point
472
Vec3 point1 = inCenterOfMassTransform1 * (support_point - normal * convex_radius);
473
Vec3 point2 = inCenterOfMassTransform1 * (support_point - normal * signed_distance);
474
Vec3 penetration_axis_world = inCenterOfMassTransform1.Multiply3x3(-normal);
475
476
// Create collision result
477
CollideShapeResult result(point1, point2, penetration_axis_world, penetration_depth, inSubShapeIDCreator1.GetID(), inSubShapeIDCreator2.GetID(), TransformedShape::sGetBodyID(ioCollector.GetContext()));
478
479
// Gather faces
480
if (inCollideShapeSettings.mCollectFacesMode == ECollectFacesMode::CollectFaces)
481
{
482
// Get supporting face of shape 1
483
shape1->GetSupportingFace(SubShapeID(), normal, inScale1, inCenterOfMassTransform1, result.mShape1Face);
484
485
// Get supporting face of shape 2
486
if (!result.mShape1Face.empty())
487
sGetSupportingFace(shape1, inCenterOfMassTransform1.GetTranslation(), scaled_plane, inCenterOfMassTransform2, result.mShape2Face);
488
}
489
490
// Notify the collector
491
JPH_IF_TRACK_NARROWPHASE_STATS(TrackNarrowPhaseCollector track;)
492
ioCollector.AddHit(result);
493
}
494
}
495
496
void PlaneShape::SaveBinaryState(StreamOut &inStream) const
497
{
498
Shape::SaveBinaryState(inStream);
499
500
inStream.Write(mPlane);
501
inStream.Write(mHalfExtent);
502
}
503
504
void PlaneShape::RestoreBinaryState(StreamIn &inStream)
505
{
506
Shape::RestoreBinaryState(inStream);
507
508
inStream.Read(mPlane);
509
inStream.Read(mHalfExtent);
510
511
CalculateLocalBounds();
512
}
513
514
void PlaneShape::SaveMaterialState(PhysicsMaterialList &outMaterials) const
515
{
516
outMaterials = { mMaterial };
517
}
518
519
void PlaneShape::RestoreMaterialState(const PhysicsMaterialRefC *inMaterials, uint inNumMaterials)
520
{
521
JPH_ASSERT(inNumMaterials == 1);
522
mMaterial = inMaterials[0];
523
}
524
525
void PlaneShape::sRegister()
526
{
527
ShapeFunctions &f = ShapeFunctions::sGet(EShapeSubType::Plane);
528
f.mConstruct = []() -> Shape * { return new PlaneShape; };
529
f.mColor = Color::sDarkRed;
530
531
for (EShapeSubType s : sConvexSubShapeTypes)
532
{
533
CollisionDispatch::sRegisterCollideShape(s, EShapeSubType::Plane, sCollideConvexVsPlane);
534
CollisionDispatch::sRegisterCastShape(s, EShapeSubType::Plane, sCastConvexVsPlane);
535
536
CollisionDispatch::sRegisterCastShape(EShapeSubType::Plane, s, CollisionDispatch::sReversedCastShape);
537
CollisionDispatch::sRegisterCollideShape(EShapeSubType::Plane, s, CollisionDispatch::sReversedCollideShape);
538
}
539
}
540
541
JPH_NAMESPACE_END
542
543