Skip to content

Instantly share code, notes, and snippets.

@holland01
Created Sep 24, 2015
Embed
What would you like to do?
Quick face-point projection algorithm incorporating SAT concepts for OBB intersection tests. It's pretty primitive, and not full-proof, but it worked well for a time...
glm::vec3 fetch_point( const point_project_pair& ppp )
{
return ppp.mProjected;
}
// Returns true if a intersects b
bool pointset_intersects( cardinal_plane_normal_t planeType,
contact::list_t& contacts,
const obb& a,
const obb& b,
const obb::pointset3D_t& aPointsProj,
const obb::pointset3D_t& bPointsProj )
{
uint32_t axis0 = ( ( uint32_t ) planeType + 1 ) % 3;
uint32_t axis1 = ( ( uint32_t ) planeType + 2 ) % 3;
// The algorithm to compute the max and min of b's cardinal points
// is dependent on vector lengths and distances bounded by bPointsProj
glm::ext::vec3_maxmin_pair_t mm =
glm::ext::maxmin_from_list< obb::pointset3D_t, point_project_pair >( bPointsProj,
fetch_point );
bool success = false;
// In order to determine whether or not there's in intersection
// between aPointsProj and bPointsProj, we use max and min tests
// for the axes of the points NOT corresponding to planeType.
// For example, if the YZ plane is the cardinal plane whose normal
// is most perpendicular to the normal of the face we've projected onto,
// then we don't involve a comparison for the x-values of the points
// within this set, as they could produce false positives.
for ( auto i = aPointsProj.begin(); i != aPointsProj.end(); ++i )
{
const glm::vec3& u = ( *i ).mProjected;
if ( glm::ext::range( u, mm.min, mm.max, axis0 )
&& glm::ext::range( u, mm.min, mm.max, axis1 ) )
{
if ( glm::distance( ( *i ).mWorldPointRef, b.origin() )
< glm::distance( a.origin(), b.origin() ) )
{
contacts.insert( std::move( contact( ( *i ).mWorldPointRef ) ) );
}
success = true;
}
}
return success;
}
bool face_intersects( obb::face_type face,
contact::list_t& contacts,
const obb& a,
const obb& b,
const obb::pointlist3D_t& aPoints,
const obb::pointlist3D_t& bPoints )
{
plane facePlane;
b.face_plane( face, facePlane );
// Perform a projection for both point sets, since we need to be comparing in the same plane
// in order to know that our tests are accurate
obb::pointset3D_t a0( std::move( b.face_project( facePlane, aPoints ) ) );
obb::pointset3D_t b0( std::move( b.face_project( facePlane, bPoints ) ) );
// Find the cardinal plane which is most parallel to the face plane's normal; this
// allows us to omit a comparison for one of the points' components.
cardinal_plane_normal_t cp = glm::ext::best_cardinal_plane_normal( facePlane.mNormal );
return pointset_intersects( cp, contacts, a, b, a0, b0 );
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment