Skip to content

Commit aa4e58f

Browse files
author
Peter Shirley
committed
First commit of code for Ray Tracing in One Weekend
1 parent ffe8e25 commit aa4e58f

File tree

8 files changed

+532
-0
lines changed

8 files changed

+532
-0
lines changed

camera.h

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#ifndef CAMERAH
2+
#define CAMERAH
3+
#include "ray.h"
4+
5+
vec3 random_in_unit_disk() {
6+
vec3 p;
7+
do {
8+
p = 2.0*vec3(drand48(),drand48(),0) - vec3(1,1,0);
9+
} while (dot(p,p) >= 1.0);
10+
return p;
11+
}
12+
13+
class camera {
14+
public:
15+
camera(vec3 lookfrom, vec3 lookat, vec3 vup, float vfov, float aspect, float aperture, float focus_dist) { // vfov is top to bottom in degrees
16+
lens_radius = aperture / 2;
17+
float theta = vfov*M_PI/180;
18+
float half_height = tan(theta/2);
19+
float half_width = aspect * half_height;
20+
origin = lookfrom;
21+
w = unit_vector(lookfrom - lookat);
22+
u = unit_vector(cross(vup, w));
23+
v = cross(w, u);
24+
lower_left_corner = origin - half_width*focus_dist*u -half_height*focus_dist*v - focus_dist*w;
25+
horizontal = 2*half_width*focus_dist*u;
26+
vertical = 2*half_height*focus_dist*v;
27+
}
28+
ray get_ray(float s, float t) {
29+
vec3 rd = lens_radius*random_in_unit_disk();
30+
vec3 offset = u * rd.x() + v * rd.y();
31+
return ray(origin + offset, lower_left_corner + s*horizontal + t*vertical - origin - offset);
32+
}
33+
34+
vec3 origin;
35+
vec3 lower_left_corner;
36+
vec3 horizontal;
37+
vec3 vertical;
38+
vec3 u, v, w;
39+
float lens_radius;
40+
};
41+
#endif
42+
43+
44+
45+

hitable.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#ifndef HITABLEH
2+
#define HITABLEH
3+
4+
#include "ray.h"
5+
6+
class material;
7+
8+
9+
10+
struct hit_record
11+
{
12+
float t;
13+
vec3 p;
14+
vec3 normal;
15+
material *mat_ptr;
16+
};
17+
18+
class hitable {
19+
public:
20+
virtual bool hit(const ray& r, float t_min, float t_max, hit_record& rec) const = 0;
21+
};
22+
23+
#endif
24+
25+
26+
27+

hitable_list.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#ifndef HITABLELISTH
2+
#define HITABLELISTH
3+
4+
#include "hitable.h"
5+
6+
class hitable_list: public hitable {
7+
public:
8+
hitable_list() {}
9+
hitable_list(hitable **l, int n) {list = l; list_size = n; }
10+
virtual bool hit(const ray& r, float tmin, float tmax, hit_record& rec) const;
11+
hitable **list;
12+
int list_size;
13+
};
14+
15+
bool hitable_list::hit(const ray& r, float t_min, float t_max, hit_record& rec) const {
16+
hit_record temp_rec;
17+
bool hit_anything = false;
18+
double closest_so_far = t_max;
19+
for (int i = 0; i < list_size; i++) {
20+
if (list[i]->hit(r, t_min, closest_so_far, temp_rec)) {
21+
hit_anything = true;
22+
closest_so_far = temp_rec.t;
23+
rec = temp_rec;
24+
}
25+
}
26+
return hit_anything;
27+
}
28+
29+
#endif
30+

