Reflection and Refraction Impossible Without Recursive Ray Tracing

Problem implementing reflections in ray tracing

Problem was this part of code

for (objects in scene){
double intersection = (*objIterator)->intersect(rayIn,normal);

if (intersection < minDistance && intersection > epsilon )
{
minDistance = intersection;
int_object = *objIterator;
int_point = rayIn.origin + intersection * rayIn.direction + (epsilon * normal);
}}

Here normal is used later for other calculations but the first line update normal for current object intersection (Even if its not close). So I added a vector to store normal of the intersection object and used it later.

Ray Tracing: Only use single ray instead of both reflection & refraction rays

This is a monte-carlo ray tracer. Its advantages are that you don't spawn an exponentially increasing number of rays - which can occur in some simple geometries.. The down side is that you need to average over a large number of samples. Typically you sample until the expected deviation from the true value is "low enough". Working out how many samples is required requires some stats - or you just take a lot of samples.

Ray Tracing In One Weekend - Refraction issues

In the method src/hittable.rs which checks if a sphere is hit, the c code looks like this.

// Find the nearest root that lies in the acceptable range.
auto root = (-half_b - sqrtd) / a;
if (root < t_min || t_max < root) {
root = (-half_b + sqrtd) / a;
if (root < t_min || t_max < root)
return false;
}

You have ported it to rust code with the following listing:

let root = (-half_b - sqrtd) / a;
if root < t_min || t_max < root {
let root = (-half_b + sqrtd) / a;
if root < t_min || t_max < root {
return None;
}
}

The problem here is the second let root. You have created a new variable with its own scope for the inner brackets but not changed the already created variable defined before. To do this you have to make it mutable.

let mut root = (-half_b - sqrtd) / a;
if root < t_min || t_max < root {
root = (-half_b + sqrtd) / a;
if root < t_min || t_max < root {
return None;
}
}

Additionally I changed the following in src/ray.rs

return match scattered {
Some((scattered_ray, albedo)) => {
match scattered_ray {
Some(sr) => {
albedo * sr.pixel_color(world, depth-1)
},
None => albedo
}
},
None => { return Color::default() }
};

to match the corresponding C code. Be aware of the unwrap used.

let scattered = rect.material.scatter(self, &rect);
if let Some((scattered_ray, albedo)) = scattered {
return albedo * scattered_ray.unwrap().pixel_color(world, depth - 1)
}
return Color::default()

And remove your tries to correct the reflections:

let reflected = Vec3::new(-reflected.x(), reflected.y(), -reflected.z());

correct glass sphere

raytracing algorithm - a few questions

You seem to have a good grasp on the algorithm.

The last line does look like it is computing some sort of weighted combination of the reflected and refracted colors.

Also, you are correct that the shadow ray tracing is not included in the basic algorithm you attached in your post. However, it is easily added by shooting a ray to the light source and determining if there is an intersection between the object you hit and the light. If there is, then the light is occluded and the object should not be lit at that point.

To explain the recursion, one can think of a pair of mirrors facing each other. You would get the infinite mirror effect (in real life). If you did not recurse and only cast reflective/refractive rays once, your virtual mirrors (or reflective surfaces in general) would only appear to reflect the other objects, and not the other objects' reflections as well. (So, no infinite mirror effects. :( )

Getting absurd reflections on a sphere in Raytracing

the image does not looks so bad. When I tried to recreate your scene in mine GLSL ray tracer I got this result:

result

As you can see it is not that much different apart of the different lighting. I only guessed the positions, sizes, colors, reflection and refraction coefficients so my scene is not exact the same as yours:

ray.beg();
// r g b rfl rfr n x y z rx ry rz
ray.add_material(0.8,0.8,0.6,0.0,0.0,_n_glass); ray.add_box ( 0.0, 0.0,-10.0,10.0,10.0, 0.1);
ray.add_material(0.8,0.8,0.6,0.0,0.0,_n_glass); ray.add_box ( 0.0, 0.0,+10.0,10.0,10.0, 0.1);
ray.add_material(1.0,0.1,0.1,0.0,0.0,_n_glass); ray.add_box (-10.0, 0.0, 0.0, 0.1,10.0,10.0);
ray.add_material(0.1,1.0,0.1,0.0,0.0,_n_glass); ray.add_box (+10.0, 0.0, 0.0, 0.1,10.0,10.0);
ray.add_material(0.8,0.6,0.8,0.0,0.0,_n_glass); ray.add_box ( 0.0,-10.0, 0.0,10.0, 0.1,10.0);
ray.add_material(0.8,0.6,0.8,0.0,0.0,_n_glass); ray.add_box ( 0.0,+10.0, 0.0,10.0, 0.1,10.0);
// r g b rfl rfr n x y z r
ray.add_material(0.7,0.0,0.0,0.0,0.0,_n_glass); ray.add_sphere (+ 1.5,- 1.5,+ 0.5,1.5);
ray.add_material(0.0,0.0,0.7,0.8,0.0,_n_glass); ray.add_sphere (- 1.5,+ 1.5,- 0.5,1.5);
ray.end();

I use these indexes:

const GLfloat _n_glass=1.561;
const GLfloat _n_vacuum=1.0;

The distortion (no reflection present) on edges of your blue sphere might be caused by low precision did you used doubles ? I do not know what libs you are using but Vec3 usually means only floats try dVec3 or what ever ... the problem might be related to this:

  • ray and ellipsoid intersection accuracy improvement

Which on pure floats tend to cause similar artifacts even noise on edges of reflective/refractive spheres. Here the same engine of mine but on floats:

float noise

as you can see the noise is more often in areas where your output does not reflect at all which indicates similar cause...

However I see in your image some aspect ratio distortions like you expect square window and got 640x480 rectangle instead so you got no or inverse aspect ratio correction. This can slightly mess the casted rays directions and further distort image after reflect/refract ...



Related Topics



Leave a reply



Submit