summaryrefslogtreecommitdiff
path: root/material_dielectric.cpp
blob: d44ab8783f8d963ad602d9bded397920285ca72f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
//
// Created by Keuin on 2022/4/15.
//

#include "material_dielectric.h"
#include "tracelog.h"

bool material_dielectric::scatter(ray3d &r, const object &hit_obj, double hit_t, random_uv_gen_3d &ruvg) const {
    const auto hit_p = r.at(hit_t);
    assert(hit_obj.is_on(hit_p));
    auto nv = hit_obj.normal_vector(hit_p);
    const auto n1 = r.direction(); // incoming ray, unit vector
    const bool outside = dot(nv, n1) < 0; // if the ray hits the outside of the surface
    double rel_ri; // relative ri, source_ri/target_ri
    if (!outside) {
        nv = -nv; // use normal vector pointing to the inner
        rel_ri = ri;
    } else {
        rel_ri = 1.0 / ri;
    }
    const auto cos_t1 = std::min(-dot(nv, n1), 1.0); // cos(theta1)
    const auto sin_t1_s = 1 - cos_t1 * cos_t1; // sin(theta1)^2
    const auto rel_ri_s = rel_ri * rel_ri;
    const auto sin_t2_s = sin_t1_s * rel_ri_s;
    double p_reflect; // probability of schlick reflection
    bool reflect = false;
    if (sin_t2_s > 1.0) {
        TRACELOG("    reflect (TIR, ri=%f)\n", ri);
        // sin(theta2)^2 > 1, no real solution
        // TIR (total internal reflection)
        reflect = true;
    } else if ((p_reflect = reflectance(cos_t1, ri)) > ruvg.range01_scalar()) {
        TRACELOG("    reflect (schlick, ri=%f, p=%f)\n", ri, p_reflect);
        reflect = true;
    }
    if (reflect) {
        r.direction(nv.reflect(n1));
        r.source(hit_p);
        return true;
    } else {
        // normal refract
        TRACELOG("    refract (forced, ri=%f)\n", ri);
        const auto sin_t2 = sqrt(sin_t2_s);
        const auto cos_t2 = sqrt(1 - sin_t2_s);
        const auto n2 = (-cos_t2 * nv) + (n1 + cos_t1 * nv).unit_vec() * sin_t2;
        r.direction(n2);
        r.source(hit_p);
        return true;
    }
}