# raytracer problem

This topic is 2912 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

Hello, My raytraces uses for all the computations double variables. My triangle intersection code is the following:
bool	Triangle::Intersect(const Line& line,const double maxDist, IntersectionData& data)
{
Vector edge1 = _b - _a;
Vector edge2 = _c - _a;

Vector pvec = line.dx() ^ edge2;

double det = edge1*pvec;

// no intersection
if(det > -0.0000000001 && det < 0.0000000001) return false;

double invDet = 1/det;

Vector tvec = line.x0() - _a;

double u = (tvec*pvec) * invDet;
if(u < 0.0000000001 || u > 1.0000000001) return false;

Vector qvec = tvec^edge1;

double v = (line.dx()*qvec) * invDet;
if(v < 0.0000000001 || (u + v) > 1.0000000001) return false;

double dist = (edge2*qvec) * invDet;

if(dist < 0.0000000001) return false;

data._vec = line.x0() + line.dx()*dist;
data._distance = dist;
data._line = &line;
data._geometry = this;
data._normal = _face_normal;
return true;
}


Note that i compare with 0.00000000001 instead of 0.0 because in the case of 0.0 i get very busted images (i use gcc , and i haven't tried this on windows). The problem is that if i have 2 triangles virtually, one next to each other, the rays pass right in between the triangles, and i get artifacts near all the edges. How can i solve this? Image Example (lots of reflections and one light).Note the black lines near all edges. Thanks, Makaan

##### Share on other sites
Try using -epsilon instead of +epsilon when testing your u and v coordinates. Your current logic will reject a tiny strip of collisions along the edges of triangles.

##### Share on other sites
You can often prevent this from happening through careful use of < vs <=. But it doesn't look like this will work for barycentric coordinates. You can switch to an algorithm that doesn't suffer from this problem though. Try using this one:
http://softsurfer.com/Archive/algorithm_0103/algorithm_0103.htm
(Their winding number method is the fastest of the two)
It's a very fast method for doing point-in-polygon, but will be slower than your method if you represent your geometry as triangles instead of n sided polygons.

Or you could write a point-in-triangle method that doesn't have this fp accuracy problem. Try doing 3 successive point-to-line distance tests to see if the point is behind each side in the triangle. No need for line segment checks here. Check against the infinite line. This should cause boundary points to be detected in at least one of the triangles.

##### Share on other sites
Maybe not the best solution, but I simply marked the triangles processed/unprocessed
I found it useful for refraction too.

##### Share on other sites
Quote:
 Original post by MakaanNote that i compare with 0.00000000001 instead of 0.0 because in the case of 0.0 i get very busted images (i use gcc , and i haven't tried this on windows).The problem is that if i have 2 triangles virtually, one next to each other, the rays pass right in between the triangles, and i get artifacts near all the edges.How can i solve this?

So it looks like you are using this method:
http://www.graphics.cornell.edu/pubs/1997/MT97.pdf

I use it in may raytracer too and it works fine. I compare with EPS=1e-10 and using floats instead of doubles and this works fine. The difference between your and my implementation is the check of the u and v values. In my implementation I'm checking u and v against 0 and 1 without epsilon and the det with epsilon. So maybe you want to change this to get rid of the black lines.

##### Share on other sites
Quote:
 Try using -epsilon instead of +epsilon when testing your u and v coordinates. Your current logic will reject a tiny strip of collisions along the edges of triangles.

I have changed u and v tests to
if(u < -0.000001 || u > 1.000001) return false;

The image is a little bit better. The intersection between triangles in the same plane doesn't have gaps but on different planes there are still gaps (a lot less but still).

I have also tried a changing < and <= to see now the image is affected. The best result i get with only -epsilon and epsilon testing.

Quote:
 In my implementation I'm checking u and v against 0 and 1 without epsilon and the det with epsilon. So maybe you want to change this to get rid of the black lines.

Just to show you how busted 0.0 and 1.0 (or 0 and 1) tests are i added an image:

I belive the problem is in line:
if(dist < 0.000001) return false;

because at the corners, when the ray reflects, the distance is very small ,almost zero (which is less than .000001), therefore i just discard valid intersection at corners ( i tested the primary rays and none passes in between triangles).
The problem is that i can't put < 0.0 because the image gets really busted (as shown above).

Thanks,
Raxvan

##### Share on other sites
Quote:
Original post by Makaan
Quote:
 In my implementation I'm checking u and v against 0 and 1 without epsilon and the det with epsilon. So maybe you want to change this to get rid of the black lines.

Just to show you how busted 0.0 and 1.0 (or 0 and 1) tests are i added an image:
...

The problem is maybe in the code that calls the intersection test. You are right to allow the "tunnel effect" for the ray (i.e. it can move without intersecting to prevent it sticking on the object it came from). However, this test should not be in the code that performs the ray-triangle intersection, but in the function that calls it.

So this is the code from my raytracer:
    // ray-triangle intersection    bool intersectRayTri(vec3 o, vec3 d, vec3 a, vec3 b, vec3 c, float& t) {    	// http://www.graphics.cornell.edu/pubs/1997/MT97.pdf    	// two-sided triangles are checked    	vec3 e1 = b - a;    	vec3 e2 = c - a;    	vec3 pvec = cross(d, e2);    	float det = dot(e1, pvec);    	if (det > -EPS && det < EPS)    		return false;    	float invDet = 1.0 / det;    	vec3 tvec = o - a;    	float u = dot(tvec, pvec) * invDet;    	if (u < 0.0 || u > 1.0)    		return false;    	vec3 qvec = cross(tvec, e1);    	float v = dot(d, qvec) * invDet;    	if (v < 0.0 || u + v > 1.0)    		return false;    	t = dot(e2, qvec) * invDet;    	return true;    }

And this how you would call it (simplified by just iterating over the triangles, you should use an acceleration structure instead):
    bool intersect(vec3 o, vec3 d, Intersection& is) {    	// iterate over every triangle    	bool hit = false;    	float t_min = INF;    	for (int i = 0; i < numTriangles; i++) {    		Triangle& tri = triangles;    		vec3 a = tri.a;    		vec3 b = tri.b;    		vec3 c = tri.c;    		float t = INF;    		if (intersectRayTri(o, d, a, b, c, t) && T_MIN < t && t < t_min) {    			hit = true;    			t_min = t;    			is.t = t;    			is.p = o + t * d;    			// set other intersection parameters...    		}    	}    	return hit;    }

Here, INF is a very big number or infinity, as you wish. T_MIN is the "tunneling distance", in my raytracer its 0.001, but you can also make it smaller (for instance if distances are measured in m, then set it to 1e-6 which is one µm).

Then your image should look fine:

##### Share on other sites
Now that's ray-tracing, congrats for that!

##### Share on other sites
Thanks nmi i solved by replacing 0.0001 with 1e-6 :)

But i will get errors at higher resolutions (1600x1200)

##### Share on other sites
Quote:
 Original post by MakaanBut i will get errors at higher resolutions (1600x1200)

Why do you think that ?

##### Share on other sites
Quote:
Original post by nmi
Quote:
 Original post by MakaanBut i will get errors at higher resolutions (1600x1200)

Why do you think that ?

It turns out that the 1e-6 fixes the problem only for 800x600 image resolution and a particular kind of projection. The error is still present. In fact i can't remove the errors only with that particular resolution ,camera position and projection.

##### Share on other sites
Quote:
 Original post by MakaanIt turns out that the 1e-6 fixes the problem only for 800x600 image resolution and a particular kind of projection. The error is still present. In fact i can't remove the errors only with that particular resolution ,camera position and projection.

Nah, that's strange. For my raytracer this code works fine. So maybe your problem is somewhere else.

##### Share on other sites
Quote:
Original post by nmi
Quote:
 Original post by MakaanIt turns out that the 1e-6 fixes the problem only for 800x600 image resolution and a particular kind of projection. The error is still present. In fact i can't remove the errors only with that particular resolution ,camera position and projection.

Nah, that's strange. For my raytracer this code works fine. So maybe your problem is somewhere else.

Do you use float for all your computations, Is it enough for good precision on small rays??? I believe that double has too much precision or my Cpu is busted.
Anyway i will try replacing all my double variables in float vars to see what happens. I don't think the problem could be in another place because spawning first rays is really simple math, and besides that there is nothing else to get wrong.

Also how big is your scene in units??

Thanks, Raxvan.

##### Share on other sites
Quote:
 Original post by MakaanDo you use float for all your computations, Is it enough for good precision on small rays??? I believe that double has too much precision or my Cpu is busted.Anyway i will try replacing all my double variables in float vars to see what happens. I don't think the problem could be in another place because spawning first rays is really simple math, and besides that there is nothing else to get wrong.Also how big is your scene in units??Thanks, Raxvan.

Until now using floats does not cause any problems, but using doubles should be fine also. So if you already have everything coded with doubles then leave it as it is.

My scene is constructed according to the data given here:
http://www.graphics.cornell.edu/online/box/data.html

The focal length of the camera is not used because of pinhole camera. The spectra were converted to RGB (using http://www.brucelindbloom.com/index.html?SpectCalcSpreadsheets.html). The power of the light source is just guessed (didn't find any information about it, if you do, then tell me pls). The coordinates are given in mm. In the beginning I didn't bother and interpreted them in m, later on I scaled them. My raytracer internally uses m as distance unit. In both cases the result looked the same.