Added degenerate versions of ray/line-quad intersect

This commit is contained in:
Tormod Haugland 2014-04-27 09:29:44 +02:00
parent ed98125fc0
commit 05865e239b
2 changed files with 516 additions and 1 deletions

View File

@ -140,6 +140,42 @@ namespace glm
); );
//! Compute the intersection of a ray and any quadrilateral.
//! From the GLM_GTX_intersect extension
template <typename genType>
GLM_FUNC_DECL bool intersectRayDegenerateQuad(
genType const & orig, genType const & dir,
genType const & v00, genType const & v10, genType const & v11, genType const & v01,
genType & bilinearCoordinates
);
//! Compute the intersection of a ray and any quadrilateral.
//! Does not compute the bilinear coordinates of the intersection.
//! From the GLM_GTX_intersect extension
template<typename genType>
GLM_FUNC_DECL bool fastIntersectRayDegenerateQuad(
genType const & orig, genType const & dir,
genType const & v00, genType const & v10, genType const & v11, genType const & v01
);
//! Compute the intersection of a line and any quadrilateral.
//! From the GLM_GTX_intersect extension
template<typename genType>
GLM_FUNC_DECL bool intersectLineDegenerateQuad(
genType const & orig, genType const & dir,
genType const & v00, genType const & v10, genType const & v11, genType const & v01,
genType & bilinearCoordinates
);
//! Compute the intersection of a line and any quadrilateral.
//! Does not compute the bilinear coordinates of the intersection.
//! From the GLM_GTX_intersect extension
template<typename genType>
GLM_FUNC_DECL bool fastIntersectLineDegenerateQuad(
genType const & orig, genType const & dir,
genType const & v00, genType const & v10, genType const & v11, genType const & v01
);
/// @} /// @}
}//namespace glm }//namespace glm

View File

