feat(examples): add the scene representation, camera and intersection
Sphere and plane records, camera ray generation from field of view and aspect ratio, and the nearest-hit search across the scene.
This commit is contained in:
3 files changed
+137
No files matched your search
@@ -0,0 +1,67 @@
|
|||||||
|
#ifndef RT_SCENE_H
|
||||||
|
#define RT_SCENE_H
|
||||||
|
|
||||||
|
#include "rt.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
vec3 origin, dir;
|
||||||
|
} ray;
|
||||||
|
|
||||||
|
typedef enum { MAT_LAMBERT = 0, MAT_METAL = 1, MAT_LIGHT = 2 } mat_kind;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
mat_kind kind;
|
||||||
|
vec3 albedo;
|
||||||
|
double fuzz;
|
||||||
|
} material;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
vec3 center;
|
||||||
|
double radius;
|
||||||
|
material mat;
|
||||||
|
} sphere;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const sphere *spheres;
|
||||||
|
int count;
|
||||||
|
vec3 background;
|
||||||
|
} scene;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
vec3 origin, lower_left, horizontal, vertical;
|
||||||
|
} camera;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
double t;
|
||||||
|
vec3 point, normal;
|
||||||
|
material mat;
|
||||||
|
int front;
|
||||||
|
} hit;
|
||||||
|
|
||||||
|
camera camera_make(vec3 look_from, vec3 look_at, vec3 up, double fov_deg, double aspect);
|
||||||
|
ray camera_ray(const camera *c, double u, double v);
|
||||||
|
|
||||||
|
int scene_hit(const scene *s, ray r, double tmin, double tmax, hit *out);
|
||||||
|
vec3 ray_colour(const scene *s, ray r, int depth, rng *rng_state);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const scene *sc;
|
||||||
|
const camera *cam;
|
||||||
|
unsigned char *rgb;
|
||||||
|
int width, height, samples, max_depth;
|
||||||
|
int row_next;
|
||||||
|
int threads;
|
||||||
|
} render_job;
|
||||||
|
|
||||||
|
/* Returns the number of worker threads actually used. */
|
||||||
|
int render_run(render_job *job);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
#include "rt_scene.h"
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
camera camera_make(vec3 look_from, vec3 look_at, vec3 up, double fov_deg, double aspect) {
|
||||||
|
double theta = fov_deg * 3.14159265358979323846 / 180.0;
|
||||||
|
double half_height = tan(theta / 2.0);
|
||||||
|
double half_width = aspect * half_height;
|
||||||
|
|
||||||
|
vec3 w = v3norm(v3sub(look_from, look_at));
|
||||||
|
vec3 u = v3norm(v3cross(up, w));
|
||||||
|
vec3 v = v3cross(w, u);
|
||||||
|
|
||||||
|
camera c;
|
||||||
|
c.origin = look_from;
|
||||||
|
c.horizontal = v3scale(u, 2.0 * half_width);
|
||||||
|
c.vertical = v3scale(v, 2.0 * half_height);
|
||||||
|
c.lower_left = v3sub(v3sub(v3sub(look_from, v3scale(u, half_width)), v3scale(v, half_height)), w);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
ray camera_ray(const camera *c, double u, double v) {
|
||||||
|
vec3 target = v3add(v3add(c->lower_left, v3scale(c->horizontal, u)), v3scale(c->vertical, v));
|
||||||
|
ray r;
|
||||||
|
r.origin = c->origin;
|
||||||
|
r.dir = v3norm(v3sub(target, c->origin));
|
||||||
|
return r;
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
#include "rt_scene.h"
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
static int sphere_hit(const sphere *s, ray r, double tmin, double tmax, hit *out) {
|
||||||
|
vec3 oc = v3sub(r.origin, s->center);
|
||||||
|
double a = v3len2(r.dir);
|
||||||
|
double half_b = v3dot(oc, r.dir);
|
||||||
|
double c = v3len2(oc) - s->radius * s->radius;
|
||||||
|
double disc = half_b * half_b - a * c;
|
||||||
|
if (disc < 0.0) return 0;
|
||||||
|
|
||||||
|
double root = sqrt(disc);
|
||||||
|
double t = (-half_b - root) / a;
|
||||||
|
if (t < tmin || t > tmax) {
|
||||||
|
t = (-half_b + root) / a;
|
||||||
|
if (t < tmin || t > tmax) return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
out->t = t;
|
||||||
|
out->point = v3add(r.origin, v3scale(r.dir, t));
|
||||||
|
vec3 outward = v3scale(v3sub(out->point, s->center), 1.0 / s->radius);
|
||||||
|
out->front = v3dot(r.dir, outward) < 0.0;
|
||||||
|
out->normal = out->front ? outward : v3neg(outward);
|
||||||
|
out->mat = s->mat;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int scene_hit(const scene *s, ray r, double tmin, double tmax, hit *out) {
|
||||||
|
hit best;
|
||||||
|
int found = 0;
|
||||||
|
double closest = tmax;
|
||||||
|
|
||||||
|
for (int i = 0; i < s->count; i++) {
|
||||||
|
hit h;
|
||||||
|
if (sphere_hit(&s->spheres[i], r, tmin, closest, &h)) {
|
||||||
|
found = 1;
|
||||||
|
closest = h.t;
|
||||||
|
best = h;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (found) *out = best;
|
||||||
|
return found;
|
||||||
|
}
|
||||||
Reference in new issue
Block a user