From 3a3c1fd8e854b99289c92ea2074b56f4fe294f53 Mon Sep 17 00:00:00 2001 From: boromisp Date: Sun, 11 Nov 2012 23:09:12 +0100 Subject: [PATCH 1/3] Added new ray-sphere intersection This version uses a geometric method (usually faster) and doesn't calculate the intersection position and normal, only the distance. --- glm/gtx/intersect.hpp | 9 +++++++++ glm/gtx/intersect.inl | 21 +++++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/glm/gtx/intersect.hpp b/glm/gtx/intersect.hpp index 1c090b67..a997555c 100644 --- a/glm/gtx/intersect.hpp +++ b/glm/gtx/intersect.hpp @@ -68,6 +68,15 @@ namespace glm genType const & vert0, genType const & vert1, genType const & vert2, genType & position); + //! Compute the intersection distance of a ray and a sphere. + //! The ray direction vector is unit length. + //! From GLM_GTX_intersect extension. + template + bool intersectRaySphere( + genType const & rayStarting, genType const & rayNormalizedDirection, + genType const & sphereCenter, const typename genType::value_type sphereRadiusSquered, + typename genType::value_type & intersectionDistance); + //! Compute the intersection of a ray and a sphere. //! From GLM_GTX_intersect extension. template diff --git a/glm/gtx/intersect.inl b/glm/gtx/intersect.inl index ad55837f..89e18886 100644 --- a/glm/gtx/intersect.inl +++ b/glm/gtx/intersect.inl @@ -127,6 +127,27 @@ namespace glm return true; } + template + GLM_FUNC_QUALIFIER bool intersectRaySphere + ( + genType const & rayStarting, genType const & rayNormalizedDirection, + genType const & sphereCenter, const typename genType::value_type sphereRadiusSquered, + typename genType::value_type & intersectionDistance + ) + { + typename genType::value_type Epsilon = std::numeric_limits::epsilon(); + genType diff = sphereCenter - rayStarting; + typename genType::value_type t0 = dot(diff, rayNormalizedDirection); + typename genType::value_type dSquared = dot(diff, diff) - t0 * t0; + if( dSquared > sphereRadiusSquered ) + { + return false; + } + typename genType::value_type t1 = sqrt( sphereRadiusSquered - dSquared ); + intersectionDistance = t0 > t1 + Epsilon ? t0 - t1 : t0 + t1; + return intersectionDistance > Epsilon; + } + template GLM_FUNC_QUALIFIER bool intersectRaySphere ( From ed12134f342d4443fef47cc8558cff415f9cee2d Mon Sep 17 00:00:00 2001 From: boromisp Date: Sun, 11 Nov 2012 23:41:11 +0100 Subject: [PATCH 2/3] Fixed the original ray-sphere intersection Changed the original analytic method to a geometrical. The errors in the original intersection calculation: The function has a sphere center parameter, but ignores it and assumes that the sphere is in the origo. It calculates the length of the ray direction vector, but later on uses this vector as a unit vector. The position calculation is simply wrong. It multiplies the direction vector with the radius of the sphere instead of the calculated intersection distance. The quadratic equation solving could be improved too: There should be an early exit for negative discriminant. The naive implementation sould be changed to a floating-point specialized one. --- glm/gtx/intersect.hpp | 6 +++--- glm/gtx/intersect.inl | 29 +++++++---------------------- 2 files changed, 10 insertions(+), 25 deletions(-) diff --git a/glm/gtx/intersect.hpp b/glm/gtx/intersect.hpp index a997555c..56aabbc9 100644 --- a/glm/gtx/intersect.hpp +++ b/glm/gtx/intersect.hpp @@ -81,9 +81,9 @@ namespace glm //! From GLM_GTX_intersect extension. template bool intersectRaySphere( - genType const & orig, genType const & dir, - genType const & center, typename genType::value_type radius, - genType & position, genType & normal); + genType const & rayStarting, genType const & rayNormalizedDirection, + genType const & sphereCenter, const typename genType::value_type sphereRadius, + genType & intersectionPosition, genType & intersectionNormal); //! Compute the intersection of a line and a sphere. //! From GLM_GTX_intersect extension diff --git a/glm/gtx/intersect.inl b/glm/gtx/intersect.inl index 89e18886..3c8527e7 100644 --- a/glm/gtx/intersect.inl +++ b/glm/gtx/intersect.inl @@ -151,31 +151,16 @@ namespace glm template GLM_FUNC_QUALIFIER bool intersectRaySphere ( - genType const & rayStarting, genType const & rayDirection, - genType const & sphereCenter, typename genType::value_type sphereRadius, - genType & position, genType & normal + genType const & rayStarting, genType const & rayNormalizedDirection, + genType const & sphereCenter, const typename genType::value_type sphereRadius, + genType & intersectionPosition, genType & intersectionNormal ) { - typename genType::value_type Epsilon = std::numeric_limits::epsilon(); - - typename genType::value_type a = dot(rayDirection, rayDirection); - typename genType::value_type b = typename genType::value_type(2) * dot(rayStarting, rayDirection); - typename genType::value_type c = dot(rayStarting, rayStarting) - sphereRadius * sphereRadius; - typename genType::value_type d = b * b - typename genType::value_type(4) * a * c; - typename genType::value_type e = sqrt(d); - typename genType::value_type x1 = (-b - e) / (typename genType::value_type(2) * a); - typename genType::value_type x2 = (-b + e) / (typename genType::value_type(2) * a); - - if(x1 > Epsilon) - { - position = rayStarting + rayDirection * sphereRadius; - normal = (position - sphereCenter) / sphereRadius; - return true; - } - else if(x2 > Epsilon) + typename genType::value_type distance; + if( intersectRaySphere( rayStarting, rayNormalizedDirection, sphereCenter, sphereRadius * sphereRadius, distance ) ) { - position = rayStarting + rayDirection * sphereRadius; - normal = (position - sphereCenter) / sphereRadius; + intersectionPosition = rayStarting + rayNormalizedDirection * distance; + intersectionNormal = (intersectionPosition - sphereCenter) / sphereRadius; return true; } return false; From 1683e78f580087155e244ead12dd6ed6ab27af2e Mon Sep 17 00:00:00 2001 From: boromisp Date: Sun, 11 Nov 2012 23:53:10 +0100 Subject: [PATCH 3/3] Fixed the line-sphere intersection The original implementation had the same mistakes than the ray-sphere intersection. Added two new 'out' parameters to return both intersection ponits. Changed the implementation to the geomethric method. --- glm/gtx/intersect.hpp | 5 +++-- glm/gtx/intersect.inl | 40 +++++++++++++++++----------------------- 2 files changed, 20 insertions(+), 25 deletions(-) diff --git a/glm/gtx/intersect.hpp b/glm/gtx/intersect.hpp index 56aabbc9..132fa7e1 100644 --- a/glm/gtx/intersect.hpp +++ b/glm/gtx/intersect.hpp @@ -90,8 +90,9 @@ namespace glm template bool intersectLineSphere( genType const & point0, genType const & point1, - genType const & center, typename genType::value_type radius, - genType & position, genType & normal); + genType const & sphereCenter, typename genType::value_type sphereRadius, + genType & intersectionPosition1, genType & intersectionNormal1, + genType & intersectionPosition2 = genType(), genType & intersectionNormal2 = genType()); /// @} }//namespace glm diff --git a/glm/gtx/intersect.inl b/glm/gtx/intersect.inl index 3c8527e7..9e361f16 100644 --- a/glm/gtx/intersect.inl +++ b/glm/gtx/intersect.inl @@ -170,33 +170,27 @@ namespace glm GLM_FUNC_QUALIFIER bool intersectLineSphere ( genType const & point0, genType const & point1, - genType const & center, typename genType::value_type radius, - genType & position, genType & normal + genType const & sphereCenter, typename genType::value_type sphereRadius, + genType & intersectionPoint1, genType & intersectionNormal1, + genType & intersectionPoint2, genType & intersectionNormal2 ) { typename genType::value_type Epsilon = std::numeric_limits::epsilon(); - - genType dir = point1 - point0; - typename genType::value_type a = dot(dir, dir); - typename genType::value_type b = typename genType::value_type(2) * dot(center, dir); - typename genType::value_type c = dot(center, center) - radius * radius; - typename genType::value_type d = b * b - typename genType::value_type(4) * a * c; - typename genType::value_type e = sqrt(d); - typename genType::value_type x1 = (-b - e) / (typename genType::value_type(2) * a); - typename genType::value_type x2 = (-b + e) / (typename genType::value_type(2) * a); - - if(x1 > Epsilon) - { - position = center + dir * radius; - normal = (position - center) / radius; - return true; - } - else if(x2 > Epsilon) + genType dir = normalize(point1 - point0); + genType diff = sphereCenter - point0; + typename genType::value_type t0 = dot(diff, dir); + typename genType::value_type dSquared = dot(diff, diff) - t0 * t0; + if( dSquared > sphereRadius * sphereRadius ) { - position = center + dir * radius; - normal = (position - center) / radius; - return true; + return false; } - return false; + typename genType::value_type t1 = sqrt( sphereRadius * sphereRadius - dSquared ); + if( t0 < t1 + Epsilon ) + t1 = -t1; + intersectionPoint1 = point0 + dir * (t0 - t1); + intersectionNormal1 = (intersectionPoint1 - sphereCenter) / sphereRadius; + intersectionPoint2 = point0 + dir * (t0 + t1); + intersectionNormal2 = (intersectionPoint2 - sphereCenter) / sphereRadius; + return true; } }//namespace glm