forked from RayTracing/InOneWeekend
-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
First commit of code for Ray Tracing in One Weekend
- Loading branch information
Peter Shirley
committed
May 6, 2016
1 parent
ffe8e25
commit aa4e58f
Showing
8 changed files
with
532 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
#ifndef CAMERAH | ||
#define CAMERAH | ||
#include "ray.h" | ||
|
||
vec3 random_in_unit_disk() { | ||
vec3 p; | ||
do { | ||
p = 2.0*vec3(drand48(),drand48(),0) - vec3(1,1,0); | ||
} while (dot(p,p) >= 1.0); | ||
return p; | ||
} | ||
|
||
class camera { | ||
public: | ||
camera(vec3 lookfrom, vec3 lookat, vec3 vup, float vfov, float aspect, float aperture, float focus_dist) { // vfov is top to bottom in degrees | ||
lens_radius = aperture / 2; | ||
float theta = vfov*M_PI/180; | ||
float half_height = tan(theta/2); | ||
float half_width = aspect * half_height; | ||
origin = lookfrom; | ||
w = unit_vector(lookfrom - lookat); | ||
u = unit_vector(cross(vup, w)); | ||
v = cross(w, u); | ||
lower_left_corner = origin - half_width*focus_dist*u -half_height*focus_dist*v - focus_dist*w; | ||
horizontal = 2*half_width*focus_dist*u; | ||
vertical = 2*half_height*focus_dist*v; | ||
} | ||
ray get_ray(float s, float t) { | ||
vec3 rd = lens_radius*random_in_unit_disk(); | ||
vec3 offset = u * rd.x() + v * rd.y(); | ||
return ray(origin + offset, lower_left_corner + s*horizontal + t*vertical - origin - offset); | ||
} | ||
|
||
vec3 origin; | ||
vec3 lower_left_corner; | ||
vec3 horizontal; | ||
vec3 vertical; | ||
vec3 u, v, w; | ||
float lens_radius; | ||
}; | ||
#endif | ||
|
||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
#ifndef HITABLEH | ||
#define HITABLEH | ||
|
||
#include "ray.h" | ||
|
||
class material; | ||
|
||
|
||
|
||
struct hit_record | ||
{ | ||
float t; | ||
vec3 p; | ||
vec3 normal; | ||
material *mat_ptr; | ||
}; | ||
|
||
class hitable { | ||
public: | ||
virtual bool hit(const ray& r, float t_min, float t_max, hit_record& rec) const = 0; | ||
}; | ||
|
||
#endif | ||
|
||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
#ifndef HITABLELISTH | ||
#define HITABLELISTH | ||
|
||
#include "hitable.h" | ||
|
||
class hitable_list: public hitable { | ||
public: | ||
hitable_list() {} | ||
hitable_list(hitable **l, int n) {list = l; list_size = n; } | ||
virtual bool hit(const ray& r, float tmin, float tmax, hit_record& rec) const; | ||
hitable **list; | ||
int list_size; | ||
}; | ||
|
||
bool hitable_list::hit(const ray& r, float t_min, float t_max, hit_record& rec) const { | ||
hit_record temp_rec; | ||
bool hit_anything = false; | ||
double closest_so_far = t_max; | ||
for (int i = 0; i < list_size; i++) { | ||
if (list[i]->hit(r, t_min, closest_so_far, temp_rec)) { | ||
hit_anything = true; | ||
closest_so_far = temp_rec.t; | ||
rec = temp_rec; | ||
} | ||
} | ||
return hit_anything; | ||
} | ||
|
||
#endif | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
#include <iostream> | ||
#include "sphere.h" | ||
#include "hitable_list.h" | ||
#include "float.h" | ||
#include "camera.h" | ||
#include "material.h" | ||
|
||
|
||
vec3 color(const ray& r, hitable *world, int depth) { | ||
hit_record rec; | ||
if (world->hit(r, 0.001, MAXFLOAT, rec)) { | ||
ray scattered; | ||
vec3 attenuation; | ||
if (depth < 50 && rec.mat_ptr->scatter(r, rec, attenuation, scattered)) { | ||
return attenuation*color(scattered, world, depth+1); | ||
} | ||
else { | ||
return vec3(0,0,0); | ||
} | ||
} | ||
else { | ||
vec3 unit_direction = unit_vector(r.direction()); | ||
float t = 0.5*(unit_direction.y() + 1.0); | ||
return (1.0-t)*vec3(1.0, 1.0, 1.0) + t*vec3(0.5, 0.7, 1.0); | ||
} | ||
} | ||
|
||
|
||
hitable *random_scene() { | ||
int n = 500; | ||
hitable **list = new hitable*[n+1]; | ||
list[0] = new sphere(vec3(0,-1000,0), 1000, new lambertian(vec3(0.5, 0.5, 0.5))); | ||
int i = 1; | ||
for (int a = -11; a < 11; a++) { | ||
for (int b = -11; b < 11; b++) { | ||
float choose_mat = drand48(); | ||
vec3 center(a+0.9*drand48(),0.2,b+0.9*drand48()); | ||
if ((center-vec3(4,0.2,0)).length() > 0.9) { | ||
if (choose_mat < 0.8) { // diffuse | ||
list[i++] = new sphere(center, 0.2, new lambertian(vec3(drand48()*drand48(), drand48()*drand48(), drand48()*drand48()))); | ||
} | ||
else if (choose_mat < 0.95) { // metal | ||
list[i++] = new sphere(center, 0.2, | ||
new metal(vec3(0.5*(1 + drand48()), 0.5*(1 + drand48()), 0.5*(1 + drand48())), 0.5*drand48())); | ||
} | ||
else { // glass | ||
list[i++] = new sphere(center, 0.2, new dielectric(1.5)); | ||
} | ||
} | ||
} | ||
} | ||
|
||
list[i++] = new sphere(vec3(0, 1, 0), 1.0, new dielectric(1.5)); | ||
list[i++] = new sphere(vec3(-4, 1, 0), 1.0, new lambertian(vec3(0.4, 0.2, 0.1))); | ||
list[i++] = new sphere(vec3(4, 1, 0), 1.0, new metal(vec3(0.7, 0.6, 0.5), 0.0)); | ||
|
||
return new hitable_list(list,i); | ||
} | ||
|
||
int main() { | ||
int nx = 1200; | ||
int ny = 800; | ||
int ns = 10; | ||
std::cout << "P3\n" << nx << " " << ny << "\n255\n"; | ||
hitable *list[5]; | ||
float R = cos(M_PI/4); | ||
list[0] = new sphere(vec3(0,0,-1), 0.5, new lambertian(vec3(0.1, 0.2, 0.5))); | ||
list[1] = new sphere(vec3(0,-100.5,-1), 100, new lambertian(vec3(0.8, 0.8, 0.0))); | ||
list[2] = new sphere(vec3(1,0,-1), 0.5, new metal(vec3(0.8, 0.6, 0.2), 0.0)); | ||
list[3] = new sphere(vec3(-1,0,-1), 0.5, new dielectric(1.5)); | ||
list[4] = new sphere(vec3(-1,0,-1), -0.45, new dielectric(1.5)); | ||
hitable *world = new hitable_list(list,5); | ||
world = random_scene(); | ||
|
||
vec3 lookfrom(13,2,3); | ||
vec3 lookat(0,0,0); | ||
float dist_to_focus = 10.0; | ||
float aperture = 0.1; | ||
|
||
camera cam(lookfrom, lookat, vec3(0,1,0), 20, float(nx)/float(ny), aperture, dist_to_focus); | ||
|
||
for (int j = ny-1; j >= 0; j--) { | ||
for (int i = 0; i < nx; i++) { | ||
vec3 col(0, 0, 0); | ||
for (int s=0; s < ns; s++) { | ||
float u = float(i + drand48()) / float(nx); | ||
float v = float(j + drand48()) / float(ny); | ||
ray r = cam.get_ray(u, v); | ||
vec3 p = r.point_at_parameter(2.0); | ||
col += color(r, world,0); | ||
} | ||
col /= float(ns); | ||
col = vec3( sqrt(col[0]), sqrt(col[1]), sqrt(col[2]) ); | ||
int ir = int(255.99*col[0]); | ||
int ig = int(255.99*col[1]); | ||
int ib = int(255.99*col[2]); | ||
std::cout << ir << " " << ig << " " << ib << "\n"; | ||
} | ||
} | ||
} | ||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
#ifndef MATERIALH | ||
#define MATERIALH | ||
|
||
struct hit_record; | ||
|
||
#include "ray.h" | ||
#include "hitable.h" | ||
|
||
|
||
float schlick(float cosine, float ref_idx) { | ||
float r0 = (1-ref_idx) / (1+ref_idx); | ||
r0 = r0*r0; | ||
return r0 + (1-r0)*pow((1 - cosine),5); | ||
} | ||
|
||
bool refract(const vec3& v, const vec3& n, float ni_over_nt, vec3& refracted) { | ||
vec3 uv = unit_vector(v); | ||
float dt = dot(uv, n); | ||
float discriminant = 1.0 - ni_over_nt*ni_over_nt*(1-dt*dt); | ||
if (discriminant > 0) { | ||
refracted = ni_over_nt*(uv - n*dt) - n*sqrt(discriminant); | ||
return true; | ||
} | ||
else | ||
return false; | ||
} | ||
|
||
|
||
vec3 reflect(const vec3& v, const vec3& n) { | ||
return v - 2*dot(v,n)*n; | ||
} | ||
|
||
|
||
vec3 random_in_unit_sphere() { | ||
vec3 p; | ||
do { | ||
p = 2.0*vec3(drand48(),drand48(),drand48()) - vec3(1,1,1); | ||
} while (p.squared_length() >= 1.0); | ||
return p; | ||
} | ||
|
||
|
||
class material { | ||
public: | ||
virtual bool scatter(const ray& r_in, const hit_record& rec, vec3& attenuation, ray& scattered) const = 0; | ||
}; | ||
|
||
class lambertian : public material { | ||
public: | ||
lambertian(const vec3& a) : albedo(a) {} | ||
virtual bool scatter(const ray& r_in, const hit_record& rec, vec3& attenuation, ray& scattered) const { | ||
vec3 target = rec.p + rec.normal + random_in_unit_sphere(); | ||
scattered = ray(rec.p, target-rec.p); | ||
attenuation = albedo; | ||
return true; | ||
} | ||
|
||
vec3 albedo; | ||
}; | ||
|
||
class metal : public material { | ||
public: | ||
metal(const vec3& a, float f) : albedo(a) { if (f < 1) fuzz = f; else fuzz = 1; } | ||
virtual bool scatter(const ray& r_in, const hit_record& rec, vec3& attenuation, ray& scattered) const { | ||
vec3 reflected = reflect(unit_vector(r_in.direction()), rec.normal); | ||
scattered = ray(rec.p, reflected + fuzz*random_in_unit_sphere()); | ||
attenuation = albedo; | ||
return (dot(scattered.direction(), rec.normal) > 0); | ||
} | ||
vec3 albedo; | ||
float fuzz; | ||
}; | ||
|
||
class dielectric : public material { | ||
public: | ||
dielectric(float ri) : ref_idx(ri) {} | ||
virtual bool scatter(const ray& r_in, const hit_record& rec, vec3& attenuation, ray& scattered) const { | ||
vec3 outward_normal; | ||
vec3 reflected = reflect(r_in.direction(), rec.normal); | ||
float ni_over_nt; | ||
attenuation = vec3(1.0, 1.0, 1.0); | ||
vec3 refracted; | ||
float reflect_prob; | ||
float cosine; | ||
if (dot(r_in.direction(), rec.normal) > 0) { | ||
outward_normal = -rec.normal; | ||
ni_over_nt = ref_idx; | ||
// cosine = ref_idx * dot(r_in.direction(), rec.normal) / r_in.direction().length(); | ||
cosine = dot(r_in.direction(), rec.normal) / r_in.direction().length(); | ||
cosine = sqrt(1 - ref_idx*ref_idx*(1-cosine*cosine)); | ||
} | ||
else { | ||
outward_normal = rec.normal; | ||
ni_over_nt = 1.0 / ref_idx; | ||
cosine = -dot(r_in.direction(), rec.normal) / r_in.direction().length(); | ||
} | ||
if (refract(r_in.direction(), outward_normal, ni_over_nt, refracted)) | ||
reflect_prob = schlick(cosine, ref_idx); | ||
else | ||
reflect_prob = 1.0; | ||
if (drand48() < reflect_prob) | ||
scattered = ray(rec.p, reflected); | ||
else | ||
scattered = ray(rec.p, refracted); | ||
return true; | ||
} | ||
|
||
float ref_idx; | ||
}; | ||
|
||
#endif | ||
|
||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
#ifndef RAYH | ||
#define RAYH | ||
#include "vec3.h" | ||
|
||
class ray | ||
{ | ||
public: | ||
ray() {} | ||
ray(const vec3& a, const vec3& b) { A = a; B = b; } | ||
vec3 origin() const { return A; } | ||
vec3 direction() const { return B; } | ||
vec3 point_at_parameter(float t) const { return A + t*B; } | ||
|
||
vec3 A; | ||
vec3 B; | ||
}; | ||
|
||
#endif | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
#ifndef SPHEREH | ||
#define SPHEREH | ||
|
||
#include "hitable.h" | ||
|
||
class sphere: public hitable { | ||
public: | ||
sphere() {} | ||
sphere(vec3 cen, float r, material *m) : center(cen), radius(r), mat_ptr(m) {}; | ||
virtual bool hit(const ray& r, float tmin, float tmax, hit_record& rec) const; | ||
vec3 center; | ||
float radius; | ||
material *mat_ptr; | ||
}; | ||
|
||
bool sphere::hit(const ray& r, float t_min, float t_max, hit_record& rec) const { | ||
vec3 oc = r.origin() - center; | ||
float a = dot(r.direction(), r.direction()); | ||
float b = dot(oc, r.direction()); | ||
float c = dot(oc, oc) - radius*radius; | ||
float discriminant = b*b - a*c; | ||
if (discriminant > 0) { | ||
float temp = (-b - sqrt(discriminant))/a; | ||
if (temp < t_max && temp > t_min) { | ||
rec.t = temp; | ||
rec.p = r.point_at_parameter(rec.t); | ||
rec.normal = (rec.p - center) / radius; | ||
rec.mat_ptr = mat_ptr; | ||
return true; | ||
} | ||
temp = (-b + sqrt(discriminant)) / a; | ||
if (temp < t_max && temp > t_min) { | ||
rec.t = temp; | ||
rec.p = r.point_at_parameter(rec.t); | ||
rec.normal = (rec.p - center) / radius; | ||
rec.mat_ptr = mat_ptr; | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
|
||
|
||
#endif | ||
|
||
|
||
|
Oops, something went wrong.