diff --git a/glm/gtx/intersect.hpp b/glm/gtx/intersect.hpp index 80f2a1cd..c3522e9d 100644 --- a/glm/gtx/intersect.hpp +++ b/glm/gtx/intersect.hpp @@ -44,12 +44,13 @@ namespace glm typename genType::value_type & intersectionDistance); //! Compute the intersection of a ray and a triangle. + /// Based om Tomas Möller implementation http://fileadmin.cs.lth.se/cs/Personal/Tomas_Akenine-Moller/raytri/ //! From GLM_GTX_intersect extension. - template + template GLM_FUNC_DECL bool intersectRayTriangle( - genType const & orig, genType const & dir, - genType const & vert0, genType const & vert1, genType const & vert2, - genType & baryPosition); + tvec3 const& orig, tvec3 const& dir, + tvec3 const& v0, tvec3 const& v1, tvec3 const& v2, + tvec3& baryPosition, T& distance); //! Compute the intersection of a line and a triangle. //! From GLM_GTX_intersect extension. diff --git a/glm/gtx/intersect.inl b/glm/gtx/intersect.inl index 904d6cca..fb9a29b1 100644 --- a/glm/gtx/intersect.inl +++ b/glm/gtx/intersect.inl @@ -23,21 +23,75 @@ namespace glm return false; } - template + template GLM_FUNC_QUALIFIER bool intersectRayTriangle ( - genType const & orig, genType const & dir, - genType const & v0, genType const & v1, genType const & v2, - genType & baryPosition + tvec3 const& orig, tvec3 const& dir, + tvec3 const& vert0, tvec3 const& vert1, tvec3 const& vert2, + tvec2& baryPosition, T& distance ) { - genType e1 = v1 - v0; - genType e2 = v2 - v0; + // find vectors for two edges sharing vert0 + tvec3 const edge1 = vert1 - vert0; + tvec3 const edge2 = vert2 - vert0; - genType p = glm::cross(dir, e2); + // begin calculating determinant - also used to calculate U parameter + tvec3 const p = glm::cross(dir, edge2); - typename genType::value_type a = glm::dot(e1, p); + // if determinant is near zero, ray lies in plane of triangle + T const det = glm::dot(edge1, p); + tvec3 qvec; + + if(det > std::numeric_limits::epsilon()) + { + // calculate distance from vert0 to ray origin + tvec3 const tvec = orig - vert0; + + // calculate U parameter and test bounds + baryPosition.x = glm::dot(tvec, p); + if(baryPosition.x < static_cast(0) || baryPosition.x > det) + return false; + + // prepare to test V parameter + qvec = glm::cross(tvec, edge1); + + // calculate V parameter and test bounds + baryPosition.y = glm::dot(dir, qvec); + if((baryPosition.y < static_cast(0)) || ((baryPosition.x + baryPosition.y) > det)) + return false; + } + else if(det < -std::numeric_limits::epsilon()) + { + // calculate distance from vert0 to ray origin + tvec3 const tvec = orig - vert0; + + // calculate U parameter and test bounds + baryPosition.x = glm::dot(tvec, p); + if((baryPosition.x > static_cast(0)) || (baryPosition.x < det)) + return false; + + // prepare to test V parameter + qvec = glm::cross(tvec, edge1); + + // calculate V parameter and test bounds + baryPosition.y = glm::dot(dir, qvec); + if((baryPosition.y > static_cast(0)) || (baryPosition.x + baryPosition.y < det)) + return false; + } + else + return false; // ray is parallel to the plane of the triangle + + T inv_det = static_cast(1) / det; + + // calculate distance, ray intersects triangle + distance = glm::dot(edge2, qvec) * inv_det; + baryPosition *= inv_det; + + return true; + } + +/* typename genType::value_type Epsilon = std::numeric_limits::epsilon(); if(a < Epsilon && a > -Epsilon) return false; @@ -62,6 +116,7 @@ namespace glm return baryPosition.z >= typename genType::value_type(0.0f); } +*/ template GLM_FUNC_QUALIFIER bool intersectLineTriangle diff --git a/readme.md b/readme.md index ee97d3d3..866a88e8 100644 --- a/readme.md +++ b/readme.md @@ -72,6 +72,7 @@ glm::mat4 camera(float Translate, glm::vec2 const & Rotate) #### Fixes: - Removed doxygen references to GTC_half_float which was removed in 0.9.4 - Fixed glm::decompose #448 +- Fixed intersectRayTriangle #6 #### Deprecation: - Removed GLM_GTX_simd_vec4 extension diff --git a/test/gtx/gtx_intersect.cpp b/test/gtx/gtx_intersect.cpp index 0eeb0031..a637dee8 100644 --- a/test/gtx/gtx_intersect.cpp +++ b/test/gtx/gtx_intersect.cpp @@ -1,9 +1,34 @@ #define GLM_ENABLE_EXPERIMENTAL +#include +#include #include -int main() +int test_intersectRayTriangle() { - int Error(0); + int Error = 0; + + glm::vec3 const Orig(0, 0, 2); + glm::vec3 const Dir(0, 0, -1); + glm::vec3 const Vert0(0, 0, 0); + glm::vec3 const Vert1(-1, -1, 0); + glm::vec3 const Vert2(1, -1, 0); + glm::vec2 BaryPosition(0); + float Distance = 0; + + bool const Result = glm::intersectRayTriangle(Orig, Dir, Vert0, Vert1, Vert2, BaryPosition, Distance); + + Error += glm::all(glm::epsilonEqual(BaryPosition, glm::vec2(0), std::numeric_limits::epsilon())) ? 0 : 1; + Error += glm::abs(Distance - 2.f) <= std::numeric_limits::epsilon() ? 0 : 1; + Error += Result ? 0 : 1; + + return Error; +} + +int main() +{ + int Error = 0; + + Error += test_intersectRayTriangle(); return Error; }