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());
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:
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 double
s ? 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 float
s tend to cause similar artifacts even noise on edges of reflective/refractive spheres. Here the same engine of mine but on float
s:
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
Where Do I Find the Current C or C++ Standard Documents
Difference Between Const Int*, Const Int * Const, and Int Const *
Correct Way of Passing Pointer to Another Thread
Why Is Iostream::Eof Inside a Loop Condition (I.E. 'While (!Stream.Eof())') Considered Wrong
Vector Converted All Negative Values to Zero
Undefined, Unspecified and Implementation-Defined Behavior
Most Efficient Way of Copying a Raw Byte Array into an Empty Byte Vector
What Should Main() Return in C and C++
Define Preprocessor Macro Through Cmake
Resolve Build Errors Due to Circular Dependency Amongst Classes
How to Print Current Time (With Milliseconds) Using C++/C++11
How to Remove "Noise" from Gcc/Clang Assembly Output
How to Fully Disable Resizing a Window Including the Resize Icon When the Mouse Hovers the Border
Checking the Neighbour Values of Arrays