the game where you go into mines and start crafting! but for consoles (forked directly from smartcmd's github)
at master 4801 lines 190 kB view raw
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