I am having a few problems with a recursive raytracer.
It works fine for a local illumination model. I also got it to work for implementing shadows due to other objects.
However, when I start the recursive process of calculating specular reflections and refractions, the image gets extremely grainy no matter what I do.
I had been told that this was possibly due to numerical errors and that instead of floats, I should use doubles. When I changed all of the float types to double types, I get
“Debug Error!
…
Invalid allocation size: 4294967295 bytes.”
with the options to Abort, Retry (ends up crashing the whole program) or Ignore (then I just keep getting the same error).
I won’t post all of my code because it is quite long, but I will post what I believe to be relevant and if more information is needed, let me know.
Thanks for the help!!
ColorType Trace_Ray(RayType ray)
{
double point[3];
ObjectType object;
ColorType color;
object = Find_Object(ray);
//At this point, Find_Object has gone through all of the objects in the scene to find the closest intersection and now we must find the color there.
if (object.t > 0) //if the ray intersects with at least one object, we can find that objects color
{
point[0] = ray.x + object.t * ray.dx;
point[1] = ray.y + object.t * ray.dy;
point[2] = ray.z + object.t * ray.dz;
color = Shade_Ray(ray, point[0], point[1], point[2], object);
}
else //this ray doesn't intersect with anything and should have the default color
{
color.r = 0.0;
color.g = 0.0;
color.b = 0.0;
}
return color;
}
ColorType Shade_Ray(RayType ray, double x, double y, double z, ObjectType s)
{
ColorType color;
double S = 1.0; //shadow tag
///////////Phong
//Compute the normal vector at the point of intersection and the vector pointing from there to the light source
double nd[3], n[3], ld[3], l[3]; //normal direction, normalized normal, light direction, normalized light
if (s.label == 0)//if object is a sphere
{
nd[0] = x - s.x;
nd[1] = y - s.y;
nd[2] = z - s.z;
n[0] = nd[0] / sqrt(nd[0]*nd[0] + nd[1]*nd[1] + nd[2]*nd[2]);
n[1] = nd[1] / sqrt(nd[0]*nd[0] + nd[1]*nd[1] + nd[2]*nd[2]);
n[2] = nd[2] / sqrt(nd[0]*nd[0] + nd[1]*nd[1] + nd[2]*nd[2]);
}
else if (s.label == 1)//object is a triangle
{
double u[3], v[3];
u[0] = s.x1 - s.x0;
u[1] = s.y1 - s.y0;
u[2] = s.z1 - s.z0;
v[0] = s.x2 - s.x0;
v[1] = s.y2 - s.y0;
v[2] = s.z2 - s.z0;
nd[0] = u[1]*v[2] - u[2]*v[1];
nd[1] = u[2]*v[0] - u[0]*v[2];
nd[2] = u[0]*v[1] - u[1]*v[0];
n[0] = nd[0] / sqrt(nd[0]*nd[0] + nd[1]*nd[1] + nd[2]*nd[2]);
n[1] = nd[1] / sqrt(nd[0]*nd[0] + nd[1]*nd[1] + nd[2]*nd[2]);
n[2] = nd[2] / sqrt(nd[0]*nd[0] + nd[1]*nd[1] + nd[2]*nd[2]);
}
ld[0] = light[0] - x;
ld[1] = light[1] - y;
ld[2] = light[2] - z;
l[0] = ld[0] / sqrt(ld[0]*ld[0] + ld[1]*ld[1] + ld[2]*ld[2]);
l[1] = ld[1] / sqrt(ld[0]*ld[0] + ld[1]*ld[1] + ld[2]*ld[2]);
l[2] = ld[2] / sqrt(ld[0]*ld[0] + ld[1]*ld[1] + ld[2]*ld[2]);
double dotNL;
double check_dot = n[0]*l[0] + n[1]*l[1] + n[2]*l[2];
if (check_dot >= 0)
{
dotNL = check_dot;
}
else
{
dotNL = 0.0;
}
double hd[3], h[3];
hd[0] = l[0] + (eye[0]-x);
hd[1] = l[1] + (eye[1]-y);
hd[2] = l[2] + (eye[2]-z);
h[0] = hd[0] / sqrt(hd[0]*hd[0] + hd[1]*hd[1] + hd[2]*hd[2]);
h[1] = hd[1] / sqrt(hd[0]*hd[0] + hd[1]*hd[1] + hd[2]*hd[2]);
h[2] = hd[2] / sqrt(hd[0]*hd[0] + hd[1]*hd[1] + hd[2]*hd[2]);
double dotNH = n[0]*h[0] + n[1]*h[1] + n[2]*h[2];
////////////////// ADD SHADING ///////////////////////////////////
for (int i = 0; i < lights.size(); i++)
{
RayType lightray;
lightray.x = x; lightray.y = y; lightray.z = z;
//The following will NOT BE ACCURATE when multiple lights are specified!!!!!! currently only one light source is being used
lightray.dx = l[0]; lightray.dy = l[1]; lightray.dz = l[2];
//Check for intersections with spheres
for (int i = 0; i < objects.size(); i++)
{
SphereType current = objects[i];
double init = -1.0;
double t;
t = sphere_intersection(lightray, current, init);
if (t > 0.0001)
{
S = S * current.trans;
}
if (S == 0) //we can stop if/when s = 0
{
i = objects.size();
}
}
//Check for intersections with triangles
if (S != 0)
{
for (int j = 0; j < triangles.size(); j++)
{
TriangleType current = triangles[j];
double init = -1.0;
double t;
t = triangle_intersection(lightray, current, init);
if (t > 0.01)
{
S = S * current.trans;
}
if (S == 0)
{
j = triangles.size();
}
}
}
}
//*EVERYTHING WORKS (AT LEAST ENOUGH FOR ME TO BE SATISFIED) UP TO THIS POINT. This is the color information due to light sources and shadows....
color.r = (s.amb * s.dr + S * (s.dif * s.dr * dotNL + s.spec * pow(dotNH, s.se)));
color.g = (s.amb * s.dg + S * (s.dif * s.dg * dotNL + s.spec * pow(dotNH, s.se)));
color.b = (s.amb * s.db + S * (s.dif * s.db * dotNL + s.spec * pow(dotNH, s.se)));
//Update the value of recur to the number of surfaces for which the original ray has gotten a color contribution
recur += 1;
////////////// ADD REFLECTIONS FROM OTHER OBJECTS - IF MAX RECURSION HAS NOT BEEN REACHED /////////////////
double vector_i[3], vector_r[3], vector_t[3], vid[3], vrd[3], vtd[3];
double NdotI, angle, angle_t;
vid[0] = ray.x - x;
vid[1] = ray.y - y;
vid[2] = ray.z - z;
vector_i[0] = vid[0]/length(vid);
vector_i[1] = vid[1]/length(vid);
vector_i[2] = vid[2]/length(vid);
NdotI = dot(n, vector_i);
angle = acos(NdotI) * 180.0/PI;
angle_t = (acos(sqrt(1 - ((s.iors/s.iorm)*(s.iors/s.iorm)*(1-(cos(angle*PI/180.0)*cos(angle*PI/180)))))))*(180.0/PI);
vtd[0] = cos(angle_t * PI/180.0)*(-(n[0])) + (s.iors/s.iorm)*(cos(angle * PI/180.0)*n[0] - vector_i[0]);
vtd[1] = cos(angle_t * PI/180.0)*(-(n[1])) + (s.iors/s.iorm)*(cos(angle * PI/180.0)*n[1] - vector_i[1]);
vtd[2] = cos(angle_t * PI/180.0)*(-(n[2])) + (s.iors/s.iorm)*(cos(angle * PI/180.0)*n[2] - vector_i[2]);
vector_t[0] = vtd[0]/length(vtd);
vector_t[1] = vtd[1]/length(vtd);
vector_t[2] = vtd[2]/length(vtd);
if (recur <= MAX_RECURSION)
{
double length_a;
length_a = cos(angle * PI/180);
vrd[0] = 2*length_a*n[0] - vector_i[0];
vrd[1] = 2*length_a*n[1] - vector_i[1];
vrd[2] = 2*length_a*n[2] - vector_i[2];
vector_r[0] = vrd[0]/length(vrd);
vector_r[1] = vrd[1]/length(vrd);
vector_r[2] = vrd[2]/length(vrd);
RayType new_ray;
new_ray.dx = vector_r[0];
new_ray.dy = vector_r[1];
new_ray.dz = vector_r[2];
new_ray.x = x; new_ray.y = y; new_ray.z = z;
//Now we must trace vector R to find the contribution from reflection
ColorType temp_color;
ObjectType temp_object;
temp_object = Find_Object(new_ray);//Find_Object just returns the closest object (for positive t values)
if ( temp_object.t > 0.001 )
{
double point[3];
point[0] = new_ray.x + temp_object.t * new_ray.dx; point[1] = new_ray.y + temp_object.t * new_ray.dy; point[2] = new_ray.z + temp_object.t * new_ray.dz;
temp_color = Shade_Ray(new_ray, point[0], point[1], point[2], temp_object);
}
else
{//didn't intersect an object, so we are done
recur = MAX_RECURSION + 1;
temp_color.r = 0.0; temp_color.g = 0.0; temp_color.b = 0.0;
}
color.r += temp_object.spec * temp_color.r; color.g += temp_object.spec * temp_color.g; color.b += temp_object.spec * temp_color.b;
}
///////////////////////////////////////////////////////////////////
//////////// REFRACTION ///////////////////////////////////////////
if (s.trans > 0.1) //s is current object, trans is its transparency
{
RayType new_ray_t;
new_ray_t.x = x; new_ray_t.y = y; new_ray_t.z = z;
new_ray_t.dx = vector_t[0]; new_ray_t.dy = vector_t[1]; new_ray_t.dz = vector_t[2];
ColorType temp_color_t;
ObjectType temp_object_t;
temp_object_t = Find_Object(new_ray_t);
if (temp_object_t.t > 0.001)
{
double point[3];
point[0] = new_ray_t.x + temp_object_t.t * new_ray_t.dx; point[1] = new_ray_t.y + temp_object_t.t * new_ray_t.dy; point[2] = new_ray_t.z + temp_object_t.t * new_ray_t.dz;
temp_color_t = Shade_Ray(new_ray_t, point[0], point[1], point[2], temp_object_t);
}
else
{
recur = MAX_RECURSION + 1;
temp_color_t.r = 0.0; temp_color_t.g = 0.0; temp_color_t.b = 0.0;
}
color.r += temp_object_t.trans * temp_color_t.r; color.g += temp_object_t.trans * temp_color_t.g; color.b += temp_object_t.trans * temp_color_t.b;
}
color.r = 255.0*color.r;
color.g = 255.0*color.g;
color.b = 255.0*color.b;
return color;
}