Browse Source

Fixed intersectRayTriangle #6

Christophe Riccio 9 years ago
parent
commit
58c5e0ef4d
4 changed files with 95 additions and 13 deletions
  1. 5 4
      glm/gtx/intersect.hpp
  2. 63 8
      glm/gtx/intersect.inl
  3. 1 0
      readme.md
  4. 26 1
      test/gtx/gtx_intersect.cpp

+ 5 - 4
glm/gtx/intersect.hpp

@@ -44,12 +44,13 @@ namespace glm
 		typename genType::value_type & intersectionDistance);
 		typename genType::value_type & intersectionDistance);
 
 
 	//! Compute the intersection of a ray and a triangle.
 	//! 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.
 	//! From GLM_GTX_intersect extension.
-	template <typename genType>
+	template <typename T, precision P>
 	GLM_FUNC_DECL bool intersectRayTriangle(
 	GLM_FUNC_DECL bool intersectRayTriangle(
-		genType const & orig, genType const & dir,
-		genType const & vert0, genType const & vert1, genType const & vert2,
-		genType & baryPosition);
+		tvec3<T, P> const& orig, tvec3<T, P> const& dir,
+		tvec3<T, P> const& v0, tvec3<T, P> const& v1, tvec3<T, P> const& v2,
+		tvec3<T, P>& baryPosition, T& distance);
 
 
 	//! Compute the intersection of a line and a triangle.
 	//! Compute the intersection of a line and a triangle.
 	//! From GLM_GTX_intersect extension.
 	//! From GLM_GTX_intersect extension.

+ 63 - 8
glm/gtx/intersect.inl

@@ -23,21 +23,75 @@ namespace glm
 		return false;
 		return false;
 	}
 	}
 
 
-	template <typename genType>
+	template <typename T, precision P>
 	GLM_FUNC_QUALIFIER bool intersectRayTriangle
 	GLM_FUNC_QUALIFIER bool intersectRayTriangle
 	(
 	(
-		genType const & orig, genType const & dir,
-		genType const & v0, genType const & v1, genType const & v2,
-		genType & baryPosition
+		tvec3<T, P> const& orig, tvec3<T, P> const& dir,
+		tvec3<T, P> const& vert0, tvec3<T, P> const& vert1, tvec3<T, P> const& vert2,
+		tvec2<T, P>& baryPosition, T& distance
 	)
 	)
 	{
 	{
-		genType e1 = v1 - v0;
-		genType e2 = v2 - v0;
+		// find vectors for two edges sharing vert0
+		tvec3<T, P> const edge1 = vert1 - vert0;
+		tvec3<T, P> const edge2 = vert2 - vert0;
+
+		// begin calculating determinant - also used to calculate U parameter
+		tvec3<T, P> const p = glm::cross(dir, edge2);
+
+		// if determinant is near zero, ray lies in plane of triangle
+		T const det = glm::dot(edge1, p);
+
+		tvec3<T, P> qvec;
 
 
-		genType p = glm::cross(dir, e2);
+		if(det > std::numeric_limits<T>::epsilon())
+		{
+			// calculate distance from vert0 to ray origin
+			tvec3<T, P> const tvec = orig - vert0;
+
+			// calculate U parameter and test bounds
+			baryPosition.x = glm::dot(tvec, p);
+			if(baryPosition.x < static_cast<T>(0) || baryPosition.x > det)
+				return false;
+
+			// prepare to test V parameter
+			qvec = glm::cross(tvec, edge1);
 
 
-		typename genType::value_type a = glm::dot(e1, p);
+			// calculate V parameter and test bounds
+			baryPosition.y = glm::dot(dir, qvec);
+			if((baryPosition.y < static_cast<T>(0)) || ((baryPosition.x + baryPosition.y) > det))
+				return false;
+		}
+		else if(det < -std::numeric_limits<T>::epsilon())
+		{
+			// calculate distance from vert0 to ray origin
+			tvec3<T, P> const tvec = orig - vert0;
+
+			// calculate U parameter and test bounds
+			baryPosition.x = glm::dot(tvec, p);
+			if((baryPosition.x > static_cast<T>(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<T>(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<T>(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<typename genType::value_type>::epsilon();
 		typename genType::value_type Epsilon = std::numeric_limits<typename genType::value_type>::epsilon();
 		if(a < Epsilon && a > -Epsilon)
 		if(a < Epsilon && a > -Epsilon)
 			return false;
 			return false;
@@ -62,6 +116,7 @@ namespace glm
 
 
 		return baryPosition.z >= typename genType::value_type(0.0f);
 		return baryPosition.z >= typename genType::value_type(0.0f);
 	}
 	}
+*/
 
 
 	template <typename genType>
 	template <typename genType>
 	GLM_FUNC_QUALIFIER bool intersectLineTriangle
 	GLM_FUNC_QUALIFIER bool intersectLineTriangle

+ 1 - 0
readme.md

@@ -72,6 +72,7 @@ glm::mat4 camera(float Translate, glm::vec2 const & Rotate)
 #### Fixes:
 #### Fixes:
 - Removed doxygen references to GTC_half_float which was removed in 0.9.4
 - Removed doxygen references to GTC_half_float which was removed in 0.9.4
 - Fixed glm::decompose #448
 - Fixed glm::decompose #448
+- Fixed intersectRayTriangle #6
 
 
 #### Deprecation:
 #### Deprecation:
 - Removed GLM_GTX_simd_vec4 extension
 - Removed GLM_GTX_simd_vec4 extension

+ 26 - 1
test/gtx/gtx_intersect.cpp

@@ -1,9 +1,34 @@
 #define GLM_ENABLE_EXPERIMENTAL
 #define GLM_ENABLE_EXPERIMENTAL
+#include <glm/glm.hpp>
+#include <glm/gtc/epsilon.hpp>
 #include <glm/gtx/intersect.hpp>
 #include <glm/gtx/intersect.hpp>
 
 
+int test_intersectRayTriangle()
+{
+	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<float>::epsilon())) ? 0 : 1;
+	Error += glm::abs(Distance - 2.f) <= std::numeric_limits<float>::epsilon() ? 0 : 1;
+	Error += Result ? 0 : 1;
+
+	return Error;
+}
+
 int main()
 int main()
 {
 {
-	int Error(0);
+	int Error = 0;
+
+	Error += test_intersectRayTriangle();
 
 
 	return Error;
 	return Error;
 }
 }