ssloy / tinyraytracer

A brief computer graphics / rendering course
https://github.com/ssloy/tinyraytracer/wiki
5.04k stars 333 forks source link

Issues with shadows when rendering duck #31

Closed ema2159 closed 1 year ago

ema2159 commented 1 year ago

Hello professor. I was just finishing my version of tinyraytracer written in Rust. In order to render the duck, I just implemented a triangle primitive, defining its intersection function (intersection with the plane containing the triangle and then checking through barycentric coordinates if the point lies inside the triangle), and its normal (cross product between two of its sides). If I render the duck using the ivory material, I get the following: image

However, if I remove the shadow rendering code, I get a proper image: image

Do you have any idea why this might be?

ema2159 commented 1 year ago

Answering my own question, the issue was that I was calculating the intersection between the ray and the planes without considering whether the plane was behind the ray or not. Originally, I was calculating the plane-ray intersection as follows:

        let d = -normal.dot(&self.a.coords); // Parameter of plane equation

        let n_dot_raydir = -normal.dot(&ray.direction);
        if n_dot_raydir <= 0. {
            return None;
        }

        // If it exists, calculate the intersection point
        let t = (normal.dot(&ray.origin.coords) + d) / n_dot_raydir;
        let intersection_point = ray.origin + t * ray.direction;

without taking into consideration the fact that if t is negative, the intersection point is behind the ray, so it should be discarded. It is sufficient to check for that condition and discard the point accordingly as follows:

        let d = -normal.dot(&self.a.coords); // Parameter of plane equation

        let n_dot_raydir = -normal.dot(&ray.direction);
        if n_dot_raydir <= 0. {
            return None;
        }

        // If it exists, calculate the intersection point
        let t = (normal.dot(&ray.origin.coords) + d) / n_dot_raydir;
        if t < 0. {
            return None;
        } 
        let intersection_point = ray.origin + t * ray.direction;

Without this, all the object properties (shadows, reflections, refractions) were being affected.