Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/jolt_physics/Jolt/Physics/Collision/ShapeCast.h
9912 views
1
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
2
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
3
// SPDX-License-Identifier: MIT
4
5
#pragma once
6
7
#include <Jolt/Geometry/AABox.h>
8
#include <Jolt/Physics/Collision/CollideShape.h>
9
#include <Jolt/Physics/Collision/Shape/Shape.h>
10
11
JPH_NAMESPACE_BEGIN
12
13
/// Structure that holds a single shape cast (a shape moving along a linear path in 3d space with no rotation)
14
template <class Vec, class Mat, class ShapeCastType>
15
struct ShapeCastT
16
{
17
JPH_OVERRIDE_NEW_DELETE
18
19
/// Constructor
20
ShapeCastT(const Shape *inShape, Vec3Arg inScale, typename Mat::ArgType inCenterOfMassStart, Vec3Arg inDirection, const AABox &inWorldSpaceBounds) :
21
mShape(inShape),
22
mScale(inScale),
23
mCenterOfMassStart(inCenterOfMassStart),
24
mDirection(inDirection),
25
mShapeWorldBounds(inWorldSpaceBounds)
26
{
27
}
28
29
/// Constructor
30
ShapeCastT(const Shape *inShape, Vec3Arg inScale, typename Mat::ArgType inCenterOfMassStart, Vec3Arg inDirection) :
31
ShapeCastT<Vec, Mat, ShapeCastType>(inShape, inScale, inCenterOfMassStart, inDirection, inShape->GetWorldSpaceBounds(inCenterOfMassStart, inScale))
32
{
33
}
34
35
/// Construct a shape cast using a world transform for a shape instead of a center of mass transform
36
static inline ShapeCastType sFromWorldTransform(const Shape *inShape, Vec3Arg inScale, typename Mat::ArgType inWorldTransform, Vec3Arg inDirection)
37
{
38
return ShapeCastType(inShape, inScale, inWorldTransform.PreTranslated(inShape->GetCenterOfMass()), inDirection);
39
}
40
41
/// Transform this shape cast using inTransform. Multiply transform on the left left hand side.
42
ShapeCastType PostTransformed(typename Mat::ArgType inTransform) const
43
{
44
Mat44 start = inTransform * mCenterOfMassStart;
45
Vec3 direction = inTransform.Multiply3x3(mDirection);
46
return { mShape, mScale, start, direction };
47
}
48
49
/// Translate this shape cast by inTranslation.
50
ShapeCastType PostTranslated(typename Vec::ArgType inTranslation) const
51
{
52
return { mShape, mScale, mCenterOfMassStart.PostTranslated(inTranslation), mDirection };
53
}
54
55
/// Get point with fraction inFraction on ray from mCenterOfMassStart to mCenterOfMassStart + mDirection (0 = start of ray, 1 = end of ray)
56
inline Vec GetPointOnRay(float inFraction) const
57
{
58
return mCenterOfMassStart.GetTranslation() + inFraction * mDirection;
59
}
60
61
const Shape * mShape; ///< Shape that's being cast (cannot be mesh shape). Note that this structure does not assume ownership over the shape for performance reasons.
62
const Vec3 mScale; ///< Scale in local space of the shape being cast (scales relative to its center of mass)
63
const Mat mCenterOfMassStart; ///< Start position and orientation of the center of mass of the shape (construct using sFromWorldTransform if you have a world transform for your shape)
64
const Vec3 mDirection; ///< Direction and length of the cast (anything beyond this length will not be reported as a hit)
65
const AABox mShapeWorldBounds; ///< Cached shape's world bounds, calculated in constructor
66
};
67
68
struct ShapeCast : public ShapeCastT<Vec3, Mat44, ShapeCast>
69
{
70
using ShapeCastT<Vec3, Mat44, ShapeCast>::ShapeCastT;
71
};
72
73
struct RShapeCast : public ShapeCastT<RVec3, RMat44, RShapeCast>
74
{
75
using ShapeCastT<RVec3, RMat44, RShapeCast>::ShapeCastT;
76
77
/// Convert from ShapeCast, converts single to double precision
78
explicit RShapeCast(const ShapeCast &inCast) :
79
RShapeCast(inCast.mShape, inCast.mScale, RMat44(inCast.mCenterOfMassStart), inCast.mDirection, inCast.mShapeWorldBounds)
80
{
81
}
82
83
/// Convert to ShapeCast, which implies casting from double precision to single precision
84
explicit operator ShapeCast() const
85
{
86
return ShapeCast(mShape, mScale, mCenterOfMassStart.ToMat44(), mDirection, mShapeWorldBounds);
87
}
88
};
89
90
/// Settings to be passed with a shape cast
91
class ShapeCastSettings : public CollideSettingsBase
92
{
93
public:
94
JPH_OVERRIDE_NEW_DELETE
95
96
/// Set the backfacing mode for all shapes
97
void SetBackFaceMode(EBackFaceMode inMode) { mBackFaceModeTriangles = mBackFaceModeConvex = inMode; }
98
99
/// How backfacing triangles should be treated (should we report moving from back to front for triangle based shapes, e.g. for MeshShape/HeightFieldShape?)
100
EBackFaceMode mBackFaceModeTriangles = EBackFaceMode::IgnoreBackFaces;
101
102
/// How backfacing convex objects should be treated (should we report starting inside an object and moving out?)
103
EBackFaceMode mBackFaceModeConvex = EBackFaceMode::IgnoreBackFaces;
104
105
/// Indicates if we want to shrink the shape by the convex radius and then expand it again. This speeds up collision detection and gives a more accurate normal at the cost of a more 'rounded' shape.
106
bool mUseShrunkenShapeAndConvexRadius = false;
107
108
/// When true, and the shape is intersecting at the beginning of the cast (fraction = 0) then this will calculate the deepest penetration point (costing additional CPU time)
109
bool mReturnDeepestPoint = false;
110
};
111
112
/// Result of a shape cast test
113
class ShapeCastResult : public CollideShapeResult
114
{
115
public:
116
JPH_OVERRIDE_NEW_DELETE
117
118
/// Default constructor
119
ShapeCastResult() = default;
120
121
/// Constructor
122
/// @param inFraction Fraction at which the cast hit
123
/// @param inContactPoint1 Contact point on shape 1
124
/// @param inContactPoint2 Contact point on shape 2
125
/// @param inContactNormalOrPenetrationDepth Contact normal pointing from shape 1 to 2 or penetration depth vector when the objects are penetrating (also from 1 to 2)
126
/// @param inBackFaceHit If this hit was a back face hit
127
/// @param inSubShapeID1 Sub shape id for shape 1
128
/// @param inSubShapeID2 Sub shape id for shape 2
129
/// @param inBodyID2 BodyID that was hit
130
ShapeCastResult(float inFraction, Vec3Arg inContactPoint1, Vec3Arg inContactPoint2, Vec3Arg inContactNormalOrPenetrationDepth, bool inBackFaceHit, const SubShapeID &inSubShapeID1, const SubShapeID &inSubShapeID2, const BodyID &inBodyID2) :
131
CollideShapeResult(inContactPoint1, inContactPoint2, inContactNormalOrPenetrationDepth, (inContactPoint2 - inContactPoint1).Length(), inSubShapeID1, inSubShapeID2, inBodyID2),
132
mFraction(inFraction),
133
mIsBackFaceHit(inBackFaceHit)
134
{
135
}
136
137
/// Function required by the CollisionCollector. A smaller fraction is considered to be a 'better hit'. For rays/cast shapes we can just use the collision fraction. The fraction and penetration depth are combined in such a way that deeper hits at fraction 0 go first.
138
inline float GetEarlyOutFraction() const { return mFraction > 0.0f? mFraction : -mPenetrationDepth; }
139
140
/// Reverses the hit result, swapping contact point 1 with contact point 2 etc.
141
/// @param inWorldSpaceCastDirection Direction of the shape cast in world space
142
ShapeCastResult Reversed(Vec3Arg inWorldSpaceCastDirection) const
143
{
144
// Calculate by how much to shift the contact points
145
Vec3 delta = mFraction * inWorldSpaceCastDirection;
146
147
ShapeCastResult result;
148
result.mContactPointOn2 = mContactPointOn1 - delta;
149
result.mContactPointOn1 = mContactPointOn2 - delta;
150
result.mPenetrationAxis = -mPenetrationAxis;
151
result.mPenetrationDepth = mPenetrationDepth;
152
result.mSubShapeID2 = mSubShapeID1;
153
result.mSubShapeID1 = mSubShapeID2;
154
result.mBodyID2 = mBodyID2;
155
result.mFraction = mFraction;
156
result.mIsBackFaceHit = mIsBackFaceHit;
157
158
result.mShape2Face.resize(mShape1Face.size());
159
for (Face::size_type i = 0; i < mShape1Face.size(); ++i)
160
result.mShape2Face[i] = mShape1Face[i] - delta;
161
162
result.mShape1Face.resize(mShape2Face.size());
163
for (Face::size_type i = 0; i < mShape2Face.size(); ++i)
164
result.mShape1Face[i] = mShape2Face[i] - delta;
165
166
return result;
167
}
168
169
float mFraction; ///< This is the fraction where the shape hit the other shape: CenterOfMassOnHit = Start + value * (End - Start)
170
bool mIsBackFaceHit; ///< True if the shape was hit from the back side
171
};
172
173
JPH_NAMESPACE_END
174
175