summaryrefslogtreecommitdiff
path: root/material_diffusive.cpp
blob: b3f0207febd58afed290f368f4679d3bc4f2affe (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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
//
// Created by Keuin on 2022/4/15.
//

#include "vec.h"
#include "material_diffusive.h"


bool material_diffuse_lambertian::scatter(ray3d &r, const object &hit_obj, double hit_t, random_uv_gen_3d &ruvg) const {
    const auto hit_point = r.at(hit_t); // hit point, on the surface
    auto nv = hit_obj.normal_vector(hit_point);
    if (dot(nv, r.direction()) > 0) return false; // discard rays from inner (or invert nv)
    auto d = nv + ruvg.normalized();
    if (d.is_zero()) d = nv;
    vec3d diffuse_target = hit_point + d;
    r.decay(albedo); // lose some light when diffused
    r.source(hit_point);
    r.direction((diffuse_target - hit_point).unit_vec()); // the new diffused ray we trace on
    return true;
}

material_diffuse_lambertian::material_diffuse_lambertian(vec3d albedo) : albedo(albedo) {
    assert(albedo.x >= 0);
    assert(albedo.y >= 0);
    assert(albedo.z >= 0);
    assert(albedo.x <= 1);
    assert(albedo.y <= 1);
    assert(albedo.z <= 1);
}

material_diffuse_lambertian::material_diffuse_lambertian(double albedo) : albedo{albedo, albedo, albedo} {
    assert(albedo >= 0);
    assert(albedo <= 1);
}

material_diffuse_simple::material_diffuse_simple(vec3d albedo) : albedo(albedo) {
    assert(albedo.x >= 0);
    assert(albedo.y >= 0);
    assert(albedo.z >= 0);
    assert(albedo.x <= 1);
    assert(albedo.y <= 1);
    assert(albedo.z <= 1);
}

bool material_diffuse_simple::scatter(ray3d &r, const object &hit_obj, double hit_t, random_uv_gen_3d &ruvg) const {
    const auto hit_point = r.at(hit_t); // hit point, on the surface
    auto nv = hit_obj.normal_vector(hit_point);
    if (dot(nv, r.direction()) > 0) return false; // discard rays from inner (or invert nv)
    auto d = nv + ruvg.normalized();
    if (d.is_zero()) d = nv;
    vec3d diffuse_target = hit_point + nv + ruvg.range01();
    r.decay(albedo); // lose some light when diffused
    r.source(hit_point);
    r.direction((diffuse_target - hit_point).unit_vec()); // the new diffused ray we trace on
    return true;
}

material_diffuse_simple::material_diffuse_simple(double albedo) : albedo{albedo, albedo, albedo} {
    assert(albedo >= 0);
    assert(albedo <= 1);
}

material_diffuse_hemispherical::material_diffuse_hemispherical(vec3d albedo) : albedo(albedo) {
    assert(albedo.x >= 0);
    assert(albedo.y >= 0);
    assert(albedo.z >= 0);
    assert(albedo.x <= 1);
    assert(albedo.y <= 1);
    assert(albedo.z <= 1);
}

bool
material_diffuse_hemispherical::scatter(ray3d &r, const object &hit_obj, double hit_t, random_uv_gen_3d &ruvg) const {
    const auto hit_point = r.at(hit_t); // hit point, on the surface
    auto nv = hit_obj.normal_vector(hit_point);
    if (dot(nv, r.direction()) > 0) return false; // discard rays from inner (or invert nv)
    auto d = nv + ruvg.normalized();
    if (d.is_zero()) d = nv;
    vec3d diffuse_target = hit_point + ruvg.hemisphere(nv);
    r.decay(albedo); // lose some light when diffused
    r.source(hit_point);
    r.direction((diffuse_target - hit_point).unit_vec()); // the new diffused ray we trace on
    return true;
}

material_diffuse_hemispherical::material_diffuse_hemispherical(double albedo) : albedo{albedo, albedo, albedo} {
    assert(albedo >= 0);
    assert(albedo <= 1);
}