Advertisement

Ray-triangle intersection -- how to tell if some pseudrandomly placed vertex is inside the mesh

Started by April 15, 2021 07:41 PM
23 comments, last by JoeJ 3 years, 9 months ago

I am having difficulty with ray-triangle intersection.

My full code is at: https://github.com/sjhalayka/ray_triangle_intersection

The sample fractal.stl file is included with the code.

When I run the code, using the example fractal.stl, I detect 2 intersections, where there should only be 1 intersection. Any ideas?

The pertinent code is:





/*
bool rayTriangleIntersect(
	const vec3& orig, const vec3& dir,
	const vec3& v0, const vec3& v1, const vec3& v2,
	float& t)
{
	// compute plane's normal
	vec3 v0v1 = v1 - v0;
	vec3 v0v2 = v2 - v0;
	// no need to normalize
	vec3 N = cross(v0v1, v0v2); // N 

	// Step 1: finding P

	// check if ray and plane are parallel ?
	float NdotRayDirection = dot(N, dir);
	if (fabs(NdotRayDirection) < 0.00001) // almost 0 
		return false; // they are parallel so they don't intersect ! 

	// compute d parameter using equation 2
	float d = dot(N, v0);

	// compute t (equation 3)
	t = (dot(N, orig) + d) / NdotRayDirection;
	// check if the triangle is in behind the ray
	if (t < 0) return false; // the triangle is behind 

	// compute the intersection point using equation 1
	vec3 P = orig + t * dir;

	// Step 2: inside-outside test
	vec3 C; // vector perpendicular to triangle's plane 

	// edge 0
	vec3 edge0 = v1 - v0;
	vec3 vp0 = P - v0;
	C = cross(edge0, vp0);
	if (dot(N, C) < 0) return false; // P is on the right side 

	// edge 1
	vec3 edge1 = v2 - v1;
	vec3 vp1 = P - v1;
	C = cross(edge1, vp1);
	if (dot(N, C) < 0)  return false; // P is on the right side 

	// edge 2
	vec3 edge2 = v0 - v2;
	vec3 vp2 = P - v2;
	C = cross(edge2, vp2);
	if (dot(N, C) < 0) return false; // P is on the right side; 

	return true; // this ray hits the triangle 
}
*/




bool RayIntersectsTriangle(const vec3 rayOrigin,
	const vec3 rayVector,
	const vec3 v0, const vec3 v1, const vec3 v2,
	vec3& outIntersectionPoint)
{
	const float EPSILON = 0.0000001f;
	vec3 vertex0 = v0;// inTriangle->vertex0;
	vec3 vertex1 = v1;// inTriangle->vertex1;
	vec3 vertex2 = v2;// inTriangle->vertex2;
	vec3 edge1, edge2, h, s, q;
	float a, f, u, v;
	edge1 = vertex1 - vertex0;
	edge2 = vertex2 - vertex0;
	h = cross(rayVector, edge2);
	a = dot(edge1, h);
	if (a > -EPSILON && a < EPSILON)
		return false;    // This ray is parallel to this triangle.
	f = 1.0f / a;
	s = rayOrigin - vertex0;
	u = f * dot(s, h);
	if (u < 0.0f || u > 1.0f)
		return false;
	q = cross(s, edge1);
	v = f * dot(rayVector, q);
	if (v < 0.0f || u + v > 1.0f)
		return false;

	// At this stage we can compute t to find out where the intersection point is on the line.

	float t = f * dot(edge2, q);

	if (t > EPSILON) // ray intersection
	{
		outIntersectionPoint = rayOrigin + rayVector * t;
		return true;
	}
	else // This means that there is a line intersection but not a ray intersection.
		return false;
}


int main(void)
{
	if (false == read_triangles_from_binary_stereo_lithography_file(triangles, "fractal.stl"))
	{
		cout << "Error: Could not properly read file fractal.stl" << endl;
		return 2;
	}

//	get_vertices_and_normals_from_triangles(triangles, face_normals, vertices, vertex_normals);

	vec3 pos = vec3(0, 0, 0);
	vec3 look_at_ray = vec3(-1, 0, 0);

	size_t intersection_count = 0;

	for (size_t i = 0; i < triangles.size(); i++)
	{
		vec3 v0 = vec3(triangles[i].vertex[0].x, triangles[i].vertex[0].y, triangles[i].vertex[0].z);
		vec3 v1 = vec3(triangles[i].vertex[1].x, triangles[i].vertex[1].y, triangles[i].vertex[1].z);
		vec3 v2 = vec3(triangles[i].vertex[2].x, triangles[i].vertex[2].y, triangles[i].vertex[2].z);

		vec3 outIntersectionPoint;

		bool found_intersection = RayIntersectsTriangle(pos,
			look_at_ray,
			v0, v1, v2,
			outIntersectionPoint);

		if (found_intersection)
		{
			intersection_count++;
		}
	}

	cout << intersection_count << endl;

	return 0;
}

taby said:
Any ideas?

Visualize both intersections, and you should easily figure out what's wrong ; )

Advertisement

I see way too much useless code,( i actuslly just read between lines and didn't even care to understand it) the idea is to check ifeach of ray vertices are on different sides of triangle plane if do so you project point onto that plane and check if projected point is within tri area, easiest idea could be checking if points resides on the same side for all triangle edges. For speedup you'll need to precompute edge normals and distances.

_WeirdCat_ said:
For speedup you'll need to precompute edge normals and distances.

This quickly becomes unpractical because it needs too much memory (although there were papers about such methods beating Moeller Trumbore methods performance.)
Above code looks pretty standard. It calculates barycentric coordinates and checks if they are in or outside. They can be reused to support texturing.

Edit: A common ‘failure' case would be an intersection ending up exactly on a shared edge, so reported twice.

JoeJ said:

This quickly becomes unpractical because it needs too much memory

I think it depends actually. I do this for physics meshes and I store plane normals for visual meshes. I have an aggressive LOD system that somewhat compensates for the extra storage. In any case I think it depends on the particular application.

Agreed. As you generate most data at runtime, you do not really have a storage problem at all.

Personally, for the reference path tracer i've made, i also calculate planes from triangle edge to ray origin - simply because i was too lazy to look up for a better method : )

Advertisement

… though, Moeller Trumbore requires only one cross product for the barycentrics. I'd assume that's always faster than loading three edge planes form memory.

https://www.scratchapixel.com/lessons/3d-basic-rendering/ray-tracing-rendering-a-triangle/moller-trumbore-ray-triangle-intersection

taby said:
am having difficulty with ray-triangle intersection.

Reading the tread title with more attention only now, is your goal here to detect if a point is inside the a mesh?

While this can be done with RT, i know of a much faster and robuster method…

Any help is much appreciated. ?

I had posted source in this thread: https://www.gamedev.net/forums/topic/709278-ray-to-octree-intersection-for-boolean-geometry/5436021/?page=1

I use the method to voxelize meshes so i can use them in my volumetric editor.

It works like this: Iterate the surface of the mesh and integrate solid angle (or form factor, to be precise) to the queried point.
A very similar method was proposed by Alec Jacobson in two papers: https://www.dgp.toronto.edu/projects/fast-winding-numbers/https

://www.cs.utah.edu/~ladislav/jacobson13robust/jacobson13robust.htmlhttps://www.cs.utah.edu/~ladislav/jacobson13robust/jacobson13robust.htmlhttps://www.cs.utah.edu/~ladislav/jacobson13robust/jacobson13robust.html

This topic is closed to new replies.

Advertisement