From b75663feabffbe6c8fd55c55d27f1078a6d351fd Mon Sep 17 00:00:00 2001 From: David Date: Fri, 20 Aug 2021 23:27:59 +0200 Subject: [PATCH] First commit --- .gitignore | 10 ++++ Makefile | 8 ++++ color.hpp | 18 ++++++++ main.cpp | 73 +++++++++++++++++++++++++++++ ray.hpp | 34 ++++++++++++++ vec3.h | 73 +++++++++++++++++++++++++++++ vec3.hpp | 132 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 348 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 color.hpp create mode 100644 main.cpp create mode 100644 ray.hpp create mode 100644 vec3.h create mode 100644 vec3.hpp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7f42aa0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +# Gnu global thingies +GPATH +GRTAGS +GTAGS + +# Executable +raytracer + +# Actual output image +image.ppm diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..a88ac5c --- /dev/null +++ b/Makefile @@ -0,0 +1,8 @@ +raytracer: main.cpp vec3.hpp color.hpp ray.hpp + @g++ -g -Wall -Wextra -Wpedantic main.cpp -o raytracer + +image: raytracer + @./raytracer > image.ppm + @if [[ $$TERM = "xterm-kitty" ]]; then\ + kitty icat image.ppm;\ + fi diff --git a/color.hpp b/color.hpp new file mode 100644 index 0000000..2fdc497 --- /dev/null +++ b/color.hpp @@ -0,0 +1,18 @@ +#ifndef COLOR_H +#define COLOR_H + +#include "vec3.hpp" + +#include +#include + +/* Writes color components as a space-delimited string of numbers in the range [0,255] */ +void write_color(FILE *fp, color c) +{ + fprintf(fp, "%d %d %d\n", + (uint8_t) (255 * c.x), + (uint8_t) (255 * c.y), + (uint8_t) (255 * c.z)); +} + +#endif diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..ea83b32 --- /dev/null +++ b/main.cpp @@ -0,0 +1,73 @@ +#include +#include + +#include "vec3.hpp" +#include "color.hpp" +#include "ray.hpp" + +color ray_color(const ray& r); +double hit_sphere(const point3& center, double radius, const ray& r); + +color ray_color(const ray& r) +{ + double t = hit_sphere(point3(0,0,-1), 0.5, r); + if (t > 0.0) + { + vec3 N = normalize(r.at(t) - vec3(0,0,-1)); + return 0.5*color(N.x+1, N.y+1, N.z+1); + } + vec3 unit_direction = normalize(r.direction); + t = 0.5*(unit_direction.y + 1.0); + + return (1-t) * color(1,1,1) + t*color(0.5, 0.7, 1.0); +} + +double hit_sphere(const point3& center, double radius, const ray& r) +{ + vec3 oc = r.origin - center; + double a = dot(r.direction, r.direction); + double b = 2.0 * dot(oc, r.direction); + double c = dot(oc,oc) - radius*radius; + double discriminant = b*b - 4*a*c; + if (discriminant < 0) + return -1; + else + return (-b - sqrt(discriminant)) / (2.0*a); +} + +int main() +{ + // Image + double aspect_ratio = 16.0 / 9; + const int32_t image_width = 400; + const int32_t image_height = (int32_t) (image_width / aspect_ratio); + + // Camera + double viewport_height = 2.0; + double viewport_width = aspect_ratio * viewport_height; + double focal_length = 1.0; + + point3 origin = point3(0,0,0); + vec3 horizontal = vec3(viewport_width, 0, 0); + vec3 vertical = vec3(0, viewport_height, 0); + vec3 lower_left_corner = origin - horizontal/2 - vertical/2 - vec3(0, 0, focal_length); + + // Render + printf("P3\n%d %d\n255\n", image_width, image_height); + + for (int32_t j = image_height - 1; j >= 0; --j) + { + fprintf(stderr, "\rScanlines remaining: %d ", j); + fflush(stderr); + for (int32_t i = 0; i < image_width; ++i) + { + double u = (double)i / (image_width-1); + double v = (double)j / (image_height-1); + ray r = ray(origin, lower_left_corner + u*horizontal + v*vertical - origin); + color pixel_color = ray_color(r); + + write_color(stdout, pixel_color); + } + } + fprintf(stderr, "\nDone\n"); +} diff --git a/ray.hpp b/ray.hpp new file mode 100644 index 0000000..ac4231e --- /dev/null +++ b/ray.hpp @@ -0,0 +1,34 @@ +#ifndef RAY_H +#define RAY_H + +#include "vec3.hpp" + +struct ray { + /* Attributes */ + point3 origin; + vec3 direction; + + /* Constructors */ + + // Default constructor. Everything gets set to 0 + ray() + { + origin = vec3(); + direction = vec3(); + } + + ray(const point3& origin, const vec3& direction) + { + this->origin = origin; + this->direction = direction; + } + + // Returns position after time t + point3 at(double t) const + { + return origin + t*direction; + } + +}; + +#endif diff --git a/vec3.h b/vec3.h new file mode 100644 index 0000000..198b3ac --- /dev/null +++ b/vec3.h @@ -0,0 +1,73 @@ +#ifndef VEC3_H +#define VEC3_H + +#include +#include + +struct vec3 { + /* Members */ + double x; + double y; + double z; + + /* Constructors */ + + // Default + vec3() { x = 0; y = 0; z = 0; }; + + // Constructor proper. Values default to 0 + vec3(double x = 0, double y = 0, double z = 0) + { + this.x = x; + this.y = y; + this.z = z; + } + + /* Overriden operators */ + + // - operator. Not to be confused with substraction + vec3 operator-() + { + return vec3(-x, -y, -z); + } + + // straightforward vector sum + vec3& operator+=(const vec3 &v) + { + this.x += v.x; + this.y += v.y; + this.z += v.z; + } + + // scalar multiplication + vec3& operator*=(const double t) + { + x *= t; + y *= t; + z *= t; + return *this; + } + + // division by a scalar t + vec3& operator/=(const double t) + { + x /= t; + y /= t; + z /= t; + return *this; + } + + /* Methods */ + + double length() + { + std::sqrt(x*x + y*y + z*z); + } +}; + +/* Type aliases */ +typedef point3 vec3; +typedef color vec3; + + +#endif diff --git a/vec3.hpp b/vec3.hpp new file mode 100644 index 0000000..81b9450 --- /dev/null +++ b/vec3.hpp @@ -0,0 +1,132 @@ +#ifndef VEC3_H +#define VEC3_H + +#include +#include + +struct vec3 { + /* Members */ + double x; + double y; + double z; + + // Constructor proper. Values default to 0 + vec3(double x = 0, double y = 0, double z = 0) + { + this->x = x; + this->y = y; + this->z = z; + } + + /* Overriden operators */ + + // - operator. Not to be confused with substraction + vec3 operator-() + { + return vec3(-x, -y, -z); + } + + // Straightforward vector sum + vec3& operator+=(const vec3 &v) + { + this->x += v.x; + this->y += v.y; + this->z += v.z; + return *this; + } + + // Scalar multiplication + vec3& operator*=(const double t) + { + x *= t; + y *= t; + z *= t; + return *this; + } + + // Division by a scalar t + vec3& operator/=(const double t) + { + x /= t; + y /= t; + z /= t; + return *this; + } + + /* Methods */ + + double length() const + { + return sqrt(x*x + y*y + z*z); + } +}; + +/* Type aliases */ +typedef vec3 point3; +typedef vec3 color; + + +/* More overloads */ + +// Straightforward vector sum +inline vec3 operator+(const vec3 &u, const vec3 &v) +{ + return vec3(u.x + v.x, + u.y + v.y, + u.z + v.z); +} + +// Straightforward vector difference +inline vec3 operator-(const vec3 &u, const vec3 &v) +{ + return vec3(u.x - v.x, + u.y - v.y, + u.z - v.z); +} + +// Hadamard product +inline vec3 operator*(const vec3 &u, const vec3 &v) +{ + return vec3(u.x * v.x, + u.y * v.y, + u.z * v.z); +} + +// Scalar product +inline vec3 operator*(double t,const vec3 &v) +{ + return vec3(t*v.x, t*v.y, t*v.z); +} + +inline vec3 operator*(const vec3 &v, double t) +{ + return t * v; +} + +// Vector division by scalar. Note that we redefine it as multiplying by 1/t to avoid division by 0 +inline vec3 operator/(vec3 v, double t) +{ + return 1/t * v; +} + +// Straightforward dot product +inline double dot(const vec3 &u, const vec3 &v) +{ + return u.x*v.x + u.y*v.y + u.z*v.z; +} + +// Cross product between two vectors +inline vec3 cross(const vec3 &u, const vec3 &v) +{ + return vec3(u.y * v.z - u.z * v.y, + u.z * v.x - u.x * v.z, + u.x * v.y - u.y * v.x); +} + +// Normalize vector so its length = 1 +inline vec3 normalize(const vec3 v) +{ + return v / v.length(); +} + +#endif