main.cc

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
#include <iostream>
2+
#include "sphere.h"
3+
#include "hitable_list.h"
4+
#include "float.h"
5+
#include "camera.h"
6+
#include "material.h"
7+
8+
9+
vec3 color(const ray& r, hitable *world, int depth) {
10+
hit_record rec;
11+
if (world->hit(r, 0.001, MAXFLOAT, rec)) {
12+
ray scattered;
13+
vec3 attenuation;
14+
if (depth < 50 && rec.mat_ptr->scatter(r, rec, attenuation, scattered)) {
15+
return attenuation*color(scattered, world, depth+1);
16+
}
17+
else {
18+
return vec3(0,0,0);
19+
}
20+
}
21+
else {
22+
vec3 unit_direction = unit_vector(r.direction());
23+
float t = 0.5*(unit_direction.y() + 1.0);
24+
return (1.0-t)*vec3(1.0, 1.0, 1.0) + t*vec3(0.5, 0.7, 1.0);
25+
}
26+
}
27+
28+
29+
hitable *random_scene() {
30+
int n = 500;
31+
hitable **list = new hitable*[n+1];
32+
list[0] = new sphere(vec3(0,-1000,0), 1000, new lambertian(vec3(0.5, 0.5, 0.5)));
33+
int i = 1;
34+
for (int a = -11; a < 11; a++) {
35+
for (int b = -11; b < 11; b++) {
36+
float choose_mat = drand48();
37+
vec3 center(a+0.9*drand48(),0.2,b+0.9*drand48());
38+
if ((center-vec3(4,0.2,0)).length() > 0.9) {
39+
if (choose_mat < 0.8) { // diffuse
40+
list[i++] = new sphere(center, 0.2, new lambertian(vec3(drand48()*drand48(), drand48()*drand48(), drand48()*drand48())));
41+
}
42+
else if (choose_mat < 0.95) { // metal
43+
list[i++] = new sphere(center, 0.2,
44+
new metal(vec3(0.5*(1 + drand48()), 0.5*(1 + drand48()), 0.5*(1 + drand48())), 0.5*drand48()));
45+
}
46+
else { // glass
47+
list[i++] = new sphere(center, 0.2, new dielectric(1.5));
48+
}
49+
}
50+
}
51+
}
52+
53+
list[i++] = new sphere(vec3(0, 1, 0), 1.0, new dielectric(1.5));
54+
list[i++] = new sphere(vec3(-4, 1, 0), 1.0, new lambertian(vec3(0.4, 0.2, 0.1)));
55+
list[i++] = new sphere(vec3(4, 1, 0), 1.0, new metal(vec3(0.7, 0.6, 0.5), 0.0));
56+
57+
return new hitable_list(list,i);
58+
}
59+
60+
int main() {
61+
int nx = 1200;
62+
int ny = 800;
63+
int ns = 10;
64+
std::cout << "P3\n" << nx << " " << ny << "\n255\n";
65+
hitable *list[5];
66+
float R = cos(M_PI/4);
67+
list[0] = new sphere(vec3(0,0,-1), 0.5, new lambertian(vec3(0.1, 0.2, 0.5)));
68+
list[1] = new sphere(vec3(0,-100.5,-1), 100, new lambertian(vec3(0.8, 0.8, 0.0)));
69+
list[2] = new sphere(vec3(1,0,-1), 0.5, new metal(vec3(0.8, 0.6, 0.2), 0.0));
70+
list[3] = new sphere(vec3(-1,0,-1), 0.5, new dielectric(1.5));
71+
list[4] = new sphere(vec3(-1,0,-1), -0.45, new dielectric(1.5));
72+
hitable *world = new hitable_list(list,5);
73+
world = random_scene();
74+
75+
vec3 lookfrom(13,2,3);
76+
vec3 lookat(0,0,0);
77+
float dist_to_focus = 10.0;
78+
float aperture = 0.1;
79+
80+
camera cam(lookfrom, lookat, vec3(0,1,0), 20, float(nx)/float(ny), aperture, dist_to_focus);
81+
82+
for (int j = ny-1; j >= 0; j--) {
83+
for (int i = 0; i < nx; i++) {
84+
vec3 col(0, 0, 0);
85+
for (int s=0; s < ns; s++) {
86+
float u = float(i + drand48()) / float(nx);
87+
float v = float(j + drand48()) / float(ny);
88+
ray r = cam.get_ray(u, v);
89+
vec3 p = r.point_at_parameter(2.0);
90+
col += color(r, world,0);
91+
}
92+
col /= float(ns);
93+
col = vec3( sqrt(col[0]), sqrt(col[1]), sqrt(col[2]) );
94+
int ir = int(255.99*col[0]);
95+
int ig = int(255.99*col[1]);
96+
int ib = int(255.99*col[2]);
97+
std::cout << ir << " " << ig << " " << ib << "\n";
98+
}
99+
}
100+
}
101+
102+
103+

