From 0e5ce7ec07a507555d5e1daead1ee1da6ffa1d9a Mon Sep 17 00:00:00 2001 From: Michael Smith Date: Mon, 21 Jan 2019 12:27:52 +0100 Subject: [PATCH] Chapter 6: Antialiasing --- code/camera.h | 27 ++++++++++++++++++++ code/rt_weekend.cpp | 59 +++++++++++++++++++++++-------------------- code/sdl_platform.cpp | 2 +- code/sphere.h | 46 +++++++++++++++++++++++++++++++++ code/target.h | 19 ++++++++++++++ code/target_list.h | 33 ++++++++++++++++++++++++ code/vec3.h | 4 ++- 7 files changed, 161 insertions(+), 29 deletions(-) create mode 100644 code/camera.h create mode 100644 code/sphere.h create mode 100644 code/target.h create mode 100644 code/target_list.h diff --git a/code/camera.h b/code/camera.h new file mode 100644 index 0000000..7ad91bb --- /dev/null +++ b/code/camera.h @@ -0,0 +1,27 @@ +#ifndef CAMERA_H +#define CAMERA_H + +#include "ray.h" + +class camera +{ +public: + camera() + { + lower_left_corner = vec3(-2.0, -1.0, -1.0); + horizontal = vec3(4.0, 0.0, 0.0); + vertical = vec3(0.0, 2.0, 0.0); + origin = vec3(0.0, 0.0, 0.0); + } + ray get_ray(float u, float v) + { + return ray(origin, lower_left_corner + u * horizontal + v * vertical - origin); + } + + vec3 origin; + vec3 lower_left_corner; + vec3 horizontal; + vec3 vertical; +}; + +#endif diff --git a/code/rt_weekend.cpp b/code/rt_weekend.cpp index d259337..0ebb324 100644 --- a/code/rt_weekend.cpp +++ b/code/rt_weekend.cpp @@ -1,48 +1,53 @@ +#include #include "rt_weekend.h" -#include "ray.h" +#include "sphere.h" +#include "target_list.h" +#include "camera.h" -bool hit_sphere(const vec3 ¢er, float radius, const ray &r) +vec3 color(const ray &r, target *world) { - vec3 oc = r.origin() - center; - float a = dot(r.direction(), r.direction()); - float b = 2.0 * dot(oc, r.direction()); - float c = dot(oc, oc) - radius * radius; - float discriminant = b * b - 4 * a * c; - - return (discriminant > 0); -} - -vec3 color (const ray &r) -{ - if (hit_sphere(vec3(0, 0, -1), 0.5, r)) - return vec3(1, 0, 0); - 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); + hit_record rec; + if (world->hit(r, 0.0, MAXFLOAT, rec)) + { + return 0.5 * vec3(rec.normal.x() + 1, rec.normal.y() + 1, rec.normal.z() + 1); + } + 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); + } } extern "C" void PluginUpdateAndRender(plugin_offscreen_buffer *Buffer) { + int ns = 1; int Pitch = Buffer->Pitch; uint8_t *Row = (uint8_t *)Buffer->Memory; - vec3 lower_left_corner(-2.0, -1.0, -1.0); - vec3 horizontal(4.0, 0.0, 0.0); - vec3 vertical(0.0, 2.0, 0.0); - vec3 origin(0.0, 0.0, 0.0); - + target *list[2]; + list[0] = new sphere(vec3(0, 0, -1), 0.5); + list[1] = new sphere(vec3(0, -100.5, -1), 100); + target *world = new target_list(list, 2); + camera cam; for(int j = Buffer->Height - 1; j >= 0; j--) { uint32_t *Pixel = (uint32_t *)Row; for(int i = 0; i < Buffer->Width; i++) { - float u = float(i) / float(Buffer->Width); - float v = float(j) / float(Buffer->Height); - ray r(origin, lower_left_corner + u * horizontal + v * vertical); - vec3 col = color(r); + vec3 col(0, 0, 0); + for (int s = 0; s < ns; s++) + { + float u = float(i + drand48()) / float(Buffer->Width); + float v = float(j + drand48()) / float(Buffer->Height); + ray r = cam.get_ray(u, v); + vec3 p = r.point_at_parameter(2.0); + col += color(r, world); + } + col /= float(ns); int ir = int(255.99 * col[0]); int ig = int(255.99 * col[1]); int ib = int(255.99 * col[2]); diff --git a/code/sdl_platform.cpp b/code/sdl_platform.cpp index c8116cf..f54aa01 100644 --- a/code/sdl_platform.cpp +++ b/code/sdl_platform.cpp @@ -12,7 +12,7 @@ const char *WindowTitle = "Ray Tracing in a Weekend"; -const uint32_t TARGET_FRAME_RATE = 15; +const uint32_t TARGET_FRAME_RATE = 10; const uint32_t TICKS_PER_FRAME = 1000 / TARGET_FRAME_RATE; const uint32_t WINDOW_WIDTH = 500; const uint32_t WINDOW_HEIGHT = 250; diff --git a/code/sphere.h b/code/sphere.h new file mode 100644 index 0000000..bb79979 --- /dev/null +++ b/code/sphere.h @@ -0,0 +1,46 @@ +#ifndef SPHERE_H +#define SPHERE_H + +#include "target.h" + +class sphere: public target +{ +public: + sphere() {}; + sphere(vec3 cen, float r) : center(cen), radius(r) {}; + virtual bool hit(const ray &r, float t_min, float t_max, hit_record &rec) const; + vec3 center; + float radius; +}; + +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; + 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; + return true; + } + } + return false; +} + +#endif diff --git a/code/target.h b/code/target.h new file mode 100644 index 0000000..ed3f42c --- /dev/null +++ b/code/target.h @@ -0,0 +1,19 @@ +#ifndef TARGET_H +#define TARGET_H + +#include "ray.h" + +struct hit_record +{ + float t; + vec3 p; + vec3 normal; +}; + +class target +{ +public: + virtual bool hit(const ray &r, float t_min, float t_max, hit_record &rec) const = 0; +}; + +#endif diff --git a/code/target_list.h b/code/target_list.h new file mode 100644 index 0000000..5b9609a --- /dev/null +++ b/code/target_list.h @@ -0,0 +1,33 @@ +#ifndef TARGETLIST_H +#define TARGETLIST_H + +#include "target.h" + +class target_list: public target +{ +public: + target_list() {} + target_list(target **l, int n) { list = l; list_size = n; } + virtual bool hit(const ray &r, float t_min, float t_max, hit_record &rec) const; + target **list; + int list_size; +}; + +bool target_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 diff --git a/code/vec3.h b/code/vec3.h index f704a0d..72f51c7 100644 --- a/code/vec3.h +++ b/code/vec3.h @@ -32,10 +32,12 @@ public: { return sqrt(e[0] * e[0] + e[1] * e[1] + e[2] * e[2]); } + inline float squared_length() const { return e[0] * e[0] + e[1] * e[1] + e[2] * e[2]; } + inline void make_unit_vector(); float e[3]; @@ -88,7 +90,7 @@ inline vec3 operator*(float t, const vec3 &v) inline vec3 operator/(vec3 v, float t) { - return vec3(v.e[0]/t, v.e[1]/t, v.e[2]/t); + return vec3(v.e[0] / t, v.e[1] / t, v.e[2] / t); } inline vec3 operator*(const vec3 &v, float t)