Post by jzarra on May 31, 2020 13:59:50 GMT
Hello Javis, thanks for writing the Ray Tracer challenge, and also for providing a support platform.
Currently I am implementing a C++ API for bringing to life the ray tracer, not necessarily by passing all the tests, but by achieving the goals at the Putting it Together sections of each chapter.
Chapter 5 was successful. Whenever a hit point is >= 0 the Canvas is written with RED, and the rest with black.
In chapter 6 I am not succeeding, since a dark purple ball is being printed. Checking with notepad the .ppm file I noticed that the hit points are all being printed with the same RGB values: 25 5 25 (dark purple).
My guess is that for some reason my lightning function does not produces the gradient purple across the ball, but constant RGB values. The funny thing is that if I command my write canvas routine to write colors when hit < 0 then the outer part of the canvas gets the purple gradient that I wish happened inside the sphere.
In my test, I am not transforming the sphere. Therefore, I created an identity matrix size 4, and inverted it. This matrix is the one I call "transform", although it is just the identity matrix that I am using for test purposes, and maybe in the future if I want to really deform/transform the sphere then just change it (hope that makes sense).
I would like to share here my routine for determining the color values at each point in inside the canvas. Again, this routing worked for Chapter 5. For Chapter 6 I have only added the necessary elements for computing the lightning function, and the using the result color to write in the canvas when hit >= 0, and black when hit is negative.
Here I share my lightning function implementation:
Please let me know any advice, comment, question, or remarks regarding my code. I have been a couple of days now and unfortunately I am not able to spot what could be wrong in my implementation.
I suspect it is in the lightning function, cause as I mentioned, whenever there is a hit all the sphere is colored with the same tone, a dark purple RGB 25 5 25.
For some time I thought the lightining function was not returning variable RGB values, but if hits < 0 and by changing the colored value to the one returned by lightning, then the outside gets kind of the desired effect.
Thanks!
Currently I am implementing a C++ API for bringing to life the ray tracer, not necessarily by passing all the tests, but by achieving the goals at the Putting it Together sections of each chapter.
Chapter 5 was successful. Whenever a hit point is >= 0 the Canvas is written with RED, and the rest with black.
In chapter 6 I am not succeeding, since a dark purple ball is being printed. Checking with notepad the .ppm file I noticed that the hit points are all being printed with the same RGB values: 25 5 25 (dark purple).
My guess is that for some reason my lightning function does not produces the gradient purple across the ball, but constant RGB values. The funny thing is that if I command my write canvas routine to write colors when hit < 0 then the outer part of the canvas gets the purple gradient that I wish happened inside the sphere.
In my test, I am not transforming the sphere. Therefore, I created an identity matrix size 4, and inverted it. This matrix is the one I call "transform", although it is just the identity matrix that I am using for test purposes, and maybe in the future if I want to really deform/transform the sphere then just change it (hope that makes sense).
I would like to share here my routine for determining the color values at each point in inside the canvas. Again, this routing worked for Chapter 5. For Chapter 6 I have only added the necessary elements for computing the lightning function, and the using the result color to write in the canvas when hit >= 0, and black when hit is negative.
for (int x = (-knvas.m_width/2), i = 0; x < (knvas.m_width/2); x++, i++) {
for (int y = (-knvas.m_height/2), j = 0; y < (knvas.m_height/2); y++, j++) {
// Create ray "r" with origin 0,0,0, and on each for loop iteration the ray direction vector changes. 128 is the Z value where the canvas rest.
// The direction of the ray is from 0,0,0 to x,y,128. Point substraction results in a vector from origin to canvas, e.g. P1-P2 is vector from P2 to P1.
Ray r (Point(0,0,0),(Vector::normalize(Point::subPoints(Point(x, y, 128),Point(0, 0, 0)))));
// determine the hits locations according to determinant value, and store hit point in a vector.
r.sphere_intersections(r, sphere);
// determine hit point by returning the minimum positive hit location on the vector populated by the previous function
hits = r.hit_location(r.accummulate_ix);
// Define eye vector as the negative/opposite of the direction of the current ray
Vector eye(Vector::negate(r.m_direction));
// Get the 3D coordinates of the hit point. Choke is the Spanish work for hit.
Point choke(Ray::position(r, hits));
// In the following lines I calculate the Normal vector at the 3D point "choke".
// I followed the function normal_at at the "Surface Normals" of Chapter 6 as a guideline. rtc is just the namespace I am using for the project, Matrix, Point, and Vector are all C++ classes.
Point object_point(rtc::Matrix::multiplyByTuple(rtc::Matrix::inverse(transform), choke));
Vector object_normal(rtc::Point::subPoints(object_point, rtc::Point(0, 0, 0)));
Vector world_normal(rtc::Matrix::multiplyByTuple(rtc::Matrix::transpose(rtc::Matrix::inverse(transform)), object_normal));
world_normal.m_w = 0;
// Because Vector and Point classes are Tuples, I make sure the normal vector has a 0 on its 4th member (w in this case).
Vector normal(Vector::normalize(world_normal));
// Here I call the lightning function, implemented as in the "Phong Reflection Model" section of Chapter 6
Color c(Ray::lighting(material, light, choke, eye, normal));
// Here I extrapolate the colors from the 0-1 range to 0-255 range.
c.m_r = static_cast<int>(255.999 * c.m_r);
c.m_g = static_cast<int>(255.999 * c.m_g);
c.m_b = static_cast<int>(255.999 * c.m_b);
// As in Chapter 5, if there is a hit I want to color the hit point with the color "c" calculated with the lightning function.
if (hits >= 0) {
knvas.write_pixel(i, j, knvas, c);
}
else {
knvas.write_pixel(i, j, knvas, black);
}
}
// Here I am just making sure hits value return to 0 before the next iteration of the for loop.
hits = 0;
}
Here I share my lightning function implementation:
static Color lighting(Material& m, Light& light, Point& p, Vector& eye, Vector& normal) {
// Create diffuse component as black color
object
Color diffuse(0, 0, 0);
// Create specular component as black color object
Color specular(0, 0, 0);
// Effective color calculation by combining object surface color with light source color.
Color effective_color(Color::multColors(m.m_color,light.m_intensity));
// Light vector that goes from the hit point to the light source. Remember P1-P2 = vector from P2 to P1.
Vector lightv(Vector::normalize(Point::subPoints(light.m_source, p)));
// Ambient color calculation by multiplying the effective color with the material ambient propery.
Color ambient_contribution(Color::scalarMultiplication(effective_color, m.m_ambient));
// Cosine of the angle between the light vector and the normal vector of the surface at the hit point.
real cosine_light_normal(Vector::dotProduct(lightv, normal));
// if the previous Cosine calculation is < 0 then the light source is behind the surface, then diffuse and specular are black.
diffuse.m_r = 0;
diffuse.m_g = 0;
diffuse.m_b = 0;
specular.m_r = 0;
specular.m_g = 0;
specular.m_b = 0;
}
else {
// Diffusion calculation as multiplication of a scalar and effective color.
Color d(Color::scalarMultiplication(effective_color, (m.m_diffuse * cosine_light_normal)));
diffuse.m_r = d.m_r;
diffuse.m_g = d.m_g;
diffuse.m_b = d.m_b;
// reflection vector
calculation. Light_2 is just the negative of the light vector.
Vector lightv_2(Vector::scalarMultiplication(lightv, -1));
Vector reflectv(Vector::reflected(lightv_2, normal));
// Cosine of angle between reflected vector and the EYE (^_^)
real reflect_dot_eye(Vector::dotProduct(reflectv,eye));
// This is like suggested in the pseudocode in Chapter 6
if (reflect_dot_eye <= 0) {
specular.m_r = 0;
specular.m_g = 0;
specular.m_b = 0;
}
else {
// This is like suggested in the pseudocode in Chapter 6
real factor(pow(reflect_dot_eye, m.m_shininess));
Color s(Color::scalarMultiplication(light.m_intensity, (m.m_specular * factor)));
specular.m_r = s.m_r;
specular.m_g = s.m_g;
specular.m_b = s.m_b;
}
}
// Return the color resulted from adding diffuse, specular and ambient contributions.
return Color::addColors(ambient_contribution, (Color::addColors(diffuse, specular)));
}
Please let me know any advice, comment, question, or remarks regarding my code. I have been a couple of days now and unfortunately I am not able to spot what could be wrong in my implementation.
I suspect it is in the lightning function, cause as I mentioned, whenever there is a hit all the sphere is colored with the same tone, a dark purple RGB 25 5 25.
For some time I thought the lightining function was not returning variable RGB values, but if hits < 0 and by changing the colored value to the one returned by lightning, then the outside gets kind of the desired effect.
Thanks!