//-------------------------------------------------------------------------------------
// XNACollision.cpp
//
// An opimtized collision library based on XNAMath
//
// Microsoft XNA Developer Connection
// Copyright (c) Microsoft Corporation. All rights reserved.
//-------------------------------------------------------------------------------------
//#include "DXUT.h"
#include <Windows.h>
#include <cfloat>
#include "xnacollision.h"
namespace XNA
{
static const XMVECTOR g_UnitQuaternionEpsilon =
{
1.0e-4f, 1.0e-4f, 1.0e-4f, 1.0e-4f
};
static const XMVECTOR g_UnitVectorEpsilon =
{
1.0e-4f, 1.0e-4f, 1.0e-4f, 1.0e-4f
};
static const XMVECTOR g_UnitPlaneEpsilon =
{
1.0e-4f, 1.0e-4f, 1.0e-4f, 1.0e-4f
};
//-----------------------------------------------------------------------------
// Return TRUE if any of the elements of a 3 vector are equal to 0xffffffff.
// Slightly more efficient than using XMVector3EqualInt.
//-----------------------------------------------------------------------------
static inline BOOL XMVector3AnyTrue( FXMVECTOR V )
{
XMVECTOR C;
// Duplicate the fourth element from the first element.
C = XMVectorSwizzle( V, 0, 1, 2, 0 );
return XMComparisonAnyTrue( XMVector4EqualIntR( C, XMVectorTrueInt() ) );
}
//-----------------------------------------------------------------------------
// Return TRUE if all of the elements of a 3 vector are equal to 0xffffffff.
// Slightly more efficient than using XMVector3EqualInt.
//-----------------------------------------------------------------------------
static inline BOOL XMVector3AllTrue( FXMVECTOR V )
{
XMVECTOR C;
// Duplicate the fourth element from the first element.
C = XMVectorSwizzle( V, 0, 1, 2, 0 );
return XMComparisonAllTrue( XMVector4EqualIntR( C, XMVectorTrueInt() ) );
}
//-----------------------------------------------------------------------------
// Return TRUE if the vector is a unit vector (length == 1).
//-----------------------------------------------------------------------------
static inline BOOL XMVector3IsUnit( FXMVECTOR V )
{
XMVECTOR Difference = XMVector3Length( V ) - XMVectorSplatOne();
return XMVector4Less( XMVectorAbs( Difference ), g_UnitVectorEpsilon );
}
//-----------------------------------------------------------------------------
// Return TRUE if the quaterion is a unit quaternion.
//-----------------------------------------------------------------------------
static inline BOOL XMQuaternionIsUnit( FXMVECTOR Q )
{
XMVECTOR Difference = XMVector4Length( Q ) - XMVectorSplatOne();
return XMVector4Less( XMVectorAbs( Difference ), g_UnitQuaternionEpsilon );
}
//-----------------------------------------------------------------------------
// Return TRUE if the plane is a unit plane.
//-----------------------------------------------------------------------------
static inline BOOL XMPlaneIsUnit( FXMVECTOR Plane )
{
XMVECTOR Difference = XMVector3Length( Plane ) - XMVectorSplatOne();
return XMVector4Less( XMVectorAbs( Difference ), g_UnitPlaneEpsilon );
}
//-----------------------------------------------------------------------------
// Transform a plane by a rotation and translation.
//-----------------------------------------------------------------------------
static inline XMVECTOR TransformPlane( FXMVECTOR Plane, FXMVECTOR Rotation, FXMVECTOR Translation )
{
XMVECTOR Normal = XMVector3Rotate( Plane, Rotation );
XMVECTOR D = XMVectorSplatW( Plane ) - XMVector3Dot( Normal, Translation );
return XMVectorInsert( Normal, D, 0, 0, 0, 0, 1 );
}
//-----------------------------------------------------------------------------
// Return the point on the line segement (S1, S2) nearest the point P.
//-----------------------------------------------------------------------------
static inline XMVECTOR PointOnLineSegmentNearestPoint( FXMVECTOR S1, FXMVECTOR S2, FXMVECTOR P )
{
XMVECTOR Dir = S2 - S1;
XMVECTOR Projection = ( XMVector3Dot( P, Dir ) - XMVector3Dot( S1, Dir ) );
XMVECTOR LengthSq = XMVector3Dot( Dir, Dir );
XMVECTOR t = Projection * XMVectorReciprocal( LengthSq );
XMVECTOR Point = S1 + t * Dir;
// t < 0
XMVECTOR SelectS1 = XMVectorLess( Projection, XMVectorZero() );
Point = XMVectorSelect( Point, S1, SelectS1 );
// t > 1
XMVECTOR SelectS2 = XMVectorGreater( Projection, LengthSq );
Point = XMVectorSelect( Point, S2, SelectS2 );
return Point;
}
//-----------------------------------------------------------------------------
// Test if the point (P) on the plane of the triangle is inside the triangle
// (V0, V1, V2).
//-----------------------------------------------------------------------------
static inline XMVECTOR PointOnPlaneInsideTriangle( FXMVECTOR P, FXMVECTOR V0, FXMVECTOR V1, CXMVECTOR V2 )
{
// Compute the triangle normal.
XMVECTOR N = XMVector3Cross( V2 - V0, V1 - V0 );
// Compute the cross products of the vector from the base of each edge to
// the point with each edge vector.
XMVECTOR C0 = XMVector3Cross( P - V0, V1 - V0 );
XMVECTOR C1 = XMVector3Cross( P - V1, V2 - V1 );
XMVECTOR C2 = XMVector3Cross( P - V2, V0 - V2 );
// If the cross product points in the same direction as the normal the the
// point is inside the edge (it is zero if is on the edge).
XMVECTOR Zero = XMVectorZero();
XMVECTOR Inside0 = XMVectorGreaterOrEqual( XMVector3Dot( C0, N ), Zero );
XMVECTOR Inside1 = XMVectorGreaterOrEqual( XMVector3Dot( C1, N ), Zero );
XMVECTOR Inside2 = XMVectorGreaterOrEqual( XMVector3Dot( C2, N ), Zero );
// If the point inside all of the edges it is inside.
return XMVectorAndInt( XMVectorAndInt( Inside0, Inside1 ), Inside2 );
}
//-----------------------------------------------------------------------------
// Find the approximate smallest enclosing bounding sphere for a set of
// points. Exact computation of the smallest enclosing bounding sphere is
// possible but is slower and requires a more complex algorithm.
// The algorithm is based on Jack Ritter, "An Efficient Bounding Sphere",
// Graphics Gems.
//-----------------------------------------------------------------------------
VOID ComputeBoundingSphereFromPoints( Sphere* pOut, UINT Count, const XMFLOAT3* pPoints, UINT Stride )
{
XMASSERT( pOut );
XMASSERT( Count > 0 );
XMASSERT( pPoints );
// Find the points with minimum and maximum x, y, and z
XMVECTOR MinX, MaxX, MinY, MaxY, MinZ, MaxZ;
MinX = MaxX = MinY = MaxY = MinZ = MaxZ = XMLoadFloat3( pPoints );
for( UINT i = 1; i < Count; i++ )
{
XMVECTOR Point = XMLoadFloat3( ( XMFLOAT3* )( ( BYTE* )pPoints + i * Stride ) );
float px = XMVectorGetX( Point );
float py = XMVectorGetY( Point );
float pz = XMVectorGetZ( Point );
if( px < XMVectorGetX( MinX ) )
MinX = Point;
if( px > XMVectorGetX( MaxX ) )
MaxX = Point;
if( py < XMVectorGetY( MinY ) )
MinY = Point;
if( py > XMVectorGetY( MaxY ) )
MaxY = Point;
if( pz < XMVectorGetZ( MinZ ) )
MinZ = Point;
if( pz > XMVectorGetZ( MaxZ ) )
MaxZ = Point;
}
// Use the min/max pair that are farthest apart to form the initial sphere.
XMVECTOR DeltaX = MaxX - MinX;
XMVECTOR DistX = XMVector3Length( DeltaX );
XMVECTOR DeltaY = MaxY - MinY;
XMVECTOR DistY = XMVector3Length( DeltaY );
XMVECTOR DeltaZ = MaxZ - MinZ;
XMVECTOR DistZ = XMVector3Length( DeltaZ );
XMVECTOR Center;
XMVECTOR Radius;
if( XMVector3Greater( DistX, DistY ) )
{
if( XMVector3Greater( DistX, DistZ ) )
{
// Use min/max x.
- 1
- 2
- 3
前往页