the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
1//-------------------------------------------------------------------------------------
2// DirectXCollision.inl -- C++ Collision Math library
3//
4// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
5// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
6// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
7// PARTICULAR PURPOSE.
8//
9// Copyright (c) Microsoft Corporation. All rights reserved.
10//-------------------------------------------------------------------------------------
11
12#ifdef _MSC_VER
13#pragma once
14#endif
15
16XMGLOBALCONST XMVECTORF32 g_BoxOffset[8] =
17{
18 { -1.0f, -1.0f, 1.0f, 0.0f },
19 { 1.0f, -1.0f, 1.0f, 0.0f },
20 { 1.0f, 1.0f, 1.0f, 0.0f },
21 { -1.0f, 1.0f, 1.0f, 0.0f },
22 { -1.0f, -1.0f, -1.0f, 0.0f },
23 { 1.0f, -1.0f, -1.0f, 0.0f },
24 { 1.0f, 1.0f, -1.0f, 0.0f },
25 { -1.0f, 1.0f, -1.0f, 0.0f },
26};
27
28XMGLOBALCONST XMVECTORF32 g_RayEpsilon = { 1e-20f, 1e-20f, 1e-20f, 1e-20f };
29XMGLOBALCONST XMVECTORF32 g_RayNegEpsilon = { -1e-20f, -1e-20f, -1e-20f, -1e-20f };
30XMGLOBALCONST XMVECTORF32 g_FltMin = { -FLT_MAX, -FLT_MAX, -FLT_MAX, -FLT_MAX };
31XMGLOBALCONST XMVECTORF32 g_FltMax = { FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX };
32
33namespace Internal
34{
35
36//-----------------------------------------------------------------------------
37// Return true if any of the elements of a 3 vector are equal to 0xffffffff.
38// Slightly more efficient than using XMVector3EqualInt.
39//-----------------------------------------------------------------------------
40inline bool XMVector3AnyTrue( _In_ FXMVECTOR V )
41{
42 // Duplicate the fourth element from the first element.
43 XMVECTOR C = XMVectorSwizzle<XM_SWIZZLE_X, XM_SWIZZLE_Y, XM_SWIZZLE_Z, XM_SWIZZLE_X>(V);
44
45 return XMComparisonAnyTrue( XMVector4EqualIntR( C, XMVectorTrueInt() ) );
46}
47
48
49//-----------------------------------------------------------------------------
50// Return true if all of the elements of a 3 vector are equal to 0xffffffff.
51// Slightly more efficient than using XMVector3EqualInt.
52//-----------------------------------------------------------------------------
53inline bool XMVector3AllTrue( _In_ FXMVECTOR V )
54{
55 // Duplicate the fourth element from the first element.
56 XMVECTOR C = XMVectorSwizzle<XM_SWIZZLE_X, XM_SWIZZLE_Y, XM_SWIZZLE_Z, XM_SWIZZLE_X>( V );
57
58 return XMComparisonAllTrue( XMVector4EqualIntR( C, XMVectorTrueInt() ) );
59}
60
61#if defined(_PREFAST) || !defined(NDEBUG)
62
63XMGLOBALCONST XMVECTORF32 g_UnitVectorEpsilon = { 1.0e-4f, 1.0e-4f, 1.0e-4f, 1.0e-4f };
64XMGLOBALCONST XMVECTORF32 g_UnitQuaternionEpsilon = { 1.0e-4f, 1.0e-4f, 1.0e-4f, 1.0e-4f };
65XMGLOBALCONST XMVECTORF32 g_UnitPlaneEpsilon = { 1.0e-4f, 1.0e-4f, 1.0e-4f, 1.0e-4f };
66
67//-----------------------------------------------------------------------------
68// Return true if the vector is a unit vector (length == 1).
69//-----------------------------------------------------------------------------
70inline bool XMVector3IsUnit( _In_ FXMVECTOR V )
71{
72 XMVECTOR Difference = XMVector3Length( V ) - XMVectorSplatOne();
73 return XMVector4Less( XMVectorAbs( Difference ), g_UnitVectorEpsilon );
74}
75
76//-----------------------------------------------------------------------------
77// Return true if the quaterion is a unit quaternion.
78//-----------------------------------------------------------------------------
79inline bool XMQuaternionIsUnit( _In_ FXMVECTOR Q )
80{
81 XMVECTOR Difference = XMVector4Length( Q ) - XMVectorSplatOne();
82 return XMVector4Less( XMVectorAbs( Difference ), g_UnitQuaternionEpsilon );
83}
84
85//-----------------------------------------------------------------------------
86// Return true if the plane is a unit plane.
87//-----------------------------------------------------------------------------
88inline bool XMPlaneIsUnit( _In_ FXMVECTOR Plane )
89{
90 XMVECTOR Difference = XMVector3Length( Plane ) - XMVectorSplatOne();
91 return XMVector4Less( XMVectorAbs( Difference ), g_UnitPlaneEpsilon );
92}
93
94#endif // __PREFAST__ || !NDEBUG
95
96//-----------------------------------------------------------------------------
97inline XMVECTOR XMPlaneTransform( _In_ FXMVECTOR Plane, _In_ FXMVECTOR Rotation, _In_ FXMVECTOR Translation )
98{
99 XMVECTOR vNormal = XMVector3Rotate( Plane, Rotation );
100 XMVECTOR vD = XMVectorSplatW( Plane ) - XMVector3Dot( vNormal, Translation );
101
102 return XMVectorInsert<0, 0, 0, 0, 1>( vNormal, vD );
103}
104
105//-----------------------------------------------------------------------------
106// Return the point on the line segement (S1, S2) nearest the point P.
107//-----------------------------------------------------------------------------
108inline XMVECTOR PointOnLineSegmentNearestPoint( _In_ FXMVECTOR S1, _In_ FXMVECTOR S2, _In_ FXMVECTOR P )
109{
110 XMVECTOR Dir = S2 - S1;
111 XMVECTOR Projection = ( XMVector3Dot( P, Dir ) - XMVector3Dot( S1, Dir ) );
112 XMVECTOR LengthSq = XMVector3Dot( Dir, Dir );
113
114 XMVECTOR t = Projection * XMVectorReciprocal( LengthSq );
115 XMVECTOR Point = S1 + t * Dir;
116
117 // t < 0
118 XMVECTOR SelectS1 = XMVectorLess( Projection, XMVectorZero() );
119 Point = XMVectorSelect( Point, S1, SelectS1 );
120
121 // t > 1
122 XMVECTOR SelectS2 = XMVectorGreater( Projection, LengthSq );
123 Point = XMVectorSelect( Point, S2, SelectS2 );
124
125 return Point;
126}
127
128//-----------------------------------------------------------------------------
129// Test if the point (P) on the plane of the triangle is inside the triangle
130// (V0, V1, V2).
131//-----------------------------------------------------------------------------
132inline XMVECTOR PointOnPlaneInsideTriangle( _In_ FXMVECTOR P, _In_ FXMVECTOR V0, _In_ FXMVECTOR V1, _In_ GXMVECTOR V2 )
133{
134 // Compute the triangle normal.
135 XMVECTOR N = XMVector3Cross( V2 - V0, V1 - V0 );
136
137 // Compute the cross products of the vector from the base of each edge to
138 // the point with each edge vector.
139 XMVECTOR C0 = XMVector3Cross( P - V0, V1 - V0 );
140 XMVECTOR C1 = XMVector3Cross( P - V1, V2 - V1 );
141 XMVECTOR C2 = XMVector3Cross( P - V2, V0 - V2 );
142
143 // If the cross product points in the same direction as the normal the the
144 // point is inside the edge (it is zero if is on the edge).
145 XMVECTOR Zero = XMVectorZero();
146 XMVECTOR Inside0 = XMVectorGreaterOrEqual( XMVector3Dot( C0, N ), Zero );
147 XMVECTOR Inside1 = XMVectorGreaterOrEqual( XMVector3Dot( C1, N ), Zero );
148 XMVECTOR Inside2 = XMVectorGreaterOrEqual( XMVector3Dot( C2, N ), Zero );
149
150 // If the point inside all of the edges it is inside.
151 return XMVectorAndInt( XMVectorAndInt( Inside0, Inside1 ), Inside2 );
152}
153
154//-----------------------------------------------------------------------------
155inline bool SolveCubic( _In_ float e, _In_ float f, _In_ float g, _Out_ float* t, _Out_ float* u, _Out_ float* v )
156{
157 float p, q, h, rc, d, theta, costh3, sinth3;
158
159 p = f - e * e / 3.0f;
160 q = g - e * f / 3.0f + e * e * e * 2.0f / 27.0f;
161 h = q * q / 4.0f + p * p * p / 27.0f;
162
163 if( h > 0.0 )
164 {
165 *t = *u = *v = 0.f;
166 return false; // only one real root
167 }
168
169 if( ( h == 0.0 ) && ( q == 0.0 ) ) // all the same root
170 {
171 *t = - e / 3;
172 *u = - e / 3;
173 *v = - e / 3;
174
175 return true;
176 }
177
178 d = sqrtf( q * q / 4.0f - h );
179 if( d < 0 )
180 rc = -powf( -d, 1.0f / 3.0f );
181 else
182 rc = powf( d, 1.0f / 3.0f );
183
184 theta = XMScalarACos( -q / ( 2.0f * d ) );
185 costh3 = XMScalarCos( theta / 3.0f );
186 sinth3 = sqrtf( 3.0f ) * XMScalarSin( theta / 3.0f );
187 *t = 2.0f * rc * costh3 - e / 3.0f;
188 *u = -rc * ( costh3 + sinth3 ) - e / 3.0f;
189 *v = -rc * ( costh3 - sinth3 ) - e / 3.0f;
190
191 return true;
192}
193
194//-----------------------------------------------------------------------------
195inline XMVECTOR CalculateEigenVector( _In_ float m11, _In_ float m12, _In_ float m13,
196 _In_ float m22, _In_ float m23, _In_ float m33, _In_ float e )
197{
198 float fTmp[3];
199 fTmp[0] = ( float )( m12 * m23 - m13 * ( m22 - e ) );
200 fTmp[1] = ( float )( m13 * m12 - m23 * ( m11 - e ) );
201 fTmp[2] = ( float )( ( m11 - e ) * ( m22 - e ) - m12 * m12 );
202
203 XMVECTOR vTmp = XMLoadFloat3( (XMFLOAT3*)fTmp );
204
205 if( XMVector3Equal( vTmp, XMVectorZero() ) ) // planar or linear
206 {
207 float f1, f2, f3;
208
209 // we only have one equation - find a valid one
210 if( ( m11 - e != 0.0 ) || ( m12 != 0.0 ) || ( m13 != 0.0 ) )
211 {
212 f1 = m11 - e; f2 = m12; f3 = m13;
213 }
214 else if( ( m12 != 0.0 ) || ( m22 - e != 0.0 ) || ( m23 != 0.0 ) )
215 {
216 f1 = m12; f2 = m22 - e; f3 = m23;
217 }
218 else if( ( m13 != 0.0 ) || ( m23 != 0.0 ) || ( m33 - e != 0.0 ) )
219 {
220 f1 = m13; f2 = m23; f3 = m33 - e;
221 }
222 else
223 {
224 // error, we'll just make something up - we have NO context
225 f1 = 1.0; f2 = 0.0; f3 = 0.0;
226 }
227
228 if( f1 == 0.0 )
229 vTmp = XMVectorSetX( vTmp, 0.0f );
230 else
231 vTmp = XMVectorSetX( vTmp, 1.0f );
232
233 if( f2 == 0.0 )
234 vTmp = XMVectorSetY( vTmp, 0.0f );
235 else
236 vTmp = XMVectorSetY( vTmp, 1.0f );
237
238 if( f3 == 0.0 )
239 {
240 vTmp = XMVectorSetZ( vTmp, 0.0f );
241 // recalculate y to make equation work
242 if( m12 != 0.0 )
243 vTmp = XMVectorSetY( vTmp, ( float )( -f1 / f2 ) );
244 }
245 else
246 {
247 vTmp = XMVectorSetZ( vTmp, ( float )( ( f2 - f1 ) / f3 ) );
248 }
249 }
250
251 if( XMVectorGetX( XMVector3LengthSq( vTmp ) ) > 1e-5f )
252 {
253 return XMVector3Normalize( vTmp );
254 }
255 else
256 {
257 // Multiply by a value large enough to make the vector non-zero.
258 vTmp *= 1e5f;
259 return XMVector3Normalize( vTmp );
260 }
261}
262
263//-----------------------------------------------------------------------------
264inline bool CalculateEigenVectors( _In_ float m11, _In_ float m12, _In_ float m13,
265 _In_ float m22, _In_ float m23, _In_ float m33,
266 _In_ float e1, _In_ float e2, _In_ float e3,
267 _Out_ XMVECTOR* pV1, _Out_ XMVECTOR* pV2, _Out_ XMVECTOR* pV3 )
268{
269 *pV1 = DirectX::Internal::CalculateEigenVector( m11, m12, m13, m22, m23, m33, e1 );
270 *pV2 = DirectX::Internal::CalculateEigenVector( m11, m12, m13, m22, m23, m33, e2 );
271 *pV3 = DirectX::Internal::CalculateEigenVector( m11, m12, m13, m22, m23, m33, e3 );
272
273 bool v1z = false;
274 bool v2z = false;
275 bool v3z = false;
276
277 XMVECTOR Zero = XMVectorZero();
278
279 if ( XMVector3Equal( *pV1, Zero ) )
280 v1z = true;
281
282 if ( XMVector3Equal( *pV2, Zero ) )
283 v2z = true;
284
285 if ( XMVector3Equal( *pV3, Zero ))
286 v3z = true;
287
288 bool e12 = ( fabsf( XMVectorGetX( XMVector3Dot( *pV1, *pV2 ) ) ) > 0.1f ); // check for non-orthogonal vectors
289 bool e13 = ( fabsf( XMVectorGetX( XMVector3Dot( *pV1, *pV3 ) ) ) > 0.1f );
290 bool e23 = ( fabsf( XMVectorGetX( XMVector3Dot( *pV2, *pV3 ) ) ) > 0.1f );
291
292 if( ( v1z && v2z && v3z ) || ( e12 && e13 && e23 ) ||
293 ( e12 && v3z ) || ( e13 && v2z ) || ( e23 && v1z ) ) // all eigenvectors are 0- any basis set
294 {
295 *pV1 = g_XMIdentityR0.v;
296 *pV2 = g_XMIdentityR1.v;
297 *pV3 = g_XMIdentityR2.v;
298 return true;
299 }
300
301 if( v1z && v2z )
302 {
303 XMVECTOR vTmp = XMVector3Cross( g_XMIdentityR1, *pV3 );
304 if( XMVectorGetX( XMVector3LengthSq( vTmp ) ) < 1e-5f )
305 {
306 vTmp = XMVector3Cross( g_XMIdentityR0, *pV3 );
307 }
308 *pV1 = XMVector3Normalize( vTmp );
309 *pV2 = XMVector3Cross( *pV3, *pV1 );
310 return true;
311 }
312
313 if( v3z && v1z )
314 {
315 XMVECTOR vTmp = XMVector3Cross( g_XMIdentityR1, *pV2 );
316 if( XMVectorGetX( XMVector3LengthSq( vTmp ) ) < 1e-5f )
317 {
318 vTmp = XMVector3Cross( g_XMIdentityR0, *pV2 );
319 }
320 *pV3 = XMVector3Normalize( vTmp );
321 *pV1 = XMVector3Cross( *pV2, *pV3 );
322 return true;
323 }
324
325 if( v2z && v3z )
326 {
327 XMVECTOR vTmp = XMVector3Cross( g_XMIdentityR1, *pV1 );
328 if( XMVectorGetX( XMVector3LengthSq( vTmp ) ) < 1e-5f )
329 {
330 vTmp = XMVector3Cross( g_XMIdentityR0, *pV1 );
331 }
332 *pV2 = XMVector3Normalize( vTmp );
333 *pV3 = XMVector3Cross( *pV1, *pV2 );
334 return true;
335 }
336
337 if( ( v1z ) || e12 )
338 {
339 *pV1 = XMVector3Cross( *pV2, *pV3 );
340 return true;
341 }
342
343 if( ( v2z ) || e23 )
344 {
345 *pV2 = XMVector3Cross( *pV3, *pV1 );
346 return true;
347 }
348
349 if( ( v3z ) || e13 )
350 {
351 *pV3 = XMVector3Cross( *pV1, *pV2 );
352 return true;
353 }
354
355 return true;
356}
357
358//-----------------------------------------------------------------------------
359inline bool CalculateEigenVectorsFromCovarianceMatrix( _In_ float Cxx, _In_ float Cyy, _In_ float Czz,
360 _In_ float Cxy, _In_ float Cxz, _In_ float Cyz,
361 _Out_ XMVECTOR* pV1, _Out_ XMVECTOR* pV2, _Out_ XMVECTOR* pV3 )
362{
363 // Calculate the eigenvalues by solving a cubic equation.
364 float e = -( Cxx + Cyy + Czz );
365 float f = Cxx * Cyy + Cyy * Czz + Czz * Cxx - Cxy * Cxy - Cxz * Cxz - Cyz * Cyz;
366 float g = Cxy * Cxy * Czz + Cxz * Cxz * Cyy + Cyz * Cyz * Cxx - Cxy * Cyz * Cxz * 2.0f - Cxx * Cyy * Czz;
367
368 float ev1, ev2, ev3;
369 if( !DirectX::Internal::SolveCubic( e, f, g, &ev1, &ev2, &ev3 ) )
370 {
371 // set them to arbitrary orthonormal basis set
372 *pV1 = g_XMIdentityR0.v;
373 *pV2 = g_XMIdentityR1.v;
374 *pV3 = g_XMIdentityR2.v;
375 return false;
376 }
377
378 return DirectX::Internal::CalculateEigenVectors( Cxx, Cxy, Cxz, Cyy, Cyz, Czz, ev1, ev2, ev3, pV1, pV2, pV3 );
379}
380
381//-----------------------------------------------------------------------------
382inline void FastIntersectTrianglePlane( FXMVECTOR V0, FXMVECTOR V1, FXMVECTOR V2, GXMVECTOR Plane,
383 XMVECTOR& Outside, XMVECTOR& Inside )
384{
385 // Plane0
386 XMVECTOR Dist0 = XMVector4Dot( V0, Plane );
387 XMVECTOR Dist1 = XMVector4Dot( V1, Plane );
388 XMVECTOR Dist2 = XMVector4Dot( V2, Plane );
389
390 XMVECTOR MinDist = XMVectorMin( Dist0, Dist1 );
391 MinDist = XMVectorMin( MinDist, Dist2 );
392
393 XMVECTOR MaxDist = XMVectorMax( Dist0, Dist1 );
394 MaxDist = XMVectorMax( MaxDist, Dist2 );
395
396 XMVECTOR Zero = XMVectorZero();
397
398 // Outside the plane?
399 Outside = XMVectorGreater( MinDist, Zero );
400
401 // Fully inside the plane?
402 Inside = XMVectorLess( MaxDist, Zero );
403}
404
405//-----------------------------------------------------------------------------
406inline void FastIntersectSpherePlane( _In_ FXMVECTOR Center, _In_ FXMVECTOR Radius, _In_ FXMVECTOR Plane,
407 _Out_ XMVECTOR& Outside, _Out_ XMVECTOR& Inside )
408{
409 XMVECTOR Dist = XMVector4Dot( Center, Plane );
410
411 // Outside the plane?
412 Outside = XMVectorGreater( Dist, Radius );
413
414 // Fully inside the plane?
415 Inside = XMVectorLess( Dist, -Radius );
416}
417
418//-----------------------------------------------------------------------------
419inline void FastIntersectAxisAlignedBoxPlane( _In_ FXMVECTOR Center, _In_ FXMVECTOR Extents, _In_ FXMVECTOR Plane,
420 _Out_ XMVECTOR& Outside, _Out_ XMVECTOR& Inside )
421{
422 // Compute the distance to the center of the box.
423 XMVECTOR Dist = XMVector4Dot( Center, Plane );
424
425 // Project the axes of the box onto the normal of the plane. Half the
426 // length of the projection (sometime called the "radius") is equal to
427 // h(u) * abs(n dot b(u))) + h(v) * abs(n dot b(v)) + h(w) * abs(n dot b(w))
428 // where h(i) are extents of the box, n is the plane normal, and b(i) are the
429 // axes of the box. In this case b(i) = [(1,0,0), (0,1,0), (0,0,1)].
430 XMVECTOR Radius = XMVector3Dot( Extents, XMVectorAbs( Plane ) );
431
432 // Outside the plane?
433 Outside = XMVectorGreater( Dist, Radius );
434
435 // Fully inside the plane?
436 Inside = XMVectorLess( Dist, -Radius );
437}
438
439//-----------------------------------------------------------------------------
440inline void FastIntersectOrientedBoxPlane( _In_ FXMVECTOR Center, _In_ FXMVECTOR Extents, _In_ FXMVECTOR Axis0, _In_ GXMVECTOR Axis1,
441 _In_ CXMVECTOR Axis2, _In_ CXMVECTOR Plane, _Out_ XMVECTOR& Outside, _Out_ XMVECTOR& Inside )
442{
443 // Compute the distance to the center of the box.
444 XMVECTOR Dist = XMVector4Dot( Center, Plane );
445
446 // Project the axes of the box onto the normal of the plane. Half the
447 // length of the projection (sometime called the "radius") is equal to
448 // h(u) * abs(n dot b(u))) + h(v) * abs(n dot b(v)) + h(w) * abs(n dot b(w))
449 // where h(i) are extents of the box, n is the plane normal, and b(i) are the
450 // axes of the box.
451 XMVECTOR Radius = XMVector3Dot( Plane, Axis0 );
452 Radius = XMVectorInsert<0, 0, 1, 0, 0>( Radius, XMVector3Dot( Plane, Axis1 ) );
453 Radius = XMVectorInsert<0, 0, 0, 1, 0>( Radius, XMVector3Dot( Plane, Axis2 ) );
454 Radius = XMVector3Dot( Extents, XMVectorAbs( Radius ) );
455
456 // Outside the plane?
457 Outside = XMVectorGreater( Dist, Radius );
458
459 // Fully inside the plane?
460 Inside = XMVectorLess( Dist, -Radius );
461}
462
463//-----------------------------------------------------------------------------
464inline void FastIntersectFrustumPlane( _In_ FXMVECTOR Point0, _In_ FXMVECTOR Point1, _In_ FXMVECTOR Point2, _In_ GXMVECTOR Point3,
465 _In_ CXMVECTOR Point4, _In_ CXMVECTOR Point5, _In_ CXMVECTOR Point6, _In_ CXMVECTOR Point7,
466 _In_ CXMVECTOR Plane, _Out_ XMVECTOR& Outside, _Out_ XMVECTOR& Inside )
467{
468 // Find the min/max projection of the frustum onto the plane normal.
469 XMVECTOR Min, Max, Dist;
470
471 Min = Max = XMVector3Dot( Plane, Point0 );
472
473 Dist = XMVector3Dot( Plane, Point1 );
474 Min = XMVectorMin( Min, Dist );
475 Max = XMVectorMax( Max, Dist );
476
477 Dist = XMVector3Dot( Plane, Point2 );
478 Min = XMVectorMin( Min, Dist );
479 Max = XMVectorMax( Max, Dist );
480
481 Dist = XMVector3Dot( Plane, Point3 );
482 Min = XMVectorMin( Min, Dist );
483 Max = XMVectorMax( Max, Dist );
484
485 Dist = XMVector3Dot( Plane, Point4 );
486 Min = XMVectorMin( Min, Dist );
487 Max = XMVectorMax( Max, Dist );
488
489 Dist = XMVector3Dot( Plane, Point5 );
490 Min = XMVectorMin( Min, Dist );
491 Max = XMVectorMax( Max, Dist );
492
493 Dist = XMVector3Dot( Plane, Point6 );
494 Min = XMVectorMin( Min, Dist );
495 Max = XMVectorMax( Max, Dist );
496
497 Dist = XMVector3Dot( Plane, Point7 );
498 Min = XMVectorMin( Min, Dist );
499 Max = XMVectorMax( Max, Dist );
500
501 XMVECTOR PlaneDist = -XMVectorSplatW( Plane );
502
503 // Outside the plane?
504 Outside = XMVectorGreater( Min, PlaneDist );
505
506 // Fully inside the plane?
507 Inside = XMVectorLess( Max, PlaneDist );
508}
509
510}; // namespace Internal
511
512
513/****************************************************************************
514 *
515 * BoundingSphere
516 *
517 ****************************************************************************/
518
519//-----------------------------------------------------------------------------
520// Transform a sphere by an angle preserving transform.
521//-----------------------------------------------------------------------------
522_Use_decl_annotations_
523inline void BoundingSphere::Transform( BoundingSphere& Out, CXMMATRIX M ) const
524{
525 // Load the center of the sphere.
526 XMVECTOR vCenter = XMLoadFloat3( &Center );
527
528 // Transform the center of the sphere.
529 XMVECTOR C = XMVector3Transform( vCenter, M );
530
531 XMVECTOR dX = XMVector3Dot( M.r[0], M.r[0] );
532 XMVECTOR dY = XMVector3Dot( M.r[1], M.r[1] );
533 XMVECTOR dZ = XMVector3Dot( M.r[2], M.r[2] );
534
535 XMVECTOR d = XMVectorMax( dX, XMVectorMax( dY, dZ ) );
536
537 // Store the center sphere.
538 XMStoreFloat3( &Out.Center, C );
539
540 // Scale the radius of the pshere.
541 float Scale = sqrtf( XMVectorGetX(d) );
542 Out.Radius = Radius * Scale;
543}
544
545_Use_decl_annotations_
546inline void BoundingSphere::Transform( BoundingSphere& Out, float Scale, FXMVECTOR Rotation, FXMVECTOR Translation ) const
547{
548 // Load the center of the sphere.
549 XMVECTOR vCenter = XMLoadFloat3( &Center );
550
551 // Transform the center of the sphere.
552 vCenter = XMVector3Rotate( vCenter * XMVectorReplicate( Scale ), Rotation ) + Translation;
553
554 // Store the center sphere.
555 XMStoreFloat3( &Out.Center, vCenter );
556
557 // Scale the radius of the pshere.
558 Out.Radius = Radius * Scale;
559}
560
561
562//-----------------------------------------------------------------------------
563// Point in sphere test.
564//-----------------------------------------------------------------------------
565_Use_decl_annotations_
566inline ContainmentType BoundingSphere::Contains( FXMVECTOR Point ) const
567{
568 XMVECTOR vCenter = XMLoadFloat3( &Center );
569 XMVECTOR vRadius = XMVectorReplicatePtr( &Radius );
570
571 XMVECTOR DistanceSquared = XMVector3LengthSq( Point - vCenter );
572 XMVECTOR RadiusSquared = XMVectorMultiply( vRadius, vRadius );
573
574 return XMVector3LessOrEqual( DistanceSquared, RadiusSquared ) ? CONTAINS : DISJOINT;
575}
576
577
578//-----------------------------------------------------------------------------
579// Triangle in sphere test
580//-----------------------------------------------------------------------------
581_Use_decl_annotations_
582inline ContainmentType BoundingSphere::Contains( FXMVECTOR V0, FXMVECTOR V1, FXMVECTOR V2 ) const
583{
584 if ( !Intersects(V0,V1,V2) )
585 return DISJOINT;
586
587 XMVECTOR vCenter = XMLoadFloat3( &Center );
588 XMVECTOR vRadius = XMVectorReplicatePtr( &Radius );
589 XMVECTOR RadiusSquared = XMVectorMultiply( vRadius, vRadius );
590
591 XMVECTOR DistanceSquared = XMVector3LengthSq( V0 - vCenter );
592 XMVECTOR Inside = XMVectorLessOrEqual(DistanceSquared, RadiusSquared);
593
594 DistanceSquared = XMVector3LengthSq( V1 - vCenter );
595 Inside = XMVectorAndInt( Inside, XMVectorLessOrEqual(DistanceSquared, RadiusSquared) );
596
597 DistanceSquared = XMVector3LengthSq( V2 - vCenter );
598 Inside = XMVectorAndInt( Inside, XMVectorLessOrEqual(DistanceSquared, RadiusSquared) );
599
600 return ( XMVector3EqualInt( Inside, XMVectorTrueInt() ) ) ? CONTAINS : INTERSECTS;
601}
602
603
604//-----------------------------------------------------------------------------
605// Sphere in sphere test.
606//-----------------------------------------------------------------------------
607_Use_decl_annotations_
608inline ContainmentType BoundingSphere::Contains( const BoundingSphere& sh ) const
609{
610 XMVECTOR Center1 = XMLoadFloat3( &Center );
611 float r1 = Radius;
612
613 XMVECTOR Center2 = XMLoadFloat3( &sh.Center );
614 float r2 = sh.Radius;
615
616 XMVECTOR V = XMVectorSubtract( Center2, Center1 );
617
618 XMVECTOR Dist = XMVector3Length( V );
619
620 float d = XMVectorGetX( Dist );
621
622 return (r1 + r2 >= d) ? ((r1 - r2 >= d) ? CONTAINS : INTERSECTS) : DISJOINT;
623}
624
625
626//-----------------------------------------------------------------------------
627// Axis-aligned box in sphere test
628//-----------------------------------------------------------------------------
629_Use_decl_annotations_
630inline ContainmentType BoundingSphere::Contains( const BoundingBox& box ) const
631{
632 if ( !box.Intersects(*this) )
633 return DISJOINT;
634
635 XMVECTOR vCenter = XMLoadFloat3( &Center );
636 XMVECTOR vRadius = XMVectorReplicatePtr( &Radius );
637 XMVECTOR RadiusSq = vRadius * vRadius;
638
639 XMVECTOR boxCenter = XMLoadFloat3( &box.Center );
640 XMVECTOR boxExtents = XMLoadFloat3( &box.Extents );
641
642 XMVECTOR InsideAll = XMVectorTrueInt();
643
644 XMVECTOR offset = boxCenter - vCenter;
645
646 for( size_t i = 0; i < BoundingBox::CORNER_COUNT; ++i )
647 {
648 XMVECTOR C = XMVectorMultiplyAdd( boxExtents, g_BoxOffset[i], offset );
649 XMVECTOR d = XMVector3LengthSq( C );
650 InsideAll = XMVectorAndInt( InsideAll, XMVectorLessOrEqual( d, RadiusSq ) );
651 }
652
653 return ( XMVector3EqualInt( InsideAll, XMVectorTrueInt() ) ) ? CONTAINS : INTERSECTS;
654}
655
656
657//-----------------------------------------------------------------------------
658// Oriented box in sphere test
659//-----------------------------------------------------------------------------
660_Use_decl_annotations_
661inline ContainmentType BoundingSphere::Contains( const BoundingOrientedBox& box ) const
662{
663 if ( !box.Intersects(*this) )
664 return DISJOINT;
665
666 XMVECTOR vCenter = XMLoadFloat3( &Center );
667 XMVECTOR vRadius = XMVectorReplicatePtr( &Radius );
668 XMVECTOR RadiusSq = vRadius * vRadius;
669
670 XMVECTOR boxCenter = XMLoadFloat3( &box.Center );
671 XMVECTOR boxExtents = XMLoadFloat3( &box.Extents );
672 XMVECTOR boxOrientation = XMLoadFloat4( &box.Orientation );
673
674 assert( DirectX::Internal::XMQuaternionIsUnit( boxOrientation ) );
675
676 XMVECTOR InsideAll = XMVectorTrueInt();
677
678 for( size_t i = 0; i < BoundingOrientedBox::CORNER_COUNT; ++i )
679 {
680 XMVECTOR C = XMVector3Rotate( boxExtents * g_BoxOffset[i], boxOrientation ) + boxCenter;
681 XMVECTOR d = XMVector3LengthSq( XMVectorSubtract( vCenter, C ) );
682 InsideAll = XMVectorAndInt( InsideAll, XMVectorLessOrEqual( d, RadiusSq ) );
683 }
684
685 return ( XMVector3EqualInt( InsideAll, XMVectorTrueInt() ) ) ? CONTAINS : INTERSECTS;
686
687}
688
689
690//-----------------------------------------------------------------------------
691// Frustum in sphere test
692//-----------------------------------------------------------------------------
693_Use_decl_annotations_
694inline ContainmentType BoundingSphere::Contains( const BoundingFrustum& fr ) const
695{
696 if ( !fr.Intersects(*this) )
697 return DISJOINT;
698
699 XMVECTOR vCenter = XMLoadFloat3( &Center );
700 XMVECTOR vRadius = XMVectorReplicatePtr( &Radius );
701 XMVECTOR RadiusSq = vRadius * vRadius;
702
703 XMVECTOR vOrigin = XMLoadFloat3( &fr.Origin );
704 XMVECTOR vOrientation = XMLoadFloat4( &fr.Orientation );
705
706 assert( DirectX::Internal::XMQuaternionIsUnit( vOrientation ) );
707
708 // Build the corners of the frustum.
709 XMVECTOR vRightTop = XMVectorSet( fr.RightSlope, fr.TopSlope, 1.0f, 0.0f );
710 XMVECTOR vRightBottom = XMVectorSet( fr.RightSlope, fr.BottomSlope, 1.0f, 0.0f );
711 XMVECTOR vLeftTop = XMVectorSet( fr.LeftSlope, fr.TopSlope, 1.0f, 0.0f );
712 XMVECTOR vLeftBottom = XMVectorSet( fr.LeftSlope, fr.BottomSlope, 1.0f, 0.0f );
713 XMVECTOR vNear = XMVectorReplicatePtr( &fr.Near );
714 XMVECTOR vFar = XMVectorReplicatePtr( &fr.Far );
715
716 XMVECTOR Corners[BoundingFrustum::CORNER_COUNT];
717 Corners[0] = vRightTop * vNear;
718 Corners[1] = vRightBottom * vNear;
719 Corners[2] = vLeftTop * vNear;
720 Corners[3] = vLeftBottom * vNear;
721 Corners[4] = vRightTop * vFar;
722 Corners[5] = vRightBottom * vFar;
723 Corners[6] = vLeftTop * vFar;
724 Corners[7] = vLeftBottom * vFar;
725
726 XMVECTOR InsideAll = XMVectorTrueInt();
727 for( size_t i = 0; i < BoundingFrustum::CORNER_COUNT; ++i )
728 {
729 XMVECTOR C = XMVector3Rotate( Corners[i], vOrientation ) + vOrigin;
730 XMVECTOR d = XMVector3LengthSq( XMVectorSubtract( vCenter, C ) );
731 InsideAll = XMVectorAndInt( InsideAll, XMVectorLessOrEqual( d, RadiusSq ) );
732 }
733
734 return ( XMVector3EqualInt( InsideAll, XMVectorTrueInt() ) ) ? CONTAINS : INTERSECTS;
735}
736
737
738//-----------------------------------------------------------------------------
739// Sphere vs. sphere test.
740//-----------------------------------------------------------------------------
741_Use_decl_annotations_
742inline bool BoundingSphere::Intersects( const BoundingSphere& sh ) const
743{
744 // Load A.
745 XMVECTOR vCenterA = XMLoadFloat3( &Center );
746 XMVECTOR vRadiusA = XMVectorReplicatePtr( &Radius );
747
748 // Load B.
749 XMVECTOR vCenterB = XMLoadFloat3( &sh.Center );
750 XMVECTOR vRadiusB = XMVectorReplicatePtr( &sh.Radius );
751
752 // Distance squared between centers.
753 XMVECTOR Delta = vCenterB - vCenterA;
754 XMVECTOR DistanceSquared = XMVector3LengthSq( Delta );
755
756 // Sum of the radii squared.
757 XMVECTOR RadiusSquared = XMVectorAdd( vRadiusA, vRadiusB );
758 RadiusSquared = XMVectorMultiply( RadiusSquared, RadiusSquared );
759
760 return XMVector3LessOrEqual( DistanceSquared, RadiusSquared );
761}
762
763
764//-----------------------------------------------------------------------------
765// Box vs. sphere test.
766//-----------------------------------------------------------------------------
767_Use_decl_annotations_
768inline bool BoundingSphere::Intersects( const BoundingBox& box ) const
769{
770 return box.Intersects( *this );
771}
772
773_Use_decl_annotations_
774inline bool BoundingSphere::Intersects( const BoundingOrientedBox& box ) const
775{
776 return box.Intersects( *this );
777}
778
779
780//-----------------------------------------------------------------------------
781// Frustum vs. sphere test.
782//-----------------------------------------------------------------------------
783_Use_decl_annotations_
784inline bool BoundingSphere::Intersects( const BoundingFrustum& fr ) const
785{
786 return fr.Intersects( *this );
787}
788
789
790//-----------------------------------------------------------------------------
791// Triangle vs sphere test
792//-----------------------------------------------------------------------------
793_Use_decl_annotations_
794inline bool BoundingSphere::Intersects( FXMVECTOR V0, FXMVECTOR V1, FXMVECTOR V2 ) const
795{
796 // Load the sphere.
797 XMVECTOR vCenter = XMLoadFloat3( &Center );
798 XMVECTOR vRadius = XMVectorReplicatePtr( &Radius );
799
800 // Compute the plane of the triangle (has to be normalized).
801 XMVECTOR N = XMVector3Normalize( XMVector3Cross( V1 - V0, V2 - V0 ) );
802
803 // Assert that the triangle is not degenerate.
804 assert( !XMVector3Equal( N, XMVectorZero() ) );
805
806 // Find the nearest feature on the triangle to the sphere.
807 XMVECTOR Dist = XMVector3Dot( vCenter - V0, N );
808
809 // If the center of the sphere is farther from the plane of the triangle than
810 // the radius of the sphere, then there cannot be an intersection.
811 XMVECTOR NoIntersection = XMVectorLess( Dist, -vRadius );
812 NoIntersection = XMVectorOrInt( NoIntersection, XMVectorGreater( Dist, vRadius ) );
813
814 // Project the center of the sphere onto the plane of the triangle.
815 XMVECTOR Point = vCenter - ( N * Dist );
816
817 // Is it inside all the edges? If so we intersect because the distance
818 // to the plane is less than the radius.
819 XMVECTOR Intersection = DirectX::Internal::PointOnPlaneInsideTriangle( Point, V0, V1, V2 );
820
821 // Find the nearest point on each edge.
822 XMVECTOR RadiusSq = vRadius * vRadius;
823
824 // Edge 0,1
825 Point = DirectX::Internal::PointOnLineSegmentNearestPoint( V0, V1, vCenter );
826
827 // If the distance to the center of the sphere to the point is less than
828 // the radius of the sphere then it must intersect.
829 Intersection = XMVectorOrInt( Intersection, XMVectorLessOrEqual( XMVector3LengthSq( vCenter - Point ), RadiusSq ) );
830
831 // Edge 1,2
832 Point = DirectX::Internal::PointOnLineSegmentNearestPoint( V1, V2, vCenter );
833
834 // If the distance to the center of the sphere to the point is less than
835 // the radius of the sphere then it must intersect.
836 Intersection = XMVectorOrInt( Intersection, XMVectorLessOrEqual( XMVector3LengthSq( vCenter - Point ), RadiusSq ) );
837
838 // Edge 2,0
839 Point = DirectX::Internal::PointOnLineSegmentNearestPoint( V2, V0, vCenter );
840
841 // If the distance to the center of the sphere to the point is less than
842 // the radius of the sphere then it must intersect.
843 Intersection = XMVectorOrInt( Intersection, XMVectorLessOrEqual( XMVector3LengthSq( vCenter - Point ), RadiusSq ) );
844
845 return XMVector4EqualInt( XMVectorAndCInt( Intersection, NoIntersection ), XMVectorTrueInt() );
846}
847
848
849//-----------------------------------------------------------------------------
850// Sphere-plane intersection
851//-----------------------------------------------------------------------------
852_Use_decl_annotations_
853inline PlaneIntersectionType BoundingSphere::Intersects( FXMVECTOR Plane ) const
854{
855 assert( DirectX::Internal::XMPlaneIsUnit( Plane ) );
856
857 // Load the sphere.
858 XMVECTOR vCenter = XMLoadFloat3( &Center );
859 XMVECTOR vRadius = XMVectorReplicatePtr( &Radius );
860
861 // Set w of the center to one so we can dot4 with a plane.
862 vCenter = XMVectorInsert<0, 0, 0, 0, 1>( vCenter, XMVectorSplatOne() );
863
864 XMVECTOR Outside, Inside;
865 DirectX::Internal::FastIntersectSpherePlane( vCenter, vRadius, Plane, Outside, Inside );
866
867 // If the sphere is outside any plane it is outside.
868 if ( XMVector4EqualInt( Outside, XMVectorTrueInt() ) )
869 return FRONT;
870
871 // If the sphere is inside all planes it is inside.
872 if ( XMVector4EqualInt( Inside, XMVectorTrueInt() ) )
873 return BACK;
874
875 // The sphere is not inside all planes or outside a plane it intersects.
876 return INTERSECTING;
877}
878
879
880//-----------------------------------------------------------------------------
881// Compute the intersection of a ray (Origin, Direction) with a sphere.
882//-----------------------------------------------------------------------------
883_Use_decl_annotations_
884inline bool BoundingSphere::Intersects( FXMVECTOR Origin, FXMVECTOR Direction, float& Dist ) const
885{
886 assert( DirectX::Internal::XMVector3IsUnit( Direction ) );
887
888 XMVECTOR vCenter = XMLoadFloat3( &Center );
889 XMVECTOR vRadius = XMVectorReplicatePtr( &Radius );
890
891 // l is the vector from the ray origin to the center of the sphere.
892 XMVECTOR l = vCenter - Origin;
893
894 // s is the projection of the l onto the ray direction.
895 XMVECTOR s = XMVector3Dot( l, Direction );
896
897 XMVECTOR l2 = XMVector3Dot( l, l );
898
899 XMVECTOR r2 = vRadius * vRadius;
900
901 // m2 is squared distance from the center of the sphere to the projection.
902 XMVECTOR m2 = l2 - s * s;
903
904 XMVECTOR NoIntersection;
905
906 // If the ray origin is outside the sphere and the center of the sphere is
907 // behind the ray origin there is no intersection.
908 NoIntersection = XMVectorAndInt( XMVectorLess( s, XMVectorZero() ), XMVectorGreater( l2, r2 ) );
909
910 // If the squared distance from the center of the sphere to the projection
911 // is greater than the radius squared the ray will miss the sphere.
912 NoIntersection = XMVectorOrInt( NoIntersection, XMVectorGreater( m2, r2 ) );
913
914 // The ray hits the sphere, compute the nearest intersection point.
915 XMVECTOR q = XMVectorSqrt( r2 - m2 );
916 XMVECTOR t1 = s - q;
917 XMVECTOR t2 = s + q;
918
919 XMVECTOR OriginInside = XMVectorLessOrEqual( l2, r2 );
920 XMVECTOR t = XMVectorSelect( t1, t2, OriginInside );
921
922 if( XMVector4NotEqualInt( NoIntersection, XMVectorTrueInt() ) )
923 {
924 // Store the x-component to *pDist.
925 XMStoreFloat( &Dist, t );
926 return true;
927 }
928
929 Dist = 0.f;
930 return false;
931}
932
933
934//-----------------------------------------------------------------------------
935// Test a sphere vs 6 planes (typically forming a frustum).
936//-----------------------------------------------------------------------------
937_Use_decl_annotations_
938inline ContainmentType BoundingSphere::ContainedBy( FXMVECTOR Plane0, FXMVECTOR Plane1, FXMVECTOR Plane2,
939 GXMVECTOR Plane3, CXMVECTOR Plane4, CXMVECTOR Plane5 ) const
940{
941 // Load the sphere.
942 XMVECTOR vCenter = XMLoadFloat3( &Center );
943 XMVECTOR vRadius = XMVectorReplicatePtr( &Radius );
944
945 // Set w of the center to one so we can dot4 with a plane.
946 vCenter = XMVectorInsert<0, 0, 0, 0, 1>( vCenter, XMVectorSplatOne() );
947
948 XMVECTOR Outside, Inside;
949
950 // Test against each plane.
951 DirectX::Internal::FastIntersectSpherePlane( vCenter, vRadius, Plane0, Outside, Inside );
952
953 XMVECTOR AnyOutside = Outside;
954 XMVECTOR AllInside = Inside;
955
956 DirectX::Internal::FastIntersectSpherePlane( vCenter, vRadius, Plane1, Outside, Inside );
957 AnyOutside = XMVectorOrInt( AnyOutside, Outside );
958 AllInside = XMVectorAndInt( AllInside, Inside );
959
960 DirectX::Internal::FastIntersectSpherePlane( vCenter, vRadius, Plane2, Outside, Inside );
961 AnyOutside = XMVectorOrInt( AnyOutside, Outside );
962 AllInside = XMVectorAndInt( AllInside, Inside );
963
964 DirectX::Internal::FastIntersectSpherePlane( vCenter, vRadius, Plane3, Outside, Inside );
965 AnyOutside = XMVectorOrInt( AnyOutside, Outside );
966 AllInside = XMVectorAndInt( AllInside, Inside );
967
968 DirectX::Internal::FastIntersectSpherePlane( vCenter, vRadius, Plane4, Outside, Inside );
969 AnyOutside = XMVectorOrInt( AnyOutside, Outside );
970 AllInside = XMVectorAndInt( AllInside, Inside );
971
972 DirectX::Internal::FastIntersectSpherePlane( vCenter, vRadius, Plane5, Outside, Inside );
973 AnyOutside = XMVectorOrInt( AnyOutside, Outside );
974 AllInside = XMVectorAndInt( AllInside, Inside );
975
976 // If the sphere is outside any plane it is outside.
977 if ( XMVector4EqualInt( AnyOutside, XMVectorTrueInt() ) )
978 return DISJOINT;
979
980 // If the sphere is inside all planes it is inside.
981 if ( XMVector4EqualInt( AllInside, XMVectorTrueInt() ) )
982 return CONTAINS;
983
984 // The sphere is not inside all planes or outside a plane, it may intersect.
985 return INTERSECTS;
986}
987
988
989//-----------------------------------------------------------------------------
990// Creates a bounding sphere that contains two other bounding spheres
991//-----------------------------------------------------------------------------
992_Use_decl_annotations_
993inline void BoundingSphere::CreateMerged( BoundingSphere& Out, const BoundingSphere& S1, const BoundingSphere& S2 )
994{
995 XMVECTOR Center1 = XMLoadFloat3( &S1.Center );
996 float r1 = S1.Radius;
997
998 XMVECTOR Center2 = XMLoadFloat3( &S2.Center );
999 float r2 = S2.Radius;
1000
1001 XMVECTOR V = XMVectorSubtract( Center2, Center1 );
1002
1003 XMVECTOR Dist = XMVector3Length( V );
1004
1005 float d = XMVectorGetX(Dist);
1006
1007 if ( r1 + r2 >= d )
1008 {
1009 if ( r1 - r2 >= d )
1010 {
1011 Out = S1;
1012 return;
1013 }
1014 else if ( r2 - r1 >= d )
1015 {
1016 Out = S2;
1017 return;
1018 }
1019 }
1020
1021 XMVECTOR N = XMVectorDivide( V, Dist );
1022
1023 float t1 = XMMin( -r1, d-r2 );
1024 float t2 = XMMax( r1, d+r2 );
1025 float t_5 = (t2 - t1) * 0.5f;
1026
1027 XMVECTOR NCenter = XMVectorAdd( Center1, XMVectorMultiply( N, XMVectorReplicate( t_5 + t1 ) ) );
1028
1029 XMStoreFloat3( &Out.Center, NCenter );
1030 Out.Radius = t_5;
1031}
1032
1033
1034//-----------------------------------------------------------------------------
1035// Create sphere enscribing bounding box
1036//-----------------------------------------------------------------------------
1037_Use_decl_annotations_
1038inline void BoundingSphere::CreateFromBoundingBox( BoundingSphere& Out, const BoundingBox& box )
1039{
1040 Out.Center = box.Center;
1041 XMVECTOR vExtents = XMLoadFloat3( &box.Extents );
1042 Out.Radius = XMVectorGetX( XMVector3Length( vExtents ) );
1043}
1044
1045_Use_decl_annotations_
1046inline void BoundingSphere::CreateFromBoundingBox( BoundingSphere& Out, const BoundingOrientedBox& box )
1047{
1048 // Bounding box orientation is irrelevant because a sphere is rotationally invariant
1049 Out.Center = box.Center;
1050 XMVECTOR vExtents = XMLoadFloat3( &box.Extents );
1051 Out.Radius = XMVectorGetX( XMVector3Length( vExtents ) );
1052}
1053
1054
1055//-----------------------------------------------------------------------------
1056// Find the approximate smallest enclosing bounding sphere for a set of
1057// points. Exact computation of the smallest enclosing bounding sphere is
1058// possible but is slower and requires a more complex algorithm.
1059// The algorithm is based on Jack Ritter, "An Efficient Bounding Sphere",
1060// Graphics Gems.
1061//-----------------------------------------------------------------------------
1062_Use_decl_annotations_
1063inline void BoundingSphere::CreateFromPoints( BoundingSphere& Out, size_t Count, const XMFLOAT3* pPoints, size_t Stride )
1064{
1065 assert( Count > 0 );
1066 assert( pPoints );
1067
1068 // Find the points with minimum and maximum x, y, and z
1069 XMVECTOR MinX, MaxX, MinY, MaxY, MinZ, MaxZ;
1070
1071 MinX = MaxX = MinY = MaxY = MinZ = MaxZ = XMLoadFloat3( pPoints );
1072
1073 for( size_t i = 1; i < Count; ++i )
1074 {
1075 XMVECTOR Point = XMLoadFloat3( reinterpret_cast<const XMFLOAT3*>( reinterpret_cast<const uint8_t*>(pPoints) + i * Stride ) );
1076
1077 float px = XMVectorGetX( Point );
1078 float py = XMVectorGetY( Point );
1079 float pz = XMVectorGetZ( Point );
1080
1081 if( px < XMVectorGetX( MinX ) )
1082 MinX = Point;
1083
1084 if( px > XMVectorGetX( MaxX ) )
1085 MaxX = Point;
1086
1087 if( py < XMVectorGetY( MinY ) )
1088 MinY = Point;
1089
1090 if( py > XMVectorGetY( MaxY ) )
1091 MaxY = Point;
1092
1093 if( pz < XMVectorGetZ( MinZ ) )
1094 MinZ = Point;
1095
1096 if( pz > XMVectorGetZ( MaxZ ) )
1097 MaxZ = Point;
1098 }
1099
1100 // Use the min/max pair that are farthest apart to form the initial sphere.
1101 XMVECTOR DeltaX = MaxX - MinX;
1102 XMVECTOR DistX = XMVector3Length( DeltaX );
1103
1104 XMVECTOR DeltaY = MaxY - MinY;
1105 XMVECTOR DistY = XMVector3Length( DeltaY );
1106
1107 XMVECTOR DeltaZ = MaxZ - MinZ;
1108 XMVECTOR DistZ = XMVector3Length( DeltaZ );
1109
1110 XMVECTOR vCenter;
1111 XMVECTOR vRadius;
1112
1113 if( XMVector3Greater( DistX, DistY ) )
1114 {
1115 if( XMVector3Greater( DistX, DistZ ) )
1116 {
1117 // Use min/max x.
1118 vCenter = XMVectorLerp(MaxX,MinX,0.5f);
1119 vRadius = DistX * 0.5f;
1120 }
1121 else
1122 {
1123 // Use min/max z.
1124 vCenter = XMVectorLerp(MaxZ,MinZ,0.5f);
1125 vRadius = DistZ * 0.5f;
1126 }
1127 }
1128 else // Y >= X
1129 {
1130 if( XMVector3Greater( DistY, DistZ ) )
1131 {
1132 // Use min/max y.
1133 vCenter = XMVectorLerp(MaxY,MinY,0.5f);
1134 vRadius = DistY * 0.5f;
1135 }
1136 else
1137 {
1138 // Use min/max z.
1139 vCenter = XMVectorLerp(MaxZ,MinZ,0.5f);
1140 vRadius = DistZ * 0.5f;
1141 }
1142 }
1143
1144 // Add any points not inside the sphere.
1145 for( size_t i = 0; i < Count; ++i )
1146 {
1147 XMVECTOR Point = XMLoadFloat3( reinterpret_cast<const XMFLOAT3*>( reinterpret_cast<const uint8_t*>(pPoints) + i * Stride ) );
1148
1149 XMVECTOR Delta = Point - vCenter;
1150
1151 XMVECTOR Dist = XMVector3Length( Delta );
1152
1153 if( XMVector3Greater( Dist, vRadius ) )
1154 {
1155 // Adjust sphere to include the new point.
1156 vRadius = ( vRadius + Dist ) * 0.5f;
1157 vCenter += ( XMVectorReplicate( 1.0f ) - XMVectorDivide(vRadius,Dist) ) * Delta;
1158 }
1159 }
1160
1161 XMStoreFloat3( &Out.Center, vCenter );
1162 XMStoreFloat( &Out.Radius, vRadius );
1163}
1164
1165
1166//-----------------------------------------------------------------------------
1167// Create sphere containing frustum
1168//-----------------------------------------------------------------------------
1169_Use_decl_annotations_
1170inline void BoundingSphere::CreateFromFrustum( BoundingSphere& Out, const BoundingFrustum& fr )
1171{
1172 XMFLOAT3 Corners[BoundingFrustum::CORNER_COUNT];
1173 fr.GetCorners( Corners );
1174 CreateFromPoints( Out, BoundingFrustum::CORNER_COUNT, Corners, sizeof(XMFLOAT3) );
1175}
1176
1177
1178/****************************************************************************
1179 *
1180 * BoundingBox
1181 *
1182 ****************************************************************************/
1183
1184//-----------------------------------------------------------------------------
1185// Transform an axis aligned box by an angle preserving transform.
1186//-----------------------------------------------------------------------------
1187_Use_decl_annotations_
1188inline void BoundingBox::Transform( BoundingBox& Out, CXMMATRIX M ) const
1189{
1190 // Load center and extents.
1191 XMVECTOR vCenter = XMLoadFloat3( &Center );
1192 XMVECTOR vExtents = XMLoadFloat3( &Extents );
1193
1194 // Compute and transform the corners and find new min/max bounds.
1195 XMVECTOR Corner = XMVectorMultiplyAdd( vExtents, g_BoxOffset[0], vCenter );
1196 Corner = XMVector3Transform( Corner, M );
1197
1198 XMVECTOR Min, Max;
1199 Min = Max = Corner;
1200
1201 for( size_t i = 1; i < CORNER_COUNT; ++i )
1202 {
1203 Corner = XMVectorMultiplyAdd( vExtents, g_BoxOffset[i], vCenter );
1204 Corner = XMVector3Transform( Corner, M );
1205
1206 Min = XMVectorMin( Min, Corner );
1207 Max = XMVectorMax( Max, Corner );
1208 }
1209
1210 // Store center and extents.
1211 XMStoreFloat3( &Out.Center, ( Min + Max ) * 0.5f );
1212 XMStoreFloat3( &Out.Extents, ( Max - Min ) * 0.5f );
1213}
1214
1215_Use_decl_annotations_
1216inline void BoundingBox::Transform( BoundingBox& Out, float Scale, FXMVECTOR Rotation, FXMVECTOR Translation ) const
1217{
1218 assert( DirectX::Internal::XMQuaternionIsUnit( Rotation ) );
1219
1220 // Load center and extents.
1221 XMVECTOR vCenter = XMLoadFloat3( &Center );
1222 XMVECTOR vExtents = XMLoadFloat3( &Extents );
1223
1224 XMVECTOR VectorScale = XMVectorReplicate( Scale );
1225
1226 // Compute and transform the corners and find new min/max bounds.
1227 XMVECTOR Corner = XMVectorMultiplyAdd( vExtents, g_BoxOffset[0], vCenter );
1228 Corner = XMVector3Rotate( Corner * VectorScale, Rotation ) + Translation;
1229
1230 XMVECTOR Min, Max;
1231 Min = Max = Corner;
1232
1233 for( size_t i = 1; i < CORNER_COUNT; ++i )
1234 {
1235 Corner = XMVectorMultiplyAdd( vExtents, g_BoxOffset[i], vCenter );
1236 Corner = XMVector3Rotate( Corner * VectorScale, Rotation ) + Translation;
1237
1238 Min = XMVectorMin( Min, Corner );
1239 Max = XMVectorMax( Max, Corner );
1240 }
1241
1242 // Store center and extents.
1243 XMStoreFloat3( &Out.Center, ( Min + Max ) * 0.5f );
1244 XMStoreFloat3( &Out.Extents, ( Max - Min ) * 0.5f );
1245}
1246
1247
1248//-----------------------------------------------------------------------------
1249// Get the corner points of the box
1250//-----------------------------------------------------------------------------
1251_Use_decl_annotations_
1252inline void BoundingBox::GetCorners( XMFLOAT3* Corners ) const
1253{
1254 assert( Corners != nullptr );
1255
1256 // Load the box
1257 XMVECTOR vCenter = XMLoadFloat3( &Center );
1258 XMVECTOR vExtents = XMLoadFloat3( &Extents );
1259
1260 for( size_t i = 0; i < CORNER_COUNT; ++i )
1261 {
1262 XMVECTOR C = XMVectorMultiplyAdd( vExtents, g_BoxOffset[i], vCenter );
1263 XMStoreFloat3( &Corners[i], C );
1264 }
1265}
1266
1267
1268//-----------------------------------------------------------------------------
1269// Point in axis-aligned box test
1270//-----------------------------------------------------------------------------
1271_Use_decl_annotations_
1272inline ContainmentType BoundingBox::Contains( FXMVECTOR Point ) const
1273{
1274 XMVECTOR vCenter = XMLoadFloat3( &Center );
1275 XMVECTOR vExtents = XMLoadFloat3( &Extents );
1276
1277 return XMVector3InBounds( Point - vCenter, vExtents ) ? CONTAINS : DISJOINT;
1278}
1279
1280
1281//-----------------------------------------------------------------------------
1282// Triangle in axis-aligned box test
1283//-----------------------------------------------------------------------------
1284_Use_decl_annotations_
1285inline ContainmentType BoundingBox::Contains( FXMVECTOR V0, FXMVECTOR V1, FXMVECTOR V2 ) const
1286{
1287 if ( !Intersects(V0,V1,V2) )
1288 return DISJOINT;
1289
1290 XMVECTOR vCenter = XMLoadFloat3( &Center );
1291 XMVECTOR vExtents = XMLoadFloat3( &Extents );
1292
1293 XMVECTOR d = XMVector3LengthSq( V0 - vCenter );
1294 XMVECTOR Inside = XMVectorLessOrEqual( d, vExtents );
1295
1296 d = XMVector3LengthSq( V1 - vCenter );
1297 Inside = XMVectorAndInt( Inside, XMVectorLessOrEqual( d, vExtents ) );
1298
1299 d = XMVector3LengthSq( V2 - vCenter );
1300 Inside = XMVectorAndInt( Inside, XMVectorLessOrEqual( d, vExtents ) );
1301
1302 return ( XMVector3EqualInt( Inside, XMVectorTrueInt() ) ) ? CONTAINS : INTERSECTS;
1303}
1304
1305
1306//-----------------------------------------------------------------------------
1307// Sphere in axis-aligned box test
1308//-----------------------------------------------------------------------------
1309_Use_decl_annotations_
1310inline ContainmentType BoundingBox::Contains( const BoundingSphere& sh ) const
1311{
1312 XMVECTOR SphereCenter = XMLoadFloat3( &sh.Center );
1313 XMVECTOR SphereRadius = XMVectorReplicatePtr( &sh.Radius );
1314
1315 XMVECTOR BoxCenter = XMLoadFloat3( &Center );
1316 XMVECTOR BoxExtents = XMLoadFloat3( &Extents );
1317
1318 XMVECTOR BoxMin = BoxCenter - BoxExtents;
1319 XMVECTOR BoxMax = BoxCenter + BoxExtents;
1320
1321 // Find the distance to the nearest point on the box.
1322 // for each i in (x, y, z)
1323 // if (SphereCenter(i) < BoxMin(i)) d2 += (SphereCenter(i) - BoxMin(i)) ^ 2
1324 // else if (SphereCenter(i) > BoxMax(i)) d2 += (SphereCenter(i) - BoxMax(i)) ^ 2
1325
1326 XMVECTOR d = XMVectorZero();
1327
1328 // Compute d for each dimension.
1329 XMVECTOR LessThanMin = XMVectorLess( SphereCenter, BoxMin );
1330 XMVECTOR GreaterThanMax = XMVectorGreater( SphereCenter, BoxMax );
1331
1332 XMVECTOR MinDelta = SphereCenter - BoxMin;
1333 XMVECTOR MaxDelta = SphereCenter - BoxMax;
1334
1335 // Choose value for each dimension based on the comparison.
1336 d = XMVectorSelect( d, MinDelta, LessThanMin );
1337 d = XMVectorSelect( d, MaxDelta, GreaterThanMax );
1338
1339 // Use a dot-product to square them and sum them together.
1340 XMVECTOR d2 = XMVector3Dot( d, d );
1341
1342 if ( XMVector3Greater( d2, XMVectorMultiply( SphereRadius, SphereRadius ) ) )
1343 return DISJOINT;
1344
1345 XMVECTOR InsideAll = XMVectorLessOrEqual( BoxMin + SphereRadius, SphereCenter );
1346 InsideAll = XMVectorAndInt( InsideAll, XMVectorLessOrEqual( SphereCenter, BoxMax - SphereRadius ) );
1347 InsideAll = XMVectorAndInt( InsideAll, XMVectorGreater( BoxMax - BoxMin, SphereRadius ) );
1348
1349 return ( XMVector3EqualInt( InsideAll, XMVectorTrueInt() ) ) ? CONTAINS : INTERSECTS;
1350}
1351
1352
1353//-----------------------------------------------------------------------------
1354// Axis-aligned box in axis-aligned box test
1355//-----------------------------------------------------------------------------
1356_Use_decl_annotations_
1357inline ContainmentType BoundingBox::Contains( const BoundingBox& box ) const
1358{
1359 XMVECTOR CenterA = XMLoadFloat3( &Center );
1360 XMVECTOR ExtentsA = XMLoadFloat3( &Extents );
1361
1362 XMVECTOR CenterB = XMLoadFloat3( &box.Center );
1363 XMVECTOR ExtentsB = XMLoadFloat3( &box.Extents );
1364
1365 XMVECTOR MinA = CenterA - ExtentsA;
1366 XMVECTOR MaxA = CenterA + ExtentsA;
1367
1368 XMVECTOR MinB = CenterB - ExtentsB;
1369 XMVECTOR MaxB = CenterB + ExtentsB;
1370
1371 // for each i in (x, y, z) if a_min(i) > b_max(i) or b_min(i) > a_max(i) then return false
1372 XMVECTOR Disjoint = XMVectorOrInt( XMVectorGreater( MinA, MaxB ), XMVectorGreater( MinB, MaxA ) );
1373
1374 if ( DirectX::Internal::XMVector3AnyTrue( Disjoint ) )
1375 return DISJOINT;
1376
1377 // for each i in (x, y, z) if a_min(i) <= b_min(i) and b_max(i) <= a_max(i) then A contains B
1378 XMVECTOR Inside = XMVectorAndInt( XMVectorLessOrEqual( MinA, MinB ), XMVectorLessOrEqual( MaxB, MaxA ) );
1379
1380 return DirectX::Internal::XMVector3AllTrue( Inside ) ? CONTAINS : INTERSECTS;
1381}
1382
1383
1384//-----------------------------------------------------------------------------
1385// Oriented box in axis-aligned box test
1386//-----------------------------------------------------------------------------
1387_Use_decl_annotations_
1388inline ContainmentType BoundingBox::Contains( const BoundingOrientedBox& box ) const
1389{
1390 if ( !box.Intersects( *this ) )
1391 return DISJOINT;
1392
1393 XMVECTOR vCenter = XMLoadFloat3( &Center );
1394 XMVECTOR vExtents = XMLoadFloat3( &Extents );
1395
1396 // Subtract off the AABB center to remove a subtract below
1397 XMVECTOR oCenter = XMLoadFloat3( &box.Center ) - vCenter;
1398
1399 XMVECTOR oExtents = XMLoadFloat3( &box.Extents );
1400 XMVECTOR oOrientation = XMLoadFloat4( &box.Orientation );
1401
1402 assert( DirectX::Internal::XMQuaternionIsUnit( oOrientation ) );
1403
1404 XMVECTOR Inside = XMVectorTrueInt();
1405
1406 for( size_t i=0; i < BoundingOrientedBox::CORNER_COUNT; ++i )
1407 {
1408 XMVECTOR C = XMVector3Rotate( oExtents * g_BoxOffset[i], oOrientation ) + oCenter;
1409 XMVECTOR d = XMVector3LengthSq( C );
1410 Inside = XMVectorAndInt( Inside, XMVectorLessOrEqual( d, vExtents ) );
1411 }
1412
1413 return ( XMVector3EqualInt( Inside, XMVectorTrueInt() ) ) ? CONTAINS : INTERSECTS;
1414}
1415
1416
1417//-----------------------------------------------------------------------------
1418// Frustum in axis-aligned box test
1419//-----------------------------------------------------------------------------
1420_Use_decl_annotations_
1421inline ContainmentType BoundingBox::Contains( const BoundingFrustum& fr ) const
1422{
1423 if ( !fr.Intersects( *this ) )
1424 return DISJOINT;
1425
1426 XMFLOAT3 Corners[BoundingFrustum::CORNER_COUNT];
1427 fr.GetCorners( Corners );
1428
1429 XMVECTOR vCenter = XMLoadFloat3( &Center );
1430 XMVECTOR vExtents = XMLoadFloat3( &Extents );
1431
1432 XMVECTOR Inside = XMVectorTrueInt();
1433
1434 for( size_t i=0; i < BoundingFrustum::CORNER_COUNT; ++i )
1435 {
1436 XMVECTOR Point = XMLoadFloat3( &Corners[i] );
1437 XMVECTOR d = XMVector3LengthSq( Point - vCenter );
1438 Inside = XMVectorAndInt( Inside, XMVectorLessOrEqual( d, vExtents ) );
1439 }
1440
1441 return ( XMVector3EqualInt( Inside, XMVectorTrueInt() ) ) ? CONTAINS : INTERSECTS;
1442}
1443
1444
1445//-----------------------------------------------------------------------------
1446// Sphere vs axis-aligned box test
1447//-----------------------------------------------------------------------------
1448_Use_decl_annotations_
1449inline bool BoundingBox::Intersects( const BoundingSphere& sh ) const
1450{
1451 XMVECTOR SphereCenter = XMLoadFloat3( &sh.Center );
1452 XMVECTOR SphereRadius = XMVectorReplicatePtr( &sh.Radius );
1453
1454 XMVECTOR BoxCenter = XMLoadFloat3( &Center );
1455 XMVECTOR BoxExtents = XMLoadFloat3( &Extents );
1456
1457 XMVECTOR BoxMin = BoxCenter - BoxExtents;
1458 XMVECTOR BoxMax = BoxCenter + BoxExtents;
1459
1460 // Find the distance to the nearest point on the box.
1461 // for each i in (x, y, z)
1462 // if (SphereCenter(i) < BoxMin(i)) d2 += (SphereCenter(i) - BoxMin(i)) ^ 2
1463 // else if (SphereCenter(i) > BoxMax(i)) d2 += (SphereCenter(i) - BoxMax(i)) ^ 2
1464
1465 XMVECTOR d = XMVectorZero();
1466
1467 // Compute d for each dimension.
1468 XMVECTOR LessThanMin = XMVectorLess( SphereCenter, BoxMin );
1469 XMVECTOR GreaterThanMax = XMVectorGreater( SphereCenter, BoxMax );
1470
1471 XMVECTOR MinDelta = SphereCenter - BoxMin;
1472 XMVECTOR MaxDelta = SphereCenter - BoxMax;
1473
1474 // Choose value for each dimension based on the comparison.
1475 d = XMVectorSelect( d, MinDelta, LessThanMin );
1476 d = XMVectorSelect( d, MaxDelta, GreaterThanMax );
1477
1478 // Use a dot-product to square them and sum them together.
1479 XMVECTOR d2 = XMVector3Dot( d, d );
1480
1481 return XMVector3LessOrEqual( d2, XMVectorMultiply( SphereRadius, SphereRadius ) );
1482}
1483
1484
1485//-----------------------------------------------------------------------------
1486// Axis-aligned box vs. axis-aligned box test
1487//-----------------------------------------------------------------------------
1488_Use_decl_annotations_
1489inline bool BoundingBox::Intersects( const BoundingBox& box ) const
1490{
1491 XMVECTOR CenterA = XMLoadFloat3( &Center );
1492 XMVECTOR ExtentsA = XMLoadFloat3( &Extents );
1493
1494 XMVECTOR CenterB = XMLoadFloat3( &box.Center );
1495 XMVECTOR ExtentsB = XMLoadFloat3( &box.Extents );
1496
1497 XMVECTOR MinA = CenterA - ExtentsA;
1498 XMVECTOR MaxA = CenterA + ExtentsA;
1499
1500 XMVECTOR MinB = CenterB - ExtentsB;
1501 XMVECTOR MaxB = CenterB + ExtentsB;
1502
1503 // for each i in (x, y, z) if a_min(i) > b_max(i) or b_min(i) > a_max(i) then return false
1504 XMVECTOR Disjoint = XMVectorOrInt( XMVectorGreater( MinA, MaxB ), XMVectorGreater( MinB, MaxA ) );
1505
1506 return !DirectX::Internal::XMVector3AnyTrue( Disjoint );
1507}
1508
1509
1510//-----------------------------------------------------------------------------
1511// Oriented box vs. axis-aligned box test
1512//-----------------------------------------------------------------------------
1513_Use_decl_annotations_
1514inline bool BoundingBox::Intersects( const BoundingOrientedBox& box ) const
1515{
1516 return box.Intersects( *this );
1517}
1518
1519
1520//-----------------------------------------------------------------------------
1521// Frustum vs. axis-aligned box test
1522//-----------------------------------------------------------------------------
1523_Use_decl_annotations_
1524inline bool BoundingBox::Intersects( const BoundingFrustum& fr ) const
1525{
1526 return fr.Intersects( *this );
1527}
1528
1529
1530//-----------------------------------------------------------------------------
1531// Triangle vs. axis aligned box test
1532//-----------------------------------------------------------------------------
1533_Use_decl_annotations_
1534inline bool BoundingBox::Intersects( FXMVECTOR V0, FXMVECTOR V1, FXMVECTOR V2 ) const
1535{
1536 XMVECTOR Zero = XMVectorZero();
1537
1538 // Load the box.
1539 XMVECTOR vCenter = XMLoadFloat3( &Center );
1540 XMVECTOR vExtents = XMLoadFloat3( &Extents );
1541
1542 XMVECTOR BoxMin = vCenter - vExtents;
1543 XMVECTOR BoxMax = vCenter + vExtents;
1544
1545 // Test the axes of the box (in effect test the AAB against the minimal AAB
1546 // around the triangle).
1547 XMVECTOR TriMin = XMVectorMin( XMVectorMin( V0, V1 ), V2 );
1548 XMVECTOR TriMax = XMVectorMax( XMVectorMax( V0, V1 ), V2 );
1549
1550 // for each i in (x, y, z) if a_min(i) > b_max(i) or b_min(i) > a_max(i) then disjoint
1551 XMVECTOR Disjoint = XMVectorOrInt( XMVectorGreater( TriMin, BoxMax ), XMVectorGreater( BoxMin, TriMax ) );
1552 if( DirectX::Internal::XMVector3AnyTrue( Disjoint ) )
1553 return false;
1554
1555 // Test the plane of the triangle.
1556 XMVECTOR Normal = XMVector3Cross( V1 - V0, V2 - V0 );
1557 XMVECTOR Dist = XMVector3Dot( Normal, V0 );
1558
1559 // Assert that the triangle is not degenerate.
1560 assert( !XMVector3Equal( Normal, Zero ) );
1561
1562 // for each i in (x, y, z) if n(i) >= 0 then v_min(i)=b_min(i), v_max(i)=b_max(i)
1563 // else v_min(i)=b_max(i), v_max(i)=b_min(i)
1564 XMVECTOR NormalSelect = XMVectorGreater( Normal, Zero );
1565 XMVECTOR V_Min = XMVectorSelect( BoxMax, BoxMin, NormalSelect );
1566 XMVECTOR V_Max = XMVectorSelect( BoxMin, BoxMax, NormalSelect );
1567
1568 // if n dot v_min + d > 0 || n dot v_max + d < 0 then disjoint
1569 XMVECTOR MinDist = XMVector3Dot( V_Min, Normal );
1570 XMVECTOR MaxDist = XMVector3Dot( V_Max, Normal );
1571
1572 XMVECTOR NoIntersection = XMVectorGreater( MinDist, Dist );
1573 NoIntersection = XMVectorOrInt( NoIntersection, XMVectorLess( MaxDist, Dist ) );
1574
1575 // Move the box center to zero to simplify the following tests.
1576 XMVECTOR TV0 = V0 - vCenter;
1577 XMVECTOR TV1 = V1 - vCenter;
1578 XMVECTOR TV2 = V2 - vCenter;
1579
1580 // Test the edge/edge axes (3*3).
1581 XMVECTOR e0 = TV1 - TV0;
1582 XMVECTOR e1 = TV2 - TV1;
1583 XMVECTOR e2 = TV0 - TV2;
1584
1585 // Make w zero.
1586 e0 = XMVectorInsert<0, 0, 0, 0, 1>( e0, Zero );
1587 e1 = XMVectorInsert<0, 0, 0, 0, 1>( e1, Zero );
1588 e2 = XMVectorInsert<0, 0, 0, 0, 1>( e2, Zero );
1589
1590 XMVECTOR Axis;
1591 XMVECTOR p0, p1, p2;
1592 XMVECTOR Min, Max;
1593 XMVECTOR Radius;
1594
1595 // Axis == (1,0,0) x e0 = (0, -e0.z, e0.y)
1596 Axis = XMVectorPermute<XM_PERMUTE_0W, XM_PERMUTE_1Z, XM_PERMUTE_0Y, XM_PERMUTE_0X>( e0, -e0 );
1597 p0 = XMVector3Dot( TV0, Axis );
1598 // p1 = XMVector3Dot( V1, Axis ); // p1 = p0;
1599 p2 = XMVector3Dot( TV2, Axis );
1600 Min = XMVectorMin( p0, p2 );
1601 Max = XMVectorMax( p0, p2 );
1602 Radius = XMVector3Dot( vExtents, XMVectorAbs( Axis ) );
1603 NoIntersection = XMVectorOrInt( NoIntersection, XMVectorGreater( Min, Radius ) );
1604 NoIntersection = XMVectorOrInt( NoIntersection, XMVectorLess( Max, -Radius ) );
1605
1606 // Axis == (1,0,0) x e1 = (0, -e1.z, e1.y)
1607 Axis = XMVectorPermute<XM_PERMUTE_0W, XM_PERMUTE_1Z, XM_PERMUTE_0Y, XM_PERMUTE_0X>( e1, -e1 );
1608 p0 = XMVector3Dot( TV0, Axis );
1609 p1 = XMVector3Dot( TV1, Axis );
1610 // p2 = XMVector3Dot( V2, Axis ); // p2 = p1;
1611 Min = XMVectorMin( p0, p1 );
1612 Max = XMVectorMax( p0, p1 );
1613 Radius = XMVector3Dot( vExtents, XMVectorAbs( Axis ) );
1614 NoIntersection = XMVectorOrInt( NoIntersection, XMVectorGreater( Min, Radius ) );
1615 NoIntersection = XMVectorOrInt( NoIntersection, XMVectorLess( Max, -Radius ) );
1616
1617 // Axis == (1,0,0) x e2 = (0, -e2.z, e2.y)
1618 Axis = XMVectorPermute<XM_PERMUTE_0W, XM_PERMUTE_1Z, XM_PERMUTE_0Y, XM_PERMUTE_0X>( e2, -e2 );
1619 p0 = XMVector3Dot( TV0, Axis );
1620 p1 = XMVector3Dot( TV1, Axis );
1621 // p2 = XMVector3Dot( V2, Axis ); // p2 = p0;
1622 Min = XMVectorMin( p0, p1 );
1623 Max = XMVectorMax( p0, p1 );
1624 Radius = XMVector3Dot( vExtents, XMVectorAbs( Axis ) );
1625 NoIntersection = XMVectorOrInt( NoIntersection, XMVectorGreater( Min, Radius ) );
1626 NoIntersection = XMVectorOrInt( NoIntersection, XMVectorLess( Max, -Radius ) );
1627
1628 // Axis == (0,1,0) x e0 = (e0.z, 0, -e0.x)
1629 Axis = XMVectorPermute<XM_PERMUTE_0Z, XM_PERMUTE_0W, XM_PERMUTE_1X, XM_PERMUTE_0Y>( e0, -e0 );
1630 p0 = XMVector3Dot( TV0, Axis );
1631 // p1 = XMVector3Dot( V1, Axis ); // p1 = p0;
1632 p2 = XMVector3Dot( TV2, Axis );
1633 Min = XMVectorMin( p0, p2 );
1634 Max = XMVectorMax( p0, p2 );
1635 Radius = XMVector3Dot( vExtents, XMVectorAbs( Axis ) );
1636 NoIntersection = XMVectorOrInt( NoIntersection, XMVectorGreater( Min, Radius ) );
1637 NoIntersection = XMVectorOrInt( NoIntersection, XMVectorLess( Max, -Radius ) );
1638
1639 // Axis == (0,1,0) x e1 = (e1.z, 0, -e1.x)
1640 Axis = XMVectorPermute<XM_PERMUTE_0Z, XM_PERMUTE_0W, XM_PERMUTE_1X, XM_PERMUTE_0Y>( e1, -e1 );
1641 p0 = XMVector3Dot( TV0, Axis );
1642 p1 = XMVector3Dot( TV1, Axis );
1643 // p2 = XMVector3Dot( V2, Axis ); // p2 = p1;
1644 Min = XMVectorMin( p0, p1 );
1645 Max = XMVectorMax( p0, p1 );
1646 Radius = XMVector3Dot( vExtents, XMVectorAbs( Axis ) );
1647 NoIntersection = XMVectorOrInt( NoIntersection, XMVectorGreater( Min, Radius ) );
1648 NoIntersection = XMVectorOrInt( NoIntersection, XMVectorLess( Max, -Radius ) );
1649
1650 // Axis == (0,0,1) x e2 = (e2.z, 0, -e2.x)
1651 Axis = XMVectorPermute<XM_PERMUTE_0Z, XM_PERMUTE_0W, XM_PERMUTE_1X, XM_PERMUTE_0Y>( e2, -e2 );
1652 p0 = XMVector3Dot( TV0, Axis );
1653 p1 = XMVector3Dot( TV1, Axis );
1654 // p2 = XMVector3Dot( V2, Axis ); // p2 = p0;
1655 Min = XMVectorMin( p0, p1 );
1656 Max = XMVectorMax( p0, p1 );
1657 Radius = XMVector3Dot( vExtents, XMVectorAbs( Axis ) );
1658 NoIntersection = XMVectorOrInt( NoIntersection, XMVectorGreater( Min, Radius ) );
1659 NoIntersection = XMVectorOrInt( NoIntersection, XMVectorLess( Max, -Radius ) );
1660
1661 // Axis == (0,0,1) x e0 = (-e0.y, e0.x, 0)
1662 Axis = XMVectorPermute<XM_PERMUTE_1Y, XM_PERMUTE_0X, XM_PERMUTE_0W, XM_PERMUTE_0Z>( e0, -e0 );
1663 p0 = XMVector3Dot( TV0, Axis );
1664 // p1 = XMVector3Dot( V1, Axis ); // p1 = p0;
1665 p2 = XMVector3Dot( TV2, Axis );
1666 Min = XMVectorMin( p0, p2 );
1667 Max = XMVectorMax( p0, p2 );
1668 Radius = XMVector3Dot( vExtents, XMVectorAbs( Axis ) );
1669 NoIntersection = XMVectorOrInt( NoIntersection, XMVectorGreater( Min, Radius ) );
1670 NoIntersection = XMVectorOrInt( NoIntersection, XMVectorLess( Max, -Radius ) );
1671
1672 // Axis == (0,0,1) x e1 = (-e1.y, e1.x, 0)
1673 Axis = XMVectorPermute<XM_PERMUTE_1Y, XM_PERMUTE_0X, XM_PERMUTE_0W, XM_PERMUTE_0Z>( e1, -e1 );
1674 p0 = XMVector3Dot( TV0, Axis );
1675 p1 = XMVector3Dot( TV1, Axis );
1676 // p2 = XMVector3Dot( V2, Axis ); // p2 = p1;
1677 Min = XMVectorMin( p0, p1 );
1678 Max = XMVectorMax( p0, p1 );
1679 Radius = XMVector3Dot( vExtents, XMVectorAbs( Axis ) );
1680 NoIntersection = XMVectorOrInt( NoIntersection, XMVectorGreater( Min, Radius ) );
1681 NoIntersection = XMVectorOrInt( NoIntersection, XMVectorLess( Max, -Radius ) );
1682
1683 // Axis == (0,0,1) x e2 = (-e2.y, e2.x, 0)
1684 Axis = XMVectorPermute<XM_PERMUTE_1Y, XM_PERMUTE_0X, XM_PERMUTE_0W, XM_PERMUTE_0Z>( e2, -e2 );
1685 p0 = XMVector3Dot( TV0, Axis );
1686 p1 = XMVector3Dot( TV1, Axis );
1687 // p2 = XMVector3Dot( V2, Axis ); // p2 = p0;
1688 Min = XMVectorMin( p0, p1 );
1689 Max = XMVectorMax( p0, p1 );
1690 Radius = XMVector3Dot( vExtents, XMVectorAbs( Axis ) );
1691 NoIntersection = XMVectorOrInt( NoIntersection, XMVectorGreater( Min, Radius ) );
1692 NoIntersection = XMVectorOrInt( NoIntersection, XMVectorLess( Max, -Radius ) );
1693
1694 return XMVector4NotEqualInt( NoIntersection, XMVectorTrueInt() );
1695}
1696
1697
1698//-----------------------------------------------------------------------------
1699_Use_decl_annotations_
1700inline PlaneIntersectionType BoundingBox::Intersects( FXMVECTOR Plane ) const
1701{
1702 assert( DirectX::Internal::XMPlaneIsUnit( Plane ) );
1703
1704 // Load the box.
1705 XMVECTOR vCenter = XMLoadFloat3( &Center );
1706 XMVECTOR vExtents = XMLoadFloat3( &Extents );
1707
1708 // Set w of the center to one so we can dot4 with a plane.
1709 vCenter = XMVectorInsert<0, 0, 0, 0, 1>( vCenter, XMVectorSplatOne() );
1710
1711 XMVECTOR Outside, Inside;
1712 DirectX::Internal::FastIntersectAxisAlignedBoxPlane( vCenter, vExtents, Plane, Outside, Inside );
1713
1714 // If the box is outside any plane it is outside.
1715 if ( XMVector4EqualInt( Outside, XMVectorTrueInt() ) )
1716 return FRONT;
1717
1718 // If the box is inside all planes it is inside.
1719 if ( XMVector4EqualInt( Inside, XMVectorTrueInt() ) )
1720 return BACK;
1721
1722 // The box is not inside all planes or outside a plane it intersects.
1723 return INTERSECTING;
1724}
1725
1726
1727//-----------------------------------------------------------------------------
1728// Compute the intersection of a ray (Origin, Direction) with an axis aligned
1729// box using the slabs method.
1730//-----------------------------------------------------------------------------
1731_Use_decl_annotations_
1732inline bool BoundingBox::Intersects( FXMVECTOR Origin, FXMVECTOR Direction, float& Dist ) const
1733{
1734 assert( DirectX::Internal::XMVector3IsUnit( Direction ) );
1735
1736 // Load the box.
1737 XMVECTOR vCenter = XMLoadFloat3( &Center );
1738 XMVECTOR vExtents = XMLoadFloat3( &Extents );
1739
1740 // Adjust ray origin to be relative to center of the box.
1741 XMVECTOR TOrigin = vCenter - Origin;
1742
1743 // Compute the dot product againt each axis of the box.
1744 // Since the axii are (1,0,0), (0,1,0), (0,0,1) no computation is necessary.
1745 XMVECTOR AxisDotOrigin = TOrigin;
1746 XMVECTOR AxisDotDirection = Direction;
1747
1748 // if (fabs(AxisDotDirection) <= Epsilon) the ray is nearly parallel to the slab.
1749 XMVECTOR IsParallel = XMVectorLessOrEqual( XMVectorAbs( AxisDotDirection ), g_RayEpsilon );
1750
1751 // Test against all three axii simultaneously.
1752 XMVECTOR InverseAxisDotDirection = XMVectorReciprocal( AxisDotDirection );
1753 XMVECTOR t1 = ( AxisDotOrigin - vExtents ) * InverseAxisDotDirection;
1754 XMVECTOR t2 = ( AxisDotOrigin + vExtents ) * InverseAxisDotDirection;
1755
1756 // Compute the max of min(t1,t2) and the min of max(t1,t2) ensuring we don't
1757 // use the results from any directions parallel to the slab.
1758 XMVECTOR t_min = XMVectorSelect( XMVectorMin( t1, t2 ), g_FltMin, IsParallel );
1759 XMVECTOR t_max = XMVectorSelect( XMVectorMax( t1, t2 ), g_FltMax, IsParallel );
1760
1761 // t_min.x = maximum( t_min.x, t_min.y, t_min.z );
1762 // t_max.x = minimum( t_max.x, t_max.y, t_max.z );
1763 t_min = XMVectorMax( t_min, XMVectorSplatY( t_min ) ); // x = max(x,y)
1764 t_min = XMVectorMax( t_min, XMVectorSplatZ( t_min ) ); // x = max(max(x,y),z)
1765 t_max = XMVectorMin( t_max, XMVectorSplatY( t_max ) ); // x = min(x,y)
1766 t_max = XMVectorMin( t_max, XMVectorSplatZ( t_max ) ); // x = min(min(x,y),z)
1767
1768 // if ( t_min > t_max ) return false;
1769 XMVECTOR NoIntersection = XMVectorGreater( XMVectorSplatX( t_min ), XMVectorSplatX( t_max ) );
1770
1771 // if ( t_max < 0.0f ) return false;
1772 NoIntersection = XMVectorOrInt( NoIntersection, XMVectorLess( XMVectorSplatX( t_max ), XMVectorZero() ) );
1773
1774 // if (IsParallel && (-Extents > AxisDotOrigin || Extents < AxisDotOrigin)) return false;
1775 XMVECTOR ParallelOverlap = XMVectorInBounds( AxisDotOrigin, vExtents );
1776 NoIntersection = XMVectorOrInt( NoIntersection, XMVectorAndCInt( IsParallel, ParallelOverlap ) );
1777
1778 if( !DirectX::Internal::XMVector3AnyTrue( NoIntersection ) )
1779 {
1780 // Store the x-component to *pDist
1781 XMStoreFloat( &Dist, t_min );
1782 return true;
1783 }
1784
1785 Dist = 0.f;
1786 return false;
1787}
1788
1789
1790//-----------------------------------------------------------------------------
1791// Test an axis alinged box vs 6 planes (typically forming a frustum).
1792//-----------------------------------------------------------------------------
1793_Use_decl_annotations_
1794inline ContainmentType BoundingBox::ContainedBy( FXMVECTOR Plane0, FXMVECTOR Plane1, FXMVECTOR Plane2,
1795 GXMVECTOR Plane3, CXMVECTOR Plane4, CXMVECTOR Plane5 ) const
1796{
1797 // Load the box.
1798 XMVECTOR vCenter = XMLoadFloat3( &Center );
1799 XMVECTOR vExtents = XMLoadFloat3( &Extents );
1800
1801 // Set w of the center to one so we can dot4 with a plane.
1802 vCenter = XMVectorInsert<0, 0, 0, 0, 1>( vCenter, XMVectorSplatOne() );
1803
1804 XMVECTOR Outside, Inside;
1805
1806 // Test against each plane.
1807 DirectX::Internal::FastIntersectAxisAlignedBoxPlane( vCenter, vExtents, Plane0, Outside, Inside );
1808
1809 XMVECTOR AnyOutside = Outside;
1810 XMVECTOR AllInside = Inside;
1811
1812 DirectX::Internal::FastIntersectAxisAlignedBoxPlane( vCenter, vExtents, Plane1, Outside, Inside );
1813 AnyOutside = XMVectorOrInt( AnyOutside, Outside );
1814 AllInside = XMVectorAndInt( AllInside, Inside );
1815
1816 DirectX::Internal::FastIntersectAxisAlignedBoxPlane( vCenter, vExtents, Plane2, Outside, Inside );
1817 AnyOutside = XMVectorOrInt( AnyOutside, Outside );
1818 AllInside = XMVectorAndInt( AllInside, Inside );
1819
1820 DirectX::Internal::FastIntersectAxisAlignedBoxPlane( vCenter, vExtents, Plane3, Outside, Inside );
1821 AnyOutside = XMVectorOrInt( AnyOutside, Outside );
1822 AllInside = XMVectorAndInt( AllInside, Inside );
1823
1824 DirectX::Internal::FastIntersectAxisAlignedBoxPlane( vCenter, vExtents, Plane4, Outside, Inside );
1825 AnyOutside = XMVectorOrInt( AnyOutside, Outside );
1826 AllInside = XMVectorAndInt( AllInside, Inside );
1827
1828 DirectX::Internal::FastIntersectAxisAlignedBoxPlane( vCenter, vExtents, Plane5, Outside, Inside );
1829 AnyOutside = XMVectorOrInt( AnyOutside, Outside );
1830 AllInside = XMVectorAndInt( AllInside, Inside );
1831
1832 // If the box is outside any plane it is outside.
1833 if ( XMVector4EqualInt( AnyOutside, XMVectorTrueInt() ) )
1834 return DISJOINT;
1835
1836 // If the box is inside all planes it is inside.
1837 if ( XMVector4EqualInt( AllInside, XMVectorTrueInt() ) )
1838 return CONTAINS;
1839
1840 // The box is not inside all planes or outside a plane, it may intersect.
1841 return INTERSECTS;
1842}
1843
1844
1845//-----------------------------------------------------------------------------
1846// Create axis-aligned box that contains two other bounding boxes
1847//-----------------------------------------------------------------------------
1848_Use_decl_annotations_
1849inline void BoundingBox::CreateMerged( BoundingBox& Out, const BoundingBox& b1, const BoundingBox& b2 )
1850{
1851 XMVECTOR b1Center = XMLoadFloat3( &b1.Center );
1852 XMVECTOR b1Extents = XMLoadFloat3( &b1.Extents );
1853
1854 XMVECTOR b2Center = XMLoadFloat3( &b2.Center );
1855 XMVECTOR b2Extents = XMLoadFloat3( &b2.Extents );
1856
1857 XMVECTOR Min = XMVectorSubtract( b1Center, b1Extents );
1858 Min = XMVectorMin( Min, XMVectorSubtract( b2Center, b2Extents ) );
1859
1860 XMVECTOR Max = XMVectorAdd( b1Center, b1Extents );
1861 Max = XMVectorMax( Max, XMVectorAdd( b2Center, b2Extents ) );
1862
1863 assert( XMVector3LessOrEqual( Min, Max ) );
1864
1865 XMStoreFloat3( &Out.Center, ( Min + Max ) * 0.5f );
1866 XMStoreFloat3( &Out.Extents, ( Max - Min ) * 0.5f );
1867}
1868
1869
1870//-----------------------------------------------------------------------------
1871// Create axis-aligned box that contains a bounding sphere
1872//-----------------------------------------------------------------------------
1873_Use_decl_annotations_
1874inline void BoundingBox::CreateFromSphere( BoundingBox& Out, const BoundingSphere& sh )
1875{
1876 XMVECTOR spCenter = XMLoadFloat3( &sh.Center );
1877 XMVECTOR shRadius = XMVectorReplicatePtr( &sh.Radius );
1878
1879 XMVECTOR Min = XMVectorSubtract( spCenter, shRadius );
1880 XMVECTOR Max = XMVectorAdd( spCenter, shRadius );
1881
1882 assert( XMVector3LessOrEqual( Min, Max ) );
1883
1884 XMStoreFloat3( &Out.Center, ( Min + Max ) * 0.5f );
1885 XMStoreFloat3( &Out.Extents, ( Max - Min ) * 0.5f );
1886}
1887
1888
1889//-----------------------------------------------------------------------------
1890// Create axis-aligned box from min/max points
1891//-----------------------------------------------------------------------------
1892_Use_decl_annotations_
1893inline void BoundingBox::CreateFromPoints( BoundingBox& Out, FXMVECTOR pt1, FXMVECTOR pt2 )
1894{
1895 XMVECTOR Min = XMVectorMin( pt1, pt2 );
1896 XMVECTOR Max = XMVectorMax( pt1, pt2 );
1897
1898 // Store center and extents.
1899 XMStoreFloat3( &Out.Center, ( Min + Max ) * 0.5f );
1900 XMStoreFloat3( &Out.Extents, ( Max - Min ) * 0.5f );
1901}
1902
1903
1904//-----------------------------------------------------------------------------
1905// Find the minimum axis aligned bounding box containing a set of points.
1906//-----------------------------------------------------------------------------
1907_Use_decl_annotations_
1908inline void BoundingBox::CreateFromPoints( BoundingBox& Out, size_t Count, const XMFLOAT3* pPoints, size_t Stride )
1909{
1910 assert( Count > 0 );
1911 assert( pPoints );
1912
1913 // Find the minimum and maximum x, y, and z
1914 XMVECTOR vMin, vMax;
1915
1916 vMin = vMax = XMLoadFloat3( pPoints );
1917
1918 for( size_t i = 1; i < Count; ++i )
1919 {
1920 XMVECTOR Point = XMLoadFloat3( reinterpret_cast<const XMFLOAT3*>( reinterpret_cast<const uint8_t*>(pPoints) + i * Stride ) );
1921
1922 vMin = XMVectorMin( vMin, Point );
1923 vMax = XMVectorMax( vMax, Point );
1924 }
1925
1926 // Store center and extents.
1927 XMStoreFloat3( &Out.Center, ( vMin + vMax ) * 0.5f );
1928 XMStoreFloat3( &Out.Extents, ( vMax - vMin ) * 0.5f );
1929}
1930
1931
1932/****************************************************************************
1933 *
1934 * BoundingOrientedBox
1935 *
1936 ****************************************************************************/
1937
1938//-----------------------------------------------------------------------------
1939// Transform an oriented box by an angle preserving transform.
1940//-----------------------------------------------------------------------------
1941_Use_decl_annotations_
1942inline void BoundingOrientedBox::Transform( BoundingOrientedBox& Out, CXMMATRIX M ) const
1943{
1944 // Load the box.
1945 XMVECTOR vCenter = XMLoadFloat3( &Center );
1946 XMVECTOR vExtents = XMLoadFloat3( &Extents );
1947 XMVECTOR vOrientation = XMLoadFloat4( &Orientation );
1948
1949 assert( DirectX::Internal::XMQuaternionIsUnit( vOrientation ) );
1950
1951 // Composite the box rotation and the transform rotation.
1952 XMVECTOR Rotation = XMQuaternionRotationMatrix( M );
1953 vOrientation = XMQuaternionMultiply( vOrientation, Rotation );
1954
1955 // Transform the center.
1956 vCenter = XMVector3Transform( vCenter, M );
1957
1958 // Scale the box extents.
1959 XMVECTOR dX = XMVector3Length( M.r[0] );
1960 XMVECTOR dY = XMVector3Length( M.r[1] );
1961 XMVECTOR dZ = XMVector3Length( M.r[2] );
1962
1963 XMVECTOR VectorScale = XMVectorSelect( dX, dY, g_XMSelect1000 );
1964 VectorScale = XMVectorSelect( VectorScale, dZ, g_XMSelect1100 );
1965 vExtents = vExtents * VectorScale;
1966
1967 // Store the box.
1968 XMStoreFloat3( &Out.Center, vCenter );
1969 XMStoreFloat3( &Out.Extents, vExtents );
1970 XMStoreFloat4( &Out.Orientation, vOrientation );
1971}
1972
1973_Use_decl_annotations_
1974inline void BoundingOrientedBox::Transform( BoundingOrientedBox& Out, float Scale, FXMVECTOR Rotation, FXMVECTOR Translation ) const
1975{
1976 assert( DirectX::Internal::XMQuaternionIsUnit( Rotation ) );
1977
1978 // Load the box.
1979 XMVECTOR vCenter = XMLoadFloat3( &Center );
1980 XMVECTOR vExtents = XMLoadFloat3( &Extents );
1981 XMVECTOR vOrientation = XMLoadFloat4( &Orientation );
1982
1983 assert( DirectX::Internal::XMQuaternionIsUnit( vOrientation ) );
1984
1985 // Composite the box rotation and the transform rotation.
1986 vOrientation = XMQuaternionMultiply( vOrientation, Rotation );
1987
1988 // Transform the center.
1989 XMVECTOR VectorScale = XMVectorReplicate( Scale );
1990 vCenter = XMVector3Rotate( vCenter * VectorScale, Rotation ) + Translation;
1991
1992 // Scale the box extents.
1993 vExtents = vExtents * VectorScale;
1994
1995 // Store the box.
1996 XMStoreFloat3( &Out.Center, vCenter );
1997 XMStoreFloat3( &Out.Extents, vExtents );
1998 XMStoreFloat4( &Out.Orientation, vOrientation );
1999}
2000
2001
2002//-----------------------------------------------------------------------------
2003// Get the corner points of the box
2004//-----------------------------------------------------------------------------
2005_Use_decl_annotations_
2006inline void BoundingOrientedBox::GetCorners( XMFLOAT3* Corners ) const
2007{
2008 assert( Corners != 0 );
2009
2010 // Load the box
2011 XMVECTOR vCenter = XMLoadFloat3( &Center );
2012 XMVECTOR vExtents = XMLoadFloat3( &Extents );
2013 XMVECTOR vOrientation = XMLoadFloat4( &Orientation );
2014
2015 assert( DirectX::Internal::XMQuaternionIsUnit( vOrientation ) );
2016
2017 for( size_t i = 0; i < CORNER_COUNT; ++i )
2018 {
2019 XMVECTOR C = XMVector3Rotate( vExtents * g_BoxOffset[i], vOrientation ) + vCenter;
2020 XMStoreFloat3( &Corners[i], C );
2021 }
2022}
2023
2024
2025//-----------------------------------------------------------------------------
2026// Point in oriented box test.
2027//-----------------------------------------------------------------------------
2028_Use_decl_annotations_
2029inline ContainmentType BoundingOrientedBox::Contains( FXMVECTOR Point ) const
2030{
2031 XMVECTOR vCenter = XMLoadFloat3( &Center );
2032 XMVECTOR vExtents = XMLoadFloat3( &Extents );
2033 XMVECTOR vOrientation = XMLoadFloat4( &Orientation );
2034
2035 // Transform the point to be local to the box.
2036 XMVECTOR TPoint = XMVector3InverseRotate( Point - vCenter, vOrientation );
2037
2038 return XMVector3InBounds( TPoint, vExtents ) ? CONTAINS : DISJOINT;
2039}
2040
2041
2042//-----------------------------------------------------------------------------
2043// Triangle in oriented bounding box
2044//-----------------------------------------------------------------------------
2045_Use_decl_annotations_
2046inline ContainmentType BoundingOrientedBox::Contains( FXMVECTOR V0, FXMVECTOR V1, FXMVECTOR V2 ) const
2047{
2048 // Load the box center & orientation.
2049 XMVECTOR vCenter = XMLoadFloat3( &Center );
2050 XMVECTOR vOrientation = XMLoadFloat4( &Orientation );
2051
2052 // Transform the triangle vertices into the space of the box.
2053 XMVECTOR TV0 = XMVector3InverseRotate( V0 - vCenter, vOrientation );
2054 XMVECTOR TV1 = XMVector3InverseRotate( V1 - vCenter, vOrientation );
2055 XMVECTOR TV2 = XMVector3InverseRotate( V2 - vCenter, vOrientation );
2056
2057 BoundingBox box;
2058 box.Center = XMFLOAT3( 0.0f, 0.0f, 0.0f );
2059 box.Extents = Extents;
2060
2061 // Use the triangle vs axis aligned box intersection routine.
2062 return box.Contains( TV0, TV1, TV2 );
2063}
2064
2065
2066//-----------------------------------------------------------------------------
2067// Sphere in oriented bounding box
2068//-----------------------------------------------------------------------------
2069_Use_decl_annotations_
2070inline ContainmentType BoundingOrientedBox::Contains( const BoundingSphere& sh ) const
2071{
2072 XMVECTOR SphereCenter = XMLoadFloat3( &sh.Center );
2073 XMVECTOR SphereRadius = XMVectorReplicatePtr( &sh.Radius );
2074
2075 XMVECTOR BoxCenter = XMLoadFloat3( &Center );
2076 XMVECTOR BoxExtents = XMLoadFloat3( &Extents );
2077 XMVECTOR BoxOrientation = XMLoadFloat4( &Orientation );
2078
2079 assert( DirectX::Internal::XMQuaternionIsUnit( BoxOrientation ) );
2080
2081 // Transform the center of the sphere to be local to the box.
2082 // BoxMin = -BoxExtents
2083 // BoxMax = +BoxExtents
2084 SphereCenter = XMVector3InverseRotate( SphereCenter - BoxCenter, BoxOrientation );
2085
2086 // Find the distance to the nearest point on the box.
2087 // for each i in (x, y, z)
2088 // if (SphereCenter(i) < BoxMin(i)) d2 += (SphereCenter(i) - BoxMin(i)) ^ 2
2089 // else if (SphereCenter(i) > BoxMax(i)) d2 += (SphereCenter(i) - BoxMax(i)) ^ 2
2090
2091 XMVECTOR d = XMVectorZero();
2092
2093 // Compute d for each dimension.
2094 XMVECTOR LessThanMin = XMVectorLess( SphereCenter, -BoxExtents );
2095 XMVECTOR GreaterThanMax = XMVectorGreater( SphereCenter, BoxExtents );
2096
2097 XMVECTOR MinDelta = SphereCenter + BoxExtents;
2098 XMVECTOR MaxDelta = SphereCenter - BoxExtents;
2099
2100 // Choose value for each dimension based on the comparison.
2101 d = XMVectorSelect( d, MinDelta, LessThanMin );
2102 d = XMVectorSelect( d, MaxDelta, GreaterThanMax );
2103
2104 // Use a dot-product to square them and sum them together.
2105 XMVECTOR d2 = XMVector3Dot( d, d );
2106 XMVECTOR SphereRadiusSq = XMVectorMultiply( SphereRadius, SphereRadius );
2107
2108 if ( XMVector4Greater( d2, SphereRadiusSq ) )
2109 return DISJOINT;
2110
2111 // See if we are completely inside the box
2112 XMVECTOR SMin = SphereCenter - SphereRadius;
2113 XMVECTOR SMax = SphereCenter + SphereRadius;
2114
2115 return ( XMVector3InBounds( SMin, BoxExtents ) && XMVector3InBounds( SMax, BoxExtents ) ) ? CONTAINS : INTERSECTS;
2116}
2117
2118
2119//-----------------------------------------------------------------------------
2120// Axis aligned box vs. oriented box. Constructs an oriented box and uses
2121// the oriented box vs. oriented box test.
2122//-----------------------------------------------------------------------------
2123_Use_decl_annotations_
2124inline ContainmentType BoundingOrientedBox::Contains( const BoundingBox& box ) const
2125{
2126 // Make the axis aligned box oriented and do an OBB vs OBB test.
2127 BoundingOrientedBox obox( box.Center, box.Extents, XMFLOAT4( 0.f, 0.f, 0.f, 1.f ) );
2128 return Contains( obox );
2129}
2130
2131
2132//-----------------------------------------------------------------------------
2133// Oriented bounding box in oriented bounding box
2134//-----------------------------------------------------------------------------
2135_Use_decl_annotations_
2136inline ContainmentType BoundingOrientedBox::Contains( const BoundingOrientedBox& box ) const
2137{
2138 if ( !Intersects(box) )
2139 return DISJOINT;
2140
2141 // Load the boxes
2142 XMVECTOR aCenter = XMLoadFloat3( &Center );
2143 XMVECTOR aExtents = XMLoadFloat3( &Extents );
2144 XMVECTOR aOrientation = XMLoadFloat4( &Orientation );
2145
2146 assert( DirectX::Internal::XMQuaternionIsUnit( aOrientation ) );
2147
2148 XMVECTOR bCenter = XMLoadFloat3( &box.Center );
2149 XMVECTOR bExtents = XMLoadFloat3( &box.Extents );
2150 XMVECTOR bOrientation = XMLoadFloat4( &box.Orientation );
2151
2152 assert( DirectX::Internal::XMQuaternionIsUnit( bOrientation ) );
2153
2154 XMVECTOR offset = bCenter - aCenter;
2155
2156 for( size_t i = 0; i < CORNER_COUNT; ++i )
2157 {
2158 // Cb = rotate( bExtents * corneroffset[i], bOrientation ) + bcenter
2159 // Ca = invrotate( Cb - aCenter, aOrientation )
2160
2161 XMVECTOR C = XMVector3Rotate( bExtents * g_BoxOffset[i], bOrientation ) + offset;
2162 C = XMVector3InverseRotate( C , aOrientation );
2163
2164 if ( !XMVector3InBounds( C, aExtents ) )
2165 return INTERSECTS;
2166 }
2167
2168 return CONTAINS;
2169}
2170
2171
2172//-----------------------------------------------------------------------------
2173// Frustum in oriented bounding box
2174//-----------------------------------------------------------------------------
2175_Use_decl_annotations_
2176inline ContainmentType BoundingOrientedBox::Contains( const BoundingFrustum& fr ) const
2177{
2178 if ( !fr.Intersects(*this) )
2179 return DISJOINT;
2180
2181 XMFLOAT3 Corners[BoundingFrustum::CORNER_COUNT];
2182 fr.GetCorners( Corners );
2183
2184 // Load the box
2185 XMVECTOR vCenter = XMLoadFloat3( &Center );
2186 XMVECTOR vExtents = XMLoadFloat3( &Extents );
2187 XMVECTOR vOrientation = XMLoadFloat4( &Orientation );
2188
2189 assert( DirectX::Internal::XMQuaternionIsUnit( vOrientation ) );
2190
2191 for( size_t i = 0; i < BoundingFrustum::CORNER_COUNT; ++i )
2192 {
2193 XMVECTOR C = XMVector3InverseRotate( XMLoadFloat3( &Corners[i] ) - vCenter, vOrientation );
2194
2195 if ( !XMVector3InBounds( C, vExtents ) )
2196 return INTERSECTS;
2197 }
2198
2199 return CONTAINS;
2200}
2201
2202
2203//-----------------------------------------------------------------------------
2204// Sphere vs. oriented box test
2205//-----------------------------------------------------------------------------
2206_Use_decl_annotations_
2207inline bool BoundingOrientedBox::Intersects( const BoundingSphere& sh ) const
2208{
2209 XMVECTOR SphereCenter = XMLoadFloat3( &sh.Center );
2210 XMVECTOR SphereRadius = XMVectorReplicatePtr( &sh.Radius );
2211
2212 XMVECTOR BoxCenter = XMLoadFloat3( &Center );
2213 XMVECTOR BoxExtents = XMLoadFloat3( &Extents );
2214 XMVECTOR BoxOrientation = XMLoadFloat4( &Orientation );
2215
2216 assert( DirectX::Internal::XMQuaternionIsUnit( BoxOrientation ) );
2217
2218 // Transform the center of the sphere to be local to the box.
2219 // BoxMin = -BoxExtents
2220 // BoxMax = +BoxExtents
2221 SphereCenter = XMVector3InverseRotate( SphereCenter - BoxCenter, BoxOrientation );
2222
2223 // Find the distance to the nearest point on the box.
2224 // for each i in (x, y, z)
2225 // if (SphereCenter(i) < BoxMin(i)) d2 += (SphereCenter(i) - BoxMin(i)) ^ 2
2226 // else if (SphereCenter(i) > BoxMax(i)) d2 += (SphereCenter(i) - BoxMax(i)) ^ 2
2227
2228 XMVECTOR d = XMVectorZero();
2229
2230 // Compute d for each dimension.
2231 XMVECTOR LessThanMin = XMVectorLess( SphereCenter, -BoxExtents );
2232 XMVECTOR GreaterThanMax = XMVectorGreater( SphereCenter, BoxExtents );
2233
2234 XMVECTOR MinDelta = SphereCenter + BoxExtents;
2235 XMVECTOR MaxDelta = SphereCenter - BoxExtents;
2236
2237 // Choose value for each dimension based on the comparison.
2238 d = XMVectorSelect( d, MinDelta, LessThanMin );
2239 d = XMVectorSelect( d, MaxDelta, GreaterThanMax );
2240
2241 // Use a dot-product to square them and sum them together.
2242 XMVECTOR d2 = XMVector3Dot( d, d );
2243
2244 return XMVector4LessOrEqual( d2, XMVectorMultiply( SphereRadius, SphereRadius ) ) ? true : false;
2245}
2246
2247
2248//-----------------------------------------------------------------------------
2249// Axis aligned box vs. oriented box. Constructs an oriented box and uses
2250// the oriented box vs. oriented box test.
2251//-----------------------------------------------------------------------------
2252_Use_decl_annotations_
2253inline bool BoundingOrientedBox::Intersects( const BoundingBox& box ) const
2254{
2255 // Make the axis aligned box oriented and do an OBB vs OBB test.
2256 BoundingOrientedBox obox( box.Center, box.Extents, XMFLOAT4( 0.f, 0.f, 0.f, 1.f ) );
2257 return Intersects( obox );
2258}
2259
2260
2261//-----------------------------------------------------------------------------
2262// Fast oriented box / oriented box intersection test using the separating axis
2263// theorem.
2264//-----------------------------------------------------------------------------
2265_Use_decl_annotations_
2266inline bool BoundingOrientedBox::Intersects( const BoundingOrientedBox& box ) const
2267{
2268 // Build the 3x3 rotation matrix that defines the orientation of B relative to A.
2269 XMVECTOR A_quat = XMLoadFloat4( &Orientation );
2270 XMVECTOR B_quat = XMLoadFloat4( &box.Orientation );
2271
2272 assert( DirectX::Internal::XMQuaternionIsUnit( A_quat ) );
2273 assert( DirectX::Internal::XMQuaternionIsUnit( B_quat ) );
2274
2275 XMVECTOR Q = XMQuaternionMultiply( A_quat, XMQuaternionConjugate( B_quat ) );
2276 XMMATRIX R = XMMatrixRotationQuaternion( Q );
2277
2278 // Compute the translation of B relative to A.
2279 XMVECTOR A_cent = XMLoadFloat3( &Center );
2280 XMVECTOR B_cent = XMLoadFloat3( &box.Center );
2281 XMVECTOR t = XMVector3InverseRotate( B_cent - A_cent, A_quat );
2282
2283 //
2284 // h(A) = extents of A.
2285 // h(B) = extents of B.
2286 //
2287 // a(u) = axes of A = (1,0,0), (0,1,0), (0,0,1)
2288 // b(u) = axes of B relative to A = (r00,r10,r20), (r01,r11,r21), (r02,r12,r22)
2289 //
2290 // For each possible separating axis l:
2291 // d(A) = sum (for i = u,v,w) h(A)(i) * abs( a(i) dot l )
2292 // d(B) = sum (for i = u,v,w) h(B)(i) * abs( b(i) dot l )
2293 // if abs( t dot l ) > d(A) + d(B) then disjoint
2294 //
2295
2296 // Load extents of A and B.
2297 XMVECTOR h_A = XMLoadFloat3( &Extents );
2298 XMVECTOR h_B = XMLoadFloat3( &box.Extents );
2299
2300 // Rows. Note R[0,1,2]X.w = 0.
2301 XMVECTOR R0X = R.r[0];
2302 XMVECTOR R1X = R.r[1];
2303 XMVECTOR R2X = R.r[2];
2304
2305 R = XMMatrixTranspose( R );
2306
2307 // Columns. Note RX[0,1,2].w = 0.
2308 XMVECTOR RX0 = R.r[0];
2309 XMVECTOR RX1 = R.r[1];
2310 XMVECTOR RX2 = R.r[2];
2311
2312 // Absolute value of rows.
2313 XMVECTOR AR0X = XMVectorAbs( R0X );
2314 XMVECTOR AR1X = XMVectorAbs( R1X );
2315 XMVECTOR AR2X = XMVectorAbs( R2X );
2316
2317 // Absolute value of columns.
2318 XMVECTOR ARX0 = XMVectorAbs( RX0 );
2319 XMVECTOR ARX1 = XMVectorAbs( RX1 );
2320 XMVECTOR ARX2 = XMVectorAbs( RX2 );
2321
2322 // Test each of the 15 possible seperating axii.
2323 XMVECTOR d, d_A, d_B;
2324
2325 // l = a(u) = (1, 0, 0)
2326 // t dot l = t.x
2327 // d(A) = h(A).x
2328 // d(B) = h(B) dot abs(r00, r01, r02)
2329 d = XMVectorSplatX( t );
2330 d_A = XMVectorSplatX( h_A );
2331 d_B = XMVector3Dot( h_B, AR0X );
2332 XMVECTOR NoIntersection = XMVectorGreater( XMVectorAbs(d), XMVectorAdd( d_A, d_B ) );
2333
2334 // l = a(v) = (0, 1, 0)
2335 // t dot l = t.y
2336 // d(A) = h(A).y
2337 // d(B) = h(B) dot abs(r10, r11, r12)
2338 d = XMVectorSplatY( t );
2339 d_A = XMVectorSplatY( h_A );
2340 d_B = XMVector3Dot( h_B, AR1X );
2341 NoIntersection = XMVectorOrInt( NoIntersection,
2342 XMVectorGreater( XMVectorAbs(d), XMVectorAdd( d_A, d_B ) ) );
2343
2344 // l = a(w) = (0, 0, 1)
2345 // t dot l = t.z
2346 // d(A) = h(A).z
2347 // d(B) = h(B) dot abs(r20, r21, r22)
2348 d = XMVectorSplatZ( t );
2349 d_A = XMVectorSplatZ( h_A );
2350 d_B = XMVector3Dot( h_B, AR2X );
2351 NoIntersection = XMVectorOrInt( NoIntersection,
2352 XMVectorGreater( XMVectorAbs(d), XMVectorAdd( d_A, d_B ) ) );
2353
2354 // l = b(u) = (r00, r10, r20)
2355 // d(A) = h(A) dot abs(r00, r10, r20)
2356 // d(B) = h(B).x
2357 d = XMVector3Dot( t, RX0 );
2358 d_A = XMVector3Dot( h_A, ARX0 );
2359 d_B = XMVectorSplatX( h_B );
2360 NoIntersection = XMVectorOrInt( NoIntersection,
2361 XMVectorGreater( XMVectorAbs(d), XMVectorAdd( d_A, d_B ) ) );
2362
2363 // l = b(v) = (r01, r11, r21)
2364 // d(A) = h(A) dot abs(r01, r11, r21)
2365 // d(B) = h(B).y
2366 d = XMVector3Dot( t, RX1 );
2367 d_A = XMVector3Dot( h_A, ARX1 );
2368 d_B = XMVectorSplatY( h_B );
2369 NoIntersection = XMVectorOrInt( NoIntersection,
2370 XMVectorGreater( XMVectorAbs(d), XMVectorAdd( d_A, d_B ) ) );
2371
2372 // l = b(w) = (r02, r12, r22)
2373 // d(A) = h(A) dot abs(r02, r12, r22)
2374 // d(B) = h(B).z
2375 d = XMVector3Dot( t, RX2 );
2376 d_A = XMVector3Dot( h_A, ARX2 );
2377 d_B = XMVectorSplatZ( h_B );
2378 NoIntersection = XMVectorOrInt( NoIntersection,
2379 XMVectorGreater( XMVectorAbs(d), XMVectorAdd( d_A, d_B ) ) );
2380
2381 // l = a(u) x b(u) = (0, -r20, r10)
2382 // d(A) = h(A) dot abs(0, r20, r10)
2383 // d(B) = h(B) dot abs(0, r02, r01)
2384 d = XMVector3Dot( t, XMVectorPermute<XM_PERMUTE_0W, XM_PERMUTE_1Z, XM_PERMUTE_0Y, XM_PERMUTE_0X>( RX0, -RX0 ) );
2385 d_A = XMVector3Dot( h_A, XMVectorSwizzle<XM_SWIZZLE_W, XM_SWIZZLE_Z, XM_SWIZZLE_Y, XM_SWIZZLE_X>( ARX0 ) );
2386 d_B = XMVector3Dot( h_B, XMVectorSwizzle<XM_SWIZZLE_W, XM_SWIZZLE_Z, XM_SWIZZLE_Y, XM_SWIZZLE_X>( AR0X ) );
2387 NoIntersection = XMVectorOrInt( NoIntersection,
2388 XMVectorGreater( XMVectorAbs(d), XMVectorAdd( d_A, d_B ) ) );
2389
2390 // l = a(u) x b(v) = (0, -r21, r11)
2391 // d(A) = h(A) dot abs(0, r21, r11)
2392 // d(B) = h(B) dot abs(r02, 0, r00)
2393 d = XMVector3Dot( t, XMVectorPermute<XM_PERMUTE_0W, XM_PERMUTE_1Z, XM_PERMUTE_0Y, XM_PERMUTE_0X>( RX1, -RX1 ) );
2394 d_A = XMVector3Dot( h_A, XMVectorSwizzle<XM_SWIZZLE_W, XM_SWIZZLE_Z, XM_SWIZZLE_Y, XM_SWIZZLE_X>( ARX1 ) );
2395 d_B = XMVector3Dot( h_B, XMVectorSwizzle<XM_SWIZZLE_Z, XM_SWIZZLE_W, XM_SWIZZLE_X, XM_SWIZZLE_Y>( AR0X ) );
2396 NoIntersection = XMVectorOrInt( NoIntersection,
2397 XMVectorGreater( XMVectorAbs(d), XMVectorAdd( d_A, d_B ) ) );
2398
2399 // l = a(u) x b(w) = (0, -r22, r12)
2400 // d(A) = h(A) dot abs(0, r22, r12)
2401 // d(B) = h(B) dot abs(r01, r00, 0)
2402 d = XMVector3Dot( t, XMVectorPermute<XM_PERMUTE_0W, XM_PERMUTE_1Z, XM_PERMUTE_0Y, XM_PERMUTE_0X>( RX2, -RX2 ) );
2403 d_A = XMVector3Dot( h_A, XMVectorSwizzle<XM_SWIZZLE_W, XM_SWIZZLE_Z, XM_SWIZZLE_Y, XM_SWIZZLE_X>( ARX2 ) );
2404 d_B = XMVector3Dot( h_B, XMVectorSwizzle<XM_SWIZZLE_Y, XM_SWIZZLE_X, XM_SWIZZLE_W, XM_SWIZZLE_Z>( AR0X ) );
2405 NoIntersection = XMVectorOrInt( NoIntersection,
2406 XMVectorGreater( XMVectorAbs(d), XMVectorAdd( d_A, d_B ) ) );
2407
2408 // l = a(v) x b(u) = (r20, 0, -r00)
2409 // d(A) = h(A) dot abs(r20, 0, r00)
2410 // d(B) = h(B) dot abs(0, r12, r11)
2411 d = XMVector3Dot( t, XMVectorPermute<XM_PERMUTE_0Z, XM_PERMUTE_0W, XM_PERMUTE_1X, XM_PERMUTE_0Y>( RX0, -RX0 ) );
2412 d_A = XMVector3Dot( h_A, XMVectorSwizzle<XM_SWIZZLE_Z, XM_SWIZZLE_W, XM_SWIZZLE_X, XM_SWIZZLE_Y>( ARX0 ) );
2413 d_B = XMVector3Dot( h_B, XMVectorSwizzle<XM_SWIZZLE_W, XM_SWIZZLE_Z, XM_SWIZZLE_Y, XM_SWIZZLE_X>( AR1X ) );
2414 NoIntersection = XMVectorOrInt( NoIntersection,
2415 XMVectorGreater( XMVectorAbs(d), XMVectorAdd( d_A, d_B ) ) );
2416
2417 // l = a(v) x b(v) = (r21, 0, -r01)
2418 // d(A) = h(A) dot abs(r21, 0, r01)
2419 // d(B) = h(B) dot abs(r12, 0, r10)
2420 d = XMVector3Dot( t, XMVectorPermute<XM_PERMUTE_0Z, XM_PERMUTE_0W, XM_PERMUTE_1X, XM_PERMUTE_0Y>( RX1, -RX1 ) );
2421 d_A = XMVector3Dot( h_A, XMVectorSwizzle<XM_SWIZZLE_Z, XM_SWIZZLE_W, XM_SWIZZLE_X, XM_SWIZZLE_Y>( ARX1 ) );
2422 d_B = XMVector3Dot( h_B, XMVectorSwizzle<XM_SWIZZLE_Z, XM_SWIZZLE_W, XM_SWIZZLE_X, XM_SWIZZLE_Y>( AR1X ) );
2423 NoIntersection = XMVectorOrInt( NoIntersection,
2424 XMVectorGreater( XMVectorAbs(d), XMVectorAdd( d_A, d_B ) ) );
2425
2426 // l = a(v) x b(w) = (r22, 0, -r02)
2427 // d(A) = h(A) dot abs(r22, 0, r02)
2428 // d(B) = h(B) dot abs(r11, r10, 0)
2429 d = XMVector3Dot( t, XMVectorPermute<XM_PERMUTE_0Z, XM_PERMUTE_0W, XM_PERMUTE_1X, XM_PERMUTE_0Y>( RX2, -RX2 ) );
2430 d_A = XMVector3Dot( h_A, XMVectorSwizzle<XM_SWIZZLE_Z, XM_SWIZZLE_W, XM_SWIZZLE_X, XM_SWIZZLE_Y>( ARX2 ) );
2431 d_B = XMVector3Dot( h_B, XMVectorSwizzle<XM_SWIZZLE_Y, XM_SWIZZLE_X, XM_SWIZZLE_W, XM_SWIZZLE_Z>( AR1X ) );
2432 NoIntersection = XMVectorOrInt( NoIntersection,
2433 XMVectorGreater( XMVectorAbs(d), XMVectorAdd( d_A, d_B ) ) );
2434
2435 // l = a(w) x b(u) = (-r10, r00, 0)
2436 // d(A) = h(A) dot abs(r10, r00, 0)
2437 // d(B) = h(B) dot abs(0, r22, r21)
2438 d = XMVector3Dot( t, XMVectorPermute<XM_PERMUTE_1Y, XM_PERMUTE_0X, XM_PERMUTE_0W, XM_PERMUTE_0Z>( RX0, -RX0 ) );
2439 d_A = XMVector3Dot( h_A, XMVectorSwizzle<XM_SWIZZLE_Y, XM_SWIZZLE_X, XM_SWIZZLE_W, XM_SWIZZLE_Z>( ARX0 ) );
2440 d_B = XMVector3Dot( h_B, XMVectorSwizzle<XM_SWIZZLE_W, XM_SWIZZLE_Z, XM_SWIZZLE_Y, XM_SWIZZLE_X>( AR2X ) );
2441 NoIntersection = XMVectorOrInt( NoIntersection,
2442 XMVectorGreater( XMVectorAbs(d), XMVectorAdd( d_A, d_B ) ) );
2443
2444 // l = a(w) x b(v) = (-r11, r01, 0)
2445 // d(A) = h(A) dot abs(r11, r01, 0)
2446 // d(B) = h(B) dot abs(r22, 0, r20)
2447 d = XMVector3Dot( t, XMVectorPermute<XM_PERMUTE_1Y, XM_PERMUTE_0X, XM_PERMUTE_0W, XM_PERMUTE_0Z>( RX1, -RX1 ) );
2448 d_A = XMVector3Dot( h_A, XMVectorSwizzle<XM_SWIZZLE_Y, XM_SWIZZLE_X, XM_SWIZZLE_W, XM_SWIZZLE_Z>( ARX1 ) );
2449 d_B = XMVector3Dot( h_B, XMVectorSwizzle<XM_SWIZZLE_Z, XM_SWIZZLE_W, XM_SWIZZLE_X, XM_SWIZZLE_Y>( AR2X ) );
2450 NoIntersection = XMVectorOrInt( NoIntersection,
2451 XMVectorGreater( XMVectorAbs(d), XMVectorAdd( d_A, d_B ) ) );
2452
2453 // l = a(w) x b(w) = (-r12, r02, 0)
2454 // d(A) = h(A) dot abs(r12, r02, 0)
2455 // d(B) = h(B) dot abs(r21, r20, 0)
2456 d = XMVector3Dot( t, XMVectorPermute<XM_PERMUTE_1Y, XM_PERMUTE_0X, XM_PERMUTE_0W, XM_PERMUTE_0Z>( RX2, -RX2 ) );
2457 d_A = XMVector3Dot( h_A, XMVectorSwizzle<XM_SWIZZLE_Y, XM_SWIZZLE_X, XM_SWIZZLE_W, XM_SWIZZLE_Z>( ARX2 ) );
2458 d_B = XMVector3Dot( h_B, XMVectorSwizzle<XM_SWIZZLE_Y, XM_SWIZZLE_X, XM_SWIZZLE_W, XM_SWIZZLE_Z>( AR2X ) );
2459 NoIntersection = XMVectorOrInt( NoIntersection,
2460 XMVectorGreater( XMVectorAbs(d), XMVectorAdd( d_A, d_B ) ) );
2461
2462 // No seperating axis found, boxes must intersect.
2463 return XMVector4NotEqualInt( NoIntersection, XMVectorTrueInt() ) ? true : false;
2464}
2465
2466
2467//-----------------------------------------------------------------------------
2468// Frustum vs. oriented box test
2469//-----------------------------------------------------------------------------
2470_Use_decl_annotations_
2471inline bool BoundingOrientedBox::Intersects( const BoundingFrustum& fr ) const
2472{
2473 return fr.Intersects( *this );
2474}
2475
2476
2477//-----------------------------------------------------------------------------
2478// Triangle vs. oriented box test.
2479//-----------------------------------------------------------------------------
2480_Use_decl_annotations_
2481inline bool BoundingOrientedBox::Intersects( FXMVECTOR V0, FXMVECTOR V1, FXMVECTOR V2 ) const
2482{
2483 // Load the box center & orientation.
2484 XMVECTOR vCenter = XMLoadFloat3( &Center );
2485 XMVECTOR vOrientation = XMLoadFloat4( &Orientation );
2486
2487 // Transform the triangle vertices into the space of the box.
2488 XMVECTOR TV0 = XMVector3InverseRotate( V0 - vCenter, vOrientation );
2489 XMVECTOR TV1 = XMVector3InverseRotate( V1 - vCenter, vOrientation );
2490 XMVECTOR TV2 = XMVector3InverseRotate( V2 - vCenter, vOrientation );
2491
2492 BoundingBox box;
2493 box.Center = XMFLOAT3( 0.0f, 0.0f, 0.0f );
2494 box.Extents = Extents;
2495
2496 // Use the triangle vs axis aligned box intersection routine.
2497 return box.Intersects( TV0, TV1, TV2 );
2498}
2499
2500
2501//-----------------------------------------------------------------------------
2502_Use_decl_annotations_
2503inline PlaneIntersectionType BoundingOrientedBox::Intersects( FXMVECTOR Plane ) const
2504{
2505 assert( DirectX::Internal::XMPlaneIsUnit( Plane ) );
2506
2507 // Load the box.
2508 XMVECTOR vCenter = XMLoadFloat3( &Center );
2509 XMVECTOR vExtents = XMLoadFloat3( &Extents );
2510 XMVECTOR BoxOrientation = XMLoadFloat4( &Orientation );
2511
2512 assert( DirectX::Internal::XMQuaternionIsUnit( BoxOrientation ) );
2513
2514 // Set w of the center to one so we can dot4 with a plane.
2515 vCenter = XMVectorInsert<0, 0, 0, 0, 1>( vCenter, XMVectorSplatOne() );
2516
2517 // Build the 3x3 rotation matrix that defines the box axes.
2518 XMMATRIX R = XMMatrixRotationQuaternion( BoxOrientation );
2519
2520 XMVECTOR Outside, Inside;
2521 DirectX::Internal::FastIntersectOrientedBoxPlane( vCenter, vExtents, R.r[0], R.r[1], R.r[2], Plane, Outside, Inside );
2522
2523 // If the box is outside any plane it is outside.
2524 if ( XMVector4EqualInt( Outside, XMVectorTrueInt() ) )
2525 return FRONT;
2526
2527 // If the box is inside all planes it is inside.
2528 if ( XMVector4EqualInt( Inside, XMVectorTrueInt() ) )
2529 return BACK;
2530
2531 // The box is not inside all planes or outside a plane it intersects.
2532 return INTERSECTING;
2533}
2534
2535
2536//-----------------------------------------------------------------------------
2537// Compute the intersection of a ray (Origin, Direction) with an oriented box
2538// using the slabs method.
2539//-----------------------------------------------------------------------------
2540_Use_decl_annotations_
2541inline bool BoundingOrientedBox::Intersects( FXMVECTOR Origin, FXMVECTOR Direction, float& Dist ) const
2542{
2543 assert( DirectX::Internal::XMVector3IsUnit( Direction ) );
2544
2545 static const XMVECTORI32 SelectY =
2546 {
2547 XM_SELECT_0, XM_SELECT_1, XM_SELECT_0, XM_SELECT_0
2548 };
2549 static const XMVECTORI32 SelectZ =
2550 {
2551 XM_SELECT_0, XM_SELECT_0, XM_SELECT_1, XM_SELECT_0
2552 };
2553
2554 // Load the box.
2555 XMVECTOR vCenter = XMLoadFloat3( &Center );
2556 XMVECTOR vExtents = XMLoadFloat3( &Extents );
2557 XMVECTOR vOrientation = XMLoadFloat4( &Orientation );
2558
2559 assert( DirectX::Internal::XMQuaternionIsUnit( vOrientation ) );
2560
2561 // Get the boxes normalized side directions.
2562 XMMATRIX R = XMMatrixRotationQuaternion( vOrientation );
2563
2564 // Adjust ray origin to be relative to center of the box.
2565 XMVECTOR TOrigin = vCenter - Origin;
2566
2567 // Compute the dot product againt each axis of the box.
2568 XMVECTOR AxisDotOrigin = XMVector3Dot( R.r[0], TOrigin );
2569 AxisDotOrigin = XMVectorSelect( AxisDotOrigin, XMVector3Dot( R.r[1], TOrigin ), SelectY );
2570 AxisDotOrigin = XMVectorSelect( AxisDotOrigin, XMVector3Dot( R.r[2], TOrigin ), SelectZ );
2571
2572 XMVECTOR AxisDotDirection = XMVector3Dot( R.r[0], Direction );
2573 AxisDotDirection = XMVectorSelect( AxisDotDirection, XMVector3Dot( R.r[1], Direction ), SelectY );
2574 AxisDotDirection = XMVectorSelect( AxisDotDirection, XMVector3Dot( R.r[2], Direction ), SelectZ );
2575
2576 // if (fabs(AxisDotDirection) <= Epsilon) the ray is nearly parallel to the slab.
2577 XMVECTOR IsParallel = XMVectorLessOrEqual( XMVectorAbs( AxisDotDirection ), g_RayEpsilon );
2578
2579 // Test against all three axes simultaneously.
2580 XMVECTOR InverseAxisDotDirection = XMVectorReciprocal( AxisDotDirection );
2581 XMVECTOR t1 = ( AxisDotOrigin - vExtents ) * InverseAxisDotDirection;
2582 XMVECTOR t2 = ( AxisDotOrigin + vExtents ) * InverseAxisDotDirection;
2583
2584 // Compute the max of min(t1,t2) and the min of max(t1,t2) ensuring we don't
2585 // use the results from any directions parallel to the slab.
2586 XMVECTOR t_min = XMVectorSelect( XMVectorMin( t1, t2 ), g_FltMin, IsParallel );
2587 XMVECTOR t_max = XMVectorSelect( XMVectorMax( t1, t2 ), g_FltMax, IsParallel );
2588
2589 // t_min.x = maximum( t_min.x, t_min.y, t_min.z );
2590 // t_max.x = minimum( t_max.x, t_max.y, t_max.z );
2591 t_min = XMVectorMax( t_min, XMVectorSplatY( t_min ) ); // x = max(x,y)
2592 t_min = XMVectorMax( t_min, XMVectorSplatZ( t_min ) ); // x = max(max(x,y),z)
2593 t_max = XMVectorMin( t_max, XMVectorSplatY( t_max ) ); // x = min(x,y)
2594 t_max = XMVectorMin( t_max, XMVectorSplatZ( t_max ) ); // x = min(min(x,y),z)
2595
2596 // if ( t_min > t_max ) return false;
2597 XMVECTOR NoIntersection = XMVectorGreater( XMVectorSplatX( t_min ), XMVectorSplatX( t_max ) );
2598
2599 // if ( t_max < 0.0f ) return false;
2600 NoIntersection = XMVectorOrInt( NoIntersection, XMVectorLess( XMVectorSplatX( t_max ), XMVectorZero() ) );
2601
2602 // if (IsParallel && (-Extents > AxisDotOrigin || Extents < AxisDotOrigin)) return false;
2603 XMVECTOR ParallelOverlap = XMVectorInBounds( AxisDotOrigin, vExtents );
2604 NoIntersection = XMVectorOrInt( NoIntersection, XMVectorAndCInt( IsParallel, ParallelOverlap ) );
2605
2606 if( !DirectX::Internal::XMVector3AnyTrue( NoIntersection ) )
2607 {
2608 // Store the x-component to *pDist
2609 XMStoreFloat( &Dist, t_min );
2610 return true;
2611 }
2612
2613 Dist = 0.f;
2614 return false;
2615}
2616
2617
2618//-----------------------------------------------------------------------------
2619// Test an oriented box vs 6 planes (typically forming a frustum).
2620//-----------------------------------------------------------------------------
2621_Use_decl_annotations_
2622inline ContainmentType BoundingOrientedBox::ContainedBy( FXMVECTOR Plane0, FXMVECTOR Plane1, FXMVECTOR Plane2,
2623 GXMVECTOR Plane3, CXMVECTOR Plane4, CXMVECTOR Plane5 ) const
2624{
2625 // Load the box.
2626 XMVECTOR vCenter = XMLoadFloat3( &Center );
2627 XMVECTOR vExtents = XMLoadFloat3( &Extents );
2628 XMVECTOR BoxOrientation = XMLoadFloat4( &Orientation );
2629
2630 assert( DirectX::Internal::XMQuaternionIsUnit( BoxOrientation ) );
2631
2632 // Set w of the center to one so we can dot4 with a plane.
2633 vCenter = XMVectorInsert<0, 0, 0, 0, 1>( vCenter, XMVectorSplatOne() );
2634
2635 // Build the 3x3 rotation matrix that defines the box axes.
2636 XMMATRIX R = XMMatrixRotationQuaternion( BoxOrientation );
2637
2638 XMVECTOR Outside, Inside;
2639
2640 // Test against each plane.
2641 DirectX::Internal::FastIntersectOrientedBoxPlane( vCenter, vExtents, R.r[0], R.r[1], R.r[2], Plane0, Outside, Inside );
2642
2643 XMVECTOR AnyOutside = Outside;
2644 XMVECTOR AllInside = Inside;
2645
2646 DirectX::Internal::FastIntersectOrientedBoxPlane( vCenter, vExtents, R.r[0], R.r[1], R.r[2], Plane1, Outside, Inside );
2647 AnyOutside = XMVectorOrInt( AnyOutside, Outside );
2648 AllInside = XMVectorAndInt( AllInside, Inside );
2649
2650 DirectX::Internal::FastIntersectOrientedBoxPlane( vCenter, vExtents, R.r[0], R.r[1], R.r[2], Plane2, Outside, Inside );
2651 AnyOutside = XMVectorOrInt( AnyOutside, Outside );
2652 AllInside = XMVectorAndInt( AllInside, Inside );
2653
2654 DirectX::Internal::FastIntersectOrientedBoxPlane( vCenter, vExtents, R.r[0], R.r[1], R.r[2], Plane3, Outside, Inside );
2655 AnyOutside = XMVectorOrInt( AnyOutside, Outside );
2656 AllInside = XMVectorAndInt( AllInside, Inside );
2657
2658 DirectX::Internal::FastIntersectOrientedBoxPlane( vCenter, vExtents, R.r[0], R.r[1], R.r[2], Plane4, Outside, Inside );
2659 AnyOutside = XMVectorOrInt( AnyOutside, Outside );
2660 AllInside = XMVectorAndInt( AllInside, Inside );
2661
2662 DirectX::Internal::FastIntersectOrientedBoxPlane( vCenter, vExtents, R.r[0], R.r[1], R.r[2], Plane5, Outside, Inside );
2663 AnyOutside = XMVectorOrInt( AnyOutside, Outside );
2664 AllInside = XMVectorAndInt( AllInside, Inside );
2665
2666 // If the box is outside any plane it is outside.
2667 if ( XMVector4EqualInt( AnyOutside, XMVectorTrueInt() ) )
2668 return DISJOINT;
2669
2670 // If the box is inside all planes it is inside.
2671 if ( XMVector4EqualInt( AllInside, XMVectorTrueInt() ) )
2672 return CONTAINS;
2673
2674 // The box is not inside all planes or outside a plane, it may intersect.
2675 return INTERSECTS;
2676}
2677
2678
2679//-----------------------------------------------------------------------------
2680// Create oriented bounding box from axis-aligned bounding box
2681//-----------------------------------------------------------------------------
2682_Use_decl_annotations_
2683inline void BoundingOrientedBox::CreateFromBoundingBox( BoundingOrientedBox& Out, const BoundingBox& box )
2684{
2685 Out.Center = box.Center;
2686 Out.Extents = box.Extents;
2687 Out.Orientation = XMFLOAT4( 0.f, 0.f, 0.f, 1.f );
2688}
2689
2690
2691//-----------------------------------------------------------------------------
2692// Find the approximate minimum oriented bounding box containing a set of
2693// points. Exact computation of minimum oriented bounding box is possible but
2694// is slower and requires a more complex algorithm.
2695// The algorithm works by computing the inertia tensor of the points and then
2696// using the eigenvectors of the intertia tensor as the axes of the box.
2697// Computing the intertia tensor of the convex hull of the points will usually
2698// result in better bounding box but the computation is more complex.
2699// Exact computation of the minimum oriented bounding box is possible but the
2700// best know algorithm is O(N^3) and is significanly more complex to implement.
2701//-----------------------------------------------------------------------------
2702_Use_decl_annotations_
2703inline void BoundingOrientedBox::CreateFromPoints( BoundingOrientedBox& Out, size_t Count, const XMFLOAT3* pPoints, size_t Stride )
2704{
2705 assert( Count > 0 );
2706 assert( pPoints != 0 );
2707
2708 XMVECTOR CenterOfMass = XMVectorZero();
2709
2710 // Compute the center of mass and inertia tensor of the points.
2711 for( size_t i = 0; i < Count; ++i )
2712 {
2713 XMVECTOR Point = XMLoadFloat3( reinterpret_cast<const XMFLOAT3*>( reinterpret_cast<const uint8_t*>(pPoints) + i * Stride ) );
2714
2715 CenterOfMass += Point;
2716 }
2717
2718 CenterOfMass *= XMVectorReciprocal( XMVectorReplicate( float( Count ) ) );
2719
2720 // Compute the inertia tensor of the points around the center of mass.
2721 // Using the center of mass is not strictly necessary, but will hopefully
2722 // improve the stability of finding the eigenvectors.
2723 XMVECTOR XX_YY_ZZ = XMVectorZero();
2724 XMVECTOR XY_XZ_YZ = XMVectorZero();
2725
2726 for( size_t i = 0; i < Count; ++i )
2727 {
2728 XMVECTOR Point = XMLoadFloat3( reinterpret_cast<const XMFLOAT3*>( reinterpret_cast<const uint8_t*>(pPoints) + i * Stride ) ) - CenterOfMass;
2729
2730 XX_YY_ZZ += Point * Point;
2731
2732 XMVECTOR XXY = XMVectorSwizzle<XM_SWIZZLE_X, XM_SWIZZLE_X, XM_SWIZZLE_Y, XM_SWIZZLE_W>( Point );
2733 XMVECTOR YZZ = XMVectorSwizzle<XM_SWIZZLE_Y, XM_SWIZZLE_Z, XM_SWIZZLE_Z, XM_SWIZZLE_W>( Point );
2734
2735 XY_XZ_YZ += XXY * YZZ;
2736 }
2737
2738 XMVECTOR v1, v2, v3;
2739
2740 // Compute the eigenvectors of the inertia tensor.
2741 DirectX::Internal::CalculateEigenVectorsFromCovarianceMatrix( XMVectorGetX( XX_YY_ZZ ), XMVectorGetY( XX_YY_ZZ ),
2742 XMVectorGetZ( XX_YY_ZZ ),
2743 XMVectorGetX( XY_XZ_YZ ), XMVectorGetY( XY_XZ_YZ ),
2744 XMVectorGetZ( XY_XZ_YZ ),
2745 &v1, &v2, &v3 );
2746
2747 // Put them in a matrix.
2748 XMMATRIX R;
2749
2750 R.r[0] = XMVectorSetW( v1, 0.f );
2751 R.r[1] = XMVectorSetW( v2, 0.f );
2752 R.r[2] = XMVectorSetW( v3, 0.f );
2753 R.r[3] = g_XMIdentityR3.v;
2754
2755 // Multiply by -1 to convert the matrix into a right handed coordinate
2756 // system (Det ~= 1) in case the eigenvectors form a left handed
2757 // coordinate system (Det ~= -1) because XMQuaternionRotationMatrix only
2758 // works on right handed matrices.
2759 XMVECTOR Det = XMMatrixDeterminant( R );
2760
2761 if( XMVector4Less( Det, XMVectorZero() ) )
2762 {
2763 R.r[0] *= g_XMNegativeOne.v;
2764 R.r[1] *= g_XMNegativeOne.v;
2765 R.r[2] *= g_XMNegativeOne.v;
2766 }
2767
2768 // Get the rotation quaternion from the matrix.
2769 XMVECTOR vOrientation = XMQuaternionRotationMatrix( R );
2770
2771 // Make sure it is normal (in case the vectors are slightly non-orthogonal).
2772 vOrientation = XMQuaternionNormalize( vOrientation );
2773
2774 // Rebuild the rotation matrix from the quaternion.
2775 R = XMMatrixRotationQuaternion( vOrientation );
2776
2777 // Build the rotation into the rotated space.
2778 XMMATRIX InverseR = XMMatrixTranspose( R );
2779
2780 // Find the minimum OBB using the eigenvectors as the axes.
2781 XMVECTOR vMin, vMax;
2782
2783 vMin = vMax = XMVector3TransformNormal( XMLoadFloat3( pPoints ), InverseR );
2784
2785 for( size_t i = 1; i < Count; ++i )
2786 {
2787 XMVECTOR Point = XMVector3TransformNormal( XMLoadFloat3( reinterpret_cast<const XMFLOAT3*>( reinterpret_cast<const uint8_t*>(pPoints) + i * Stride ) ),
2788 InverseR );
2789
2790 vMin = XMVectorMin( vMin, Point );
2791 vMax = XMVectorMax( vMax, Point );
2792 }
2793
2794 // Rotate the center into world space.
2795 XMVECTOR vCenter = ( vMin + vMax ) * 0.5f;
2796 vCenter = XMVector3TransformNormal( vCenter, R );
2797
2798 // Store center, extents, and orientation.
2799 XMStoreFloat3( &Out.Center, vCenter );
2800 XMStoreFloat3( &Out.Extents, ( vMax - vMin ) * 0.5f );
2801 XMStoreFloat4( &Out.Orientation, vOrientation );
2802}
2803
2804
2805/****************************************************************************
2806 *
2807 * BoundingFrustum
2808 *
2809 ****************************************************************************/
2810
2811//-----------------------------------------------------------------------------
2812// Transform a frustum by an angle preserving transform.
2813//-----------------------------------------------------------------------------
2814_Use_decl_annotations_
2815inline void BoundingFrustum::Transform( BoundingFrustum& Out, CXMMATRIX M ) const
2816{
2817 // Load the frustum.
2818 XMVECTOR vOrigin = XMLoadFloat3( &Origin );
2819 XMVECTOR vOrientation = XMLoadFloat4( &Orientation );
2820
2821 assert( DirectX::Internal::XMQuaternionIsUnit( vOrientation ) );
2822
2823 // Composite the frustum rotation and the transform rotation.
2824 XMVECTOR Rotation = XMQuaternionRotationMatrix( M );
2825 vOrientation = XMQuaternionMultiply( vOrientation, Rotation );
2826
2827 // Transform the center.
2828 vOrigin = XMVector3Transform( vOrigin, M );
2829
2830 // Store the frustum.
2831 XMStoreFloat3( &Out.Origin, vOrigin );
2832 XMStoreFloat4( &Out.Orientation, vOrientation );
2833
2834 // Scale the near and far distances (the slopes remain the same).
2835 XMVECTOR dX = XMVector3Dot( M.r[0], M.r[0] );
2836 XMVECTOR dY = XMVector3Dot( M.r[1], M.r[1] );
2837 XMVECTOR dZ = XMVector3Dot( M.r[2], M.r[2] );
2838
2839 XMVECTOR d = XMVectorMax( dX, XMVectorMax( dY, dZ ) );
2840 float Scale = sqrtf( XMVectorGetX(d) );
2841
2842 Out.Near = Near * Scale;
2843 Out.Far = Far * Scale;
2844
2845 // Copy the slopes.
2846 Out.RightSlope = RightSlope;
2847 Out.LeftSlope = LeftSlope;
2848 Out.TopSlope = TopSlope;
2849 Out.BottomSlope = BottomSlope;
2850}
2851
2852_Use_decl_annotations_
2853inline void BoundingFrustum::Transform( BoundingFrustum& Out, float Scale, FXMVECTOR Rotation, FXMVECTOR Translation ) const
2854{
2855 assert( DirectX::Internal::XMQuaternionIsUnit( Rotation ) );
2856
2857 // Load the frustum.
2858 XMVECTOR vOrigin = XMLoadFloat3( &Origin );
2859 XMVECTOR vOrientation = XMLoadFloat4( &Orientation );
2860
2861 assert( DirectX::Internal::XMQuaternionIsUnit( vOrientation ) );
2862
2863 // Composite the frustum rotation and the transform rotation.
2864 vOrientation = XMQuaternionMultiply( vOrientation, Rotation );
2865
2866 // Transform the origin.
2867 vOrigin = XMVector3Rotate( vOrigin * XMVectorReplicate( Scale ), Rotation ) + Translation;
2868
2869 // Store the frustum.
2870 XMStoreFloat3( &Out.Origin, vOrigin );
2871 XMStoreFloat4( &Out.Orientation, vOrientation );
2872
2873 // Scale the near and far distances (the slopes remain the same).
2874 Out.Near = Near * Scale;
2875 Out.Far = Far * Scale;
2876
2877 // Copy the slopes.
2878 Out.RightSlope = RightSlope;
2879 Out.LeftSlope = LeftSlope;
2880 Out.TopSlope = TopSlope;
2881 Out.BottomSlope = BottomSlope;
2882}
2883
2884
2885//-----------------------------------------------------------------------------
2886// Get the corner points of the frustum
2887//-----------------------------------------------------------------------------
2888_Use_decl_annotations_
2889inline void BoundingFrustum::GetCorners( XMFLOAT3* Corners ) const
2890{
2891 assert( Corners != 0 );
2892
2893 // Load origin and orientation of the frustum.
2894 XMVECTOR vOrigin = XMLoadFloat3( &Origin );
2895 XMVECTOR vOrientation = XMLoadFloat4( &Orientation );
2896
2897 assert( DirectX::Internal::XMQuaternionIsUnit( vOrientation ) );
2898
2899 // Build the corners of the frustum.
2900 XMVECTOR vRightTop = XMVectorSet( RightSlope, TopSlope, 1.0f, 0.0f );
2901 XMVECTOR vRightBottom = XMVectorSet( RightSlope, BottomSlope, 1.0f, 0.0f );
2902 XMVECTOR vLeftTop = XMVectorSet( LeftSlope, TopSlope, 1.0f, 0.0f );
2903 XMVECTOR vLeftBottom = XMVectorSet( LeftSlope, BottomSlope, 1.0f, 0.0f );
2904 XMVECTOR vNear = XMVectorReplicatePtr( &Near );
2905 XMVECTOR vFar = XMVectorReplicatePtr( &Far );
2906
2907 // Returns 8 corners position of bounding frustum.
2908 // Near Far
2909 // 0----1 4----5
2910 // | | | |
2911 // | | | |
2912 // 3----2 7----6
2913
2914 XMVECTOR vCorners[CORNER_COUNT];
2915 vCorners[0] = vLeftTop * vNear;
2916 vCorners[1] = vRightTop * vNear;
2917 vCorners[2] = vRightBottom * vNear;
2918 vCorners[3] = vLeftBottom * vNear;
2919 vCorners[4] = vLeftTop * vFar;
2920 vCorners[5] = vRightTop * vFar;
2921 vCorners[6] = vRightBottom * vFar;
2922 vCorners[7] = vLeftBottom * vFar;
2923
2924 for( size_t i=0; i < CORNER_COUNT; ++i )
2925 {
2926 XMVECTOR C = XMVector3Rotate( vCorners[i], vOrientation ) + vOrigin;
2927 XMStoreFloat3( &Corners[i], C );
2928 }
2929}
2930
2931
2932//-----------------------------------------------------------------------------
2933// Point in frustum test.
2934//-----------------------------------------------------------------------------
2935_Use_decl_annotations_
2936inline ContainmentType BoundingFrustum::Contains( FXMVECTOR Point ) const
2937{
2938 // Build frustum planes.
2939 XMVECTOR Planes[6];
2940 Planes[0] = XMVectorSet( 0.0f, 0.0f, -1.0f, Near );
2941 Planes[1] = XMVectorSet( 0.0f, 0.0f, 1.0f, -Far );
2942 Planes[2] = XMVectorSet( 1.0f, 0.0f, -RightSlope, 0.0f );
2943 Planes[3] = XMVectorSet( -1.0f, 0.0f, LeftSlope, 0.0f );
2944 Planes[4] = XMVectorSet( 0.0f, 1.0f, -TopSlope, 0.0f );
2945 Planes[5] = XMVectorSet( 0.0f, -1.0f, BottomSlope, 0.0f );
2946
2947 // Load origin and orientation.
2948 XMVECTOR vOrigin = XMLoadFloat3( &Origin );
2949 XMVECTOR vOrientation = XMLoadFloat4( &Orientation );
2950
2951 assert( DirectX::Internal::XMQuaternionIsUnit( vOrientation ) );
2952
2953 // Transform point into local space of frustum.
2954 XMVECTOR TPoint = XMVector3InverseRotate( Point - vOrigin, vOrientation );
2955
2956 // Set w to one.
2957 TPoint = XMVectorInsert<0, 0, 0, 0, 1>( TPoint, XMVectorSplatOne() );
2958
2959 XMVECTOR Zero = XMVectorZero();
2960 XMVECTOR Outside = Zero;
2961
2962 // Test point against each plane of the frustum.
2963 for( size_t i = 0; i < 6; ++i )
2964 {
2965 XMVECTOR Dot = XMVector4Dot( TPoint, Planes[i] );
2966 Outside = XMVectorOrInt( Outside, XMVectorGreater( Dot, Zero ) );
2967 }
2968
2969 return XMVector4NotEqualInt( Outside, XMVectorTrueInt() ) ? CONTAINS : DISJOINT;
2970}
2971
2972
2973//-----------------------------------------------------------------------------
2974// Triangle vs frustum test.
2975//-----------------------------------------------------------------------------
2976_Use_decl_annotations_
2977inline ContainmentType BoundingFrustum::Contains( FXMVECTOR V0, FXMVECTOR V1, FXMVECTOR V2 ) const
2978{
2979 // Load origin and orientation of the frustum.
2980 XMVECTOR vOrigin = XMLoadFloat3( &Origin );
2981 XMVECTOR vOrientation = XMLoadFloat4( &Orientation );
2982
2983 // Create 6 planes (do it inline to encourage use of registers)
2984 XMVECTOR NearPlane = XMVectorSet( 0.0f, 0.0f, -1.0f, Near );
2985 NearPlane = DirectX::Internal::XMPlaneTransform( NearPlane, vOrientation, vOrigin );
2986 NearPlane = XMPlaneNormalize( NearPlane );
2987
2988 XMVECTOR FarPlane = XMVectorSet( 0.0f, 0.0f, 1.0f, -Far );
2989 FarPlane = DirectX::Internal::XMPlaneTransform( FarPlane, vOrientation, vOrigin );
2990 FarPlane = XMPlaneNormalize( FarPlane );
2991
2992 XMVECTOR RightPlane = XMVectorSet( 1.0f, 0.0f, -RightSlope, 0.0f );
2993 RightPlane = DirectX::Internal::XMPlaneTransform( RightPlane, vOrientation, vOrigin );
2994 RightPlane = XMPlaneNormalize( RightPlane );
2995
2996 XMVECTOR LeftPlane = XMVectorSet( -1.0f, 0.0f, LeftSlope, 0.0f );
2997 LeftPlane = DirectX::Internal::XMPlaneTransform( LeftPlane, vOrientation, vOrigin );
2998 LeftPlane = XMPlaneNormalize( LeftPlane );
2999
3000 XMVECTOR TopPlane = XMVectorSet( 0.0f, 1.0f, -TopSlope, 0.0f );
3001 TopPlane = DirectX::Internal::XMPlaneTransform( TopPlane, vOrientation, vOrigin );
3002 TopPlane = XMPlaneNormalize( TopPlane );
3003
3004 XMVECTOR BottomPlane = XMVectorSet( 0.0f, -1.0f, BottomSlope, 0.0f );
3005 BottomPlane = DirectX::Internal::XMPlaneTransform( BottomPlane, vOrientation, vOrigin );
3006 BottomPlane = XMPlaneNormalize( BottomPlane );
3007
3008 return TriangleTests::ContainedBy( V0, V1, V2, NearPlane, FarPlane, RightPlane, LeftPlane, TopPlane, BottomPlane );
3009}
3010
3011
3012//-----------------------------------------------------------------------------
3013_Use_decl_annotations_
3014inline ContainmentType BoundingFrustum::Contains( const BoundingSphere& sh ) const
3015{
3016 // Load origin and orientation of the frustum.
3017 XMVECTOR vOrigin = XMLoadFloat3( &Origin );
3018 XMVECTOR vOrientation = XMLoadFloat4( &Orientation );
3019
3020 // Create 6 planes (do it inline to encourage use of registers)
3021 XMVECTOR NearPlane = XMVectorSet( 0.0f, 0.0f, -1.0f, Near );
3022 NearPlane = DirectX::Internal::XMPlaneTransform( NearPlane, vOrientation, vOrigin );
3023 NearPlane = XMPlaneNormalize( NearPlane );
3024
3025 XMVECTOR FarPlane = XMVectorSet( 0.0f, 0.0f, 1.0f, -Far );
3026 FarPlane = DirectX::Internal::XMPlaneTransform( FarPlane, vOrientation, vOrigin );
3027 FarPlane = XMPlaneNormalize( FarPlane );
3028
3029 XMVECTOR RightPlane = XMVectorSet( 1.0f, 0.0f, -RightSlope, 0.0f );
3030 RightPlane = DirectX::Internal::XMPlaneTransform( RightPlane, vOrientation, vOrigin );
3031 RightPlane = XMPlaneNormalize( RightPlane );
3032
3033 XMVECTOR LeftPlane = XMVectorSet( -1.0f, 0.0f, LeftSlope, 0.0f );
3034 LeftPlane = DirectX::Internal::XMPlaneTransform( LeftPlane, vOrientation, vOrigin );
3035 LeftPlane = XMPlaneNormalize( LeftPlane );
3036
3037 XMVECTOR TopPlane = XMVectorSet( 0.0f, 1.0f, -TopSlope, 0.0f );
3038 TopPlane = DirectX::Internal::XMPlaneTransform( TopPlane, vOrientation, vOrigin );
3039 TopPlane = XMPlaneNormalize( TopPlane );
3040
3041 XMVECTOR BottomPlane = XMVectorSet( 0.0f, -1.0f, BottomSlope, 0.0f );
3042 BottomPlane = DirectX::Internal::XMPlaneTransform( BottomPlane, vOrientation, vOrigin );
3043 BottomPlane = XMPlaneNormalize( BottomPlane );
3044
3045 return sh.ContainedBy( NearPlane, FarPlane, RightPlane, LeftPlane, TopPlane, BottomPlane );
3046}
3047
3048
3049//-----------------------------------------------------------------------------
3050_Use_decl_annotations_
3051inline ContainmentType BoundingFrustum::Contains( const BoundingBox& box ) const
3052{
3053 // Load origin and orientation of the frustum.
3054 XMVECTOR vOrigin = XMLoadFloat3( &Origin );
3055 XMVECTOR vOrientation = XMLoadFloat4( &Orientation );
3056
3057 // Create 6 planes (do it inline to encourage use of registers)
3058 XMVECTOR NearPlane = XMVectorSet( 0.0f, 0.0f, -1.0f, Near );
3059 NearPlane = DirectX::Internal::XMPlaneTransform( NearPlane, vOrientation, vOrigin );
3060 NearPlane = XMPlaneNormalize( NearPlane );
3061
3062 XMVECTOR FarPlane = XMVectorSet( 0.0f, 0.0f, 1.0f, -Far );
3063 FarPlane = DirectX::Internal::XMPlaneTransform( FarPlane, vOrientation, vOrigin );
3064 FarPlane = XMPlaneNormalize( FarPlane );
3065
3066 XMVECTOR RightPlane = XMVectorSet( 1.0f, 0.0f, -RightSlope, 0.0f );
3067 RightPlane = DirectX::Internal::XMPlaneTransform( RightPlane, vOrientation, vOrigin );
3068 RightPlane = XMPlaneNormalize( RightPlane );
3069
3070 XMVECTOR LeftPlane = XMVectorSet( -1.0f, 0.0f, LeftSlope, 0.0f );
3071 LeftPlane = DirectX::Internal::XMPlaneTransform( LeftPlane, vOrientation, vOrigin );
3072 LeftPlane = XMPlaneNormalize( LeftPlane );
3073
3074 XMVECTOR TopPlane = XMVectorSet( 0.0f, 1.0f, -TopSlope, 0.0f );
3075 TopPlane = DirectX::Internal::XMPlaneTransform( TopPlane, vOrientation, vOrigin );
3076 TopPlane = XMPlaneNormalize( TopPlane );
3077
3078 XMVECTOR BottomPlane = XMVectorSet( 0.0f, -1.0f, BottomSlope, 0.0f );
3079 BottomPlane = DirectX::Internal::XMPlaneTransform( BottomPlane, vOrientation, vOrigin );
3080 BottomPlane = XMPlaneNormalize( BottomPlane );
3081
3082 return box.ContainedBy( NearPlane, FarPlane, RightPlane, LeftPlane, TopPlane, BottomPlane );
3083}
3084
3085
3086//-----------------------------------------------------------------------------
3087_Use_decl_annotations_
3088inline ContainmentType BoundingFrustum::Contains( const BoundingOrientedBox& box ) const
3089{
3090 // Load origin and orientation of the frustum.
3091 XMVECTOR vOrigin = XMLoadFloat3( &Origin );
3092 XMVECTOR vOrientation = XMLoadFloat4( &Orientation );
3093
3094 // Create 6 planes (do it inline to encourage use of registers)
3095 XMVECTOR NearPlane = XMVectorSet( 0.0f, 0.0f, -1.0f, Near );
3096 NearPlane = DirectX::Internal::XMPlaneTransform( NearPlane, vOrientation, vOrigin );
3097 NearPlane = XMPlaneNormalize( NearPlane );
3098
3099 XMVECTOR FarPlane = XMVectorSet( 0.0f, 0.0f, 1.0f, -Far );
3100 FarPlane = DirectX::Internal::XMPlaneTransform( FarPlane, vOrientation, vOrigin );
3101 FarPlane = XMPlaneNormalize( FarPlane );
3102
3103 XMVECTOR RightPlane = XMVectorSet( 1.0f, 0.0f, -RightSlope, 0.0f );
3104 RightPlane = DirectX::Internal::XMPlaneTransform( RightPlane, vOrientation, vOrigin );
3105 RightPlane = XMPlaneNormalize( RightPlane );
3106
3107 XMVECTOR LeftPlane = XMVectorSet( -1.0f, 0.0f, LeftSlope, 0.0f );
3108 LeftPlane = DirectX::Internal::XMPlaneTransform( LeftPlane, vOrientation, vOrigin );
3109 LeftPlane = XMPlaneNormalize( LeftPlane );
3110
3111 XMVECTOR TopPlane = XMVectorSet( 0.0f, 1.0f, -TopSlope, 0.0f );
3112 TopPlane = DirectX::Internal::XMPlaneTransform( TopPlane, vOrientation, vOrigin );
3113 TopPlane = XMPlaneNormalize( TopPlane );
3114
3115 XMVECTOR BottomPlane = XMVectorSet( 0.0f, -1.0f, BottomSlope, 0.0f );
3116 BottomPlane = DirectX::Internal::XMPlaneTransform( BottomPlane, vOrientation, vOrigin );
3117 BottomPlane = XMPlaneNormalize( BottomPlane );
3118
3119 return box.ContainedBy( NearPlane, FarPlane, RightPlane, LeftPlane, TopPlane, BottomPlane );
3120}
3121
3122
3123//-----------------------------------------------------------------------------
3124_Use_decl_annotations_
3125inline ContainmentType BoundingFrustum::Contains( const BoundingFrustum& fr ) const
3126{
3127 // Load origin and orientation of the frustum.
3128 XMVECTOR vOrigin = XMLoadFloat3( &Origin );
3129 XMVECTOR vOrientation = XMLoadFloat4( &Orientation );
3130
3131 // Create 6 planes (do it inline to encourage use of registers)
3132 XMVECTOR NearPlane = XMVectorSet( 0.0f, 0.0f, -1.0f, Near );
3133 NearPlane = DirectX::Internal::XMPlaneTransform( NearPlane, vOrientation, vOrigin );
3134 NearPlane = XMPlaneNormalize( NearPlane );
3135
3136 XMVECTOR FarPlane = XMVectorSet( 0.0f, 0.0f, 1.0f, -Far );
3137 FarPlane = DirectX::Internal::XMPlaneTransform( FarPlane, vOrientation, vOrigin );
3138 FarPlane = XMPlaneNormalize( FarPlane );
3139
3140 XMVECTOR RightPlane = XMVectorSet( 1.0f, 0.0f, -RightSlope, 0.0f );
3141 RightPlane = DirectX::Internal::XMPlaneTransform( RightPlane, vOrientation, vOrigin );
3142 RightPlane = XMPlaneNormalize( RightPlane );
3143
3144 XMVECTOR LeftPlane = XMVectorSet( -1.0f, 0.0f, LeftSlope, 0.0f );
3145 LeftPlane = DirectX::Internal::XMPlaneTransform( LeftPlane, vOrientation, vOrigin );
3146 LeftPlane = XMPlaneNormalize( LeftPlane );
3147
3148 XMVECTOR TopPlane = XMVectorSet( 0.0f, 1.0f, -TopSlope, 0.0f );
3149 TopPlane = DirectX::Internal::XMPlaneTransform( TopPlane, vOrientation, vOrigin );
3150 TopPlane = XMPlaneNormalize( TopPlane );
3151
3152 XMVECTOR BottomPlane = XMVectorSet( 0.0f, -1.0f, BottomSlope, 0.0f );
3153 BottomPlane = DirectX::Internal::XMPlaneTransform( BottomPlane, vOrientation, vOrigin );
3154 BottomPlane = XMPlaneNormalize( BottomPlane );
3155
3156 return fr.ContainedBy( NearPlane, FarPlane, RightPlane, LeftPlane, TopPlane, BottomPlane );
3157}
3158
3159
3160//-----------------------------------------------------------------------------
3161// Exact sphere vs frustum test. The algorithm first checks the sphere against
3162// the planes of the frustum, then if the plane checks were indeterminate finds
3163// the nearest feature (plane, line, point) on the frustum to the center of the
3164// sphere and compares the distance to the nearest feature to the radius of the
3165// sphere
3166//-----------------------------------------------------------------------------
3167_Use_decl_annotations_
3168inline bool BoundingFrustum::Intersects( const BoundingSphere& sh ) const
3169{
3170 XMVECTOR Zero = XMVectorZero();
3171
3172 // Build the frustum planes.
3173 XMVECTOR Planes[6];
3174 Planes[0] = XMVectorSet( 0.0f, 0.0f, -1.0f, Near );
3175 Planes[1] = XMVectorSet( 0.0f, 0.0f, 1.0f, -Far );
3176 Planes[2] = XMVectorSet( 1.0f, 0.0f, -RightSlope, 0.0f );
3177 Planes[3] = XMVectorSet( -1.0f, 0.0f, LeftSlope, 0.0f );
3178 Planes[4] = XMVectorSet( 0.0f, 1.0f, -TopSlope, 0.0f );
3179 Planes[5] = XMVectorSet( 0.0f, -1.0f, BottomSlope, 0.0f );
3180
3181 // Normalize the planes so we can compare to the sphere radius.
3182 Planes[2] = XMVector3Normalize( Planes[2] );
3183 Planes[3] = XMVector3Normalize( Planes[3] );
3184 Planes[4] = XMVector3Normalize( Planes[4] );
3185 Planes[5] = XMVector3Normalize( Planes[5] );
3186
3187 // Load origin and orientation of the frustum.
3188 XMVECTOR vOrigin = XMLoadFloat3( &Origin );
3189 XMVECTOR vOrientation = XMLoadFloat4( &Orientation );
3190
3191 assert( DirectX::Internal::XMQuaternionIsUnit( vOrientation ) );
3192
3193 // Load the sphere.
3194 XMVECTOR vCenter = XMLoadFloat3( &sh.Center );
3195 XMVECTOR vRadius = XMVectorReplicatePtr( &sh.Radius );
3196
3197 // Transform the center of the sphere into the local space of frustum.
3198 vCenter = XMVector3InverseRotate( vCenter - vOrigin, vOrientation );
3199
3200 // Set w of the center to one so we can dot4 with the plane.
3201 vCenter = XMVectorInsert<0, 0, 0, 0, 1>( vCenter, XMVectorSplatOne() );
3202
3203 // Check against each plane of the frustum.
3204 XMVECTOR Outside = XMVectorFalseInt();
3205 XMVECTOR InsideAll = XMVectorTrueInt();
3206 XMVECTOR CenterInsideAll = XMVectorTrueInt();
3207
3208 XMVECTOR Dist[6];
3209
3210 for( size_t i = 0; i < 6; ++i )
3211 {
3212 Dist[i] = XMVector4Dot( vCenter, Planes[i] );
3213
3214 // Outside the plane?
3215 Outside = XMVectorOrInt( Outside, XMVectorGreater( Dist[i], vRadius ) );
3216
3217 // Fully inside the plane?
3218 InsideAll = XMVectorAndInt( InsideAll, XMVectorLessOrEqual( Dist[i], -vRadius ) );
3219
3220 // Check if the center is inside the plane.
3221 CenterInsideAll = XMVectorAndInt( CenterInsideAll, XMVectorLessOrEqual( Dist[i], Zero ) );
3222 }
3223
3224 // If the sphere is outside any of the planes it is outside.
3225 if ( XMVector4EqualInt( Outside, XMVectorTrueInt() ) )
3226 return false;
3227
3228 // If the sphere is inside all planes it is fully inside.
3229 if ( XMVector4EqualInt( InsideAll, XMVectorTrueInt() ) )
3230 return true;
3231
3232 // If the center of the sphere is inside all planes and the sphere intersects
3233 // one or more planes then it must intersect.
3234 if ( XMVector4EqualInt( CenterInsideAll, XMVectorTrueInt() ) )
3235 return true;
3236
3237 // The sphere may be outside the frustum or intersecting the frustum.
3238 // Find the nearest feature (face, edge, or corner) on the frustum
3239 // to the sphere.
3240
3241 // The faces adjacent to each face are:
3242 static const size_t adjacent_faces[6][4] =
3243 {
3244 { 2, 3, 4, 5 }, // 0
3245 { 2, 3, 4, 5 }, // 1
3246 { 0, 1, 4, 5 }, // 2
3247 { 0, 1, 4, 5 }, // 3
3248 { 0, 1, 2, 3 }, // 4
3249 { 0, 1, 2, 3 }
3250 }; // 5
3251
3252 XMVECTOR Intersects = XMVectorFalseInt();
3253
3254 // Check to see if the nearest feature is one of the planes.
3255 for( size_t i = 0; i < 6; ++i )
3256 {
3257 // Find the nearest point on the plane to the center of the sphere.
3258 XMVECTOR Point = vCenter - (Planes[i] * Dist[i]);
3259
3260 // Set w of the point to one.
3261 Point = XMVectorInsert<0, 0, 0, 0, 1>( Point, XMVectorSplatOne() );
3262
3263 // If the point is inside the face (inside the adjacent planes) then
3264 // this plane is the nearest feature.
3265 XMVECTOR InsideFace = XMVectorTrueInt();
3266
3267 for ( size_t j = 0; j < 4; j++ )
3268 {
3269 size_t plane_index = adjacent_faces[i][j];
3270
3271 InsideFace = XMVectorAndInt( InsideFace,
3272 XMVectorLessOrEqual( XMVector4Dot( Point, Planes[plane_index] ), Zero ) );
3273 }
3274
3275 // Since we have already checked distance from the plane we know that the
3276 // sphere must intersect if this plane is the nearest feature.
3277 Intersects = XMVectorOrInt( Intersects,
3278 XMVectorAndInt( XMVectorGreater( Dist[i], Zero ), InsideFace ) );
3279 }
3280
3281 if ( XMVector4EqualInt( Intersects, XMVectorTrueInt() ) )
3282 return true;
3283
3284 // Build the corners of the frustum.
3285 XMVECTOR vRightTop = XMVectorSet( RightSlope, TopSlope, 1.0f, 0.0f );
3286 XMVECTOR vRightBottom = XMVectorSet( RightSlope, BottomSlope, 1.0f, 0.0f );
3287 XMVECTOR vLeftTop = XMVectorSet( LeftSlope, TopSlope, 1.0f, 0.0f );
3288 XMVECTOR vLeftBottom = XMVectorSet( LeftSlope, BottomSlope, 1.0f, 0.0f );
3289 XMVECTOR vNear = XMVectorReplicatePtr( &Near );
3290 XMVECTOR vFar = XMVectorReplicatePtr( &Far );
3291
3292 XMVECTOR Corners[CORNER_COUNT];
3293 Corners[0] = vRightTop * vNear;
3294 Corners[1] = vRightBottom * vNear;
3295 Corners[2] = vLeftTop * vNear;
3296 Corners[3] = vLeftBottom * vNear;
3297 Corners[4] = vRightTop * vFar;
3298 Corners[5] = vRightBottom * vFar;
3299 Corners[6] = vLeftTop * vFar;
3300 Corners[7] = vLeftBottom * vFar;
3301
3302 // The Edges are:
3303 static const size_t edges[12][2] =
3304 {
3305 { 0, 1 }, { 2, 3 }, { 0, 2 }, { 1, 3 }, // Near plane
3306 { 4, 5 }, { 6, 7 }, { 4, 6 }, { 5, 7 }, // Far plane
3307 { 0, 4 }, { 1, 5 }, { 2, 6 }, { 3, 7 },
3308 }; // Near to far
3309
3310 XMVECTOR RadiusSq = vRadius * vRadius;
3311
3312 // Check to see if the nearest feature is one of the edges (or corners).
3313 for( size_t i = 0; i < 12; ++i )
3314 {
3315 size_t ei0 = edges[i][0];
3316 size_t ei1 = edges[i][1];
3317
3318 // Find the nearest point on the edge to the center of the sphere.
3319 // The corners of the frustum are included as the endpoints of the edges.
3320 XMVECTOR Point = DirectX::Internal::PointOnLineSegmentNearestPoint( Corners[ei0], Corners[ei1], vCenter );
3321
3322 XMVECTOR Delta = vCenter - Point;
3323
3324 XMVECTOR DistSq = XMVector3Dot( Delta, Delta );
3325
3326 // If the distance to the center of the sphere to the point is less than
3327 // the radius of the sphere then it must intersect.
3328 Intersects = XMVectorOrInt( Intersects, XMVectorLessOrEqual( DistSq, RadiusSq ) );
3329 }
3330
3331 if ( XMVector4EqualInt( Intersects, XMVectorTrueInt() ) )
3332 return true;
3333
3334 // The sphere must be outside the frustum.
3335 return false;
3336}
3337
3338
3339//-----------------------------------------------------------------------------
3340// Exact axis aligned box vs frustum test. Constructs an oriented box and uses
3341// the oriented box vs frustum test.
3342//-----------------------------------------------------------------------------
3343_Use_decl_annotations_
3344inline bool BoundingFrustum::Intersects( const BoundingBox& box ) const
3345{
3346 // Make the axis aligned box oriented and do an OBB vs frustum test.
3347 BoundingOrientedBox obox( box.Center, box.Extents, XMFLOAT4( 0.f, 0.f, 0.f, 1.f ) );
3348 return Intersects( obox );
3349}
3350
3351
3352//-----------------------------------------------------------------------------
3353// Exact oriented box vs frustum test.
3354//-----------------------------------------------------------------------------
3355_Use_decl_annotations_
3356inline bool BoundingFrustum::Intersects( const BoundingOrientedBox& box ) const
3357{
3358 static const XMVECTORI32 SelectY =
3359 {
3360 XM_SELECT_0, XM_SELECT_1, XM_SELECT_0, XM_SELECT_0
3361 };
3362 static const XMVECTORI32 SelectZ =
3363 {
3364 XM_SELECT_0, XM_SELECT_0, XM_SELECT_1, XM_SELECT_0
3365 };
3366
3367 XMVECTOR Zero = XMVectorZero();
3368
3369 // Build the frustum planes.
3370 XMVECTOR Planes[6];
3371 Planes[0] = XMVectorSet( 0.0f, 0.0f, -1.0f, Near );
3372 Planes[1] = XMVectorSet( 0.0f, 0.0f, 1.0f, -Far );
3373 Planes[2] = XMVectorSet( 1.0f, 0.0f, -RightSlope, 0.0f );
3374 Planes[3] = XMVectorSet( -1.0f, 0.0f, LeftSlope, 0.0f );
3375 Planes[4] = XMVectorSet( 0.0f, 1.0f, -TopSlope, 0.0f );
3376 Planes[5] = XMVectorSet( 0.0f, -1.0f, BottomSlope, 0.0f );
3377
3378 // Load origin and orientation of the frustum.
3379 XMVECTOR vOrigin = XMLoadFloat3( &Origin );
3380 XMVECTOR FrustumOrientation = XMLoadFloat4( &Orientation );
3381
3382 assert( DirectX::Internal::XMQuaternionIsUnit( FrustumOrientation ) );
3383
3384 // Load the box.
3385 XMVECTOR Center = XMLoadFloat3( &box.Center );
3386 XMVECTOR Extents = XMLoadFloat3( &box.Extents );
3387 XMVECTOR BoxOrientation = XMLoadFloat4( &box.Orientation );
3388
3389 assert( DirectX::Internal::XMQuaternionIsUnit( BoxOrientation ) );
3390
3391 // Transform the oriented box into the space of the frustum in order to
3392 // minimize the number of transforms we have to do.
3393 Center = XMVector3InverseRotate( Center - vOrigin, FrustumOrientation );
3394 BoxOrientation = XMQuaternionMultiply( BoxOrientation, XMQuaternionConjugate( FrustumOrientation ) );
3395
3396 // Set w of the center to one so we can dot4 with the plane.
3397 Center = XMVectorInsert<0, 0, 0, 0, 1>( Center, XMVectorSplatOne() );
3398
3399 // Build the 3x3 rotation matrix that defines the box axes.
3400 XMMATRIX R = XMMatrixRotationQuaternion( BoxOrientation );
3401
3402 // Check against each plane of the frustum.
3403 XMVECTOR Outside = XMVectorFalseInt();
3404 XMVECTOR InsideAll = XMVectorTrueInt();
3405 XMVECTOR CenterInsideAll = XMVectorTrueInt();
3406
3407 for( size_t i = 0; i < 6; ++i )
3408 {
3409 // Compute the distance to the center of the box.
3410 XMVECTOR Dist = XMVector4Dot( Center, Planes[i] );
3411
3412 // Project the axes of the box onto the normal of the plane. Half the
3413 // length of the projection (sometime called the "radius") is equal to
3414 // h(u) * abs(n dot b(u))) + h(v) * abs(n dot b(v)) + h(w) * abs(n dot b(w))
3415 // where h(i) are extents of the box, n is the plane normal, and b(i) are the
3416 // axes of the box.
3417 XMVECTOR Radius = XMVector3Dot( Planes[i], R.r[0] );
3418 Radius = XMVectorSelect( Radius, XMVector3Dot( Planes[i], R.r[1] ), SelectY );
3419 Radius = XMVectorSelect( Radius, XMVector3Dot( Planes[i], R.r[2] ), SelectZ );
3420 Radius = XMVector3Dot( Extents, XMVectorAbs( Radius ) );
3421
3422 // Outside the plane?
3423 Outside = XMVectorOrInt( Outside, XMVectorGreater( Dist, Radius ) );
3424
3425 // Fully inside the plane?
3426 InsideAll = XMVectorAndInt( InsideAll, XMVectorLessOrEqual( Dist, -Radius ) );
3427
3428 // Check if the center is inside the plane.
3429 CenterInsideAll = XMVectorAndInt( CenterInsideAll, XMVectorLessOrEqual( Dist, Zero ) );
3430 }
3431
3432 // If the box is outside any of the planes it is outside.
3433 if ( XMVector4EqualInt( Outside, XMVectorTrueInt() ) )
3434 return false;
3435
3436 // If the box is inside all planes it is fully inside.
3437 if ( XMVector4EqualInt( InsideAll, XMVectorTrueInt() ) )
3438 return true;
3439
3440 // If the center of the box is inside all planes and the box intersects
3441 // one or more planes then it must intersect.
3442 if ( XMVector4EqualInt( CenterInsideAll, XMVectorTrueInt() ) )
3443 return true;
3444
3445 // Build the corners of the frustum.
3446 XMVECTOR vRightTop = XMVectorSet( RightSlope, TopSlope, 1.0f, 0.0f );
3447 XMVECTOR vRightBottom = XMVectorSet( RightSlope, BottomSlope, 1.0f, 0.0f );
3448 XMVECTOR vLeftTop = XMVectorSet( LeftSlope, TopSlope, 1.0f, 0.0f );
3449 XMVECTOR vLeftBottom = XMVectorSet( LeftSlope, BottomSlope, 1.0f, 0.0f );
3450 XMVECTOR vNear = XMVectorReplicatePtr( &Near );
3451 XMVECTOR vFar = XMVectorReplicatePtr( &Far );
3452
3453 XMVECTOR Corners[CORNER_COUNT];
3454 Corners[0] = vRightTop * vNear;
3455 Corners[1] = vRightBottom * vNear;
3456 Corners[2] = vLeftTop * vNear;
3457 Corners[3] = vLeftBottom * vNear;
3458 Corners[4] = vRightTop * vFar;
3459 Corners[5] = vRightBottom * vFar;
3460 Corners[6] = vLeftTop * vFar;
3461 Corners[7] = vLeftBottom * vFar;
3462
3463 // Test against box axes (3)
3464 {
3465 // Find the min/max values of the projection of the frustum onto each axis.
3466 XMVECTOR FrustumMin, FrustumMax;
3467
3468 FrustumMin = XMVector3Dot( Corners[0], R.r[0] );
3469 FrustumMin = XMVectorSelect( FrustumMin, XMVector3Dot( Corners[0], R.r[1] ), SelectY );
3470 FrustumMin = XMVectorSelect( FrustumMin, XMVector3Dot( Corners[0], R.r[2] ), SelectZ );
3471 FrustumMax = FrustumMin;
3472
3473 for( size_t i = 1; i < BoundingOrientedBox::CORNER_COUNT; ++i )
3474 {
3475 XMVECTOR Temp = XMVector3Dot( Corners[i], R.r[0] );
3476 Temp = XMVectorSelect( Temp, XMVector3Dot( Corners[i], R.r[1] ), SelectY );
3477 Temp = XMVectorSelect( Temp, XMVector3Dot( Corners[i], R.r[2] ), SelectZ );
3478
3479 FrustumMin = XMVectorMin( FrustumMin, Temp );
3480 FrustumMax = XMVectorMax( FrustumMax, Temp );
3481 }
3482
3483 // Project the center of the box onto the axes.
3484 XMVECTOR BoxDist = XMVector3Dot( Center, R.r[0] );
3485 BoxDist = XMVectorSelect( BoxDist, XMVector3Dot( Center, R.r[1] ), SelectY );
3486 BoxDist = XMVectorSelect( BoxDist, XMVector3Dot( Center, R.r[2] ), SelectZ );
3487
3488 // The projection of the box onto the axis is just its Center and Extents.
3489 // if (min > box_max || max < box_min) reject;
3490 XMVECTOR Result = XMVectorOrInt( XMVectorGreater( FrustumMin, BoxDist + Extents ),
3491 XMVectorLess( FrustumMax, BoxDist - Extents ) );
3492
3493 if( DirectX::Internal::XMVector3AnyTrue( Result ) )
3494 return false;
3495 }
3496
3497 // Test against edge/edge axes (3*6).
3498 XMVECTOR FrustumEdgeAxis[6];
3499
3500 FrustumEdgeAxis[0] = vRightTop;
3501 FrustumEdgeAxis[1] = vRightBottom;
3502 FrustumEdgeAxis[2] = vLeftTop;
3503 FrustumEdgeAxis[3] = vLeftBottom;
3504 FrustumEdgeAxis[4] = vRightTop - vLeftTop;
3505 FrustumEdgeAxis[5] = vLeftBottom - vLeftTop;
3506
3507 for( size_t i = 0; i < 3; ++i )
3508 {
3509 for( size_t j = 0; j < 6; j++ )
3510 {
3511 // Compute the axis we are going to test.
3512 XMVECTOR Axis = XMVector3Cross( R.r[i], FrustumEdgeAxis[j] );
3513
3514 // Find the min/max values of the projection of the frustum onto the axis.
3515 XMVECTOR FrustumMin, FrustumMax;
3516
3517 FrustumMin = FrustumMax = XMVector3Dot( Axis, Corners[0] );
3518
3519 for( size_t k = 1; k < CORNER_COUNT; k++ )
3520 {
3521 XMVECTOR Temp = XMVector3Dot( Axis, Corners[k] );
3522 FrustumMin = XMVectorMin( FrustumMin, Temp );
3523 FrustumMax = XMVectorMax( FrustumMax, Temp );
3524 }
3525
3526 // Project the center of the box onto the axis.
3527 XMVECTOR Dist = XMVector3Dot( Center, Axis );
3528
3529 // Project the axes of the box onto the axis to find the "radius" of the box.
3530 XMVECTOR Radius = XMVector3Dot( Axis, R.r[0] );
3531 Radius = XMVectorSelect( Radius, XMVector3Dot( Axis, R.r[1] ), SelectY );
3532 Radius = XMVectorSelect( Radius, XMVector3Dot( Axis, R.r[2] ), SelectZ );
3533 Radius = XMVector3Dot( Extents, XMVectorAbs( Radius ) );
3534
3535 // if (center > max + radius || center < min - radius) reject;
3536 Outside = XMVectorOrInt( Outside, XMVectorGreater( Dist, FrustumMax + Radius ) );
3537 Outside = XMVectorOrInt( Outside, XMVectorLess( Dist, FrustumMin - Radius ) );
3538 }
3539 }
3540
3541 if ( XMVector4EqualInt( Outside, XMVectorTrueInt() ) )
3542 return false;
3543
3544 // If we did not find a separating plane then the box must intersect the frustum.
3545 return true;
3546}
3547
3548
3549//-----------------------------------------------------------------------------
3550// Exact frustum vs frustum test.
3551//-----------------------------------------------------------------------------
3552_Use_decl_annotations_
3553inline bool BoundingFrustum::Intersects( const BoundingFrustum& fr ) const
3554{
3555 // Load origin and orientation of frustum B.
3556 XMVECTOR OriginB = XMLoadFloat3( &Origin );
3557 XMVECTOR OrientationB = XMLoadFloat4( &Orientation );
3558
3559 assert( DirectX::Internal::XMQuaternionIsUnit( OrientationB ) );
3560
3561 // Build the planes of frustum B.
3562 XMVECTOR AxisB[6];
3563 AxisB[0] = XMVectorSet( 0.0f, 0.0f, -1.0f, 0.0f );
3564 AxisB[1] = XMVectorSet( 0.0f, 0.0f, 1.0f, 0.0f );
3565 AxisB[2] = XMVectorSet( 1.0f, 0.0f, -RightSlope, 0.0f );
3566 AxisB[3] = XMVectorSet( -1.0f, 0.0f, LeftSlope, 0.0f );
3567 AxisB[4] = XMVectorSet( 0.0f, 1.0f, -TopSlope, 0.0f );
3568 AxisB[5] = XMVectorSet( 0.0f, -1.0f, BottomSlope, 0.0f );
3569
3570 XMVECTOR PlaneDistB[6];
3571 PlaneDistB[0] = -XMVectorReplicatePtr( &Near );
3572 PlaneDistB[1] = XMVectorReplicatePtr( &Far );
3573 PlaneDistB[2] = XMVectorZero();
3574 PlaneDistB[3] = XMVectorZero();
3575 PlaneDistB[4] = XMVectorZero();
3576 PlaneDistB[5] = XMVectorZero();
3577
3578 // Load origin and orientation of frustum A.
3579 XMVECTOR OriginA = XMLoadFloat3( &fr.Origin );
3580 XMVECTOR OrientationA = XMLoadFloat4( &fr.Orientation );
3581
3582 assert( DirectX::Internal::XMQuaternionIsUnit( OrientationA ) );
3583
3584 // Transform frustum A into the space of the frustum B in order to
3585 // minimize the number of transforms we have to do.
3586 OriginA = XMVector3InverseRotate( OriginA - OriginB, OrientationB );
3587 OrientationA = XMQuaternionMultiply( OrientationA, XMQuaternionConjugate( OrientationB ) );
3588
3589 // Build the corners of frustum A (in the local space of B).
3590 XMVECTOR RightTopA = XMVectorSet( fr.RightSlope, fr.TopSlope, 1.0f, 0.0f );
3591 XMVECTOR RightBottomA = XMVectorSet( fr.RightSlope, fr.BottomSlope, 1.0f, 0.0f );
3592 XMVECTOR LeftTopA = XMVectorSet(fr.LeftSlope,fr.TopSlope, 1.0f, 0.0f );
3593 XMVECTOR LeftBottomA = XMVectorSet( fr.LeftSlope, fr.BottomSlope, 1.0f, 0.0f );
3594 XMVECTOR NearA = XMVectorReplicatePtr( &fr.Near );
3595 XMVECTOR FarA = XMVectorReplicatePtr( &fr.Far );
3596
3597 RightTopA = XMVector3Rotate( RightTopA, OrientationA );
3598 RightBottomA = XMVector3Rotate( RightBottomA, OrientationA );
3599 LeftTopA = XMVector3Rotate( LeftTopA, OrientationA );
3600 LeftBottomA = XMVector3Rotate( LeftBottomA, OrientationA );
3601
3602 XMVECTOR CornersA[CORNER_COUNT];
3603 CornersA[0] = OriginA + RightTopA * NearA;
3604 CornersA[1] = OriginA + RightBottomA * NearA;
3605 CornersA[2] = OriginA + LeftTopA * NearA;
3606 CornersA[3] = OriginA + LeftBottomA * NearA;
3607 CornersA[4] = OriginA + RightTopA * FarA;
3608 CornersA[5] = OriginA + RightBottomA * FarA;
3609 CornersA[6] = OriginA + LeftTopA * FarA;
3610 CornersA[7] = OriginA + LeftBottomA * FarA;
3611
3612 // Check frustum A against each plane of frustum B.
3613 XMVECTOR Outside = XMVectorFalseInt();
3614 XMVECTOR InsideAll = XMVectorTrueInt();
3615
3616 for( size_t i = 0; i < 6; ++i )
3617 {
3618 // Find the min/max projection of the frustum onto the plane normal.
3619 XMVECTOR Min, Max;
3620
3621 Min = Max = XMVector3Dot( AxisB[i], CornersA[0] );
3622
3623 for( size_t j = 1; j < CORNER_COUNT; j++ )
3624 {
3625 XMVECTOR Temp = XMVector3Dot( AxisB[i], CornersA[j] );
3626 Min = XMVectorMin( Min, Temp );
3627 Max = XMVectorMax( Max, Temp );
3628 }
3629
3630 // Outside the plane?
3631 Outside = XMVectorOrInt( Outside, XMVectorGreater( Min, PlaneDistB[i] ) );
3632
3633 // Fully inside the plane?
3634 InsideAll = XMVectorAndInt( InsideAll, XMVectorLessOrEqual( Max, PlaneDistB[i] ) );
3635 }
3636
3637 // If the frustum A is outside any of the planes of frustum B it is outside.
3638 if ( XMVector4EqualInt( Outside, XMVectorTrueInt() ) )
3639 return false;
3640
3641 // If frustum A is inside all planes of frustum B it is fully inside.
3642 if ( XMVector4EqualInt( InsideAll, XMVectorTrueInt() ) )
3643 return true;
3644
3645 // Build the corners of frustum B.
3646 XMVECTOR RightTopB = XMVectorSet( RightSlope, TopSlope, 1.0f, 0.0f );
3647 XMVECTOR RightBottomB = XMVectorSet( RightSlope, BottomSlope, 1.0f, 0.0f );
3648 XMVECTOR LeftTopB = XMVectorSet( LeftSlope, TopSlope, 1.0f, 0.0f );
3649 XMVECTOR LeftBottomB = XMVectorSet( LeftSlope, BottomSlope, 1.0f, 0.0f );
3650 XMVECTOR NearB = XMVectorReplicatePtr( &Near );
3651 XMVECTOR FarB = XMVectorReplicatePtr( &Far );
3652
3653 XMVECTOR CornersB[BoundingFrustum::CORNER_COUNT];
3654 CornersB[0] = RightTopB * NearB;
3655 CornersB[1] = RightBottomB * NearB;
3656 CornersB[2] = LeftTopB * NearB;
3657 CornersB[3] = LeftBottomB * NearB;
3658 CornersB[4] = RightTopB * FarB;
3659 CornersB[5] = RightBottomB * FarB;
3660 CornersB[6] = LeftTopB * FarB;
3661 CornersB[7] = LeftBottomB * FarB;
3662
3663 // Build the planes of frustum A (in the local space of B).
3664 XMVECTOR AxisA[6];
3665 XMVECTOR PlaneDistA[6];
3666
3667 AxisA[0] = XMVectorSet( 0.0f, 0.0f, -1.0f, 0.0f );
3668 AxisA[1] = XMVectorSet( 0.0f, 0.0f, 1.0f, 0.0f );
3669 AxisA[2] = XMVectorSet( 1.0f, 0.0f, -fr.RightSlope, 0.0f );
3670 AxisA[3] = XMVectorSet( -1.0f, 0.0f, fr.LeftSlope, 0.0f );
3671 AxisA[4] = XMVectorSet( 0.0f, 1.0f, -fr.TopSlope, 0.0f );
3672 AxisA[5] = XMVectorSet( 0.0f, -1.0f, fr.BottomSlope, 0.0f );
3673
3674 AxisA[0] = XMVector3Rotate( AxisA[0], OrientationA );
3675 AxisA[1] = -AxisA[0];
3676 AxisA[2] = XMVector3Rotate( AxisA[2], OrientationA );
3677 AxisA[3] = XMVector3Rotate( AxisA[3], OrientationA );
3678 AxisA[4] = XMVector3Rotate( AxisA[4], OrientationA );
3679 AxisA[5] = XMVector3Rotate( AxisA[5], OrientationA );
3680
3681 PlaneDistA[0] = XMVector3Dot( AxisA[0], CornersA[0] ); // Re-use corner on near plane.
3682 PlaneDistA[1] = XMVector3Dot( AxisA[1], CornersA[4] ); // Re-use corner on far plane.
3683 PlaneDistA[2] = XMVector3Dot( AxisA[2], OriginA );
3684 PlaneDistA[3] = XMVector3Dot( AxisA[3], OriginA );
3685 PlaneDistA[4] = XMVector3Dot( AxisA[4], OriginA );
3686 PlaneDistA[5] = XMVector3Dot( AxisA[5], OriginA );
3687
3688 // Check each axis of frustum A for a seperating plane (5).
3689 for( size_t i = 0; i < 6; ++i )
3690 {
3691 // Find the minimum projection of the frustum onto the plane normal.
3692 XMVECTOR Min;
3693
3694 Min = XMVector3Dot( AxisA[i], CornersB[0] );
3695
3696 for( size_t j = 1; j < CORNER_COUNT; j++ )
3697 {
3698 XMVECTOR Temp = XMVector3Dot( AxisA[i], CornersB[j] );
3699 Min = XMVectorMin( Min, Temp );
3700 }
3701
3702 // Outside the plane?
3703 Outside = XMVectorOrInt( Outside, XMVectorGreater( Min, PlaneDistA[i] ) );
3704 }
3705
3706 // If the frustum B is outside any of the planes of frustum A it is outside.
3707 if ( XMVector4EqualInt( Outside, XMVectorTrueInt() ) )
3708 return false;
3709
3710 // Check edge/edge axes (6 * 6).
3711 XMVECTOR FrustumEdgeAxisA[6];
3712 FrustumEdgeAxisA[0] = RightTopA;
3713 FrustumEdgeAxisA[1] = RightBottomA;
3714 FrustumEdgeAxisA[2] = LeftTopA;
3715 FrustumEdgeAxisA[3] = LeftBottomA;
3716 FrustumEdgeAxisA[4] = RightTopA - LeftTopA;
3717 FrustumEdgeAxisA[5] = LeftBottomA - LeftTopA;
3718
3719 XMVECTOR FrustumEdgeAxisB[6];
3720 FrustumEdgeAxisB[0] = RightTopB;
3721 FrustumEdgeAxisB[1] = RightBottomB;
3722 FrustumEdgeAxisB[2] = LeftTopB;
3723 FrustumEdgeAxisB[3] = LeftBottomB;
3724 FrustumEdgeAxisB[4] = RightTopB - LeftTopB;
3725 FrustumEdgeAxisB[5] = LeftBottomB - LeftTopB;
3726
3727 for( size_t i = 0; i < 6; ++i )
3728 {
3729 for( size_t j = 0; j < 6; j++ )
3730 {
3731 // Compute the axis we are going to test.
3732 XMVECTOR Axis = XMVector3Cross( FrustumEdgeAxisA[i], FrustumEdgeAxisB[j] );
3733
3734 // Find the min/max values of the projection of both frustums onto the axis.
3735 XMVECTOR MinA, MaxA;
3736 XMVECTOR MinB, MaxB;
3737
3738 MinA = MaxA = XMVector3Dot( Axis, CornersA[0] );
3739 MinB = MaxB = XMVector3Dot( Axis, CornersB[0] );
3740
3741 for( size_t k = 1; k < CORNER_COUNT; k++ )
3742 {
3743 XMVECTOR TempA = XMVector3Dot( Axis, CornersA[k] );
3744 MinA = XMVectorMin( MinA, TempA );
3745 MaxA = XMVectorMax( MaxA, TempA );
3746
3747 XMVECTOR TempB = XMVector3Dot( Axis, CornersB[k] );
3748 MinB = XMVectorMin( MinB, TempB );
3749 MaxB = XMVectorMax( MaxB, TempB );
3750 }
3751
3752 // if (MinA > MaxB || MinB > MaxA) reject
3753 Outside = XMVectorOrInt( Outside, XMVectorGreater( MinA, MaxB ) );
3754 Outside = XMVectorOrInt( Outside, XMVectorGreater( MinB, MaxA ) );
3755 }
3756 }
3757
3758 // If there is a seperating plane, then the frustums do not intersect.
3759 if ( XMVector4EqualInt( Outside, XMVectorTrueInt() ) )
3760 return false;
3761
3762 // If we did not find a separating plane then the frustums intersect.
3763 return true;
3764}
3765
3766
3767//-----------------------------------------------------------------------------
3768// Triangle vs frustum test.
3769//-----------------------------------------------------------------------------
3770_Use_decl_annotations_
3771inline bool BoundingFrustum::Intersects( FXMVECTOR V0, FXMVECTOR V1, FXMVECTOR V2 ) const
3772{
3773 // Build the frustum planes (NOTE: D is negated from the usual).
3774 XMVECTOR Planes[6];
3775 Planes[0] = XMVectorSet( 0.0f, 0.0f, -1.0f, -Near );
3776 Planes[1] = XMVectorSet( 0.0f, 0.0f, 1.0f, Far );
3777 Planes[2] = XMVectorSet( 1.0f, 0.0f, -RightSlope, 0.0f );
3778 Planes[3] = XMVectorSet( -1.0f, 0.0f, LeftSlope, 0.0f );
3779 Planes[4] = XMVectorSet( 0.0f, 1.0f, -TopSlope, 0.0f );
3780 Planes[5] = XMVectorSet( 0.0f, -1.0f, BottomSlope, 0.0f );
3781
3782 // Load origin and orientation of the frustum.
3783 XMVECTOR vOrigin = XMLoadFloat3( &Origin );
3784 XMVECTOR vOrientation = XMLoadFloat4( &Orientation );
3785
3786 assert( DirectX::Internal::XMQuaternionIsUnit( vOrientation ) );
3787
3788 // Transform triangle into the local space of frustum.
3789 XMVECTOR TV0 = XMVector3InverseRotate( V0 - vOrigin, vOrientation );
3790 XMVECTOR TV1 = XMVector3InverseRotate( V1 - vOrigin, vOrientation );
3791 XMVECTOR TV2 = XMVector3InverseRotate( V2 - vOrigin, vOrientation );
3792
3793 // Test each vertex of the triangle against the frustum planes.
3794 XMVECTOR Outside = XMVectorFalseInt();
3795 XMVECTOR InsideAll = XMVectorTrueInt();
3796
3797 for( size_t i = 0; i < 6; ++i )
3798 {
3799 XMVECTOR Dist0 = XMVector3Dot( TV0, Planes[i] );
3800 XMVECTOR Dist1 = XMVector3Dot( TV1, Planes[i] );
3801 XMVECTOR Dist2 = XMVector3Dot( TV2, Planes[i] );
3802
3803 XMVECTOR MinDist = XMVectorMin( Dist0, Dist1 );
3804 MinDist = XMVectorMin( MinDist, Dist2 );
3805 XMVECTOR MaxDist = XMVectorMax( Dist0, Dist1 );
3806 MaxDist = XMVectorMax( MaxDist, Dist2 );
3807
3808 XMVECTOR PlaneDist = XMVectorSplatW( Planes[i] );
3809
3810 // Outside the plane?
3811 Outside = XMVectorOrInt( Outside, XMVectorGreater( MinDist, PlaneDist ) );
3812
3813 // Fully inside the plane?
3814 InsideAll = XMVectorAndInt( InsideAll, XMVectorLessOrEqual( MaxDist, PlaneDist ) );
3815 }
3816
3817 // If the triangle is outside any of the planes it is outside.
3818 if ( XMVector4EqualInt( Outside, XMVectorTrueInt() ) )
3819 return false;
3820
3821 // If the triangle is inside all planes it is fully inside.
3822 if ( XMVector4EqualInt( InsideAll, XMVectorTrueInt() ) )
3823 return true;
3824
3825 // Build the corners of the frustum.
3826 XMVECTOR vRightTop = XMVectorSet( RightSlope, TopSlope, 1.0f, 0.0f );
3827 XMVECTOR vRightBottom = XMVectorSet( RightSlope, BottomSlope, 1.0f, 0.0f );
3828 XMVECTOR vLeftTop = XMVectorSet( LeftSlope, TopSlope, 1.0f, 0.0f );
3829 XMVECTOR vLeftBottom = XMVectorSet( LeftSlope, BottomSlope, 1.0f, 0.0f );
3830 XMVECTOR vNear = XMVectorReplicatePtr( &Near );
3831 XMVECTOR vFar = XMVectorReplicatePtr( &Far );
3832
3833 XMVECTOR Corners[CORNER_COUNT];
3834 Corners[0] = vRightTop * vNear;
3835 Corners[1] = vRightBottom * vNear;
3836 Corners[2] = vLeftTop * vNear;
3837 Corners[3] = vLeftBottom * vNear;
3838 Corners[4] = vRightTop * vFar;
3839 Corners[5] = vRightBottom * vFar;
3840 Corners[6] = vLeftTop * vFar;
3841 Corners[7] = vLeftBottom * vFar;
3842
3843 // Test the plane of the triangle.
3844 XMVECTOR Normal = XMVector3Cross( V1 - V0, V2 - V0 );
3845 XMVECTOR Dist = XMVector3Dot( Normal, V0 );
3846
3847 XMVECTOR MinDist, MaxDist;
3848 MinDist = MaxDist = XMVector3Dot( Corners[0], Normal );
3849 for( size_t i = 1; i < CORNER_COUNT; ++i )
3850 {
3851 XMVECTOR Temp = XMVector3Dot( Corners[i], Normal );
3852 MinDist = XMVectorMin( MinDist, Temp );
3853 MaxDist = XMVectorMax( MaxDist, Temp );
3854 }
3855
3856 Outside = XMVectorOrInt( XMVectorGreater( MinDist, Dist ), XMVectorLess( MaxDist, Dist ) );
3857 if ( XMVector4EqualInt( Outside, XMVectorTrueInt() ) )
3858 return false;
3859
3860 // Check the edge/edge axes (3*6).
3861 XMVECTOR TriangleEdgeAxis[3];
3862 TriangleEdgeAxis[0] = V1 - V0;
3863 TriangleEdgeAxis[1] = V2 - V1;
3864 TriangleEdgeAxis[2] = V0 - V2;
3865
3866 XMVECTOR FrustumEdgeAxis[6];
3867 FrustumEdgeAxis[0] = vRightTop;
3868 FrustumEdgeAxis[1] = vRightBottom;
3869 FrustumEdgeAxis[2] = vLeftTop;
3870 FrustumEdgeAxis[3] = vLeftBottom;
3871 FrustumEdgeAxis[4] = vRightTop - vLeftTop;
3872 FrustumEdgeAxis[5] = vLeftBottom - vLeftTop;
3873
3874 for( size_t i = 0; i < 3; ++i )
3875 {
3876 for( size_t j = 0; j < 6; j++ )
3877 {
3878 // Compute the axis we are going to test.
3879 XMVECTOR Axis = XMVector3Cross( TriangleEdgeAxis[i], FrustumEdgeAxis[j] );
3880
3881 // Find the min/max of the projection of the triangle onto the axis.
3882 XMVECTOR MinA, MaxA;
3883
3884 XMVECTOR Dist0 = XMVector3Dot( V0, Axis );
3885 XMVECTOR Dist1 = XMVector3Dot( V1, Axis );
3886 XMVECTOR Dist2 = XMVector3Dot( V2, Axis );
3887
3888 MinA = XMVectorMin( Dist0, Dist1 );
3889 MinA = XMVectorMin( MinA, Dist2 );
3890 MaxA = XMVectorMax( Dist0, Dist1 );
3891 MaxA = XMVectorMax( MaxA, Dist2 );
3892
3893 // Find the min/max of the projection of the frustum onto the axis.
3894 XMVECTOR MinB, MaxB;
3895
3896 MinB = MaxB = XMVector3Dot( Axis, Corners[0] );
3897
3898 for( size_t k = 1; k < CORNER_COUNT; k++ )
3899 {
3900 XMVECTOR Temp = XMVector3Dot( Axis, Corners[k] );
3901 MinB = XMVectorMin( MinB, Temp );
3902 MaxB = XMVectorMax( MaxB, Temp );
3903 }
3904
3905 // if (MinA > MaxB || MinB > MaxA) reject;
3906 Outside = XMVectorOrInt( Outside, XMVectorGreater( MinA, MaxB ) );
3907 Outside = XMVectorOrInt( Outside, XMVectorGreater( MinB, MaxA ) );
3908 }
3909 }
3910
3911 if ( XMVector4EqualInt( Outside, XMVectorTrueInt() ) )
3912 return false;
3913
3914 // If we did not find a separating plane then the triangle must intersect the frustum.
3915 return true;
3916}
3917
3918
3919//-----------------------------------------------------------------------------
3920_Use_decl_annotations_
3921inline PlaneIntersectionType BoundingFrustum::Intersects( FXMVECTOR Plane ) const
3922{
3923 assert( DirectX::Internal::XMPlaneIsUnit( Plane ) );
3924
3925 // Load origin and orientation of the frustum.
3926 XMVECTOR vOrigin = XMLoadFloat3( &Origin );
3927 XMVECTOR vOrientation = XMLoadFloat4( &Orientation );
3928
3929 assert( DirectX::Internal::XMQuaternionIsUnit( vOrientation ) );
3930
3931 // Set w of the origin to one so we can dot4 with a plane.
3932 vOrigin = XMVectorInsert<0, 0, 0, 0, 1>( vOrigin, XMVectorSplatOne() );
3933
3934 // Build the corners of the frustum (in world space).
3935 XMVECTOR RightTop = XMVectorSet( RightSlope, TopSlope, 1.0f, 0.0f );
3936 XMVECTOR RightBottom = XMVectorSet( RightSlope, BottomSlope, 1.0f, 0.0f );
3937 XMVECTOR LeftTop = XMVectorSet( LeftSlope, TopSlope, 1.0f, 0.0f );
3938 XMVECTOR LeftBottom = XMVectorSet( LeftSlope, BottomSlope, 1.0f, 0.0f );
3939 XMVECTOR vNear = XMVectorReplicatePtr( &Near );
3940 XMVECTOR vFar = XMVectorReplicatePtr( &Far );
3941
3942 RightTop = XMVector3Rotate( RightTop, vOrientation );
3943 RightBottom = XMVector3Rotate( RightBottom, vOrientation );
3944 LeftTop = XMVector3Rotate( LeftTop, vOrientation );
3945 LeftBottom = XMVector3Rotate( LeftBottom, vOrientation );
3946
3947 XMVECTOR Corners0 = vOrigin + RightTop * vNear;
3948 XMVECTOR Corners1 = vOrigin + RightBottom * vNear;
3949 XMVECTOR Corners2 = vOrigin + LeftTop * vNear;
3950 XMVECTOR Corners3 = vOrigin + LeftBottom * vNear;
3951 XMVECTOR Corners4 = vOrigin + RightTop * vFar;
3952 XMVECTOR Corners5 = vOrigin + RightBottom * vFar;
3953 XMVECTOR Corners6 = vOrigin + LeftTop * vFar;
3954 XMVECTOR Corners7 = vOrigin + LeftBottom * vFar;
3955
3956 XMVECTOR Outside, Inside;
3957 DirectX::Internal::FastIntersectFrustumPlane( Corners0, Corners1, Corners2, Corners3,
3958 Corners4, Corners5, Corners6, Corners7,
3959 Plane, Outside, Inside );
3960
3961 // If the frustum is outside any plane it is outside.
3962 if ( XMVector4EqualInt( Outside, XMVectorTrueInt() ) )
3963 return FRONT;
3964
3965 // If the frustum is inside all planes it is inside.
3966 if ( XMVector4EqualInt( Inside, XMVectorTrueInt() ) )
3967 return BACK;
3968
3969 // The frustum is not inside all planes or outside a plane it intersects.
3970 return INTERSECTING;
3971}
3972
3973
3974//-----------------------------------------------------------------------------
3975// Ray vs. frustum test
3976//-----------------------------------------------------------------------------
3977_Use_decl_annotations_
3978inline bool BoundingFrustum::Intersects( FXMVECTOR rayOrigin, FXMVECTOR Direction, float& Dist ) const
3979{
3980 // If ray starts inside the frustum, return a distance of 0 for the hit
3981 if ( Contains(rayOrigin) == CONTAINS )
3982 {
3983 Dist = 0.0f;
3984 return true;
3985 }
3986
3987 // Build the frustum planes.
3988 XMVECTOR Planes[6];
3989 Planes[0] = XMVectorSet( 0.0f, 0.0f, -1.0f, Near );
3990 Planes[1] = XMVectorSet( 0.0f, 0.0f, 1.0f, -Far );
3991 Planes[2] = XMVectorSet( 1.0f, 0.0f, -RightSlope, 0.0f );
3992 Planes[3] = XMVectorSet( -1.0f, 0.0f, LeftSlope, 0.0f );
3993 Planes[4] = XMVectorSet( 0.0f, 1.0f, -TopSlope, 0.0f );
3994 Planes[5] = XMVectorSet( 0.0f, -1.0f, BottomSlope, 0.0f );
3995
3996 // Load origin and orientation of the frustum.
3997 XMVECTOR frOrigin = XMLoadFloat3( &Origin );
3998 XMVECTOR frOrientation = XMLoadFloat4( &Orientation );
3999
4000 // This algorithm based on "Fast Ray-Convex Polyhedron Intersectin," in James Arvo, ed., Graphics Gems II pp. 247-250
4001 float tnear = -FLT_MAX;
4002 float tfar = FLT_MAX;
4003
4004 for( size_t i=0; i < 6; ++i )
4005 {
4006 XMVECTOR Plane = DirectX::Internal::XMPlaneTransform( Planes[i], frOrientation, frOrigin );
4007 Plane = XMPlaneNormalize( Plane );
4008
4009 XMVECTOR AxisDotOrigin = XMPlaneDotCoord( Plane, rayOrigin );
4010 XMVECTOR AxisDotDirection = XMVector3Dot( Plane, Direction );
4011
4012 if ( XMVector3LessOrEqual( XMVectorAbs( AxisDotDirection ), g_RayEpsilon ) )
4013 {
4014 // Ray is parallel to plane - check if ray origin is inside plane's
4015 if ( XMVector3Greater( AxisDotOrigin, g_XMZero ) )
4016 {
4017 // Ray origin is outside half-space.
4018 Dist = 0.f;
4019 return false;
4020 }
4021 }
4022 else
4023 {
4024 // Ray not parallel - get distance to plane.
4025 float vd = XMVectorGetX( AxisDotDirection );
4026 float vn = XMVectorGetX( AxisDotOrigin );
4027 float t = -vn / vd;
4028 if (vd < 0.0f)
4029 {
4030 // Front face - T is a near point.
4031 if (t > tfar)
4032 {
4033 Dist = 0.f;
4034 return false;
4035 }
4036 if (t > tnear)
4037 {
4038 // Hit near face.
4039 tnear = t;
4040 }
4041 }
4042 else
4043 {
4044 // back face - T is far point.
4045 if (t < tnear)
4046 {
4047 Dist = 0.f;
4048 return false;
4049 }
4050 if (t < tfar)
4051 {
4052 // Hit far face.
4053 tfar = t;
4054 }
4055 }
4056 }
4057 }
4058
4059 // Survived all tests.
4060 // Note: if ray originates on polyhedron, may want to change 0.0f to some
4061 // epsilon to avoid intersecting the originating face.
4062 float distance = ( tnear >= 0.0f ) ? tnear : tfar;
4063 if (distance >= 0.0f)
4064 {
4065 Dist = distance;
4066 return true;
4067 }
4068
4069 Dist = 0.f;
4070 return false;
4071}
4072
4073
4074//-----------------------------------------------------------------------------
4075// Test a frustum vs 6 planes (typically forming another frustum).
4076//-----------------------------------------------------------------------------
4077_Use_decl_annotations_
4078inline ContainmentType BoundingFrustum::ContainedBy( FXMVECTOR Plane0, FXMVECTOR Plane1, FXMVECTOR Plane2,
4079 GXMVECTOR Plane3, CXMVECTOR Plane4, CXMVECTOR Plane5 ) const
4080{
4081 // Load origin and orientation of the frustum.
4082 XMVECTOR vOrigin = XMLoadFloat3( &Origin );
4083 XMVECTOR vOrientation = XMLoadFloat4( &Orientation );
4084
4085 assert( DirectX::Internal::XMQuaternionIsUnit( vOrientation ) );
4086
4087 // Set w of the origin to one so we can dot4 with a plane.
4088 vOrigin = XMVectorInsert<0, 0, 0, 0, 1>( vOrigin, XMVectorSplatOne() );
4089
4090 // Build the corners of the frustum (in world space).
4091 XMVECTOR RightTop = XMVectorSet( RightSlope, TopSlope, 1.0f, 0.0f );
4092 XMVECTOR RightBottom = XMVectorSet( RightSlope, BottomSlope, 1.0f, 0.0f );
4093 XMVECTOR LeftTop = XMVectorSet( LeftSlope, TopSlope, 1.0f, 0.0f );
4094 XMVECTOR LeftBottom = XMVectorSet( LeftSlope, BottomSlope, 1.0f, 0.0f );
4095 XMVECTOR vNear = XMVectorReplicatePtr( &Near );
4096 XMVECTOR vFar = XMVectorReplicatePtr( &Far );
4097
4098 RightTop = XMVector3Rotate( RightTop, vOrientation );
4099 RightBottom = XMVector3Rotate( RightBottom, vOrientation );
4100 LeftTop = XMVector3Rotate( LeftTop, vOrientation );
4101 LeftBottom = XMVector3Rotate( LeftBottom, vOrientation );
4102
4103 XMVECTOR Corners0 = vOrigin + RightTop * vNear;
4104 XMVECTOR Corners1 = vOrigin + RightBottom * vNear;
4105 XMVECTOR Corners2 = vOrigin + LeftTop * vNear;
4106 XMVECTOR Corners3 = vOrigin + LeftBottom * vNear;
4107 XMVECTOR Corners4 = vOrigin + RightTop * vFar;
4108 XMVECTOR Corners5 = vOrigin + RightBottom * vFar;
4109 XMVECTOR Corners6 = vOrigin + LeftTop * vFar;
4110 XMVECTOR Corners7 = vOrigin + LeftBottom * vFar;
4111
4112 XMVECTOR Outside, Inside;
4113
4114 // Test against each plane.
4115 DirectX::Internal::FastIntersectFrustumPlane( Corners0, Corners1, Corners2, Corners3,
4116 Corners4, Corners5, Corners6, Corners7,
4117 Plane0, Outside, Inside );
4118
4119 XMVECTOR AnyOutside = Outside;
4120 XMVECTOR AllInside = Inside;
4121
4122 DirectX::Internal::FastIntersectFrustumPlane( Corners0, Corners1, Corners2, Corners3,
4123 Corners4, Corners5, Corners6, Corners7,
4124 Plane1, Outside, Inside );
4125
4126 AnyOutside = XMVectorOrInt( AnyOutside, Outside );
4127 AllInside = XMVectorAndInt( AllInside, Inside );
4128
4129 DirectX::Internal::FastIntersectFrustumPlane( Corners0, Corners1, Corners2, Corners3,
4130 Corners4, Corners5, Corners6, Corners7,
4131 Plane2, Outside, Inside );
4132
4133 AnyOutside = XMVectorOrInt( AnyOutside, Outside );
4134 AllInside = XMVectorAndInt( AllInside, Inside );
4135
4136 DirectX::Internal::FastIntersectFrustumPlane( Corners0, Corners1, Corners2, Corners3,
4137 Corners4, Corners5, Corners6, Corners7,
4138 Plane3, Outside, Inside );
4139
4140 AnyOutside = XMVectorOrInt( AnyOutside, Outside );
4141 AllInside = XMVectorAndInt( AllInside, Inside );
4142
4143 DirectX::Internal::FastIntersectFrustumPlane( Corners0, Corners1, Corners2, Corners3,
4144 Corners4, Corners5, Corners6, Corners7,
4145 Plane4, Outside, Inside );
4146
4147 AnyOutside = XMVectorOrInt( AnyOutside, Outside );
4148 AllInside = XMVectorAndInt( AllInside, Inside );
4149
4150 DirectX::Internal::FastIntersectFrustumPlane( Corners0, Corners1, Corners2, Corners3,
4151 Corners4, Corners5, Corners6, Corners7,
4152 Plane5, Outside, Inside );
4153
4154 AnyOutside = XMVectorOrInt( AnyOutside, Outside );
4155 AllInside = XMVectorAndInt( AllInside, Inside );
4156
4157 // If the frustum is outside any plane it is outside.
4158 if ( XMVector4EqualInt( AnyOutside, XMVectorTrueInt() ) )
4159 return DISJOINT;
4160
4161 // If the frustum is inside all planes it is inside.
4162 if ( XMVector4EqualInt( AllInside, XMVectorTrueInt() ) )
4163 return CONTAINS;
4164
4165 // The frustum is not inside all planes or outside a plane, it may intersect.
4166 return INTERSECTS;
4167}
4168
4169
4170//-----------------------------------------------------------------------------
4171// Build the 6 frustum planes from a frustum.
4172//
4173// The intended use for these routines is for fast culling to a view frustum.
4174// When the volume being tested against a view frustum is small relative to the
4175// view frustum it is usually either inside all six planes of the frustum
4176// (CONTAINS) or outside one of the planes of the frustum (DISJOINT). If neither
4177// of these cases is true then it may or may not be intersecting the frustum
4178// (INTERSECTS)
4179//-----------------------------------------------------------------------------
4180_Use_decl_annotations_
4181inline void BoundingFrustum::GetPlanes( XMVECTOR* NearPlane, XMVECTOR* FarPlane, XMVECTOR* RightPlane,
4182 XMVECTOR* LeftPlane, XMVECTOR* TopPlane, XMVECTOR* BottomPlane ) const
4183{
4184 // Load origin and orientation of the frustum.
4185 XMVECTOR vOrigin = XMLoadFloat3( &Origin );
4186 XMVECTOR vOrientation = XMLoadFloat4( &Orientation );
4187
4188 if (NearPlane)
4189 {
4190 XMVECTOR vNearPlane = XMVectorSet( 0.0f, 0.0f, -1.0f, Near );
4191 vNearPlane = DirectX::Internal::XMPlaneTransform( vNearPlane, vOrientation, vOrigin );
4192 *NearPlane = XMPlaneNormalize( vNearPlane );
4193 }
4194
4195 if (FarPlane)
4196 {
4197 XMVECTOR vFarPlane = XMVectorSet( 0.0f, 0.0f, 1.0f, -Far );
4198 vFarPlane = DirectX::Internal::XMPlaneTransform( vFarPlane, vOrientation, vOrigin );
4199 *FarPlane = XMPlaneNormalize( vFarPlane );
4200 }
4201
4202 if (RightPlane)
4203 {
4204 XMVECTOR vRightPlane = XMVectorSet( 1.0f, 0.0f, -RightSlope, 0.0f );
4205 vRightPlane = DirectX::Internal::XMPlaneTransform( vRightPlane, vOrientation, vOrigin );
4206 *RightPlane = XMPlaneNormalize( vRightPlane );
4207 }
4208
4209 if (LeftPlane)
4210 {
4211 XMVECTOR vLeftPlane = XMVectorSet( -1.0f, 0.0f, LeftSlope, 0.0f );
4212 vLeftPlane = DirectX::Internal::XMPlaneTransform( vLeftPlane, vOrientation, vOrigin );
4213 *LeftPlane = XMPlaneNormalize( vLeftPlane );
4214 }
4215
4216 if (TopPlane)
4217 {
4218 XMVECTOR vTopPlane = XMVectorSet( 0.0f, 1.0f, -TopSlope, 0.0f );
4219 vTopPlane = DirectX::Internal::XMPlaneTransform( vTopPlane, vOrientation, vOrigin );
4220 *TopPlane = XMPlaneNormalize( vTopPlane );
4221 }
4222
4223 if (BottomPlane)
4224 {
4225 XMVECTOR vBottomPlane = XMVectorSet( 0.0f, -1.0f, BottomSlope, 0.0f );
4226 vBottomPlane = DirectX::Internal::XMPlaneTransform( vBottomPlane, vOrientation, vOrigin );
4227 *BottomPlane = XMPlaneNormalize( vBottomPlane );
4228 }
4229}
4230
4231
4232//-----------------------------------------------------------------------------
4233// Build a frustum from a persepective projection matrix. The matrix may only
4234// contain a projection; any rotation, translation or scale will cause the
4235// constructed frustum to be incorrect.
4236//-----------------------------------------------------------------------------
4237_Use_decl_annotations_
4238inline void BoundingFrustum::CreateFromMatrix( BoundingFrustum& Out, CXMMATRIX Projection )
4239{
4240 // Corners of the projection frustum in homogenous space.
4241 static XMVECTORF32 HomogenousPoints[6] =
4242 {
4243 { 1.0f, 0.0f, 1.0f, 1.0f }, // right (at far plane)
4244 { -1.0f, 0.0f, 1.0f, 1.0f }, // left
4245 { 0.0f, 1.0f, 1.0f, 1.0f }, // top
4246 { 0.0f, -1.0f, 1.0f, 1.0f }, // bottom
4247
4248 { 0.0f, 0.0f, 0.0f, 1.0f }, // near
4249 { 0.0f, 0.0f, 1.0f, 1.0f } // far
4250 };
4251
4252 XMVECTOR Determinant;
4253 XMMATRIX matInverse = XMMatrixInverse( &Determinant, Projection );
4254
4255 // Compute the frustum corners in world space.
4256 XMVECTOR Points[6];
4257
4258 for( size_t i = 0; i < 6; ++i )
4259 {
4260 // Transform point.
4261 Points[i] = XMVector4Transform( HomogenousPoints[i], matInverse );
4262 }
4263
4264 Out.Origin = XMFLOAT3( 0.0f, 0.0f, 0.0f );
4265 Out.Orientation = XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f );
4266
4267 // Compute the slopes.
4268 Points[0] = Points[0] * XMVectorReciprocal( XMVectorSplatZ( Points[0] ) );
4269 Points[1] = Points[1] * XMVectorReciprocal( XMVectorSplatZ( Points[1] ) );
4270 Points[2] = Points[2] * XMVectorReciprocal( XMVectorSplatZ( Points[2] ) );
4271 Points[3] = Points[3] * XMVectorReciprocal( XMVectorSplatZ( Points[3] ) );
4272
4273 Out.RightSlope = XMVectorGetX( Points[0] );
4274 Out.LeftSlope = XMVectorGetX( Points[1] );
4275 Out.TopSlope = XMVectorGetY( Points[2] );
4276 Out.BottomSlope = XMVectorGetY( Points[3] );
4277
4278 // Compute near and far.
4279 Points[4] = Points[4] * XMVectorReciprocal( XMVectorSplatW( Points[4] ) );
4280 Points[5] = Points[5] * XMVectorReciprocal( XMVectorSplatW( Points[5] ) );
4281
4282 Out.Near = XMVectorGetZ( Points[4] );
4283 Out.Far = XMVectorGetZ( Points[5] );
4284}
4285
4286
4287/****************************************************************************
4288 *
4289 * TriangleTests
4290 *
4291 ****************************************************************************/
4292
4293namespace TriangleTests
4294{
4295
4296//-----------------------------------------------------------------------------
4297// Compute the intersection of a ray (Origin, Direction) with a triangle
4298// (V0, V1, V2). Return true if there is an intersection and also set *pDist
4299// to the distance along the ray to the intersection.
4300//
4301// The algorithm is based on Moller, Tomas and Trumbore, "Fast, Minimum Storage
4302// Ray-Triangle Intersection", Journal of Graphics Tools, vol. 2, no. 1,
4303// pp 21-28, 1997.
4304//-----------------------------------------------------------------------------
4305_Use_decl_annotations_
4306inline bool Intersects( FXMVECTOR Origin, FXMVECTOR Direction, FXMVECTOR V0, GXMVECTOR V1, CXMVECTOR V2, float& Dist )
4307{
4308 assert( DirectX::Internal::XMVector3IsUnit( Direction ) );
4309
4310 XMVECTOR Zero = XMVectorZero();
4311
4312 XMVECTOR e1 = V1 - V0;
4313 XMVECTOR e2 = V2 - V0;
4314
4315 // p = Direction ^ e2;
4316 XMVECTOR p = XMVector3Cross( Direction, e2 );
4317
4318 // det = e1 * p;
4319 XMVECTOR det = XMVector3Dot( e1, p );
4320
4321 XMVECTOR u, v, t;
4322
4323 if( XMVector3GreaterOrEqual( det, g_RayEpsilon ) )
4324 {
4325 // Determinate is positive (front side of the triangle).
4326 XMVECTOR s = Origin - V0;
4327
4328 // u = s * p;
4329 u = XMVector3Dot( s, p );
4330
4331 XMVECTOR NoIntersection = XMVectorLess( u, Zero );
4332 NoIntersection = XMVectorOrInt( NoIntersection, XMVectorGreater( u, det ) );
4333
4334 // q = s ^ e1;
4335 XMVECTOR q = XMVector3Cross( s, e1 );
4336
4337 // v = Direction * q;
4338 v = XMVector3Dot( Direction, q );
4339
4340 NoIntersection = XMVectorOrInt( NoIntersection, XMVectorLess( v, Zero ) );
4341 NoIntersection = XMVectorOrInt( NoIntersection, XMVectorGreater( u + v, det ) );
4342
4343 // t = e2 * q;
4344 t = XMVector3Dot( e2, q );
4345
4346 NoIntersection = XMVectorOrInt( NoIntersection, XMVectorLess( t, Zero ) );
4347
4348 if( XMVector4EqualInt( NoIntersection, XMVectorTrueInt() ) )
4349 {
4350 Dist = 0.f;
4351 return false;
4352 }
4353 }
4354 else if( XMVector3LessOrEqual( det, g_RayNegEpsilon ) )
4355 {
4356 // Determinate is negative (back side of the triangle).
4357 XMVECTOR s = Origin - V0;
4358
4359 // u = s * p;
4360 u = XMVector3Dot( s, p );
4361
4362 XMVECTOR NoIntersection = XMVectorGreater( u, Zero );
4363 NoIntersection = XMVectorOrInt( NoIntersection, XMVectorLess( u, det ) );
4364
4365 // q = s ^ e1;
4366 XMVECTOR q = XMVector3Cross( s, e1 );
4367
4368 // v = Direction * q;
4369 v = XMVector3Dot( Direction, q );
4370
4371 NoIntersection = XMVectorOrInt( NoIntersection, XMVectorGreater( v, Zero ) );
4372 NoIntersection = XMVectorOrInt( NoIntersection, XMVectorLess( u + v, det ) );
4373
4374 // t = e2 * q;
4375 t = XMVector3Dot( e2, q );
4376
4377 NoIntersection = XMVectorOrInt( NoIntersection, XMVectorGreater( t, Zero ) );
4378
4379 if ( XMVector4EqualInt( NoIntersection, XMVectorTrueInt() ) )
4380 {
4381 Dist = 0.f;
4382 return false;
4383 }
4384 }
4385 else
4386 {
4387 // Parallel ray.
4388 Dist = 0.f;
4389 return false;
4390 }
4391
4392 t = XMVectorDivide ( t, det );
4393
4394 // (u / det) and (v / dev) are the barycentric cooridinates of the intersection.
4395
4396 // Store the x-component to *pDist
4397 XMStoreFloat( &Dist, t );
4398
4399 return true;
4400}
4401
4402
4403//-----------------------------------------------------------------------------
4404// Test if two triangles intersect.
4405//
4406// The final test of algorithm is based on Shen, Heng, and Tang, "A Fast
4407// Triangle-Triangle Overlap Test Using Signed Distances", Journal of Graphics
4408// Tools, vol. 8, no. 1, pp 17-23, 2003 and Guigue and Devillers, "Fast and
4409// Robust Triangle-Triangle Overlap Test Using Orientation Predicates", Journal
4410// of Graphics Tools, vol. 8, no. 1, pp 25-32, 2003.
4411//
4412// The final test could be considered an edge-edge separating plane test with
4413// the 9 possible cases narrowed down to the only two pairs of edges that can
4414// actaully result in a seperation.
4415//-----------------------------------------------------------------------------
4416_Use_decl_annotations_
4417inline bool Intersects( FXMVECTOR A0, FXMVECTOR A1, FXMVECTOR A2, GXMVECTOR B0, CXMVECTOR B1, CXMVECTOR B2 )
4418{
4419 static const XMVECTORI32 SelectY =
4420 {
4421 XM_SELECT_0, XM_SELECT_1, XM_SELECT_0, XM_SELECT_0
4422 };
4423 static const XMVECTORI32 SelectZ =
4424 {
4425 XM_SELECT_0, XM_SELECT_0, XM_SELECT_1, XM_SELECT_0
4426 };
4427 static const XMVECTORI32 Select0111 =
4428 {
4429 XM_SELECT_0, XM_SELECT_1, XM_SELECT_1, XM_SELECT_1
4430 };
4431 static const XMVECTORI32 Select1011 =
4432 {
4433 XM_SELECT_1, XM_SELECT_0, XM_SELECT_1, XM_SELECT_1
4434 };
4435 static const XMVECTORI32 Select1101 =
4436 {
4437 XM_SELECT_1, XM_SELECT_1, XM_SELECT_0, XM_SELECT_1
4438 };
4439
4440 XMVECTOR Zero = XMVectorZero();
4441
4442 // Compute the normal of triangle A.
4443 XMVECTOR N1 = XMVector3Cross( A1 - A0, A2 - A0 );
4444
4445 // Assert that the triangle is not degenerate.
4446 assert( !XMVector3Equal( N1, Zero ) );
4447
4448 // Test points of B against the plane of A.
4449 XMVECTOR BDist = XMVector3Dot( N1, B0 - A0 );
4450 BDist = XMVectorSelect( BDist, XMVector3Dot( N1, B1 - A0 ), SelectY );
4451 BDist = XMVectorSelect( BDist, XMVector3Dot( N1, B2 - A0 ), SelectZ );
4452
4453 // Ensure robustness with co-planar triangles by zeroing small distances.
4454 uint32_t BDistIsZeroCR;
4455 XMVECTOR BDistIsZero = XMVectorGreaterR( &BDistIsZeroCR, g_RayEpsilon, XMVectorAbs( BDist ) );
4456 BDist = XMVectorSelect( BDist, Zero, BDistIsZero );
4457
4458 uint32_t BDistIsLessCR;
4459 XMVECTOR BDistIsLess = XMVectorGreaterR( &BDistIsLessCR, Zero, BDist );
4460
4461 uint32_t BDistIsGreaterCR;
4462 XMVECTOR BDistIsGreater = XMVectorGreaterR( &BDistIsGreaterCR, BDist, Zero );
4463
4464 // If all the points are on the same side we don't intersect.
4465 if( XMComparisonAllTrue( BDistIsLessCR ) || XMComparisonAllTrue( BDistIsGreaterCR ) )
4466 return false;
4467
4468 // Compute the normal of triangle B.
4469 XMVECTOR N2 = XMVector3Cross( B1 - B0, B2 - B0 );
4470
4471 // Assert that the triangle is not degenerate.
4472 assert( !XMVector3Equal( N2, Zero ) );
4473
4474 // Test points of A against the plane of B.
4475 XMVECTOR ADist = XMVector3Dot( N2, A0 - B0 );
4476 ADist = XMVectorSelect( ADist, XMVector3Dot( N2, A1 - B0 ), SelectY );
4477 ADist = XMVectorSelect( ADist, XMVector3Dot( N2, A2 - B0 ), SelectZ );
4478
4479 // Ensure robustness with co-planar triangles by zeroing small distances.
4480 uint32_t ADistIsZeroCR;
4481 XMVECTOR ADistIsZero = XMVectorGreaterR( &ADistIsZeroCR, g_RayEpsilon, XMVectorAbs( BDist ) );
4482 ADist = XMVectorSelect( ADist, Zero, ADistIsZero );
4483
4484 uint32_t ADistIsLessCR;
4485 XMVECTOR ADistIsLess = XMVectorGreaterR( &ADistIsLessCR, Zero, ADist );
4486
4487 uint32_t ADistIsGreaterCR;
4488 XMVECTOR ADistIsGreater = XMVectorGreaterR( &ADistIsGreaterCR, ADist, Zero );
4489
4490 // If all the points are on the same side we don't intersect.
4491 if( XMComparisonAllTrue( ADistIsLessCR ) || XMComparisonAllTrue( ADistIsGreaterCR ) )
4492 return false;
4493
4494 // Special case for co-planar triangles.
4495 if( XMComparisonAllTrue( ADistIsZeroCR ) || XMComparisonAllTrue( BDistIsZeroCR ) )
4496 {
4497 XMVECTOR Axis, Dist, MinDist;
4498
4499 // Compute an axis perpindicular to the edge (points out).
4500 Axis = XMVector3Cross( N1, A1 - A0 );
4501 Dist = XMVector3Dot( Axis, A0 );
4502
4503 // Test points of B against the axis.
4504 MinDist = XMVector3Dot( B0, Axis );
4505 MinDist = XMVectorMin( MinDist, XMVector3Dot( B1, Axis ) );
4506 MinDist = XMVectorMin( MinDist, XMVector3Dot( B2, Axis ) );
4507 if( XMVector4GreaterOrEqual( MinDist, Dist ) )
4508 return false;
4509
4510 // Edge (A1, A2)
4511 Axis = XMVector3Cross( N1, A2 - A1 );
4512 Dist = XMVector3Dot( Axis, A1 );
4513
4514 MinDist = XMVector3Dot( B0, Axis );
4515 MinDist = XMVectorMin( MinDist, XMVector3Dot( B1, Axis ) );
4516 MinDist = XMVectorMin( MinDist, XMVector3Dot( B2, Axis ) );
4517 if( XMVector4GreaterOrEqual( MinDist, Dist ) )
4518 return false;
4519
4520 // Edge (A2, A0)
4521 Axis = XMVector3Cross( N1, A0 - A2 );
4522 Dist = XMVector3Dot( Axis, A2 );
4523
4524 MinDist = XMVector3Dot( B0, Axis );
4525 MinDist = XMVectorMin( MinDist, XMVector3Dot( B1, Axis ) );
4526 MinDist = XMVectorMin( MinDist, XMVector3Dot( B2, Axis ) );
4527 if( XMVector4GreaterOrEqual( MinDist, Dist ) )
4528 return false;
4529
4530 // Edge (B0, B1)
4531 Axis = XMVector3Cross( N2, B1 - B0 );
4532 Dist = XMVector3Dot( Axis, B0 );
4533
4534 MinDist = XMVector3Dot( A0, Axis );
4535 MinDist = XMVectorMin( MinDist, XMVector3Dot( A1, Axis ) );
4536 MinDist = XMVectorMin( MinDist, XMVector3Dot( A2, Axis ) );
4537 if( XMVector4GreaterOrEqual( MinDist, Dist ) )
4538 return false;
4539
4540 // Edge (B1, B2)
4541 Axis = XMVector3Cross( N2, B2 - B1 );
4542 Dist = XMVector3Dot( Axis, B1 );
4543
4544 MinDist = XMVector3Dot( A0, Axis );
4545 MinDist = XMVectorMin( MinDist, XMVector3Dot( A1, Axis ) );
4546 MinDist = XMVectorMin( MinDist, XMVector3Dot( A2, Axis ) );
4547 if( XMVector4GreaterOrEqual( MinDist, Dist ) )
4548 return false;
4549
4550 // Edge (B2,B0)
4551 Axis = XMVector3Cross( N2, B0 - B2 );
4552 Dist = XMVector3Dot( Axis, B2 );
4553
4554 MinDist = XMVector3Dot( A0, Axis );
4555 MinDist = XMVectorMin( MinDist, XMVector3Dot( A1, Axis ) );
4556 MinDist = XMVectorMin( MinDist, XMVector3Dot( A2, Axis ) );
4557 if( XMVector4GreaterOrEqual( MinDist, Dist ) )
4558 return false;
4559
4560 return true;
4561 }
4562
4563 //
4564 // Find the single vertex of A and B (ie the vertex on the opposite side
4565 // of the plane from the other two) and reorder the edges so we can compute
4566 // the signed edge/edge distances.
4567 //
4568 // if ( (V0 >= 0 && V1 < 0 && V2 < 0) ||
4569 // (V0 > 0 && V1 <= 0 && V2 <= 0) ||
4570 // (V0 <= 0 && V1 > 0 && V2 > 0) ||
4571 // (V0 < 0 && V1 >= 0 && V2 >= 0) ) then V0 is singular;
4572 //
4573 // If our singular vertex is not on the positive side of the plane we reverse
4574 // the triangle winding so that the overlap comparisons will compare the
4575 // correct edges with the correct signs.
4576 //
4577 XMVECTOR ADistIsLessEqual = XMVectorOrInt( ADistIsLess, ADistIsZero );
4578 XMVECTOR ADistIsGreaterEqual = XMVectorOrInt( ADistIsGreater, ADistIsZero );
4579
4580 XMVECTOR AA0, AA1, AA2;
4581 bool bPositiveA;
4582
4583 if( DirectX::Internal::XMVector3AllTrue( XMVectorSelect( ADistIsGreaterEqual, ADistIsLess, Select0111 ) ) ||
4584 DirectX::Internal::XMVector3AllTrue( XMVectorSelect( ADistIsGreater, ADistIsLessEqual, Select0111 ) ) )
4585 {
4586 // A0 is singular, crossing from positive to negative.
4587 AA0 = A0; AA1 = A1; AA2 = A2;
4588 bPositiveA = true;
4589 }
4590 else if( DirectX::Internal::XMVector3AllTrue( XMVectorSelect( ADistIsLessEqual, ADistIsGreater, Select0111 ) ) ||
4591 DirectX::Internal::XMVector3AllTrue( XMVectorSelect( ADistIsLess, ADistIsGreaterEqual, Select0111 ) ) )
4592 {
4593 // A0 is singular, crossing from negative to positive.
4594 AA0 = A0; AA1 = A2; AA2 = A1;
4595 bPositiveA = false;
4596 }
4597 else if( DirectX::Internal::XMVector3AllTrue( XMVectorSelect( ADistIsGreaterEqual, ADistIsLess, Select1011 ) ) ||
4598 DirectX::Internal::XMVector3AllTrue( XMVectorSelect( ADistIsGreater, ADistIsLessEqual, Select1011 ) ) )
4599 {
4600 // A1 is singular, crossing from positive to negative.
4601 AA0 = A1; AA1 = A2; AA2 = A0;
4602 bPositiveA = true;
4603 }
4604 else if( DirectX::Internal::XMVector3AllTrue( XMVectorSelect( ADistIsLessEqual, ADistIsGreater, Select1011 ) ) ||
4605 DirectX::Internal::XMVector3AllTrue( XMVectorSelect( ADistIsLess, ADistIsGreaterEqual, Select1011 ) ) )
4606 {
4607 // A1 is singular, crossing from negative to positive.
4608 AA0 = A1; AA1 = A0; AA2 = A2;
4609 bPositiveA = false;
4610 }
4611 else if( DirectX::Internal::XMVector3AllTrue( XMVectorSelect( ADistIsGreaterEqual, ADistIsLess, Select1101 ) ) ||
4612 DirectX::Internal::XMVector3AllTrue( XMVectorSelect( ADistIsGreater, ADistIsLessEqual, Select1101 ) ) )
4613 {
4614 // A2 is singular, crossing from positive to negative.
4615 AA0 = A2; AA1 = A0; AA2 = A1;
4616 bPositiveA = true;
4617 }
4618 else if( DirectX::Internal::XMVector3AllTrue( XMVectorSelect( ADistIsLessEqual, ADistIsGreater, Select1101 ) ) ||
4619 DirectX::Internal::XMVector3AllTrue( XMVectorSelect( ADistIsLess, ADistIsGreaterEqual, Select1101 ) ) )
4620 {
4621 // A2 is singular, crossing from negative to positive.
4622 AA0 = A2; AA1 = A1; AA2 = A0;
4623 bPositiveA = false;
4624 }
4625 else
4626 {
4627 assert( false );
4628 return false;
4629 }
4630
4631 XMVECTOR BDistIsLessEqual = XMVectorOrInt( BDistIsLess, BDistIsZero );
4632 XMVECTOR BDistIsGreaterEqual = XMVectorOrInt( BDistIsGreater, BDistIsZero );
4633
4634 XMVECTOR BB0, BB1, BB2;
4635 bool bPositiveB;
4636
4637 if( DirectX::Internal::XMVector3AllTrue( XMVectorSelect( BDistIsGreaterEqual, BDistIsLess, Select0111 ) ) ||
4638 DirectX::Internal::XMVector3AllTrue( XMVectorSelect( BDistIsGreater, BDistIsLessEqual, Select0111 ) ) )
4639 {
4640 // B0 is singular, crossing from positive to negative.
4641 BB0 = B0; BB1 = B1; BB2 = B2;
4642 bPositiveB = true;
4643 }
4644 else if( DirectX::Internal::XMVector3AllTrue( XMVectorSelect( BDistIsLessEqual, BDistIsGreater, Select0111 ) ) ||
4645 DirectX::Internal::XMVector3AllTrue( XMVectorSelect( BDistIsLess, BDistIsGreaterEqual, Select0111 ) ) )
4646 {
4647 // B0 is singular, crossing from negative to positive.
4648 BB0 = B0; BB1 = B2; BB2 = B1;
4649 bPositiveB = false;
4650 }
4651 else if( DirectX::Internal::XMVector3AllTrue( XMVectorSelect( BDistIsGreaterEqual, BDistIsLess, Select1011 ) ) ||
4652 DirectX::Internal::XMVector3AllTrue( XMVectorSelect( BDistIsGreater, BDistIsLessEqual, Select1011 ) ) )
4653 {
4654 // B1 is singular, crossing from positive to negative.
4655 BB0 = B1; BB1 = B2; BB2 = B0;
4656 bPositiveB = true;
4657 }
4658 else if( DirectX::Internal::XMVector3AllTrue( XMVectorSelect( BDistIsLessEqual, BDistIsGreater, Select1011 ) ) ||
4659 DirectX::Internal::XMVector3AllTrue( XMVectorSelect( BDistIsLess, BDistIsGreaterEqual, Select1011 ) ) )
4660 {
4661 // B1 is singular, crossing from negative to positive.
4662 BB0 = B1; BB1 = B0; BB2 = B2;
4663 bPositiveB = false;
4664 }
4665 else if( DirectX::Internal::XMVector3AllTrue( XMVectorSelect( BDistIsGreaterEqual, BDistIsLess, Select1101 ) ) ||
4666 DirectX::Internal::XMVector3AllTrue( XMVectorSelect( BDistIsGreater, BDistIsLessEqual, Select1101 ) ) )
4667 {
4668 // B2 is singular, crossing from positive to negative.
4669 BB0 = B2; BB1 = B0; BB2 = B1;
4670 bPositiveB = true;
4671 }
4672 else if( DirectX::Internal::XMVector3AllTrue( XMVectorSelect( BDistIsLessEqual, BDistIsGreater, Select1101 ) ) ||
4673 DirectX::Internal::XMVector3AllTrue( XMVectorSelect( BDistIsLess, BDistIsGreaterEqual, Select1101 ) ) )
4674 {
4675 // B2 is singular, crossing from negative to positive.
4676 BB0 = B2; BB1 = B1; BB2 = B0;
4677 bPositiveB = false;
4678 }
4679 else
4680 {
4681 assert( false );
4682 return false;
4683 }
4684
4685 XMVECTOR Delta0, Delta1;
4686
4687 // Reverse the direction of the test depending on whether the singular vertices are
4688 // the same sign or different signs.
4689 if( bPositiveA ^ bPositiveB )
4690 {
4691 Delta0 = ( BB0 - AA0 );
4692 Delta1 = ( AA0 - BB0 );
4693 }
4694 else
4695 {
4696 Delta0 = ( AA0 - BB0 );
4697 Delta1 = ( BB0 - AA0 );
4698 }
4699
4700 // Check if the triangles overlap on the line of intersection between the
4701 // planes of the two triangles by finding the signed line distances.
4702 XMVECTOR Dist0 = XMVector3Dot( Delta0, XMVector3Cross( ( BB2 - BB0 ), ( AA2 - AA0 ) ) );
4703 if( XMVector4Greater( Dist0, Zero ) )
4704 return false;
4705
4706 XMVECTOR Dist1 = XMVector3Dot( Delta1, XMVector3Cross( ( BB1 - BB0 ), ( AA1 - AA0 ) ) );
4707 if( XMVector4Greater( Dist1, Zero ) )
4708 return false;
4709
4710 return true;
4711}
4712
4713
4714//-----------------------------------------------------------------------------
4715// Ray-triangle test
4716//-----------------------------------------------------------------------------
4717_Use_decl_annotations_
4718inline PlaneIntersectionType Intersects( FXMVECTOR V0, FXMVECTOR V1, FXMVECTOR V2, GXMVECTOR Plane )
4719{
4720 XMVECTOR One = XMVectorSplatOne();
4721
4722 assert( DirectX::Internal::XMPlaneIsUnit( Plane ) );
4723
4724 // Set w of the points to one so we can dot4 with a plane.
4725 XMVECTOR TV0 = XMVectorInsert<0, 0, 0, 0, 1>(V0, One);
4726 XMVECTOR TV1 = XMVectorInsert<0, 0, 0, 0, 1>(V1, One);
4727 XMVECTOR TV2 = XMVectorInsert<0, 0, 0, 0, 1>(V2, One);
4728
4729 XMVECTOR Outside, Inside;
4730 DirectX::Internal::FastIntersectTrianglePlane( TV0, TV1, TV2, Plane, Outside, Inside );
4731
4732 // If the triangle is outside any plane it is outside.
4733 if ( XMVector4EqualInt( Outside, XMVectorTrueInt() ) )
4734 return FRONT;
4735
4736 // If the triangle is inside all planes it is inside.
4737 if ( XMVector4EqualInt( Inside, XMVectorTrueInt() ) )
4738 return BACK;
4739
4740 // The triangle is not inside all planes or outside a plane it intersects.
4741 return INTERSECTING;
4742}
4743
4744
4745//-----------------------------------------------------------------------------
4746// Test a triangle vs 6 planes (typically forming a frustum).
4747//-----------------------------------------------------------------------------
4748_Use_decl_annotations_
4749inline ContainmentType ContainedBy( FXMVECTOR V0, FXMVECTOR V1, FXMVECTOR V2,
4750 GXMVECTOR Plane0, CXMVECTOR Plane1, CXMVECTOR Plane2,
4751 CXMVECTOR Plane3, CXMVECTOR Plane4, CXMVECTOR Plane5 )
4752{
4753 XMVECTOR One = XMVectorSplatOne();
4754
4755 // Set w of the points to one so we can dot4 with a plane.
4756 XMVECTOR TV0 = XMVectorInsert<0, 0, 0, 0, 1>(V0, One);
4757 XMVECTOR TV1 = XMVectorInsert<0, 0, 0, 0, 1>(V1, One);
4758 XMVECTOR TV2 = XMVectorInsert<0, 0, 0, 0, 1>(V2, One);
4759
4760 XMVECTOR Outside, Inside;
4761
4762 // Test against each plane.
4763 DirectX::Internal::FastIntersectTrianglePlane( TV0, TV1, TV2, Plane0, Outside, Inside );
4764
4765 XMVECTOR AnyOutside = Outside;
4766 XMVECTOR AllInside = Inside;
4767
4768 DirectX::Internal::FastIntersectTrianglePlane( TV0, TV1, TV2, Plane1, Outside, Inside );
4769 AnyOutside = XMVectorOrInt( AnyOutside, Outside );
4770 AllInside = XMVectorAndInt( AllInside, Inside );
4771
4772 DirectX::Internal::FastIntersectTrianglePlane( TV0, TV1, TV2, Plane2, Outside, Inside );
4773 AnyOutside = XMVectorOrInt( AnyOutside, Outside );
4774 AllInside = XMVectorAndInt( AllInside, Inside );
4775
4776 DirectX::Internal::FastIntersectTrianglePlane( TV0, TV1, TV2, Plane3, Outside, Inside );
4777 AnyOutside = XMVectorOrInt( AnyOutside, Outside );
4778 AllInside = XMVectorAndInt( AllInside, Inside );
4779
4780 DirectX::Internal::FastIntersectTrianglePlane( TV0, TV1, TV2, Plane4, Outside, Inside );
4781 AnyOutside = XMVectorOrInt( AnyOutside, Outside );
4782 AllInside = XMVectorAndInt( AllInside, Inside );
4783
4784 DirectX::Internal::FastIntersectTrianglePlane( TV0, TV1, TV2, Plane5, Outside, Inside );
4785 AnyOutside = XMVectorOrInt( AnyOutside, Outside );
4786 AllInside = XMVectorAndInt( AllInside, Inside );
4787
4788 // If the triangle is outside any plane it is outside.
4789 if ( XMVector4EqualInt( AnyOutside, XMVectorTrueInt() ) )
4790 return DISJOINT;
4791
4792 // If the triangle is inside all planes it is inside.
4793 if ( XMVector4EqualInt( AllInside, XMVectorTrueInt() ) )
4794 return CONTAINS;
4795
4796 // The triangle is not inside all planes or outside a plane, it may intersect.
4797 return INTERSECTS;
4798}
4799
4800}; // namespace TriangleTests
4801