-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path01-basic-raytracing.cc
More file actions
142 lines (117 loc) · 4.31 KB
/
01-basic-raytracing.cc
File metadata and controls
142 lines (117 loc) · 4.31 KB
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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
// Basic Raytracing
//
// Book chapter: https://gabrielgambetta.com/computer-graphics-from-scratch/02-basic-raytracing.html
// Book example: https://github.com/ggambetta/computer-graphics-from-scratch/blob/master/demos/raytracer-01.html
//
// ```
// clang++ -std=c++17 examples/01-basic-raytracing.cc -o bin/01-basic-raytracing -O3 -fno-fast-math
// bin/01-basic-raytracing
// ```
#include "bmp.h"
struct fVec3 {
float x, y, z;
fVec3 operator-(const fVec3& other) const {
return { x - other.x, y - other.y, z - other.z };
}
float dot(const fVec3& other) const {
return x * other.x + y * other.y + z * other.z;
}
};
struct Sphere {
fVec3 center;
float radius;
BMPColor color;
};
struct Scene {
const float viewport_size = 1;
const float projection_plane_z = 1;
fVec3 camera_position;
BMPColor background_color;
vector<Sphere> spheres;
};
struct ImageSize {
int32_t width;
int32_t height;
};
struct Image {
const ImageSize size;
// flattened array of pixels
vector<BMPColor> data;
Image(int32_t width, int32_t height):
size{width, height}, data(width * height) {}
// computes the offset for the data based on x and y coordinates
int32_t offset(int32_t x, int32_t y) const {
x = size.width / 2 + x;
y = size.height / 2 - y - 1;
if (x < 0 || x >= size.width || y < 0 || y >= size.height) {
throw out_of_range("Pixel coordinates must be within [0 < width, 0 < height]");
}
return x + size.width * y;
}
};
// converts 2D canvas coordinates to 3D viewport coordinates.
fVec3 canvasToViewport(int32_t x, int32_t y, const ImageSize& size, const Scene& scene) {
return fVec3 {
(float)x * scene.viewport_size / size.width,
(float)y * scene.viewport_size / size.height,
scene.projection_plane_z
};
}
// computes the intersection of a ray and a sphere. Returns the values of t for the intersections.
pair<float, float> intersectRaySphere(const fVec3& origin, const fVec3& direction, const Sphere& sphere) {
fVec3 oc = origin - sphere.center;
float a = direction.dot(direction);
float b = 2 * oc.dot(direction);
float c = oc.dot(oc) - (sphere.radius * sphere.radius);
float discriminant = (b * b) - (4 * a * c);
if (discriminant < 0) {
return {INFINITY, INFINITY};
}
float t1 = (-b + sqrt(discriminant)) / (2 * a);
float t2 = (-b - sqrt(discriminant)) / (2 * a);
return {t1, t2};
}
// traces a ray against the set of spheres in the scene.
BMPColor traceRay(const fVec3& origin, const fVec3& direction, float t_min, float t_max, const Scene& scene) {
float closest_t = INFINITY;
Sphere closest_sphere;
for (int32_t i = 0; i < scene.spheres.size(); i++) {
auto [xt_min, xt_max] = intersectRaySphere(origin, direction, scene.spheres[i]);
if (xt_min < closest_t && t_min < xt_min && xt_min < t_max) {
closest_t = xt_min;
closest_sphere = scene.spheres[i];
}
if (xt_max < closest_t && t_min < xt_max && xt_max < t_max) {
closest_t = xt_max;
closest_sphere = scene.spheres[i];
}
}
if (closest_t == INFINITY) {
return scene.background_color;
}
return closest_sphere.color;
}
int main() {
Image image = {600, 600};
Scene scene = {
.viewport_size = 1,
.projection_plane_z = 1,
.camera_position = {0, 0, 0},
.background_color = {255, 255, 255},
.spheres = {
Sphere{.center = {0, -1, 3}, .radius = 1, .color = {255, 0, 0}},
Sphere{.center = {-2, 0, 4}, .radius = 1, .color = {0, 255, 0}},
Sphere{.center = {2, 0, 4}, .radius = 1, .color = {0, 0, 255}},
Sphere{.center = {0, -5001, 0}, .radius = 5000, .color = {255, 255, 0}}
}
};
for (int32_t x = -image.size.width / 2; x < image.size.width / 2; x++) {
for(int32_t y = -image.size.height / 2; y < image.size.height / 2; y++) {
fVec3 direction = canvasToViewport(x, y, image.size, scene);
BMPColor color = traceRay(scene.camera_position, direction, 1, INFINITY, scene);
image.data[image.offset(x, y)] = color;
}
}
save_image(image.data, image.size.width, image.size.height, "results/01-basic-raytracing.bmp");
return 0;
}