// Copyright (c) Xenko contributors (https://xenko.com) and Silicon Studio Corp. (https://www.siliconstudio.co.jp)
// Distributed under the MIT license. See the LICENSE.md file in the project root for more information.
//
// -----------------------------------------------------------------------------
// Original code from SlimMath project. http://code.google.com/p/slimmath/
// Greetings to SlimDX Group. Original code published with the following license:
// -----------------------------------------------------------------------------
/*
* Copyright (c) 2007-2011 SlimDX Group
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
using System;
namespace math
{
/*
* This class is organized so that the least complex objects come first so that the least
* complex objects will have the most methods in most cases. Note that not all shapes exist
* at this time and not all shapes have a corresponding struct. Only the objects that have
* a corresponding struct should come first in naming and in parameter order. The order of
* complexity is as follows:
*
* 1. Point
* 2. Ray
* 3. Segment
* 4. Plane
* 5. Triangle
* 6. Polygon
* 7. Box
* 8. Sphere
* 9. Ellipsoid
* 10. Cylinder
* 11. Cone
* 12. Capsule
* 13. Torus
* 14. Polyhedron
* 15. Frustum
*/
///
/// Contains static methods to help in determining intersections, containment, etc.
///
public static class CollisionHelper
{
///
/// Determines the closest point between a point and a triangle.
///
/// The point to test.
/// The first vertex to test.
/// The second vertex to test.
/// The third vertex to test.
/// When the method completes, contains the closest point between the two objects.
public static void ClosestPointPointTriangle( ref Vec3 point, ref Vec3 vertex1, ref Vec3 vertex2, ref Vec3 vertex3, out Vec3 result )
{
//Source: Real-Time Collision Detection by Christer Ericson
//Reference: Page 136
//Check if P in vertex region outside A
Vec3 ab = vertex2 - vertex1;
Vec3 ac = vertex3 - vertex1;
Vec3 ap = point - vertex1;
float d1 = Vec3.Dot( ab, ap );
float d2 = Vec3.Dot( ac, ap );
if( d1 <= 0.0f && d2 <= 0.0f )
{
result = vertex1; //Barycentric coordinates (1,0,0)
return;
}
//Check if P in vertex region outside B
Vec3 bp = point - vertex2;
float d3 = Vec3.Dot( ab, bp );
float d4 = Vec3.Dot( ac, bp );
if( d3 >= 0.0f && d4 <= d3 )
{
result = vertex2; // barycentric coordinates (0,1,0)
return;
}
//Check if P in edge region of AB, if so return projection of P onto AB
float vc = d1 * d4 - d3 * d2;
if( vc <= 0.0f && d1 >= 0.0f && d3 <= 0.0f )
{
float v = d1 / ( d1 - d3 );
result = vertex1 + v * ab; //Barycentric coordinates (1-v,v,0)
return;
}
//Check if P in vertex region outside C
Vec3 cp = point - vertex3;
float d5 = Vec3.Dot( ab, cp );
float d6 = Vec3.Dot( ac, cp );
if( d6 >= 0.0f && d5 <= d6 )
{
result = vertex3; //Barycentric coordinates (0,0,1)
return;
}
//Check if P in edge region of AC, if so return projection of P onto AC
float vb = d5 * d2 - d1 * d6;
if( vb <= 0.0f && d2 >= 0.0f && d6 <= 0.0f )
{
float w = d2 / ( d2 - d6 );
result = vertex1 + w * ac; //Barycentric coordinates (1-w,0,w)
return;
}
//Check if P in edge region of BC, if so return projection of P onto BC
float va = d3 * d6 - d5 * d4;
if( va <= 0.0f && ( d4 - d3 ) >= 0.0f && ( d5 - d6 ) >= 0.0f )
{
float w = ( d4 - d3 ) / ( ( d4 - d3 ) + ( d5 - d6 ) );
result = vertex2 + w * ( vertex3 - vertex2 ); //Barycentric coordinates (0,1-w,w)
return;
}
//P inside face region. Compute Q through its barycentric coordinates (u,v,w)
float denom = 1.0f / ( va + vb + vc );
float v2 = vb * denom;
float w2 = vc * denom;
result = vertex1 + ab * v2 + ac * w2; //= u*vertex1 + v*vertex2 + w*vertex3, u = va * denom = 1.0f - v - w
}
///
/// Determines the closest point between a and a point.
///
/// The plane to test.
/// The point to test.
/// When the method completes, contains the closest point between the two objects.
public static void ClosestPointPlanePoint( ref Plane plane, ref Vec3 point, out Vec3 result )
{
//Source: Real-Time Collision Detection by Christer Ericson
//Reference: Page 126
float dot;
Vec3.Dot( ref plane.Normal, ref point, out dot );
float t = dot - plane.D;
result = point - ( t * plane.Normal );
}
///
/// Determines the closest point between a and a point.
///
/// The box to test.
/// The point to test.
/// When the method completes, contains the closest point between the two objects.
public static void ClosestPointBoxPoint( ref BoundingBox box, ref Vec3 point, out Vec3 result )
{
//Source: Real-Time Collision Detection by Christer Ericson
//Reference: Page 130
Vec3 temp;
Vec3.Max( ref point, ref box.Minimum, out temp );
Vec3.Min( ref temp, ref box.Maximum, out result );
}
///
/// Determines the closest point between a and a point.
///
/// The bounding sphere.
/// The point to test.
/// When the method completes, contains the closest point between the two objects;
/// or, if the point is directly in the center of the sphere, contains .
public static void ClosestPointSpherePoint( ref BoundingSphere sphere, ref Vec3 point, out Vec3 result )
{
//Source: Jorgy343
//Reference: None
//Get the unit direction from the sphere's center to the point.
Vec3.Subtract( ref point, ref sphere.Center, out result );
result.Normalize();
//Multiply the unit direction by the sphere's radius to get a vector
//the length of the sphere.
result *= sphere.Radius;
//Add the sphere's center to the direction to get a point on the sphere.
result += sphere.Center;
}
///
/// Determines the closest point between a and a .
///
/// The first sphere to test.
/// The second sphere to test.
/// When the method completes, contains the closest point between the two objects;
/// or, if the point is directly in the center of the sphere, contains .
///
/// If the two spheres are overlapping, but not directly ontop of each other, the closest point
/// is the 'closest' point of intersection. This can also be considered is the deepest point of
/// intersection.
///
public static void ClosestPointSphereSphere( ref BoundingSphere sphere1, ref BoundingSphere sphere2, out Vec3 result )
{
//Source: Jorgy343
//Reference: None
//Get the unit direction from the first sphere's center to the second sphere's center.
Vec3.Subtract( ref sphere2.Center, ref sphere1.Center, out result );
result.Normalize();
//Multiply the unit direction by the first sphere's radius to get a vector
//the length of the first sphere.
result *= sphere1.Radius;
//Add the first sphere's center to the direction to get a point on the first sphere.
result += sphere1.Center;
}
///
/// Determines the distance between a and a point.
///
/// The plane to test.
/// The point to test.
/// The distance between the two objects.
public static float DistancePlanePoint( ref Plane plane, ref Vec3 point )
{
//Source: Real-Time Collision Detection by Christer Ericson
//Reference: Page 127
float dot;
Vec3.Dot( ref plane.Normal, ref point, out dot );
return dot - plane.D;
}
///
/// Determines the distance between a and a point.
///
/// The box to test.
/// The point to test.
/// The distance between the two objects.
public static float DistanceBoxPoint( ref BoundingBox box, ref Vec3 point )
{
//Source: Real-Time Collision Detection by Christer Ericson
//Reference: Page 131
float distance = 0f;
if( point.X < box.Minimum.X )
distance += ( box.Minimum.X - point.X ) * ( box.Minimum.X - point.X );
if( point.X > box.Maximum.X )
distance += ( point.X - box.Maximum.X ) * ( point.X - box.Maximum.X );
if( point.Y < box.Minimum.Y )
distance += ( box.Minimum.Y - point.Y ) * ( box.Minimum.Y - point.Y );
if( point.Y > box.Maximum.Y )
distance += ( point.Y - box.Maximum.Y ) * ( point.Y - box.Maximum.Y );
if( point.Z < box.Minimum.Z )
distance += ( box.Minimum.Z - point.Z ) * ( box.Minimum.Z - point.Z );
if( point.Z > box.Maximum.Z )
distance += ( point.Z - box.Maximum.Z ) * ( point.Z - box.Maximum.Z );
return (float)Math.Sqrt( distance );
}
///
/// Determines the distance between a and a .
///
/// The first box to test.
/// The second box to test.
/// The distance between the two objects.
public static float DistanceBoxBox( ref BoundingBox box1, ref BoundingBox box2 )
{
//Source:
//Reference:
float distance = 0f;
//Distance for X.
if( box1.Minimum.X > box2.Maximum.X )
{
float delta = box2.Maximum.X - box1.Minimum.X;
distance += delta * delta;
}
else if( box2.Minimum.X > box1.Maximum.X )
{
float delta = box1.Maximum.X - box2.Minimum.X;
distance += delta * delta;
}
//Distance for Y.
if( box1.Minimum.Y > box2.Maximum.Y )
{
float delta = box2.Maximum.Y - box1.Minimum.Y;
distance += delta * delta;
}
else if( box2.Minimum.Y > box1.Maximum.Y )
{
float delta = box1.Maximum.Y - box2.Minimum.Y;
distance += delta * delta;
}
//Distance for Z.
if( box1.Minimum.Z > box2.Maximum.Z )
{
float delta = box2.Maximum.Z - box1.Minimum.Z;
distance += delta * delta;
}
else if( box2.Minimum.Z > box1.Maximum.Z )
{
float delta = box1.Maximum.Z - box2.Minimum.Z;
distance += delta * delta;
}
return (float)Math.Sqrt( distance );
}
///
/// Determines the distance between a and a point.
///
/// The sphere to test.
/// The point to test.
/// The distance between the two objects.
public static float DistanceSpherePoint( ref BoundingSphere sphere, ref Vec3 point )
{
//Source: Jorgy343
//Reference: None
float distance;
Vec3.Distance( ref sphere.Center, ref point, out distance );
distance -= sphere.Radius;
return Math.Max( distance, 0f );
}
///
/// Determines the distance between a and a .
///
/// The first sphere to test.
/// The second sphere to test.
/// The distance between the two objects.
public static float DistanceSphereSphere( ref BoundingSphere sphere1, ref BoundingSphere sphere2 )
{
//Source: Jorgy343
//Reference: None
float distance;
Vec3.Distance( ref sphere1.Center, ref sphere2.Center, out distance );
distance -= sphere1.Radius + sphere2.Radius;
return Math.Max( distance, 0f );
}
///
/// Determines whether there is an intersection between a and a point.
///
/// The ray to test.
/// The point to test.
/// Whether the two objects intersect.
public static bool RayIntersectsPoint( ref Ray ray, ref Vec3 point )
{
//Source: RayIntersectsSphere
//Reference: None
Vec3 m;
Vec3.Subtract( ref ray.Position, ref point, out m );
//Same thing as RayIntersectsSphere except that the radius of the sphere (point)
//is the epsilon for zero.
float b = Vec3.Dot( m, ray.Direction );
float c = Vec3.Dot( m, m ) - MathUtil.ZeroTolerance;
if( c > 0f && b > 0f )
return false;
float discriminant = b * b - c;
if( discriminant < 0f )
return false;
return true;
}
///
/// Determines whether there is an intersection between a and a .
///
/// The first ray to test.
/// The second ray to test.
/// When the method completes, contains the point of intersection,
/// or if there was no intersection.
/// Whether the two objects intersect.
///
/// This method performs a ray vs ray intersection test based on the following formula
/// from Goldman.
/// s = det([o_2 - o_1, d_2, d_1 x d_2]) / ||d_1 x d_2||^2
/// t = det([o_2 - o_1, d_1, d_1 x d_2]) / ||d_1 x d_2||^2
/// Where o_1 is the position of the first ray, o_2 is the position of the second ray,
/// d_1 is the normalized direction of the first ray, d_2 is the normalized direction
/// of the second ray, det denotes the determinant of a matrix, x denotes the cross
/// product, [ ] denotes a matrix, and || || denotes the length or magnitude of a vector.
///
public static bool RayIntersectsRay( ref Ray ray1, ref Ray ray2, out Vec3 point )
{
//Source: Real-Time Rendering, Third Edition
//Reference: Page 780
Vec3 cross;
Vec3.Cross( ref ray1.Direction, ref ray2.Direction, out cross );
float denominator = cross.Length();
//Lines are parallel.
if( Math.Abs( denominator ) < MathUtil.ZeroTolerance )
{
//Lines are parallel and on top of each other.
if( Math.Abs( ray2.Position.X - ray1.Position.X ) < MathUtil.ZeroTolerance &&
Math.Abs( ray2.Position.Y - ray1.Position.Y ) < MathUtil.ZeroTolerance &&
Math.Abs( ray2.Position.Z - ray1.Position.Z ) < MathUtil.ZeroTolerance )
{
point = Vec3.Zero;
return true;
}
}
denominator = denominator * denominator;
//3x3 matrix for the first ray.
float m11 = ray2.Position.X - ray1.Position.X;
float m12 = ray2.Position.Y - ray1.Position.Y;
float m13 = ray2.Position.Z - ray1.Position.Z;
float m21 = ray2.Direction.X;
float m22 = ray2.Direction.Y;
float m23 = ray2.Direction.Z;
float m31 = cross.X;
float m32 = cross.Y;
float m33 = cross.Z;
//Determinant of first matrix.
float dets =
m11 * m22 * m33 +
m12 * m23 * m31 +
m13 * m21 * m32 -
m11 * m23 * m32 -
m12 * m21 * m33 -
m13 * m22 * m31;
//3x3 matrix for the second ray.
m21 = ray1.Direction.X;
m22 = ray1.Direction.Y;
m23 = ray1.Direction.Z;
//Determinant of the second matrix.
float dett =
m11 * m22 * m33 +
m12 * m23 * m31 +
m13 * m21 * m32 -
m11 * m23 * m32 -
m12 * m21 * m33 -
m13 * m22 * m31;
//t values of the point of intersection.
float s = dets / denominator;
float t = dett / denominator;
//The points of intersection.
Vec3 point1 = ray1.Position + ( s * ray1.Direction );
Vec3 point2 = ray2.Position + ( t * ray2.Direction );
//If the points are not equal, no intersection has occurred.
if( Math.Abs( point2.X - point1.X ) > MathUtil.ZeroTolerance ||
Math.Abs( point2.Y - point1.Y ) > MathUtil.ZeroTolerance ||
Math.Abs( point2.Z - point1.Z ) > MathUtil.ZeroTolerance )
{
point = Vec3.Zero;
return false;
}
point = point1;
return true;
}
///
/// Determines whether there is an intersection between a and a .
///
/// The ray to test.
/// The plane to test.
/// When the method completes, contains the distance of the intersection,
/// or 0 if there was no intersection.
/// Whether the two objects intersect.
public static bool RayIntersectsPlane( ref Ray ray, ref Plane plane, out float distance )
{
//Source: Real-Time Collision Detection by Christer Ericson
//Reference: Page 175
float direction;
Vec3.Dot( ref plane.Normal, ref ray.Direction, out direction );
if( Math.Abs( direction ) < MathUtil.ZeroTolerance )
{
distance = 0f;
return false;
}
float position;
Vec3.Dot( ref plane.Normal, ref ray.Position, out position );
distance = ( -plane.D - position ) / direction;
if( distance < 0f )
{
if( distance < -MathUtil.ZeroTolerance )
{
distance = 0;
return false;
}
distance = 0f;
}
return true;
}
///
/// Determines whether there is an intersection between a and a .
///
/// The ray to test.
/// The plane to test
/// When the method completes, contains the point of intersection,
/// or if there was no intersection.
/// Whether the two objects intersected.
public static bool RayIntersectsPlane( ref Ray ray, ref Plane plane, out Vec3 point )
{
//Source: Real-Time Collision Detection by Christer Ericson
//Reference: Page 175
float distance;
if( !RayIntersectsPlane( ref ray, ref plane, out distance ) )
{
point = Vec3.Zero;
return false;
}
point = ray.Position + ( ray.Direction * distance );
return true;
}
///
/// Determines whether there is an intersection between a and a triangle.
///
/// The ray to test.
/// The first vertex of the triangle to test.
/// The second vertex of the triagnle to test.
/// The third vertex of the triangle to test.
/// When the method completes, contains the distance of the intersection,
/// or 0 if there was no intersection.
/// Whether the two objects intersected.
///
/// This method tests if the ray intersects either the front or back of the triangle.
/// If the ray is parallel to the triangle's plane, no intersection is assumed to have
/// happened. If the intersection of the ray and the triangle is behind the origin of
/// the ray, no intersection is assumed to have happened. In both cases of assumptions,
/// this method returns false.
///
public static bool RayIntersectsTriangle( ref Ray ray, ref Vec3 vertex1, ref Vec3 vertex2, ref Vec3 vertex3, out float distance )
{
//Source: Fast Minimum Storage Ray / Triangle Intersection
//Reference: http://www.cs.virginia.edu/~gfx/Courses/2003/ImageSynthesis/papers/Acceleration/Fast%20MinimumStorage%20RayTriangle%20Intersection.pdf
//Compute vectors along two edges of the triangle.
Vec3 edge1, edge2;
//Edge 1
edge1.X = vertex2.X - vertex1.X;
edge1.Y = vertex2.Y - vertex1.Y;
edge1.Z = vertex2.Z - vertex1.Z;
//Edge2
edge2.X = vertex3.X - vertex1.X;
edge2.Y = vertex3.Y - vertex1.Y;
edge2.Z = vertex3.Z - vertex1.Z;
//Cross product of ray direction and edge2 - first part of determinant.
Vec3 directioncrossedge2;
directioncrossedge2.X = ( ray.Direction.Y * edge2.Z ) - ( ray.Direction.Z * edge2.Y );
directioncrossedge2.Y = ( ray.Direction.Z * edge2.X ) - ( ray.Direction.X * edge2.Z );
directioncrossedge2.Z = ( ray.Direction.X * edge2.Y ) - ( ray.Direction.Y * edge2.X );
//Compute the determinant.
float determinant;
//Dot product of edge1 and the first part of determinant.
determinant = ( edge1.X * directioncrossedge2.X ) + ( edge1.Y * directioncrossedge2.Y ) + ( edge1.Z * directioncrossedge2.Z );
//If the ray is parallel to the triangle plane, there is no collision.
//This also means that we are not culling, the ray may hit both the
//back and the front of the triangle.
if( determinant > -MathUtil.ZeroTolerance && determinant < MathUtil.ZeroTolerance )
{
distance = 0f;
return false;
}
float inversedeterminant = 1.0f / determinant;
//Calculate the U parameter of the intersection point.
Vec3 distanceVector;
distanceVector.X = ray.Position.X - vertex1.X;
distanceVector.Y = ray.Position.Y - vertex1.Y;
distanceVector.Z = ray.Position.Z - vertex1.Z;
float triangleU;
triangleU = ( distanceVector.X * directioncrossedge2.X ) + ( distanceVector.Y * directioncrossedge2.Y ) + ( distanceVector.Z * directioncrossedge2.Z );
triangleU *= inversedeterminant;
//Make sure it is inside the triangle.
if( triangleU < 0f || triangleU > 1f )
{
distance = 0f;
return false;
}
//Calculate the V parameter of the intersection point.
Vec3 distancecrossedge1;
distancecrossedge1.X = ( distanceVector.Y * edge1.Z ) - ( distanceVector.Z * edge1.Y );
distancecrossedge1.Y = ( distanceVector.Z * edge1.X ) - ( distanceVector.X * edge1.Z );
distancecrossedge1.Z = ( distanceVector.X * edge1.Y ) - ( distanceVector.Y * edge1.X );
float triangleV;
triangleV = ( ( ray.Direction.X * distancecrossedge1.X ) + ( ray.Direction.Y * distancecrossedge1.Y ) ) + ( ray.Direction.Z * distancecrossedge1.Z );
triangleV *= inversedeterminant;
//Make sure it is inside the triangle.
if( triangleV < 0f || triangleU + triangleV > 1f )
{
distance = 0f;
return false;
}
//Compute the distance along the ray to the triangle.
float raydistance;
raydistance = ( edge2.X * distancecrossedge1.X ) + ( edge2.Y * distancecrossedge1.Y ) + ( edge2.Z * distancecrossedge1.Z );
raydistance *= inversedeterminant;
//Is the triangle behind the ray origin?
if( raydistance < 0f )
{
distance = 0f;
return false;
}
distance = raydistance;
return true;
}
///
/// Determines whether there is an intersection between a and a triangle.
///
/// The ray to test.
/// The first vertex of the triangle to test.
/// The second vertex of the triangle to test.
/// The third vertex of the triangle to test.
/// When the method completes, contains the point of intersection,
/// or if there was no intersection.
/// Whether the two objects intersected.
public static bool RayIntersectsTriangle( ref Ray ray, ref Vec3 vertex1, ref Vec3 vertex2, ref Vec3 vertex3, out Vec3 point )
{
float distance;
if( !RayIntersectsTriangle( ref ray, ref vertex1, ref vertex2, ref vertex3, out distance ) )
{
point = Vec3.Zero;
return false;
}
point = ray.Position + ( ray.Direction * distance );
return true;
}
///
/// Determines whether there is an intersection between a and a rectangle (2D).
///
/// The ray to test
/// The world matrix applied on the rectangle
/// The size of the rectangle in 3D
/// The index of axis defining the normal of the rectangle in the world. This value should be 0, 1 or 2
/// The position of the intersection point in the world
/// true if the ray and rectangle intersects.
public static bool RayIntersectsRectangle( ref Ray ray, ref Matrix rectangleWorldMatrix, ref Vec3 rectangleSize, int normalAxis, out Vec3 intersectionPoint )
{
bool intersects;
int testAxis1;
int testAxis2;
switch( normalAxis )
{
case 0:
testAxis1 = 1;
testAxis2 = 2;
break;
case 1:
testAxis1 = 2;
testAxis2 = 0;
break;
case 2:
testAxis1 = 0;
testAxis2 = 1;
break;
default:
throw new ArgumentOutOfRangeException( "normalAxis" );
}
var rectanglePosition = new Vec3( rectangleWorldMatrix.M41, rectangleWorldMatrix.M42, rectangleWorldMatrix.M43 );
var normalRowStart = normalAxis << 2;
var plane = new Plane( rectanglePosition, new Vec3( rectangleWorldMatrix[normalRowStart], rectangleWorldMatrix[normalRowStart + 1], rectangleWorldMatrix[normalRowStart + 2] ) );
// early exist the planes were parallels
if( !plane.Intersects( ref ray, out intersectionPoint ) )
return false;
// the position of the intersection point with respect to the rectangle center
var intersectionInRectangle = intersectionPoint - rectanglePosition;
// optimization for the simple but very frequent case where the element is not rotated
if( rectangleWorldMatrix.M12 == 0 && rectangleWorldMatrix.M13 == 0 &&
rectangleWorldMatrix.M21 == 0 && rectangleWorldMatrix.M23 == 0 &&
rectangleWorldMatrix.M31 == 0 && rectangleWorldMatrix.M32 == 0 )
{
var halfSize1 = Math.Abs( rectangleWorldMatrix[( testAxis1 << 2 ) + testAxis1] * rectangleSize[testAxis1] / 2f );
var halfSize2 = Math.Abs( rectangleWorldMatrix[( testAxis2 << 2 ) + testAxis2] * rectangleSize[testAxis2] / 2f );
intersects = -halfSize1 <= intersectionInRectangle[testAxis1] && intersectionInRectangle[testAxis1] <= halfSize1 &&
-halfSize2 <= intersectionInRectangle[testAxis2] && intersectionInRectangle[testAxis2] <= halfSize2;
}
// general case: decompose the rectangle into two triangles and check that all angles are less than 180 degrees in at least one of the triangles.
else
{
// find the most significant component of the plane normal
var normalTestIndex = 0;
for( int i = 1; i < 3; i++ )
{
if( Math.Abs( plane.Normal[i] ) > Math.Abs( plane.Normal[normalTestIndex] ) )
normalTestIndex = i;
}
var normalSign = Math.Sign( plane.Normal[normalTestIndex] );
// the base vector
var base1 = rectangleSize[testAxis1] * new Vec3( rectangleWorldMatrix[( testAxis1 << 2 )], rectangleWorldMatrix[( testAxis1 << 2 ) + 1], rectangleWorldMatrix[( testAxis1 << 2 ) + 2] ) / 2;
var base2 = rectangleSize[testAxis2] * new Vec3( rectangleWorldMatrix[( testAxis2 << 2 )], rectangleWorldMatrix[( testAxis2 << 2 ) + 1], rectangleWorldMatrix[( testAxis2 << 2 ) + 2] ) / 2;
// build the first triangle and perform the test
var v1 = -base1 - base2 - intersectionInRectangle;
var v2 = +base1 - base2 - intersectionInRectangle;
var v3 = +base1 + base2 - intersectionInRectangle;
intersects = Math.Sign( Vec3.Cross( v1, v2 )[normalTestIndex] ) == normalSign &&
Math.Sign( Vec3.Cross( v2, v3 )[normalTestIndex] ) == normalSign &&
Math.Sign( Vec3.Cross( v3, v1 )[normalTestIndex] ) == normalSign;
// early exit on success
if( intersects )
return true;
// build second triangle and perform the test
v1 = -base1 - base2 - intersectionInRectangle;
v2 = +base1 + base2 - intersectionInRectangle;
v3 = -base1 + base2 - intersectionInRectangle;
intersects = Math.Sign( Vec3.Cross( v1, v2 )[normalTestIndex] ) == normalSign &&
Math.Sign( Vec3.Cross( v2, v3 )[normalTestIndex] ) == normalSign &&
Math.Sign( Vec3.Cross( v3, v1 )[normalTestIndex] ) == normalSign;
}
return intersects;
}
///
/// Determines whether there is an intersection between a and a .
///
/// The ray to test.
/// The box to test.
/// When the method completes, contains the distance of the intersection,
/// or 0 if there was no intersection.
/// Whether the two objects intersected.
public static bool RayIntersectsBox( ref Ray ray, ref BoundingBox box, out float distance )
{
//Source: Real-Time Collision Detection by Christer Ericson
//Reference: Page 179
distance = 0f;
float tmax = float.MaxValue;
if( Math.Abs( ray.Direction.X ) < MathUtil.ZeroTolerance )
{
if( ray.Position.X < box.Minimum.X || ray.Position.X > box.Maximum.X )
{
distance = 0f;
return false;
}
}
else
{
float inverse = 1.0f / ray.Direction.X;
float t1 = ( box.Minimum.X - ray.Position.X ) * inverse;
float t2 = ( box.Maximum.X - ray.Position.X ) * inverse;
if( t1 > t2 )
{
float temp = t1;
t1 = t2;
t2 = temp;
}
distance = Math.Max( t1, distance );
tmax = Math.Min( t2, tmax );
if( distance > tmax )
{
distance = 0f;
return false;
}
}
if( Math.Abs( ray.Direction.Y ) < MathUtil.ZeroTolerance )
{
if( ray.Position.Y < box.Minimum.Y || ray.Position.Y > box.Maximum.Y )
{
distance = 0f;
return false;
}
}
else
{
float inverse = 1.0f / ray.Direction.Y;
float t1 = ( box.Minimum.Y - ray.Position.Y ) * inverse;
float t2 = ( box.Maximum.Y - ray.Position.Y ) * inverse;
if( t1 > t2 )
{
float temp = t1;
t1 = t2;
t2 = temp;
}
distance = Math.Max( t1, distance );
tmax = Math.Min( t2, tmax );
if( distance > tmax )
{
distance = 0f;
return false;
}
}
if( Math.Abs( ray.Direction.Z ) < MathUtil.ZeroTolerance )
{
if( ray.Position.Z < box.Minimum.Z || ray.Position.Z > box.Maximum.Z )
{
distance = 0f;
return false;
}
}
else
{
float inverse = 1.0f / ray.Direction.Z;
float t1 = ( box.Minimum.Z - ray.Position.Z ) * inverse;
float t2 = ( box.Maximum.Z - ray.Position.Z ) * inverse;
if( t1 > t2 )
{
float temp = t1;
t1 = t2;
t2 = temp;
}
distance = Math.Max( t1, distance );
tmax = Math.Min( t2, tmax );
if( distance > tmax )
{
distance = 0f;
return false;
}
}
return true;
}
///
/// Determines whether there is an intersection between a and a .
///
/// The ray to test.
/// The box to test.
/// When the method completes, contains the point of intersection,
/// or if there was no intersection.
/// Whether the two objects intersected.
public static bool RayIntersectsBox( ref Ray ray, ref BoundingBox box, out Vec3 point )
{
float distance;
if( !RayIntersectsBox( ref ray, ref box, out distance ) )
{
point = Vec3.Zero;
return false;
}
point = ray.Position + ( ray.Direction * distance );
return true;
}
///
/// Determines whether there is an intersection between a and a .
///
/// The ray to test.
/// The sphere to test.
/// When the method completes, contains the distance of the intersection,
/// or 0 if there was no intersection.
/// Whether the two objects intersected.
public static bool RayIntersectsSphere( ref Ray ray, ref BoundingSphere sphere, out float distance )
{
//Source: Real-Time Collision Detection by Christer Ericson
//Reference: Page 177
Vec3 m;
Vec3.Subtract( ref ray.Position, ref sphere.Center, out m );
float b = Vec3.Dot( m, ray.Direction );
float c = Vec3.Dot( m, m ) - ( sphere.Radius * sphere.Radius );
if( c > 0f && b > 0f )
{
distance = 0f;
return false;
}
float discriminant = b * b - c;
if( discriminant < 0f )
{
distance = 0f;
return false;
}
distance = -b - (float)Math.Sqrt( discriminant );
if( distance < 0f )
distance = 0f;
return true;
}
///
/// Determines whether there is an intersection between a and a .
///
/// The ray to test.
/// The sphere to test.
/// When the method completes, contains the point of intersection,
/// or if there was no intersection.
/// Whether the two objects intersected.
public static bool RayIntersectsSphere( ref Ray ray, ref BoundingSphere sphere, out Vec3 point )
{
float distance;
if( !RayIntersectsSphere( ref ray, ref sphere, out distance ) )
{
point = Vec3.Zero;
return false;
}
point = ray.Position + ( ray.Direction * distance );
return true;
}
///
/// Determines whether there is an intersection between a and a point.
///
/// The plane to test.
/// The point to test.
/// Whether the two objects intersected.
public static PlaneIntersectionType PlaneIntersectsPoint( ref Plane plane, ref Vec3 point )
{
float distance;
Vec3.Dot( ref plane.Normal, ref point, out distance );
distance += plane.D;
if( distance > 0f )
return PlaneIntersectionType.Front;
if( distance < 0f )
return PlaneIntersectionType.Back;
return PlaneIntersectionType.Intersecting;
}
///
/// Determines whether there is an intersection between a and a .
///
/// The first plane to test.
/// The second plane to test.
/// Whether the two objects intersected.
public static bool PlaneIntersectsPlane( ref Plane plane1, ref Plane plane2 )
{
Vec3 direction;
Vec3.Cross( ref plane1.Normal, ref plane2.Normal, out direction );
//If direction is the zero vector, the planes are parallel and possibly
//coincident. It is not an intersection. The dot product will tell us.
float denominator;
Vec3.Dot( ref direction, ref direction, out denominator );
if( Math.Abs( denominator ) < MathUtil.ZeroTolerance )
return false;
return true;
}
///
/// Determines whether there is an intersection between a and a .
///
/// The first plane to test.
/// The second plane to test.
/// When the method completes, contains the line of intersection
/// as a , or a zero ray if there was no intersection.
/// Whether the two objects intersected.
///
/// Although a ray is set to have an origin, the ray returned by this method is really
/// a line in three dimensions which has no real origin. The ray is considered valid when
/// both the positive direction is used and when the negative direction is used.
///
public static bool PlaneIntersectsPlane( ref Plane plane1, ref Plane plane2, out Ray line )
{
//Source: Real-Time Collision Detection by Christer Ericson
//Reference: Page 207
Vec3 direction;
Vec3.Cross( ref plane1.Normal, ref plane2.Normal, out direction );
//If direction is the zero vector, the planes are parallel and possibly
//coincident. It is not an intersection. The dot product will tell us.
float denominator;
Vec3.Dot( ref direction, ref direction, out denominator );
//We assume the planes are normalized, therefore the denominator
//only serves as a parallel and coincident check. Otherwise we need
//to deivide the point by the denominator.
if( Math.Abs( denominator ) < MathUtil.ZeroTolerance )
{
line = new Ray();
return false;
}
Vec3 point;
Vec3 temp = plane1.D * plane2.Normal - plane2.D * plane1.Normal;
Vec3.Cross( ref temp, ref direction, out point );
line.Position = point;
line.Direction = direction;
line.Direction.Normalize();
return true;
}
///
/// Determines whether there is an intersection between a and a triangle.
///
/// The plane to test.
/// The first vertex of the triangle to test.
/// The second vertex of the triagnle to test.
/// The third vertex of the triangle to test.
/// Whether the two objects intersected.
public static PlaneIntersectionType PlaneIntersectsTriangle( ref Plane plane, ref Vec3 vertex1, ref Vec3 vertex2, ref Vec3 vertex3 )
{
//Source: Real-Time Collision Detection by Christer Ericson
//Reference: Page 207
PlaneIntersectionType test1 = PlaneIntersectsPoint( ref plane, ref vertex1 );
PlaneIntersectionType test2 = PlaneIntersectsPoint( ref plane, ref vertex2 );
PlaneIntersectionType test3 = PlaneIntersectsPoint( ref plane, ref vertex3 );
if( test1 == PlaneIntersectionType.Front && test2 == PlaneIntersectionType.Front && test3 == PlaneIntersectionType.Front )
return PlaneIntersectionType.Front;
if( test1 == PlaneIntersectionType.Back && test2 == PlaneIntersectionType.Back && test3 == PlaneIntersectionType.Back )
return PlaneIntersectionType.Back;
return PlaneIntersectionType.Intersecting;
}
///
/// Determines whether there is an intersection between a and a .
///
/// The plane to test.
/// The box to test.
/// Whether the two objects intersected.
public static PlaneIntersectionType PlaneIntersectsBox( ref Plane plane, ref BoundingBox box )
{
//Source: Real-Time Collision Detection by Christer Ericson
//Reference: Page 161
Vec3 min;
Vec3 max;
max.X = ( plane.Normal.X >= 0.0f ) ? box.Minimum.X : box.Maximum.X;
max.Y = ( plane.Normal.Y >= 0.0f ) ? box.Minimum.Y : box.Maximum.Y;
max.Z = ( plane.Normal.Z >= 0.0f ) ? box.Minimum.Z : box.Maximum.Z;
min.X = ( plane.Normal.X >= 0.0f ) ? box.Maximum.X : box.Minimum.X;
min.Y = ( plane.Normal.Y >= 0.0f ) ? box.Maximum.Y : box.Minimum.Y;
min.Z = ( plane.Normal.Z >= 0.0f ) ? box.Maximum.Z : box.Minimum.Z;
float distance;
Vec3.Dot( ref plane.Normal, ref max, out distance );
if( distance + plane.D > 0.0f )
return PlaneIntersectionType.Front;
distance = Vec3.Dot( plane.Normal, min );
if( distance + plane.D < 0.0f )
return PlaneIntersectionType.Back;
return PlaneIntersectionType.Intersecting;
}
///
/// Determines whether there is an intersection between a and a .
///
/// The plane to test.
/// The sphere to test.
/// Whether the two objects intersected.
public static PlaneIntersectionType PlaneIntersectsSphere( ref Plane plane, ref BoundingSphere sphere )
{
//Source: Real-Time Collision Detection by Christer Ericson
//Reference: Page 160
float distance;
Vec3.Dot( ref plane.Normal, ref sphere.Center, out distance );
distance += plane.D;
if( distance > sphere.Radius )
return PlaneIntersectionType.Front;
if( distance < -sphere.Radius )
return PlaneIntersectionType.Back;
return PlaneIntersectionType.Intersecting;
}
/* This implentation is wrong
///
/// Determines whether there is an intersection between a and a triangle.
///
/// The box to test.
/// The first vertex of the triangle to test.
/// The second vertex of the triagnle to test.
/// The third vertex of the triangle to test.
/// Whether the two objects intersected.
public static bool BoxIntersectsTriangle(ref BoundingBox box, ref Vector3 vertex1, ref Vector3 vertex2, ref Vector3 vertex3)
{
if (BoxContainsPoint(ref box, ref vertex1) == ContainmentType.Contains)
return true;
if (BoxContainsPoint(ref box, ref vertex2) == ContainmentType.Contains)
return true;
if (BoxContainsPoint(ref box, ref vertex3) == ContainmentType.Contains)
return true;
return false;
}
*/
///
/// Determines whether there is an intersection between a and a .
///
/// The first box to test.
/// The second box to test.
/// Whether the two objects intersected.
public static bool BoxIntersectsBox( ref BoundingBox box1, ref BoundingBox box2 )
{
if( box1.Minimum.X > box2.Maximum.X || box2.Minimum.X > box1.Maximum.X )
return false;
if( box1.Minimum.Y > box2.Maximum.Y || box2.Minimum.Y > box1.Maximum.Y )
return false;
if( box1.Minimum.Z > box2.Maximum.Z || box2.Minimum.Z > box1.Maximum.Z )
return false;
return true;
}
///
/// Determines whether there is an intersection between a and a .
///
/// The box to test.
/// The sphere to test.
/// Whether the two objects intersected.
public static bool BoxIntersectsSphere( ref BoundingBox box, ref BoundingSphere sphere )
{
//Source: Real-Time Collision Detection by Christer Ericson
//Reference: Page 166
Vec3 vector;
Vec3.Clamp( ref sphere.Center, ref box.Minimum, ref box.Maximum, out vector );
float distance = Vec3.DistanceSquared( sphere.Center, vector );
return distance <= sphere.Radius * sphere.Radius;
}
///
/// Determines whether there is an intersection between a and a triangle.
///
/// The sphere to test.
/// The first vertex of the triangle to test.
/// The second vertex of the triagnle to test.
/// The third vertex of the triangle to test.
/// Whether the two objects intersected.
public static bool SphereIntersectsTriangle( ref BoundingSphere sphere, ref Vec3 vertex1, ref Vec3 vertex2, ref Vec3 vertex3 )
{
//Source: Real-Time Collision Detection by Christer Ericson
//Reference: Page 167
Vec3 point;
ClosestPointPointTriangle( ref sphere.Center, ref vertex1, ref vertex2, ref vertex3, out point );
Vec3 v = point - sphere.Center;
float dot;
Vec3.Dot( ref v, ref v, out dot );
return dot <= sphere.Radius * sphere.Radius;
}
///
/// Determines whether there is an intersection between a and a .
///
/// First sphere to test.
/// Second sphere to test.
/// Whether the two objects intersected.
public static bool SphereIntersectsSphere( ref BoundingSphere sphere1, ref BoundingSphere sphere2 )
{
float radiisum = sphere1.Radius + sphere2.Radius;
return Vec3.DistanceSquared( sphere1.Center, sphere2.Center ) <= radiisum * radiisum;
}
///
/// Determines whether a contains a point.
///
/// The box to test.
/// The point to test.
/// The type of containment the two objects have.
public static ContainmentType BoxContainsPoint( ref BoundingBox box, ref Vec3 point )
{
if( box.Minimum.X <= point.X && box.Maximum.X >= point.X &&
box.Minimum.Y <= point.Y && box.Maximum.Y >= point.Y &&
box.Minimum.Z <= point.Z && box.Maximum.Z >= point.Z )
{
return ContainmentType.Contains;
}
return ContainmentType.Disjoint;
}
/* This implentation is wrong
///
/// Determines whether a contains a triangle.
///
/// The box to test.
/// The first vertex of the triangle to test.
/// The second vertex of the triagnle to test.
/// The third vertex of the triangle to test.
/// The type of containment the two objects have.
public static ContainmentType BoxContainsTriangle(ref BoundingBox box, ref Vector3 vertex1, ref Vector3 vertex2, ref Vector3 vertex3)
{
ContainmentType test1 = BoxContainsPoint(ref box, ref vertex1);
ContainmentType test2 = BoxContainsPoint(ref box, ref vertex2);
ContainmentType test3 = BoxContainsPoint(ref box, ref vertex3);
if (test1 == ContainmentType.Contains && test2 == ContainmentType.Contains && test3 == ContainmentType.Contains)
return ContainmentType.Contains;
if (test1 == ContainmentType.Contains || test2 == ContainmentType.Contains || test3 == ContainmentType.Contains)
return ContainmentType.Intersects;
return ContainmentType.Disjoint;
}
*/
///
/// Determines whether a contains a .
///
/// The first box to test.
/// The second box to test.
/// The type of containment the two objects have.
public static ContainmentType BoxContainsBox( ref BoundingBox box1, ref BoundingBox box2 )
{
if( box1.Maximum.X < box2.Minimum.X || box1.Minimum.X > box2.Maximum.X )
return ContainmentType.Disjoint;
if( box1.Maximum.Y < box2.Minimum.Y || box1.Minimum.Y > box2.Maximum.Y )
return ContainmentType.Disjoint;
if( box1.Maximum.Z < box2.Minimum.Z || box1.Minimum.Z > box2.Maximum.Z )
return ContainmentType.Disjoint;
if( box1.Minimum.X <= box2.Minimum.X && ( box2.Maximum.X <= box1.Maximum.X &&
box1.Minimum.Y <= box2.Minimum.Y && box2.Maximum.Y <= box1.Maximum.Y ) &&
box1.Minimum.Z <= box2.Minimum.Z && box2.Maximum.Z <= box1.Maximum.Z )
{
return ContainmentType.Contains;
}
return ContainmentType.Intersects;
}
///
/// Determines whether a contains a .
///
/// The box to test.
/// The sphere to test.
/// The type of containment the two objects have.
public static ContainmentType BoxContainsSphere( ref BoundingBox box, ref BoundingSphere sphere )
{
Vec3 vector;
Vec3.Clamp( ref sphere.Center, ref box.Minimum, ref box.Maximum, out vector );
float distance = Vec3.DistanceSquared( sphere.Center, vector );
if( distance > sphere.Radius * sphere.Radius )
return ContainmentType.Disjoint;
if( ( ( box.Minimum.X + sphere.Radius <= sphere.Center.X ) && ( sphere.Center.X <= box.Maximum.X - sphere.Radius ) && ( box.Maximum.X - box.Minimum.X > sphere.Radius ) ) &&
( ( box.Minimum.Y + sphere.Radius <= sphere.Center.Y ) && ( sphere.Center.Y <= box.Maximum.Y - sphere.Radius ) && ( box.Maximum.Y - box.Minimum.Y > sphere.Radius ) ) &&
( ( box.Minimum.Z + sphere.Radius <= sphere.Center.Z ) && ( sphere.Center.Z <= box.Maximum.Z - sphere.Radius ) && ( box.Maximum.Z - box.Minimum.Z > sphere.Radius ) ) )
{
return ContainmentType.Contains;
}
return ContainmentType.Intersects;
}
///
/// Determines whether a contains a point.
///
/// The sphere to test.
/// The point to test.
/// The type of containment the two objects have.
public static ContainmentType SphereContainsPoint( ref BoundingSphere sphere, ref Vec3 point )
{
if( Vec3.DistanceSquared( point, sphere.Center ) <= sphere.Radius * sphere.Radius )
return ContainmentType.Contains;
return ContainmentType.Disjoint;
}
///
/// Determines whether a contains a triangle.
///
/// The sphere to test.
/// The first vertex of the triangle to test.
/// The second vertex of the triagnle to test.
/// The third vertex of the triangle to test.
/// The type of containment the two objects have.
public static ContainmentType SphereContainsTriangle( ref BoundingSphere sphere, ref Vec3 vertex1, ref Vec3 vertex2, ref Vec3 vertex3 )
{
//Source: Jorgy343
//Reference: None
ContainmentType test1 = SphereContainsPoint( ref sphere, ref vertex1 );
ContainmentType test2 = SphereContainsPoint( ref sphere, ref vertex2 );
ContainmentType test3 = SphereContainsPoint( ref sphere, ref vertex3 );
if( test1 == ContainmentType.Contains && test2 == ContainmentType.Contains && test3 == ContainmentType.Contains )
return ContainmentType.Contains;
if( SphereIntersectsTriangle( ref sphere, ref vertex1, ref vertex2, ref vertex3 ) )
return ContainmentType.Intersects;
return ContainmentType.Disjoint;
}
///
/// Determines whether a contains a .
///
/// The sphere to test.
/// The box to test.
/// The type of containment the two objects have.
public static ContainmentType SphereContainsBox( ref BoundingSphere sphere, ref BoundingBox box )
{
Vec3 vector;
if( !BoxIntersectsSphere( ref box, ref sphere ) )
return ContainmentType.Disjoint;
float radiussquared = sphere.Radius * sphere.Radius;
vector.X = sphere.Center.X - box.Minimum.X;
vector.Y = sphere.Center.Y - box.Maximum.Y;
vector.Z = sphere.Center.Z - box.Maximum.Z;
if( vector.LengthSquared() > radiussquared )
return ContainmentType.Intersects;
vector.X = sphere.Center.X - box.Maximum.X;
vector.Y = sphere.Center.Y - box.Maximum.Y;
vector.Z = sphere.Center.Z - box.Maximum.Z;
if( vector.LengthSquared() > radiussquared )
return ContainmentType.Intersects;
vector.X = sphere.Center.X - box.Maximum.X;
vector.Y = sphere.Center.Y - box.Minimum.Y;
vector.Z = sphere.Center.Z - box.Maximum.Z;
if( vector.LengthSquared() > radiussquared )
return ContainmentType.Intersects;
vector.X = sphere.Center.X - box.Minimum.X;
vector.Y = sphere.Center.Y - box.Minimum.Y;
vector.Z = sphere.Center.Z - box.Maximum.Z;
if( vector.LengthSquared() > radiussquared )
return ContainmentType.Intersects;
vector.X = sphere.Center.X - box.Minimum.X;
vector.Y = sphere.Center.Y - box.Maximum.Y;
vector.Z = sphere.Center.Z - box.Minimum.Z;
if( vector.LengthSquared() > radiussquared )
return ContainmentType.Intersects;
vector.X = sphere.Center.X - box.Maximum.X;
vector.Y = sphere.Center.Y - box.Maximum.Y;
vector.Z = sphere.Center.Z - box.Minimum.Z;
if( vector.LengthSquared() > radiussquared )
return ContainmentType.Intersects;
vector.X = sphere.Center.X - box.Maximum.X;
vector.Y = sphere.Center.Y - box.Minimum.Y;
vector.Z = sphere.Center.Z - box.Minimum.Z;
if( vector.LengthSquared() > radiussquared )
return ContainmentType.Intersects;
vector.X = sphere.Center.X - box.Minimum.X;
vector.Y = sphere.Center.Y - box.Minimum.Y;
vector.Z = sphere.Center.Z - box.Minimum.Z;
if( vector.LengthSquared() > radiussquared )
return ContainmentType.Intersects;
return ContainmentType.Contains;
}
///
/// Determines whether a contains a .
///
/// The first sphere to test.
/// The second sphere to test.
/// The type of containment the two objects have.
public static ContainmentType SphereContainsSphere( ref BoundingSphere sphere1, ref BoundingSphere sphere2 )
{
float distance = Vec3.Distance( sphere1.Center, sphere2.Center );
if( sphere1.Radius + sphere2.Radius < distance )
return ContainmentType.Disjoint;
if( sphere1.Radius - sphere2.Radius < distance )
return ContainmentType.Intersects;
return ContainmentType.Contains;
}
///
/// Determines whether a intersects or contains an AABB determined by its center and extent.
/// Faster variant specific for frustum culling.
///
/// The frustum.
/// The bounding box ext.
/// true if XXXX, false otherwise.
public static bool FrustumContainsBox( ref BoundingFrustum frustum, ref BoundingBoxExt boundingBoxExt )
{
unsafe
{
fixed( Plane* planeStart = &frustum.LeftPlane )
{
var plane = planeStart;
for( int i = 0; i < 6; ++i )
{
// Previous code:
if( Vec3.Dot( boundingBoxExt.Center, plane->Normal )
+ boundingBoxExt.Extent.X * Math.Abs( plane->Normal.X )
+ boundingBoxExt.Extent.Y * Math.Abs( plane->Normal.Y )
+ boundingBoxExt.Extent.Z * Math.Abs( plane->Normal.Z )
<= -plane->D )
return false;
plane++;
}
}
return true;
}
/*
unsafe
{
fixed (Plane* planeStart = &frustum.LeftPlane)
fixed (Vector3* pExtent = &boundingBoxExt.Extent)
{
var plane = planeStart;
for (int i = 0; i < 6; ++i)
{
// Previous code:
//if (Vector3.Dot(boundingBoxExt.Center, plane->Normal)
// + boundingBoxExt.Extent.X * Math.Abs(plane->Normal.X)
// + boundingBoxExt.Extent.Y * Math.Abs(plane->Normal.Y)
// + boundingBoxExt.Extent.Z * Math.Abs(plane->Normal.Z)
// <= -plane->D)
// Optimized version (only 1 dot and cheaper Math.Abs)
// https://fgiesen.wordpress.com/2010/10/17/view-frustum-culling/
// return dot3(center, plane) + dot3(extent, absPlane) <= -plane.w;
// or
// vector4 signFlip = componentwise_and(plane, 0x80000000);
// vector3 centerOffset = xor(extent, signFlip)
// dot3(center + centerOffset, plane) <= -plane.w;
uint val = (((uint*)&plane->Normal)[0] & 0x80000000) ^ ((uint*)pExtent)[0];
var dist = plane->Normal.X * ((*(float*)(&val)) + boundingBoxExt.Center.X);
val = (((uint*)&plane->Normal)[1] & 0x80000000) ^ ((uint*)pExtent)[1];
dist += plane->Normal.Y * ((*(float*)(&val)) + boundingBoxExt.Center.Y);
val = (((uint*)&plane->Normal)[2] & 0x80000000) ^ ((uint*)pExtent)[2];
dist += plane->Normal.Z * ((*(float*)(&val)) + boundingBoxExt.Center.Z);
if (dist <= -plane->D)
return false;
plane++;
}
}
return true;
}
*/
}
}
}