-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathscene.cpp
115 lines (106 loc) · 3.55 KB
/
scene.cpp
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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
// Homepage: https://github.com/ananthvk/cpp-raytracer
#include "scene.hpp"
Scene::Scene()
{
// A sample render scene
materials.push_back(new LambertianDiffuse(color(0.5, 0.5, 0.5)));
materials.push_back(new Glass(WHITE, 1.5));
materials.push_back(new LambertianDiffuse(color(0.4, 0.2, 0.1)));
materials.push_back(new Metal(color(0.7, 0.6, 0.5), 0.0));
objects.push_back(new Sphere(vec3(0, -1000, 0), 1000, 0));
objects.push_back(new Sphere(vec3(0, 1, 0), 1.0, 1));
objects.push_back(new Sphere(vec3(-4, 1, 0), 1.0, 2));
objects.push_back(new Sphere(vec3(4, 1, 0), 1.0, 3));
// Generate 50 materials
for (int i = 0; i < 50; ++i)
{
double u = uniform();
double x = uniform(), y = uniform(), z = uniform();
double p = uniform(0, 0.5);
if (u < 0.5)
{
// 50 % of all spheres are diffuse
materials.push_back(new LambertianDiffuse(color(x, y, z)));
}
else if (u < 0.9)
{
// Metals, 40 % chance
materials.push_back(new Metal(color(x, y, z), p));
}
else
{
// Glass with refractive indices between 1.1 and 1.6
materials.push_back(new Glass(WHITE, 1.1 + p));
}
}
// Generate the random spheres
for (int a = -3; a < 3; a++)
{
for (int b = -3; b < 3; b++)
{
vec3 center(a + 0.9 * uniform(), 0.2, b + 0.9 * uniform());
if (linalg::length((center - vec3(4, 0.2, 0))) > 0.9)
{
int material = randint(4, materials.size() - 1);
objects.push_back(new Sphere(center, 0.2, material));
}
}
}
}
color Scene::color_at(const Ray &ray, int recursion_limit) const
{
if (recursion_limit == 0)
{
// The function has reached recursion limit, so no more light can be
// gathered, so return black.
return color(0, 0, 0);
}
// 0.001 is used to prevent intersection of the ray with the same surface
// from which it is cast, to prevent shadow acne
auto params = RayParams({ray, 0.001, INFINITY});
// Find the closest intersection of this ray in this given scene
Intersection intersect = closest_intersect(params);
if (intersect.occured)
{
// Perform material-ray interactions, such as reflection, refraction, etc
auto interaction = materials[intersect.material_id]->interact(params, intersect);
if (interaction.additional_rays)
{
return linalg::cmul(interaction.attenuation,
color_at(interaction.ray, recursion_limit - 1));
}
return interaction.attenuation;
}
// The ray does not intersect with any object, so return the sky color
double t = 0.5 * (ray.direction().y + 1.0);
return lerp(WHITE, SKY_COLOR_2, t);
}
Intersection Scene::closest_intersect(const RayParams ¶ms) const
{
double intersect_distance = INF;
Intersection closest;
closest.occured = false;
for (const auto &obj : objects)
{
auto i = obj->intersect(params);
// If this intersection is closer to the ray's origin, choose it as the closest
// intersection
if (i.occured && i.parametric < intersect_distance)
{
intersect_distance = i.parametric;
closest = i;
}
}
return closest;
}
Scene::~Scene()
{
for (size_t i = 0; i < materials.size(); ++i)
{
delete materials[i];
}
for (size_t i = 0; i < objects.size(); ++i)
{
delete objects[i];
}
}