Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/jolt_physics/Jolt/Geometry/RayTriangle.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
/// Intersect ray with triangle, returns closest point or FLT_MAX if no hit (branch less version)
10
/// Adapted from: http://en.wikipedia.org/wiki/M%C3%B6ller%E2%80%93Trumbore_intersection_algorithm
11
JPH_INLINE float RayTriangle(Vec3Arg inOrigin, Vec3Arg inDirection, Vec3Arg inV0, Vec3Arg inV1, Vec3Arg inV2)
12
{
13
// Epsilon
14
Vec3 epsilon = Vec3::sReplicate(1.0e-12f);
15
16
// Zero & one
17
Vec3 zero = Vec3::sZero();
18
Vec3 one = Vec3::sOne();
19
20
// Find vectors for two edges sharing inV0
21
Vec3 e1 = inV1 - inV0;
22
Vec3 e2 = inV2 - inV0;
23
24
// Begin calculating determinant - also used to calculate u parameter
25
Vec3 p = inDirection.Cross(e2);
26
27
// if determinant is near zero, ray lies in plane of triangle
28
Vec3 det = Vec3::sReplicate(e1.Dot(p));
29
30
// Check if determinant is near zero
31
UVec4 det_near_zero = Vec3::sLess(det.Abs(), epsilon);
32
33
// When the determinant is near zero, set it to one to avoid dividing by zero
34
det = Vec3::sSelect(det, Vec3::sOne(), det_near_zero);
35
36
// Calculate distance from inV0 to ray origin
37
Vec3 s = inOrigin - inV0;
38
39
// Calculate u parameter
40
Vec3 u = Vec3::sReplicate(s.Dot(p)) / det;
41
42
// Prepare to test v parameter
43
Vec3 q = s.Cross(e1);
44
45
// Calculate v parameter
46
Vec3 v = Vec3::sReplicate(inDirection.Dot(q)) / det;
47
48
// Get intersection point
49
Vec3 t = Vec3::sReplicate(e2.Dot(q)) / det;
50
51
// Check if there is an intersection
52
UVec4 no_intersection =
53
UVec4::sOr
54
(
55
UVec4::sOr
56
(
57
UVec4::sOr
58
(
59
det_near_zero,
60
Vec3::sLess(u, zero)
61
),
62
UVec4::sOr
63
(
64
Vec3::sLess(v, zero),
65
Vec3::sGreater(u + v, one)
66
)
67
),
68
Vec3::sLess(t, zero)
69
);
70
71
// Select intersection point or FLT_MAX based on if there is an intersection or not
72
return Vec3::sSelect(t, Vec3::sReplicate(FLT_MAX), no_intersection).GetX();
73
}
74
75
/// Intersect ray with 4 triangles in SOA format, returns 4 vector of closest points or FLT_MAX if no hit (uses bit tricks to do less divisions)
76
JPH_INLINE Vec4 RayTriangle4(Vec3Arg inOrigin, Vec3Arg inDirection, Vec4Arg inV0X, Vec4Arg inV0Y, Vec4Arg inV0Z, Vec4Arg inV1X, Vec4Arg inV1Y, Vec4Arg inV1Z, Vec4Arg inV2X, Vec4Arg inV2Y, Vec4Arg inV2Z)
77
{
78
// Epsilon
79
Vec4 epsilon = Vec4::sReplicate(1.0e-12f);
80
81
// Zero
82
Vec4 zero = Vec4::sZero();
83
84
// Find vectors for two edges sharing inV0
85
Vec4 e1x = inV1X - inV0X;
86
Vec4 e1y = inV1Y - inV0Y;
87
Vec4 e1z = inV1Z - inV0Z;
88
Vec4 e2x = inV2X - inV0X;
89
Vec4 e2y = inV2Y - inV0Y;
90
Vec4 e2z = inV2Z - inV0Z;
91
92
// Get direction vector components
93
Vec4 dx = inDirection.SplatX();
94
Vec4 dy = inDirection.SplatY();
95
Vec4 dz = inDirection.SplatZ();
96
97
// Begin calculating determinant - also used to calculate u parameter
98
Vec4 px = dy * e2z - dz * e2y;
99
Vec4 py = dz * e2x - dx * e2z;
100
Vec4 pz = dx * e2y - dy * e2x;
101
102
// if determinant is near zero, ray lies in plane of triangle
103
Vec4 det = e1x * px + e1y * py + e1z * pz;
104
105
// Get sign bit for determinant and make positive
106
Vec4 det_sign = Vec4::sAnd(det, UVec4::sReplicate(0x80000000).ReinterpretAsFloat());
107
det = Vec4::sXor(det, det_sign);
108
109
// Check which determinants are near zero
110
UVec4 det_near_zero = Vec4::sLess(det, epsilon);
111
112
// Set components of the determinant to 1 that are near zero to avoid dividing by zero
113
det = Vec4::sSelect(det, Vec4::sOne(), det_near_zero);
114
115
// Calculate distance from inV0 to ray origin
116
Vec4 sx = inOrigin.SplatX() - inV0X;
117
Vec4 sy = inOrigin.SplatY() - inV0Y;
118
Vec4 sz = inOrigin.SplatZ() - inV0Z;
119
120
// Calculate u parameter and flip sign if determinant was negative
121
Vec4 u = Vec4::sXor(sx * px + sy * py + sz * pz, det_sign);
122
123
// Prepare to test v parameter
124
Vec4 qx = sy * e1z - sz * e1y;
125
Vec4 qy = sz * e1x - sx * e1z;
126
Vec4 qz = sx * e1y - sy * e1x;
127
128
// Calculate v parameter and flip sign if determinant was negative
129
Vec4 v = Vec4::sXor(dx * qx + dy * qy + dz * qz, det_sign);
130
131
// Get intersection point and flip sign if determinant was negative
132
Vec4 t = Vec4::sXor(e2x * qx + e2y * qy + e2z * qz, det_sign);
133
134
// Check if there is an intersection
135
UVec4 no_intersection =
136
UVec4::sOr
137
(
138
UVec4::sOr
139
(
140
UVec4::sOr
141
(
142
det_near_zero,
143
Vec4::sLess(u, zero)
144
),
145
UVec4::sOr
146
(
147
Vec4::sLess(v, zero),
148
Vec4::sGreater(u + v, det)
149
)
150
),
151
Vec4::sLess(t, zero)
152
);
153
154
// Select intersection point or FLT_MAX based on if there is an intersection or not
155
return Vec4::sSelect(t / det, Vec4::sReplicate(FLT_MAX), no_intersection);
156
}
157
158
JPH_NAMESPACE_END
159
160