#include "ff.h" #include "vec3.h" #include #include #include #include #define W 800 #define H 600 #define VP_H 2.0 #define VP_W (VP_H * W / H) #define FOCLEN 1.0 typedef struct { vec3_t orig, dir; } ray_t; typedef struct { vec3_t centre; double rad; } sphere_t; static const vec3_t lightblue = { 0.4, 0.6, 1.0 }; static const vec3_t white = { 1.0, 1.0, 1.0 }; static const vec3_t red = { 1.0, 0.1, 0.2 }; static const vec3_t camera = { 0, 0, 0 }; static const vec3_t vp_disp = { 0, 0, FOCLEN }; static const vec3_t vp_u = { VP_W, 0, 0 }; static const vec3_t vp_v = { 0, -VP_H, 0 }; static const vec3_t pix_x_step = { VP_W / W, 0, 0 }; static const vec3_t pix_y_step = { 0, -VP_H / H, 0 }; static const sphere_t obj = { .centre = { 1.0, 0.0, -3.0 }, .rad = 1.0, }; static pix_t pix[W * H]; static double intersect(sphere_t sphere, ray_t ray) { const vec3_t disp = vec3_sub(sphere.centre, ray.orig); const double a = vec3_dot(ray.dir, ray.dir); const double b = -2.0 * vec3_dot(ray.dir, disp); const double c = vec3_dot(disp, disp) - sphere.rad * sphere.rad; const double discriminant = b * b - 4 * a * c; if (discriminant < 0) return -1.0; else return (-b - sqrt(discriminant)) / (2.0 * a); } static vec3_t raycol(ray_t ray) { const double t = intersect(obj, ray); if (t > 0.0) { const vec3_t p = vec3_add(ray.orig, vec3_scale(ray.dir, t)); const vec3_t normal = vec3_unit(vec3_sub(p, obj.centre)); return vec3_scale(vec3_add(normal, white), 0.5); } const double a = (ray.dir.y + 1.0) / 2.0; return vec3_add(vec3_scale(lightblue, a), vec3_scale(white, 1 - a)); } static void setpix(vec3_t col, pix_t *out) { out->r = UINT16_MAX * col.x; out->g = UINT16_MAX * col.y; out->b = UINT16_MAX * col.z; out->a = UINT16_MAX; } int main() { img_t img = { .w = W, .h = H, .pix = pix }; const vec3_t vp_topleft = vec3_sub( vec3_sub(vec3_sub(camera, vp_disp), vec3_scale(vp_u, 0.5)), vec3_scale(vp_v, 0.5)); const vec3_t pix_orig = vec3_add( vec3_add(vp_topleft, vec3_scale(pix_x_step, 0.5)), vec3_scale(pix_y_step, 0.5)); for (unsigned y = 0; y < H; ++y) { fprintf(stderr, "\r[%3d/%3d]", y, H); fflush(stderr); const vec3_t row = vec3_add(pix_orig, vec3_scale(pix_y_step, y)); for (unsigned x = 0; x < W; ++x) { const ray_t ray = { .orig = camera, .dir = vec3_unit(vec3_add(row, vec3_scale(pix_x_step, x))), }; const vec3_t col = raycol(ray); setpix(col, pix + (W * y + x)); } } fprintf(stderr, "\r[%3d/%3d]\n", H, H); ff_write(STDOUT_FILENO, img); return 0; }