RavEngine
Loading...
Searching...
No Matches
GuIntersectionTriangleBoxRef.h
1// Redistribution and use in source and binary forms, with or without
2// modification, are permitted provided that the following conditions
3// are met:
4// * Redistributions of source code must retain the above copyright
5// notice, this list of conditions and the following disclaimer.
6// * Redistributions in binary form must reproduce the above copyright
7// notice, this list of conditions and the following disclaimer in the
8// documentation and/or other materials provided with the distribution.
9// * Neither the name of NVIDIA CORPORATION nor the names of its
10// contributors may be used to endorse or promote products derived
11// from this software without specific prior written permission.
12//
13// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
14// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
17// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24//
25// Copyright (c) 2008-2022 NVIDIA Corporation. All rights reserved.
26// Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
27// Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
28
29#ifndef GU_INTERSECTION_TRIANGLE_BOX_REF_H
30#define GU_INTERSECTION_TRIANGLE_BOX_REF_H
31
32#include "foundation/PxVec3.h"
33
34/********************************************************/
35/* AABB-triangle overlap test code */
36/* by Tomas Akenine-M?r */
37/* Function: int triBoxOverlap(float boxcenter[3], */
38/* float boxhalfsize[3],float triverts[3][3]); */
39/* History: */
40/* 2001-03-05: released the code in its first version */
41/* 2001-06-18: changed the order of the tests, faster */
42/* */
43/* Acknowledgement: Many thanks to Pierre Terdiman for */
44/* suggestions and discussions on how to optimize code. */
45/* Thanks to David Hunt for finding a ">="-bug! */
46/********************************************************/
47
48namespace physx
49{
50
51#define CROSS(dest,v1,v2) \
52 dest.x=v1.y*v2.z-v1.z*v2.y; \
53 dest.y=v1.z*v2.x-v1.x*v2.z; \
54 dest.z=v1.x*v2.y-v1.y*v2.x;
55
56#define DOT(v1,v2) (v1.x*v2.x+v1.y*v2.y+v1.z*v2.z)
57
58#define FINDMINMAX(x0, x1, x2, minimum, maximum) \
59 minimum = physx::intrinsics::selectMin(x0, x1); \
60 maximum = physx::intrinsics::selectMax(x0, x1); \
61 minimum = physx::intrinsics::selectMin(minimum, x2); \
62 maximum = physx::intrinsics::selectMax(maximum, x2);
63
64 static PX_CUDA_CALLABLE PX_FORCE_INLINE PxIntBool planeBoxOverlap(const PxVec3& normal, PxReal d, const PxVec3& maxbox)
65 {
66 PxVec3 vmin, vmax;
67
68 if (normal.x>0.0f)
69 {
70 vmin.x = -maxbox.x;
71 vmax.x = maxbox.x;
72 }
73 else
74 {
75 vmin.x = maxbox.x;
76 vmax.x = -maxbox.x;
77 }
78
79 if (normal.y>0.0f)
80 {
81 vmin.y = -maxbox.y;
82 vmax.y = maxbox.y;
83 }
84 else
85 {
86 vmin.y = maxbox.y;
87 vmax.y = -maxbox.y;
88 }
89
90 if (normal.z>0.0f)
91 {
92 vmin.z = -maxbox.z;
93 vmax.z = maxbox.z;
94 }
95 else
96 {
97 vmin.z = maxbox.z;
98 vmax.z = -maxbox.z;
99 }
100
101 if(normal.dot(vmin) + d > 0.0f)
102 return PxIntFalse;
103 if(normal.dot(vmax) + d >= 0.0f)
104 return PxIntTrue;
105 return PxIntFalse;
106 }
107
108 /*======================== X-tests ========================*/
109#define AXISTEST_X01(a, b, fa, fb) \
110 p0 = a*v0.y - b*v0.z; \
111 p2 = a*v2.y - b*v2.z; \
112 minimum = physx::intrinsics::selectMin(p0, p2); \
113 maximum = physx::intrinsics::selectMax(p0, p2); \
114 rad = fa * extents.y + fb * extents.z; \
115 if(minimum>rad || maximum<-rad) return PxIntFalse;
116
117#define AXISTEST_X2(a, b, fa, fb) \
118 p0 = a*v0.y - b*v0.z; \
119 p1 = a*v1.y - b*v1.z; \
120 minimum = physx::intrinsics::selectMin(p0, p1); \
121 maximum = physx::intrinsics::selectMax(p0, p1); \
122 rad = fa * extents.y + fb * extents.z; \
123 if(minimum>rad || maximum<-rad) return PxIntFalse;
124
125 /*======================== Y-tests ========================*/
126#define AXISTEST_Y02(a, b, fa, fb) \
127 p0 = -a*v0.x + b*v0.z; \
128 p2 = -a*v2.x + b*v2.z; \
129 minimum = physx::intrinsics::selectMin(p0, p2); \
130 maximum = physx::intrinsics::selectMax(p0, p2); \
131 rad = fa * extents.x + fb * extents.z; \
132 if(minimum>rad || maximum<-rad) return PxIntFalse;
133
134#define AXISTEST_Y1(a, b, fa, fb) \
135 p0 = -a*v0.x + b*v0.z; \
136 p1 = -a*v1.x + b*v1.z; \
137 minimum = physx::intrinsics::selectMin(p0, p1); \
138 maximum = physx::intrinsics::selectMax(p0, p1); \
139 rad = fa * extents.x + fb * extents.z; \
140 if(minimum>rad || maximum<-rad) return PxIntFalse;
141
142 /*======================== Z-tests ========================*/
143#define AXISTEST_Z12(a, b, fa, fb) \
144 p1 = a*v1.x - b*v1.y; \
145 p2 = a*v2.x - b*v2.y; \
146 minimum = physx::intrinsics::selectMin(p1, p2); \
147 maximum = physx::intrinsics::selectMax(p1, p2); \
148 rad = fa * extents.x + fb * extents.y; \
149 if(minimum>rad || maximum<-rad) return PxIntFalse;
150
151#define AXISTEST_Z0(a, b, fa, fb) \
152 p0 = a*v0.x - b*v0.y; \
153 p1 = a*v1.x - b*v1.y; \
154 minimum = physx::intrinsics::selectMin(p0, p1); \
155 maximum = physx::intrinsics::selectMax(p0, p1); \
156 rad = fa * extents.x + fb * extents.y; \
157 if(minimum>rad || maximum<-rad) return PxIntFalse;
158
159 namespace Gu
160 {
161 template <const bool bDoVertexChecks = false>
162 static PX_CUDA_CALLABLE PX_FORCE_INLINE PxIntBool intersectTriangleBox_RefImpl(const PxVec3& boxcenter, const PxVec3& extents, const PxVec3& tp0, const PxVec3& tp1, const PxVec3& tp2)
163 {
164 /* use separating axis theorem to test overlap between triangle and box */
165 /* need to test for overlap in these directions: */
166 /* 1) the {x,y,z}-directions (actually, since we use the AABB of the triangle */
167 /* we do not even need to test these) */
168 /* 2) normal of the triangle */
169 /* 3) crossproduct(edge from tri, {x,y,z}-directin) */
170 /* this gives 3x3=9 more tests */
171
172 // This is the fastest branch on Sun - move everything so that the boxcenter is in (0,0,0)
173 const PxVec3 v0 = tp0 - boxcenter;
174 const PxVec3 v1 = tp1 - boxcenter;
175 const PxVec3 v2 = tp2 - boxcenter;
176
177 if (bDoVertexChecks)
178 {
179 if (PxAbs(v0.x) <= extents.x && PxAbs(v0.y) <= extents.y && PxAbs(v0.z) <= extents.z)
180 return PxIntTrue;
181 if (PxAbs(v1.x) <= extents.x && PxAbs(v1.y) <= extents.y && PxAbs(v1.z) <= extents.z)
182 return PxIntTrue;
183 if (PxAbs(v2.x) <= extents.x && PxAbs(v2.y) <= extents.y && PxAbs(v2.z) <= extents.z)
184 return PxIntTrue;
185 }
186
187 // compute triangle edges
188 const PxVec3 e0 = v1 - v0; // tri edge 0
189 const PxVec3 e1 = v2 - v1; // tri edge 1
190 const PxVec3 e2 = v0 - v2; // tri edge 2
191
192 float minimum, maximum, rad, p0, p1, p2;
193
194 // Bullet 3: test the 9 tests first (this was faster)
195 float fex = PxAbs(e0.x);
196 float fey = PxAbs(e0.y);
197 float fez = PxAbs(e0.z);
198 AXISTEST_X01(e0.z, e0.y, fez, fey);
199 AXISTEST_Y02(e0.z, e0.x, fez, fex);
200 AXISTEST_Z12(e0.y, e0.x, fey, fex);
201
202 fex = PxAbs(e1.x);
203 fey = PxAbs(e1.y);
204 fez = PxAbs(e1.z);
205 AXISTEST_X01(e1.z, e1.y, fez, fey);
206 AXISTEST_Y02(e1.z, e1.x, fez, fex);
207 AXISTEST_Z0(e1.y, e1.x, fey, fex);
208
209 fex = PxAbs(e2.x);
210 fey = PxAbs(e2.y);
211 fez = PxAbs(e2.z);
212 AXISTEST_X2(e2.z, e2.y, fez, fey);
213 AXISTEST_Y1(e2.z, e2.x, fez, fex);
214 AXISTEST_Z12(e2.y, e2.x, fey, fex);
215
216 // Bullet 1:
217 // first test overlap in the {x,y,z}-directions
218 // find minimum, maximum of the triangle each direction, and test for overlap in
219 // that direction -- this is equivalent to testing a minimal AABB around
220 // the triangle against the AABB
221
222 // test in X-direction
223 FINDMINMAX(v0.x, v1.x, v2.x, minimum, maximum);
224 if(minimum>extents.x || maximum<-extents.x)
225 return PxIntFalse;
226
227 // test in Y-direction
228 FINDMINMAX(v0.y, v1.y, v2.y, minimum, maximum);
229 if(minimum>extents.y || maximum<-extents.y)
230 return PxIntFalse;
231
232 // test in Z-direction
233 FINDMINMAX(v0.z, v1.z, v2.z, minimum, maximum);
234 if(minimum>extents.z || maximum<-extents.z)
235 return PxIntFalse;
236
237 // Bullet 2:
238 // test if the box intersects the plane of the triangle
239 // compute plane equation of triangle: normal*x+d=0
240 PxVec3 normal;
241 CROSS(normal, e0, e1);
242 const float d = -DOT(normal, v0); // plane eq: normal.x+d=0
243 if(!planeBoxOverlap(normal, d, extents))
244 return PxIntFalse;
245
246 return PxIntTrue; // box and triangle overlaps
247 }
248 }
249
250#undef CROSS
251#undef DOT
252#undef FINDMINMAX
253#undef AXISTEST_X01
254#undef AXISTEST_X2
255#undef AXISTEST_Y02
256#undef AXISTEST_Y1
257#undef AXISTEST_Z12
258#undef AXISTEST_Z0
259
260}
261
262#endif
263
PX_CUDA_CALLABLE PX_FORCE_INLINE float dot(const PxVec3 &v) const
returns the scalar product of this and other.
Definition PxVec3.h:276
#define PX_FORCE_INLINE
Definition PxPreprocessor.h:335
Sorts an array of objects in ascending order, assuming that the predicate implements the < operator:
Definition PxBoxController.h:39
PX_CUDA_CALLABLE PX_FORCE_INLINE float PxAbs(float a)
abs returns the absolute value of its argument.
Definition PxMath.h:109