material.h

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
#ifndef MATERIALH
2+
#define MATERIALH
3+
4+
struct hit_record;
5+
6+
#include "ray.h"
7+
#include "hitable.h"
8+
9+
10+
float schlick(float cosine, float ref_idx) {
11+
float r0 = (1-ref_idx) / (1+ref_idx);
12+
r0 = r0*r0;
13+
return r0 + (1-r0)*pow((1 - cosine),5);
14+
}
15+
16+
bool refract(const vec3& v, const vec3& n, float ni_over_nt, vec3& refracted) {
17+
vec3 uv = unit_vector(v);
18+
float dt = dot(uv, n);
19+
float discriminant = 1.0 - ni_over_nt*ni_over_nt*(1-dt*dt);
20+
if (discriminant > 0) {
21+
refracted = ni_over_nt*(uv - n*dt) - n*sqrt(discriminant);
22+
return true;
23+
}
24+
else
25+
return false;
26+
}
27+
28+
29+
vec3 reflect(const vec3& v, const vec3& n) {
30+
return v - 2*dot(v,n)*n;
31+
}
32+
33+
34+
vec3 random_in_unit_sphere() {
35+
vec3 p;
36+
do {
37+
p = 2.0*vec3(drand48(),drand48(),drand48()) - vec3(1,1,1);
38+
} while (p.squared_length() >= 1.0);
39+
return p;
40+
}
41+
42+
43+
class material {
44+
public:
45+
virtual bool scatter(const ray& r_in, const hit_record& rec, vec3& attenuation, ray& scattered) const = 0;
46+
};
47+
48+
class lambertian : public material {
49+
public:
50+
lambertian(const vec3& a) : albedo(a) {}
51+
virtual bool scatter(const ray& r_in, const hit_record& rec, vec3& attenuation, ray& scattered) const {
52+
vec3 target = rec.p + rec.normal + random_in_unit_sphere();
53+
scattered = ray(rec.p, target-rec.p);
54+
attenuation = albedo;
55+
return true;
56+
}
57+
58+
vec3 albedo;
59+
};
60+
61+
class metal : public material {
62+
public:
63+
metal(const vec3& a, float f) : albedo(a) { if (f < 1) fuzz = f; else fuzz = 1; }
64+
virtual bool scatter(const ray& r_in, const hit_record& rec, vec3& attenuation, ray& scattered) const {
65+
vec3 reflected = reflect(unit_vector(r_in.direction()), rec.normal);
66+
scattered = ray(rec.p, reflected + fuzz*random_in_unit_sphere());
67+
attenuation = albedo;
68+
return (dot(scattered.direction(), rec.normal) > 0);
69+
}
70+
vec3 albedo;
71+
float fuzz;
72+
};
73+
74+
class dielectric : public material {
75+
public:
76+
dielectric(float ri) : ref_idx(ri) {}
77+
virtual bool scatter(const ray& r_in, const hit_record& rec, vec3& attenuation, ray& scattered) const {
78+
vec3 outward_normal;
79+
vec3 reflected = reflect(r_in.direction(), rec.normal);
80+
float ni_over_nt;
81+
attenuation = vec3(1.0, 1.0, 1.0);
82+
vec3 refracted;
83+
float reflect_prob;
84+
float cosine;
85+
if (dot(r_in.direction(), rec.normal) > 0) {
86+
outward_normal = -rec.normal;
87+
ni_over_nt = ref_idx;
88+
// cosine = ref_idx * dot(r_in.direction(), rec.normal) / r_in.direction().length();
89+
cosine = dot(r_in.direction(), rec.normal) / r_in.direction().length();
90+
cosine = sqrt(1 - ref_idx*ref_idx*(1-cosine*cosine));
91+
}
92+
else {
93+
outward_normal = rec.normal;
94+
ni_over_nt = 1.0 / ref_idx;
95+
cosine = -dot(r_in.direction(), rec.normal) / r_in.direction().length();
96+
}
97+
if (refract(r_in.direction(), outward_normal, ni_over_nt, refracted))
98+
reflect_prob = schlick(cosine, ref_idx);
99+
else
100+
reflect_prob = 1.0;
101+
if (drand48() < reflect_prob)
102+
scattered = ray(rec.p, reflected);
103+
else
104+
scattered = ray(rec.p, refracted);
105+
return true;
106+
}
107+
108+
float ref_idx;
109+
};
110+
111+
#endif
112+
113+
114+
115+

ray.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#ifndef RAYH
2+
#define RAYH
3+
#include "vec3.h"
4+
5+
class ray
6+
{
7+
public:
8+
ray() {}
9+
ray(const vec3& a, const vec3& b) { A = a; B = b; }
10+
vec3 origin() const { return A; }
11+
vec3 direction() const { return B; }
12+
vec3 point_at_parameter(float t) const { return A + t*B; }
13+
14+
vec3 A;
15+
vec3 B;
16+
};
17+
18+
#endif
19+
20+

sphere.h

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#ifndef SPHEREH
2+
#define SPHEREH
3+
4+
#include "hitable.h"
5+
6+
class sphere: public hitable {
7+
public:
8+
sphere() {}
9+
sphere(vec3 cen, float r, material *m) : center(cen), radius(r), mat_ptr(m) {};
10+
virtual bool hit(const ray& r, float tmin, float tmax, hit_record& rec) const;
11+
vec3 center;
12+
float radius;
13+
material *mat_ptr;
14+
};
15+
16+
bool sphere::hit(const ray& r, float t_min, float t_max, hit_record& rec) const {
17+
vec3 oc = r.origin() - center;
18+
float a = dot(r.direction(), r.direction());
19+
float b = dot(oc, r.direction());
20+
float c = dot(oc, oc) - radius*radius;
21+
float discriminant = b*b - a*c;
22+
if (discriminant > 0) {
23+
float temp = (-b - sqrt(discriminant))/a;
24+
if (temp < t_max && temp > t_min) {
25+
rec.t = temp;
26+
rec.p = r.point_at_parameter(rec.t);
27+
rec.normal = (rec.p - center) / radius;
28+
rec.mat_ptr = mat_ptr;
29+
return true;
30+
}
31+
temp = (-b + sqrt(discriminant)) / a;
32+
if (temp < t_max && temp > t_min) {
33+
rec.t = temp;
34+
rec.p = r.point_at_parameter(rec.t);
35+
rec.normal = (rec.p - center) / radius;
36+
rec.mat_ptr = mat_ptr;
37+
return true;
38+
}
39+
}
40+
return false;
41+
}
42+
43+
44+
#endif
45+
46+
47+

0 commit comments

Comments
 (0)