@ -449,7 +449,7 @@ namespace glm
return true; return true;
} }
template<typename genType> template<typename genType>
GLM_FUNC_QUALIFIER bool intersectLineQuad GLM_FUNC_QUALIFIER bool intersectLineQuad
( (
@ -676,5 +676,484 @@ namespace glm
return true; return true;
} }
template<typename genType>
GLM_FUNC_QUALIFIER bool intersectLineQuad
(
genType const & orig, genType const & dir,
genType const & v00, genType const & v10, genType const & v11, genType const & v01,
genType & bilinearCoordinates
)
{
// Epsilon to reject parallell lines
typename genType::value_type epsilon = std::numeric_limits<typename genType::value_type>::epsilon();
// Calculate edges and normal of first triangle
genType e01 = v10 - v00;
genType e03 = v01 - v00;
genType p = glm::cross(dir, e03);
typename genType::value_type det = glm::dot(e01, p);
// Reject rays orthagonal to the normal vector. I.e. rays parallell to the plane.
if(det < epsilon && det > -epsilon)
return false;
typename genType::value_type inv_det = typename genType::value_type(1.0f)/det;
genType s = orig - v00;
// Calculate the barycentric alpha coordinate of the first triangle
typename genType::value_type alpha = inv_det * glm::dot(s, p);
// It lies outside the triangle
if(alpha > typename genType::value_type(1.0f))
return false;
if(alpha < typename genType::value_type(0.0f))
return false;
// Vector perpendicular to T and e01
genType q = glm::cross(s, e01);
// Calculate barycentric beta coordinate of the first triangle
typename genType::value_type beta = inv_det * glm::dot(dir, q);
if(beta > typename genType::value_type(1.0f))
return false;
if(beta < typename genType::value_type(0.0f))
return false;
bilinearCoordinates.z = inv_det * glm::dot(e03, q);
if(alpha + beta > typename genType::value_type(1.0f)){
// Do exactly the same for the second triangle
genType e23 = v01 - v11;
genType e21 = v10 - v11;
p = glm::cross(dir, e21);
det = glm::dot(e23, p);
if(det < epsilon && det > -epsilon)
return false;
inv_det = typename genType::value_type(1.0f)/det;
s = orig - v11;
alpha = inv_det * glm::dot(s, p);
if(alpha < typename genType::value_type(0.0f))
return false;
q = glm::cross(s, e23);
beta = inv_det * glm::dot(dir, q);
if(beta < typename genType::value_type(0.0f))
return false;
// This to support degenerate squares
if(beta + alpha > typename genType::value_type(1.0f))
return false;
bilinearCoordinates.z = inv_det * glm::dot(e21, q);
}
// Compute barycentric coordinates of v11
genType e02 = v11 - v00;
genType N = glm::cross(e01, e03);
typename genType::value_type alpha_11, beta_11;
if(abs(N.x) >= abs(N.y) && abs(N.x) >= abs(N.z)) {
alpha_11 = (e02.y * e03.z - e02.z * e03.y) / N.x;
beta_11 = (e01.y * e02.z - e01.z * e02.y) / N.x;
} else if(abs(N.y) >= abs(N.x) && abs(N.y) >= abs(N.z)) {
alpha_11 = (e02.z * e03.x - e02.x * e03.z) / N.x;
beta_11 = (e01.z * e02.x - e01.x * e02.z) / N.x;
} else {
alpha_11 = (e02.x * e03.y - e02.y * e03.x) / N.z;
beta_11 = (e01.x * e02.y - e01.y * e02.x) / N.z;
}
// Compute bilinear coordinates of the intersection point
if(abs(alpha_11 - typename genType::value_type(1.0f)) < epsilon) {
bilinearCoordinates.x = alpha;
if(abs(beta_11 - typename genType::value_type(1.0f)) < epsilon){
bilinearCoordinates.y = beta;
} else {
bilinearCoordinates.y = beta/(bilinearCoordinates.x * (beta_11 - typename genType::value_type(1.0f)) + typename genType::value_type(1.0f));
}
} else if(abs(beta_11 - typename genType::value_type(1.0f)) < epsilon) {
bilinearCoordinates.y = alpha;
bilinearCoordinates.x = alpha/(bilinearCoordinates.y*(alpha_11 - typename genType::value_type(1.0f)) + typename genType::value_type(1.0f));
} else {
typename genType::value_type a, b, c, discr, q;
a = -(beta_11 - typename genType::value_type(1.0f));
b = alpha*(beta_11 - 1) - beta*(alpha_11 - typename genType::value_type(1.0f)) - typename genType::value_type(1.0f);
c = alpha;
discr = b*b - typename genType::value_type(4.0f)*a*c;
// Get sign of b
typename genType::value_type sign = (typename genType::value_type(0) < b) - (b < typename genType::value_type(0));
q = -(typename genType::value_type(0.5f)) * (b + sign*glm::fastSqrt(discr));
bilinearCoordinates.x = q/a;
if(bilinearCoordinates.x < 0 || bilinearCoordinates.y > 1){
bilinearCoordinates.x = c/q;
}
bilinearCoordinates.y = beta/(bilinearCoordinates.x*(beta_11 - 1) + 1);
}
return true;
}
template<typename genType>
GLM_FUNC_QUALIFIER bool fastIntersectLineQuad
(
genType const & orig, genType const & dir,
genType const & v00, genType const & v10, genType const & v11, genType const & v01
)
{
// Epsilon to reject parallell lines
typename genType::value_type epsilon = std::numeric_limits<typename genType::value_type>::epsilon();
// Calculate edges and normal of first triangle
genType e01 = v10 - v00;
genType e03 = v01 - v00;
genType p = glm::cross(dir, e03);
typename genType::value_type det = glm::dot(e01, p);
// Reject rays orthagonal to the normal vector. I.e. rays parallell to the plane.
if(det < epsilon && det > -epsilon)
return false;
typename genType::value_type inv_det = typename genType::value_type(1.0f)/det;
genType s = orig - v00;
// Calculate the barycentric alpha coordinate of the first triangle
typename genType::value_type alpha = inv_det * glm::dot(s, p);
// It lies outside the triangle
if(alpha > typename genType::value_type(1.0f))
return false;
if(alpha < typename genType::value_type(0.0f))
return false;
// Vector perpendicular to T and e01
genType q = glm::cross(s, e01);
// Calculate barycentric beta coordinate of the first triangle
typename genType::value_type beta = inv_det * glm::dot(dir, q);
if(beta > typename genType::value_type(1.0f))
return false;
if(beta < typename genType::value_type(0.0f))
return false;
if(alpha + beta > typename genType::value_type(1.0f)){
// Do exactly the same for the second triangle
genType e23 = v01 - v11;
genType e21 = v10 - v11;
p = glm::cross(dir, e21);
det = glm::dot(e23, p);
if(det < epsilon && det > -epsilon)
return false;
inv_det = typename genType::value_type(1.0f)/det;
s = orig - v11;
alpha = inv_det * glm::dot(s, p);
if(alpha < typename genType::value_type(0.0f))
return false;
q = glm::cross(s, e23);
beta = inv_det * glm::dot(dir, q);
if(beta < typename genType::value_type(0.0f))
return false;
// This to support degenerate squares
if(beta + alpha > typename genType::value_type(1.0f))
return false;
}
return true;
}
template<typename genType>
GLM_FUNC_QUALIFIER bool intersectLineDegenerateQuad
(
genType const & orig, genType const & dir,
genType const & v00, genType const & v10, genType const & v11, genType const & v01,
genType & bilinearCoordinates
)
{
genType e01, e03, p, s, q;
typename genType::value_type epsilon, det, inv_det, alpha, beta;
bool isInOne = true;
// Epsilon to reject parallell lines
epsilon = std::numeric_limits<typename genType::value_type>::epsilon();
// Calculate edges and normal of first triangle
e01 = v10 - v00;
e03 = v01 - v00;
p = glm::cross(dir, e03);
det = glm::dot(e01, p);
// Reject rays orthagonal to the normal vector. I.e. rays parallell to the plane.
if(det < epsilon && det > -epsilon){
isInOne = false;
goto second;
}
inv_det = typename genType::value_type(1.0f)/det;
s = orig - v00;
// Calculate the barycentric alpha coordinate of the first triangle
alpha = inv_det * glm::dot(s, p);
// It lies outside the triangle
if(alpha > typename genType::value_type(1.0f)){
isInOne = false;
goto second;
}
if(alpha < typename genType::value_type(0.0f)){
isInOne = false;
goto second;
}
// Vector perpendicular to T and e01
q = glm::cross(s, e01);
// Calculate barycentric beta coordinate of the first triangle
beta = inv_det * glm::dot(dir, q);
if(beta > typename genType::value_type(1.0f)){
isInOne = false;
goto second;
}
if(beta < typename genType::value_type(0.0f)){
isInOne = false;
goto second;
}
/* Intersection is not in the first triangle, check the second*/
second:
if(!isInOne || alpha + beta > typename genType::value_type(1.0f)){
// Do exactly the same for the second triangle
genType e23 = v01 - v11;
genType e21 = v10 - v11;
p = glm::cross(dir, e21);
det = glm::dot(e23, p);
if(det < epsilon && det > -epsilon){
return false;
}
inv_det = typename genType::value_type(1.0f)/det;
s = orig - v11;
alpha = inv_det * glm::dot(s, p);
if(alpha < typename genType::value_type(0.0f))
return false;
q = glm::cross(s, e23);
beta = inv_det * glm::dot(dir, q);
if(beta < typename genType::value_type(0.0f))
return false;
// This to support degenerate squares
if(beta + alpha > typename genType::value_type(1.0f))
return false;
}
// Compute barycentric coordinates of v11
genType e02 = v11 - v00;
genType N = glm::cross(e01, e03);
typename genType::value_type alpha_11, beta_11;
if(abs(N.x) >= abs(N.y) && abs(N.x) >= abs(N.z)) {
alpha_11 = (e02.y * e03.z - e02.z * e03.y) / N.x;
beta_11 = (e01.y * e02.z - e01.z * e02.y) / N.x;
} else if(abs(N.y) >= abs(N.x) && abs(N.y) >= abs(N.z)) {
alpha_11 = (e02.z * e03.x - e02.x * e03.z) / N.x;
beta_11 = (e01.z * e02.x - e01.x * e02.z) / N.x;
} else {
alpha_11 = (e02.x * e03.y - e02.y * e03.x) / N.z;
beta_11 = (e01.x * e02.y - e01.y * e02.x) / N.z;
}
// Compute bilinear coordinates of the intersection point
if(abs(alpha_11 - typename genType::value_type(1.0f)) < epsilon) {
bilinearCoordinates.x = alpha;
if(abs(beta_11 - typename genType::value_type(1.0f)) < epsilon){
bilinearCoordinates.y = beta;
} else {
bilinearCoordinates.y = beta/(bilinearCoordinates.x * (beta_11 - typename genType::value_type(1.0f)) + typename genType::value_type(1.0f));
}
} else if(abs(beta_11 - typename genType::value_type(1.0f)) < epsilon) {
bilinearCoordinates.y = alpha;
bilinearCoordinates.x = alpha/(bilinearCoordinates.y*(alpha_11 - typename genType::value_type(1.0f)) + typename genType::value_type(1.0f));
} else {
typename genType::value_type a, b, c, discr, q;
a = -(beta_11 - typename genType::value_type(1.0f));
b = alpha*(beta_11 - 1) - beta*(alpha_11 - typename genType::value_type(1.0f)) - typename genType::value_type(1.0f);
c = alpha;
discr = b*b - typename genType::value_type(4.0f)*a*c;
// Get sign of b
typename genType::value_type sign = (typename genType::value_type(0) < b) - (b < typename genType::value_type(0));
q = -(typename genType::value_type(0.5f)) * (b + sign*glm::fastSqrt(discr));
bilinearCoordinates.x = q/a;
if(bilinearCoordinates.x < 0 || bilinearCoordinates.y > 1){
bilinearCoordinates.x = c/q;
}
bilinearCoordinates.y = beta/(bilinearCoordinates.x*(beta_11 - 1) + 1);
}
return true;
}
template<typename genType>
GLM_FUNC_QUALIFIER bool fastIntersectLineDegenerateQuad
(
genType const & orig, genType const & dir,
genType const & v00, genType const & v10, genType const & v11, genType const & v01
)
{
genType e01, e03, p, s, q;
typename genType::value_type epsilon, det, inv_det, alpha, beta;
bool isInOne = true;
// Epsilon to reject parallell lines
epsilon = std::numeric_limits<typename genType::value_type>::epsilon();
// Calculate edges and normal of first triangle
e01 = v10 - v00;
e03 = v01 - v00;
p = glm::cross(dir, e03);
det = glm::dot(e01, p);
// Reject rays orthagonal to the normal vector. I.e. rays parallell to the plane.
if(det < epsilon && det > -epsilon){
isInOne = false;
goto second;
}
inv_det = typename genType::value_type(1.0f)/det;
s = orig - v00;
// Calculate the barycentric alpha coordinate of the first triangle
alpha = inv_det * glm::dot(s, p);
// It lies outside the triangle
if(alpha > typename genType::value_type(1.0f)){
isInOne = false;
goto second;
}
if(alpha < typename genType::value_type(0.0f)){
isInOne = false;
goto second;
}
// Vector perpendicular to T and e01
q = glm::cross(s, e01);
// Calculate barycentric beta coordinate of the first triangle
beta = inv_det * glm::dot(dir, q);
if(beta > typename genType::value_type(1.0f)){
isInOne = false;
goto second;
}
if(beta < typename genType::value_type(0.0f)){
isInOne = false;
goto second;
}
/* Intersection is not in the first triangle, check the second*/
second:
if(!isInOne || alpha + beta > typename genType::value_type(1.0f)){
// Do exactly the same for the second triangle
genType e23 = v01 - v11;
genType e21 = v10 - v11;
p = glm::cross(dir, e21);
det = glm::dot(e23, p);
if(det < epsilon && det > -epsilon){
return false;
}
inv_det = typename genType::value_type(1.0f)/det;
s = orig - v11;
alpha = inv_det * glm::dot(s, p);
if(alpha < typename genType::value_type(0.0f))
return false;
q = glm::cross(s, e23);
beta = inv_det * glm::dot(dir, q);
if(beta < typename genType::value_type(0.0f))
return false;
// This to support degenerate squares
if(beta + alpha > typename genType::value_type(1.0f))
return false;
}
return true;
}
}//namespace glm }//namespace glm