Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/jolt_physics/Jolt/Geometry/RayAABox.h
9913 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
JPH_NAMESPACE_BEGIN
8
9
/// Helper structure holding the reciprocal of a ray for Ray vs AABox testing
10
class RayInvDirection
11
{
12
public:
13
/// Constructors
14
inline RayInvDirection() = default;
15
inline explicit RayInvDirection(Vec3Arg inDirection) { Set(inDirection); }
16
17
/// Set reciprocal from ray direction
18
inline void Set(Vec3Arg inDirection)
19
{
20
// if (abs(inDirection) <= Epsilon) the ray is nearly parallel to the slab.
21
mIsParallel = Vec3::sLessOrEqual(inDirection.Abs(), Vec3::sReplicate(1.0e-20f));
22
23
// Calculate 1 / direction while avoiding division by zero
24
mInvDirection = Vec3::sSelect(inDirection, Vec3::sOne(), mIsParallel).Reciprocal();
25
}
26
27
Vec3 mInvDirection; ///< 1 / ray direction
28
UVec4 mIsParallel; ///< for each component if it is parallel to the coordinate axis
29
};
30
31
/// Intersect AABB with ray, returns minimal distance along ray or FLT_MAX if no hit
32
/// Note: Can return negative value if ray starts in box
33
JPH_INLINE float RayAABox(Vec3Arg inOrigin, const RayInvDirection &inInvDirection, Vec3Arg inBoundsMin, Vec3Arg inBoundsMax)
34
{
35
// Constants
36
Vec3 flt_min = Vec3::sReplicate(-FLT_MAX);
37
Vec3 flt_max = Vec3::sReplicate(FLT_MAX);
38
39
// Test against all three axes simultaneously.
40
Vec3 t1 = (inBoundsMin - inOrigin) * inInvDirection.mInvDirection;
41
Vec3 t2 = (inBoundsMax - inOrigin) * inInvDirection.mInvDirection;
42
43
// Compute the max of min(t1,t2) and the min of max(t1,t2) ensuring we don't
44
// use the results from any directions parallel to the slab.
45
Vec3 t_min = Vec3::sSelect(Vec3::sMin(t1, t2), flt_min, inInvDirection.mIsParallel);
46
Vec3 t_max = Vec3::sSelect(Vec3::sMax(t1, t2), flt_max, inInvDirection.mIsParallel);
47
48
// t_min.xyz = maximum(t_min.x, t_min.y, t_min.z);
49
t_min = Vec3::sMax(t_min, t_min.Swizzle<SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_X>());
50
t_min = Vec3::sMax(t_min, t_min.Swizzle<SWIZZLE_Z, SWIZZLE_X, SWIZZLE_Y>());
51
52
// t_max.xyz = minimum(t_max.x, t_max.y, t_max.z);
53
t_max = Vec3::sMin(t_max, t_max.Swizzle<SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_X>());
54
t_max = Vec3::sMin(t_max, t_max.Swizzle<SWIZZLE_Z, SWIZZLE_X, SWIZZLE_Y>());
55
56
// if (t_min > t_max) return FLT_MAX;
57
UVec4 no_intersection = Vec3::sGreater(t_min, t_max);
58
59
// if (t_max < 0.0f) return FLT_MAX;
60
no_intersection = UVec4::sOr(no_intersection, Vec3::sLess(t_max, Vec3::sZero()));
61
62
// if (inInvDirection.mIsParallel && !(Min <= inOrigin && inOrigin <= Max)) return FLT_MAX; else return t_min;
63
UVec4 no_parallel_overlap = UVec4::sOr(Vec3::sLess(inOrigin, inBoundsMin), Vec3::sGreater(inOrigin, inBoundsMax));
64
no_intersection = UVec4::sOr(no_intersection, UVec4::sAnd(inInvDirection.mIsParallel, no_parallel_overlap));
65
no_intersection = UVec4::sOr(no_intersection, no_intersection.SplatY());
66
no_intersection = UVec4::sOr(no_intersection, no_intersection.SplatZ());
67
return Vec3::sSelect(t_min, flt_max, no_intersection).GetX();
68
}
69
70
/// Intersect 4 AABBs with ray, returns minimal distance along ray or FLT_MAX if no hit
71
/// Note: Can return negative value if ray starts in box
72
JPH_INLINE Vec4 RayAABox4(Vec3Arg inOrigin, const RayInvDirection &inInvDirection, Vec4Arg inBoundsMinX, Vec4Arg inBoundsMinY, Vec4Arg inBoundsMinZ, Vec4Arg inBoundsMaxX, Vec4Arg inBoundsMaxY, Vec4Arg inBoundsMaxZ)
73
{
74
// Constants
75
Vec4 flt_min = Vec4::sReplicate(-FLT_MAX);
76
Vec4 flt_max = Vec4::sReplicate(FLT_MAX);
77
78
// Origin
79
Vec4 originx = inOrigin.SplatX();
80
Vec4 originy = inOrigin.SplatY();
81
Vec4 originz = inOrigin.SplatZ();
82
83
// Parallel
84
UVec4 parallelx = inInvDirection.mIsParallel.SplatX();
85
UVec4 parallely = inInvDirection.mIsParallel.SplatY();
86
UVec4 parallelz = inInvDirection.mIsParallel.SplatZ();
87
88
// Inverse direction
89
Vec4 invdirx = inInvDirection.mInvDirection.SplatX();
90
Vec4 invdiry = inInvDirection.mInvDirection.SplatY();
91
Vec4 invdirz = inInvDirection.mInvDirection.SplatZ();
92
93
// Test against all three axes simultaneously.
94
Vec4 t1x = (inBoundsMinX - originx) * invdirx;
95
Vec4 t1y = (inBoundsMinY - originy) * invdiry;
96
Vec4 t1z = (inBoundsMinZ - originz) * invdirz;
97
Vec4 t2x = (inBoundsMaxX - originx) * invdirx;
98
Vec4 t2y = (inBoundsMaxY - originy) * invdiry;
99
Vec4 t2z = (inBoundsMaxZ - originz) * invdirz;
100
101
// Compute the max of min(t1,t2) and the min of max(t1,t2) ensuring we don't
102
// use the results from any directions parallel to the slab.
103
Vec4 t_minx = Vec4::sSelect(Vec4::sMin(t1x, t2x), flt_min, parallelx);
104
Vec4 t_miny = Vec4::sSelect(Vec4::sMin(t1y, t2y), flt_min, parallely);
105
Vec4 t_minz = Vec4::sSelect(Vec4::sMin(t1z, t2z), flt_min, parallelz);
106
Vec4 t_maxx = Vec4::sSelect(Vec4::sMax(t1x, t2x), flt_max, parallelx);
107
Vec4 t_maxy = Vec4::sSelect(Vec4::sMax(t1y, t2y), flt_max, parallely);
108
Vec4 t_maxz = Vec4::sSelect(Vec4::sMax(t1z, t2z), flt_max, parallelz);
109
110
// t_min.xyz = maximum(t_min.x, t_min.y, t_min.z);
111
Vec4 t_min = Vec4::sMax(Vec4::sMax(t_minx, t_miny), t_minz);
112
113
// t_max.xyz = minimum(t_max.x, t_max.y, t_max.z);
114
Vec4 t_max = Vec4::sMin(Vec4::sMin(t_maxx, t_maxy), t_maxz);
115
116
// if (t_min > t_max) return FLT_MAX;
117
UVec4 no_intersection = Vec4::sGreater(t_min, t_max);
118
119
// if (t_max < 0.0f) return FLT_MAX;
120
no_intersection = UVec4::sOr(no_intersection, Vec4::sLess(t_max, Vec4::sZero()));
121
122
// if bounds are invalid return FLOAT_MAX;
123
UVec4 bounds_invalid = UVec4::sOr(UVec4::sOr(Vec4::sGreater(inBoundsMinX, inBoundsMaxX), Vec4::sGreater(inBoundsMinY, inBoundsMaxY)), Vec4::sGreater(inBoundsMinZ, inBoundsMaxZ));
124
no_intersection = UVec4::sOr(no_intersection, bounds_invalid);
125
126
// if (inInvDirection.mIsParallel && !(Min <= inOrigin && inOrigin <= Max)) return FLT_MAX; else return t_min;
127
UVec4 no_parallel_overlapx = UVec4::sAnd(parallelx, UVec4::sOr(Vec4::sLess(originx, inBoundsMinX), Vec4::sGreater(originx, inBoundsMaxX)));
128
UVec4 no_parallel_overlapy = UVec4::sAnd(parallely, UVec4::sOr(Vec4::sLess(originy, inBoundsMinY), Vec4::sGreater(originy, inBoundsMaxY)));
129
UVec4 no_parallel_overlapz = UVec4::sAnd(parallelz, UVec4::sOr(Vec4::sLess(originz, inBoundsMinZ), Vec4::sGreater(originz, inBoundsMaxZ)));
130
no_intersection = UVec4::sOr(no_intersection, UVec4::sOr(UVec4::sOr(no_parallel_overlapx, no_parallel_overlapy), no_parallel_overlapz));
131
return Vec4::sSelect(t_min, flt_max, no_intersection);
132
}
133
134
/// Intersect AABB with ray, returns minimal and maximal distance along ray or FLT_MAX, -FLT_MAX if no hit
135
/// Note: Can return negative value for outMin if ray starts in box
136
JPH_INLINE void RayAABox(Vec3Arg inOrigin, const RayInvDirection &inInvDirection, Vec3Arg inBoundsMin, Vec3Arg inBoundsMax, float &outMin, float &outMax)
137
{
138
// Constants
139
Vec3 flt_min = Vec3::sReplicate(-FLT_MAX);
140
Vec3 flt_max = Vec3::sReplicate(FLT_MAX);
141
142
// Test against all three axes simultaneously.
143
Vec3 t1 = (inBoundsMin - inOrigin) * inInvDirection.mInvDirection;
144
Vec3 t2 = (inBoundsMax - inOrigin) * inInvDirection.mInvDirection;
145
146
// Compute the max of min(t1,t2) and the min of max(t1,t2) ensuring we don't
147
// use the results from any directions parallel to the slab.
148
Vec3 t_min = Vec3::sSelect(Vec3::sMin(t1, t2), flt_min, inInvDirection.mIsParallel);
149
Vec3 t_max = Vec3::sSelect(Vec3::sMax(t1, t2), flt_max, inInvDirection.mIsParallel);
150
151
// t_min.xyz = maximum(t_min.x, t_min.y, t_min.z);
152
t_min = Vec3::sMax(t_min, t_min.Swizzle<SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_X>());
153
t_min = Vec3::sMax(t_min, t_min.Swizzle<SWIZZLE_Z, SWIZZLE_X, SWIZZLE_Y>());
154
155
// t_max.xyz = minimum(t_max.x, t_max.y, t_max.z);
156
t_max = Vec3::sMin(t_max, t_max.Swizzle<SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_X>());
157
t_max = Vec3::sMin(t_max, t_max.Swizzle<SWIZZLE_Z, SWIZZLE_X, SWIZZLE_Y>());
158
159
// if (t_min > t_max) return FLT_MAX;
160
UVec4 no_intersection = Vec3::sGreater(t_min, t_max);
161
162
// if (t_max < 0.0f) return FLT_MAX;
163
no_intersection = UVec4::sOr(no_intersection, Vec3::sLess(t_max, Vec3::sZero()));
164
165
// if (inInvDirection.mIsParallel && !(Min <= inOrigin && inOrigin <= Max)) return FLT_MAX; else return t_min;
166
UVec4 no_parallel_overlap = UVec4::sOr(Vec3::sLess(inOrigin, inBoundsMin), Vec3::sGreater(inOrigin, inBoundsMax));
167
no_intersection = UVec4::sOr(no_intersection, UVec4::sAnd(inInvDirection.mIsParallel, no_parallel_overlap));
168
no_intersection = UVec4::sOr(no_intersection, no_intersection.SplatY());
169
no_intersection = UVec4::sOr(no_intersection, no_intersection.SplatZ());
170
outMin = Vec3::sSelect(t_min, flt_max, no_intersection).GetX();
171
outMax = Vec3::sSelect(t_max, flt_min, no_intersection).GetX();
172
}
173
174
/// Intersect AABB with ray, returns true if there is a hit closer than inClosest
175
JPH_INLINE bool RayAABoxHits(Vec3Arg inOrigin, const RayInvDirection &inInvDirection, Vec3Arg inBoundsMin, Vec3Arg inBoundsMax, float inClosest)
176
{
177
// Constants
178
Vec3 flt_min = Vec3::sReplicate(-FLT_MAX);
179
Vec3 flt_max = Vec3::sReplicate(FLT_MAX);
180
181
// Test against all three axes simultaneously.
182
Vec3 t1 = (inBoundsMin - inOrigin) * inInvDirection.mInvDirection;
183
Vec3 t2 = (inBoundsMax - inOrigin) * inInvDirection.mInvDirection;
184
185
// Compute the max of min(t1,t2) and the min of max(t1,t2) ensuring we don't
186
// use the results from any directions parallel to the slab.
187
Vec3 t_min = Vec3::sSelect(Vec3::sMin(t1, t2), flt_min, inInvDirection.mIsParallel);
188
Vec3 t_max = Vec3::sSelect(Vec3::sMax(t1, t2), flt_max, inInvDirection.mIsParallel);
189
190
// t_min.xyz = maximum(t_min.x, t_min.y, t_min.z);
191
t_min = Vec3::sMax(t_min, t_min.Swizzle<SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_X>());
192
t_min = Vec3::sMax(t_min, t_min.Swizzle<SWIZZLE_Z, SWIZZLE_X, SWIZZLE_Y>());
193
194
// t_max.xyz = minimum(t_max.x, t_max.y, t_max.z);
195
t_max = Vec3::sMin(t_max, t_max.Swizzle<SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_X>());
196
t_max = Vec3::sMin(t_max, t_max.Swizzle<SWIZZLE_Z, SWIZZLE_X, SWIZZLE_Y>());
197
198
// if (t_min > t_max) return false;
199
UVec4 no_intersection = Vec3::sGreater(t_min, t_max);
200
201
// if (t_max < 0.0f) return false;
202
no_intersection = UVec4::sOr(no_intersection, Vec3::sLess(t_max, Vec3::sZero()));
203
204
// if (t_min > inClosest) return false;
205
no_intersection = UVec4::sOr(no_intersection, Vec3::sGreater(t_min, Vec3::sReplicate(inClosest)));
206
207
// if (inInvDirection.mIsParallel && !(Min <= inOrigin && inOrigin <= Max)) return false; else return true;
208
UVec4 no_parallel_overlap = UVec4::sOr(Vec3::sLess(inOrigin, inBoundsMin), Vec3::sGreater(inOrigin, inBoundsMax));
209
no_intersection = UVec4::sOr(no_intersection, UVec4::sAnd(inInvDirection.mIsParallel, no_parallel_overlap));
210
211
return !no_intersection.TestAnyXYZTrue();
212
}
213
214
/// Intersect AABB with ray without hit fraction, based on separating axis test
215
/// @see http://www.codercorner.com/RayAABB.cpp
216
JPH_INLINE bool RayAABoxHits(Vec3Arg inOrigin, Vec3Arg inDirection, Vec3Arg inBoundsMin, Vec3Arg inBoundsMax)
217
{
218
Vec3 extents = inBoundsMax - inBoundsMin;
219
220
Vec3 diff = 2.0f * inOrigin - inBoundsMin - inBoundsMax;
221
Vec3 abs_diff = diff.Abs();
222
223
UVec4 no_intersection = UVec4::sAnd(Vec3::sGreater(abs_diff, extents), Vec3::sGreaterOrEqual(diff * inDirection, Vec3::sZero()));
224
225
Vec3 abs_dir = inDirection.Abs();
226
Vec3 abs_dir_yzz = abs_dir.Swizzle<SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_Z>();
227
Vec3 abs_dir_xyx = abs_dir.Swizzle<SWIZZLE_X, SWIZZLE_Y, SWIZZLE_X>();
228
229
Vec3 extents_yzz = extents.Swizzle<SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_Z>();
230
Vec3 extents_xyx = extents.Swizzle<SWIZZLE_X, SWIZZLE_Y, SWIZZLE_X>();
231
232
Vec3 diff_yzx = diff.Swizzle<SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_X>();
233
234
Vec3 dir_yzx = inDirection.Swizzle<SWIZZLE_Y, SWIZZLE_Z, SWIZZLE_X>();
235
236
no_intersection = UVec4::sOr(no_intersection, Vec3::sGreater((inDirection * diff_yzx - dir_yzx * diff).Abs(), extents_xyx * abs_dir_yzz + extents_yzz * abs_dir_xyx));
237
238
return !no_intersection.TestAnyXYZTrue();
239
}
240
241
JPH_NAMESPACE_END
242
243