Lautaro10263
Lautaro10263

Reputation: 1

Problem with total internal reflection in ray tracing (Ray tracing in a weekend)

I'm following the steps in the book 'Ray Tracing in a weekend' and I'm having some problems with the section 11.3 Total internal reflection. When I try create the image I get this result:

Left sphere with refraction

This is the code for the intersection with the sphere, it returns an intersection with the sphere or null:

std::optional<Intersection> Sphere::intersect(const Ray& r, double tMin, double tMax) const {
    vec o_c = this->center- r.origin();

    auto a = r.direction().length_squared() () 
    auto b = dot(r.direction(), o_c);
    auto c = o_c.length_squared() - radius * radius;
    
    auto d = b * b - a * c;

    // at^2 + tb + c = 0 not real solution

    if (d < 0) {
        return std::nullopt;
    }

    // Verify root in [tMin, tMax]

   double dSqrt = std::sqrt(d);
    double root = (b - dSqrt) / a;
    if (root < tMin || root > tMax) {
        root = (b + dSqrt) / a;
        if (root < tMin || root > tMax) return std::nullopt;
    }

    Intersection i;
    i.t = root;
    i.point = r(i.t);
    i.normal = unit_vector(i.point - center);
        i.material = material;

    return i;
 };

This is the code for the refraction:

inline vec refraction(const vec& v, const vec& normal, double refraction_index) {
    vec rparal{ .0, .0, .0 };
    vec rperp{ .0, .0, .0 };

    bool front_face = (dot(v, normal) < 0);
    double ri = front_face ? 1.0 / refraction_index : refraction_index;

    vec outward_normal = front_face ? normal : -normal;
    
    double cos_tita = fmin(dot(-v, outward_normal ), 1.0);
    double sen_tita = sqrt(1 - cos_tita * cos_tita);

    
    if (ri * sen_tita > 1) {
        return reflect(v, outward_normal);
    }
    
    rperp = ri * (v + (dot(-v, outward_normal) * outward_normal)); 
    rparal = (-sqrt(abs(1 - rperp.length_squared()))) * outward_normal;

    return rparal + rperp;
};

And this is the code for the color_ray:

color color_ray(const Ray& r, int deep, const Geometry& g) {

    if (deep <= 0)
        return color(0, 0, 0);

    auto i = g.intersect(r, 0.001, infinity);

    if (i) {
        color intensity;

         // Check if the material is reflective
        if (i->material->reflective) {

            vec reflectedVector = reflect(unit_vector(r.direction()), i->normal) + 
            (i->material->coef_Reflective * vec::random_Unit_vector());

            Ray reflected_Ray = Ray(i->point, reflectedVector);
            intensity = i->material->DifuseColor * color_ray(reflected_Ray, deep - 1, g);

         // Check if the material is refractive
        } else if (i->material->refractive) {

           vec refractedVector = refraction(unit_vector(r.direction()), i->normal, 
                                 i->material>refraction_index);

       Ray refracted_Ray = Ray(i->point, refractedVector);
           intensity = color_ray(refracted_Ray , deep - 1, g);

        } else {

            intensity = i->material->DifuseColor * color_ray(Ray(i->point, i->normal +                    vec::randomUnitVector()), deep - 1, g);

        }

        return intensity;
    }
    
    vec unit_direction = unit_vector(r.direction());
    auto a = 0.5 * (unit_direction .y() + 1);
    return (1.0 - a) * color(1.0, 1.0, 1.0) + a * color(0.5, 0.7, 1.0);
};

I should get the following image as a result:

Image from Ray Tracing in a weekend section 11.3

Let me know if you need more information, any help is appreciated :)

Upvotes: 0

Views: 72

Answers (1)

Lautaro10263
Lautaro10263

Reputation: 1

Well, I found the solution, the problem was in

rparal = (-sqrt(abs(1 - rperp.length_squared()))) * outward_normal;

I deleted the parenthesis and I changed 'abs' for 'fabs' and that solved the problem.

rparal = -sqrt(fabs(1 - rperp.length_squared())) * outward_normal;

Here is the new image generated: New image without problem

Upvotes: 0

Related Questions