From b5bc962e834992eeba2abdd10f6e37ee2ba20295 Mon Sep 17 00:00:00 2001 From: Vito Caputo Date: Mon, 19 Mar 2018 21:39:09 -0700 Subject: ray: libize raytracer core, introduces src/libs This is the first step of breaking out all the core rendering stuffs into reusable libraries and making modules purely compositional, consumers of various included rendering/effects libraries. Expect multiple modules leveraging libray for a variety of scenes and such. Also expect compositions mixing the various libraries for more interesting visuals. --- configure.ac | 2 + src/Makefile.am | 4 +- src/libs/ray/ray_3f.h | 154 ++++++++++++++++++ src/libs/ray/ray_camera.c | 70 ++++++++ src/libs/ray/ray_camera.h | 84 ++++++++++ src/libs/ray/ray_color.h | 29 ++++ src/libs/ray/ray_euler.c | 90 +++++++++++ src/libs/ray/ray_euler.h | 33 ++++ src/libs/ray/ray_light_emitter.h | 18 +++ src/libs/ray/ray_object.h | 18 +++ src/libs/ray/ray_object_light.h | 14 ++ src/libs/ray/ray_object_plane.h | 16 ++ src/libs/ray/ray_object_point.h | 15 ++ src/libs/ray/ray_object_sphere.h | 16 ++ src/libs/ray/ray_object_type.h | 12 ++ src/libs/ray/ray_ray.h | 11 ++ src/libs/ray/ray_render.c | 251 +++++++++++++++++++++++++++++ src/libs/ray/ray_render.h | 15 ++ src/libs/ray/ray_render_object.h | 121 ++++++++++++++ src/libs/ray/ray_render_object_plane.h | 61 +++++++ src/libs/ray/ray_render_object_point.h | 45 ++++++ src/libs/ray/ray_render_object_sphere.h | 90 +++++++++++ src/libs/ray/ray_scene.h | 16 ++ src/libs/ray/ray_surface.h | 15 ++ src/modules/ray/Makefile.am | 4 +- src/modules/ray/ray_3f.h | 154 ------------------ src/modules/ray/ray_camera.c | 70 -------- src/modules/ray/ray_camera.h | 84 ---------- src/modules/ray/ray_color.h | 29 ---- src/modules/ray/ray_euler.c | 90 ----------- src/modules/ray/ray_euler.h | 33 ---- src/modules/ray/ray_light_emitter.h | 18 --- src/modules/ray/ray_object.h | 18 --- src/modules/ray/ray_object_light.h | 14 -- src/modules/ray/ray_object_plane.h | 16 -- src/modules/ray/ray_object_point.h | 15 -- src/modules/ray/ray_object_sphere.h | 16 -- src/modules/ray/ray_object_type.h | 12 -- src/modules/ray/ray_ray.h | 11 -- src/modules/ray/ray_render.c | 251 ----------------------------- src/modules/ray/ray_render.h | 15 -- src/modules/ray/ray_render_object.h | 121 -------------- src/modules/ray/ray_render_object_plane.h | 61 ------- src/modules/ray/ray_render_object_point.h | 45 ------ src/modules/ray/ray_render_object_sphere.h | 90 ----------- src/modules/ray/ray_scene.h | 16 -- src/modules/ray/ray_surface.h | 15 -- 47 files changed, 1200 insertions(+), 1198 deletions(-) create mode 100644 src/libs/ray/ray_3f.h create mode 100644 src/libs/ray/ray_camera.c create mode 100644 src/libs/ray/ray_camera.h create mode 100644 src/libs/ray/ray_color.h create mode 100644 src/libs/ray/ray_euler.c create mode 100644 src/libs/ray/ray_euler.h create mode 100644 src/libs/ray/ray_light_emitter.h create mode 100644 src/libs/ray/ray_object.h create mode 100644 src/libs/ray/ray_object_light.h create mode 100644 src/libs/ray/ray_object_plane.h create mode 100644 src/libs/ray/ray_object_point.h create mode 100644 src/libs/ray/ray_object_sphere.h create mode 100644 src/libs/ray/ray_object_type.h create mode 100644 src/libs/ray/ray_ray.h create mode 100644 src/libs/ray/ray_render.c create mode 100644 src/libs/ray/ray_render.h create mode 100644 src/libs/ray/ray_render_object.h create mode 100644 src/libs/ray/ray_render_object_plane.h create mode 100644 src/libs/ray/ray_render_object_point.h create mode 100644 src/libs/ray/ray_render_object_sphere.h create mode 100644 src/libs/ray/ray_scene.h create mode 100644 src/libs/ray/ray_surface.h delete mode 100644 src/modules/ray/ray_3f.h delete mode 100644 src/modules/ray/ray_camera.c delete mode 100644 src/modules/ray/ray_camera.h delete mode 100644 src/modules/ray/ray_color.h delete mode 100644 src/modules/ray/ray_euler.c delete mode 100644 src/modules/ray/ray_euler.h delete mode 100644 src/modules/ray/ray_light_emitter.h delete mode 100644 src/modules/ray/ray_object.h delete mode 100644 src/modules/ray/ray_object_light.h delete mode 100644 src/modules/ray/ray_object_plane.h delete mode 100644 src/modules/ray/ray_object_point.h delete mode 100644 src/modules/ray/ray_object_sphere.h delete mode 100644 src/modules/ray/ray_object_type.h delete mode 100644 src/modules/ray/ray_ray.h delete mode 100644 src/modules/ray/ray_render.c delete mode 100644 src/modules/ray/ray_render.h delete mode 100644 src/modules/ray/ray_render_object.h delete mode 100644 src/modules/ray/ray_render_object_plane.h delete mode 100644 src/modules/ray/ray_render_object_point.h delete mode 100644 src/modules/ray/ray_render_object_sphere.h delete mode 100644 src/modules/ray/ray_scene.h delete mode 100644 src/modules/ray/ray_surface.h diff --git a/configure.ac b/configure.ac index 578e420..ced42a7 100644 --- a/configure.ac +++ b/configure.ac @@ -34,6 +34,8 @@ LIBS="$LIBS $SDL_LIBS" AC_CONFIG_FILES([ Makefile src/Makefile + src/libs/Makefile + src/libs/ray/Makefile src/modules/Makefile src/modules/julia/Makefile src/modules/plasma/Makefile diff --git a/src/Makefile.am b/src/Makefile.am index b94b0f3..08546c4 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,7 +1,7 @@ -SUBDIRS = modules +SUBDIRS = libs modules bin_PROGRAMS = rototiller rototiller_SOURCES = fb.c fb.h fps.c fps.h rototiller.c rototiller.h sdl_fb.c settings.h settings.c setup.h setup.c threads.c threads.h util.c util.h if ENABLE_DRM rototiller_SOURCES += drm_fb.c endif -rototiller_LDADD = -lm modules/julia/libjulia.a modules/plasma/libplasma.a modules/ray/libray.a modules/roto/libroto.a modules/sparkler/libsparkler.a modules/stars/libstars.a +rototiller_LDADD = modules/julia/libjulia.a modules/plasma/libplasma.a modules/ray/libray.a modules/roto/libroto.a modules/sparkler/libsparkler.a modules/stars/libstars.a libs/ray/libray.a -lm diff --git a/src/libs/ray/ray_3f.h b/src/libs/ray/ray_3f.h new file mode 100644 index 0000000..2c04a5a --- /dev/null +++ b/src/libs/ray/ray_3f.h @@ -0,0 +1,154 @@ +#ifndef _RAY_3F_H +#define _RAY_3F_H + +#include + +typedef struct ray_3f_t { + float x, y, z; +} ray_3f_t; + + +/* return the result of (a + b) */ +static inline ray_3f_t ray_3f_add(const ray_3f_t *a, const ray_3f_t *b) +{ + ray_3f_t res = { + .x = a->x + b->x, + .y = a->y + b->y, + .z = a->z + b->z, + }; + + return res; +} + + +/* return the result of (a - b) */ +static inline ray_3f_t ray_3f_sub(const ray_3f_t *a, const ray_3f_t *b) +{ + ray_3f_t res = { + .x = a->x - b->x, + .y = a->y - b->y, + .z = a->z - b->z, + }; + + return res; +} + + +/* return the result of (-v) */ +static inline ray_3f_t ray_3f_negate(const ray_3f_t *v) +{ + ray_3f_t res = { + .x = -v->x, + .y = -v->y, + .z = -v->z, + }; + + return res; +} + + +/* return the result of (a * b) */ +static inline ray_3f_t ray_3f_mult(const ray_3f_t *a, const ray_3f_t *b) +{ + ray_3f_t res = { + .x = a->x * b->x, + .y = a->y * b->y, + .z = a->z * b->z, + }; + + return res; +} + + +/* return the result of (v * scalar) */ +static inline ray_3f_t ray_3f_mult_scalar(const ray_3f_t *v, float scalar) +{ + ray_3f_t res = { + .x = v->x * scalar, + .y = v->y * scalar, + .z = v->z * scalar, + }; + + return res; +} + + +/* return the result of (uv / scalar) */ +static inline ray_3f_t ray_3f_div_scalar(const ray_3f_t *v, float scalar) +{ + ray_3f_t res = { + .x = v->x / scalar, + .y = v->y / scalar, + .z = v->z / scalar, + }; + + return res; +} + + +/* return the result of (a . b) */ +static inline float ray_3f_dot(const ray_3f_t *a, const ray_3f_t *b) +{ + return a->x * b->x + a->y * b->y + a->z * b->z; +} + + +/* return the length of the supplied vector */ +static inline float ray_3f_length(const ray_3f_t *v) +{ + return sqrtf(ray_3f_dot(v, v)); +} + + +/* return the normalized form of the supplied vector */ +static inline ray_3f_t ray_3f_normalize(const ray_3f_t *v) +{ + return ray_3f_mult_scalar(v, 1.0f / ray_3f_length(v)); +} + + +/* return the distance between two arbitrary points */ +static inline float ray_3f_distance(const ray_3f_t *a, const ray_3f_t *b) +{ + ray_3f_t delta = ray_3f_sub(a, b); + + return ray_3f_length(&delta); +} + + +/* return the cross product of two unit vectors */ +static inline ray_3f_t ray_3f_cross(const ray_3f_t *a, const ray_3f_t *b) +{ + ray_3f_t product; + + product.x = a->y * b->z - a->z * b->y; + product.y = a->z * b->x - a->x * b->z; + product.z = a->x * b->y - a->y * b->x; + + return product; +} + + +/* return the linearly interpolated vector between the two vectors at point alpha (0-1.0) */ +static inline ray_3f_t ray_3f_lerp(const ray_3f_t *a, const ray_3f_t *b, float alpha) +{ + ray_3f_t lerp_a, lerp_b; + + lerp_a = ray_3f_mult_scalar(a, 1.0f - alpha); + lerp_b = ray_3f_mult_scalar(b, alpha); + + return ray_3f_add(&lerp_a, &lerp_b); +} + + +/* return the normalized linearly interpolated vector between the two vectors at point alpha (0-1.0) */ +static inline ray_3f_t ray_3f_nlerp(const ray_3f_t *a, const ray_3f_t *b, float alpha) +{ + ray_3f_t lerp; + + lerp = ray_3f_lerp(a, b, alpha); + + return ray_3f_normalize(&lerp); +} + +#endif diff --git a/src/libs/ray/ray_camera.c b/src/libs/ray/ray_camera.c new file mode 100644 index 0000000..b942cf3 --- /dev/null +++ b/src/libs/ray/ray_camera.c @@ -0,0 +1,70 @@ +#include "fb.h" + +#include "ray_camera.h" +#include "ray_euler.h" + + +/* Produce a vector from the provided orientation vectors and proportions. */ +static ray_3f_t project_corner(ray_3f_t *forward, ray_3f_t *left, ray_3f_t *up, float focal_length, float horiz, float vert) +{ + ray_3f_t tmp; + ray_3f_t corner; + + corner = ray_3f_mult_scalar(forward, focal_length); + tmp = ray_3f_mult_scalar(left, horiz); + corner = ray_3f_add(&corner, &tmp); + tmp = ray_3f_mult_scalar(up, vert); + corner = ray_3f_add(&corner, &tmp); + + return ray_3f_normalize(&corner); +} + + +/* Produce vectors for the corners of the entire camera frame, used for interpolation. */ +static void project_corners(const ray_camera_t *camera, ray_camera_frame_t *frame) +{ + ray_3f_t forward, left, up, right, down; + float half_horiz = (float)camera->width * 0.5f; + float half_vert = (float)camera->height * 0.5f; + + ray_euler_basis(&camera->orientation, &forward, &up, &left); + right = ray_3f_negate(&left); + down = ray_3f_negate(&up); + + frame->nw = project_corner(&forward, &left, &up, camera->focal_length, half_horiz, half_vert); + frame->ne = project_corner(&forward, &right, &up, camera->focal_length, half_horiz, half_vert); + frame->se = project_corner(&forward, &right, &down, camera->focal_length, half_horiz, half_vert); + frame->sw = project_corner(&forward, &left, &down, camera->focal_length, half_horiz, half_vert); +} + + +/* Prepare a frame of camera projection, initializing res_frame. */ +void ray_camera_frame_prepare(const ray_camera_t *camera, ray_camera_frame_t *res_frame) +{ + res_frame->camera = camera; + + project_corners(camera, res_frame); + + res_frame->x_delta = 1.0f / (float)camera->width; + res_frame->y_delta = 1.0f / (float)camera->height; +} + + +/* Begin a frame's fragment, initializing frame and ray. */ +void ray_camera_fragment_begin(ray_camera_frame_t *frame, fb_fragment_t *fb_fragment, ray_ray_t *res_ray, ray_camera_fragment_t *res_fragment) +{ + res_fragment->frame = frame; + res_fragment->fb_fragment = fb_fragment; + res_fragment->ray = res_ray; + + res_fragment->x = res_fragment->y = 0; + + res_fragment->x_alpha = frame->x_delta * (float)fb_fragment->x; + res_fragment->y_alpha = frame->y_delta * (float)fb_fragment->y; + + res_fragment->cur_w = ray_3f_lerp(&frame->nw, &frame->sw, res_fragment->y_alpha); + res_fragment->cur_e = ray_3f_lerp(&frame->ne, &frame->se, res_fragment->y_alpha); + + res_ray->origin = frame->camera->position; + res_ray->direction = ray_3f_nlerp(&res_fragment->cur_w, &res_fragment->cur_e, res_fragment->x_alpha); +} diff --git a/src/libs/ray/ray_camera.h b/src/libs/ray/ray_camera.h new file mode 100644 index 0000000..e393beb --- /dev/null +++ b/src/libs/ray/ray_camera.h @@ -0,0 +1,84 @@ +#ifndef _RAY_CAMERA_H +#define _RAY_CAMERA_H + +#include + +#include "fb.h" + +#include "ray_3f.h" +#include "ray_euler.h" +#include "ray_ray.h" + + +typedef struct ray_camera_t { + ray_3f_t position; /* position of camera, the origin of all its rays */ + ray_euler_t orientation; /* orientation of the camera */ + float focal_length; /* controls the field of view */ + unsigned width; /* width of camera viewport in pixels */ + unsigned height; /* height of camera viewport in pixels */ +} ray_camera_t; + + +typedef struct ray_camera_frame_t { + const ray_camera_t *camera; /* the camera supplied to frame_begin() */ + + ray_3f_t nw, ne, sw, se; /* directions pointing through the corners of the frame fragment */ + float x_delta, y_delta; /* interpolation step delta along the x and y axis */ +} ray_camera_frame_t; + + +typedef struct ray_camera_fragment_t { + ray_camera_frame_t *frame; /* the frame supplied to fragment_begin() */ + fb_fragment_t *fb_fragment; /* the fragment supplied to fragment_begin() */ + ray_ray_t *ray; /* the ray supplied to frame_begin(), which gets updated as we step through the frame. */ + + ray_3f_t cur_w, cur_e; /* current row's west and east ends */ + float x_alpha, y_alpha; /* interpolation position along the x and y axis */ + unsigned x, y; /* integral position within frame fragment */ +} ray_camera_fragment_t; + + +void ray_camera_frame_prepare(const ray_camera_t *camera, ray_camera_frame_t *res_frame); +void ray_camera_fragment_begin(ray_camera_frame_t *frame, fb_fragment_t *fb_fragment, ray_ray_t *res_ray, ray_camera_fragment_t *res_fragment); + + +/* Step the ray through the fragment on the x axis, returns 1 when rays remain on this axis, 0 at the end. */ +/* When 1 is returned, fragment->ray is left pointing through the new coordinate. */ +static inline int ray_camera_fragment_x_step(ray_camera_fragment_t *fragment) +{ + fragment->x++; + + if (fragment->x >= fragment->fb_fragment->width) { + fragment->x = 0; + fragment->x_alpha = fragment->frame->x_delta * (float)fragment->fb_fragment->x; + return 0; + } + + fragment->x_alpha += fragment->frame->x_delta; + fragment->ray->direction = ray_3f_nlerp(&fragment->cur_w, &fragment->cur_e, fragment->x_alpha); + + return 1; +} + + +/* Step the ray through the fragment on the y axis, returns 1 when rays remain on this axis, 0 at the end. */ +/* When 1 is returned, fragment->ray is left pointing through the new coordinate. */ +static inline int ray_camera_fragment_y_step(ray_camera_fragment_t *fragment) +{ + fragment->y++; + + if (fragment->y >= fragment->fb_fragment->height) { + fragment->y = 0; + fragment->y_alpha = fragment->frame->y_delta * (float)fragment->fb_fragment->y; + return 0; + } + + fragment->y_alpha += fragment->frame->y_delta; + fragment->cur_w = ray_3f_lerp(&fragment->frame->nw, &fragment->frame->sw, fragment->y_alpha); + fragment->cur_e = ray_3f_lerp(&fragment->frame->ne, &fragment->frame->se, fragment->y_alpha); + fragment->ray->direction = ray_3f_nlerp(&fragment->cur_w, &fragment->cur_e, fragment->x_alpha); + + return 1; +} + +#endif diff --git a/src/libs/ray/ray_color.h b/src/libs/ray/ray_color.h new file mode 100644 index 0000000..9fe62c1 --- /dev/null +++ b/src/libs/ray/ray_color.h @@ -0,0 +1,29 @@ +#ifndef _RAY_COLOR_H +#define _RAY_COLOR_H + +#include + +#include "ray_3f.h" + +typedef ray_3f_t ray_color_t; + +/* convert a vector into a packed, 32-bit rgb pixel value */ +static inline uint32_t ray_color_to_uint32_rgb(ray_color_t color) { + uint32_t pixel; + + /* doing this all per-pixel, ugh. */ + + if (color.x > 1.0f) color.x = 1.0f; + if (color.y > 1.0f) color.y = 1.0f; + if (color.z > 1.0f) color.z = 1.0f; + + pixel = (uint32_t)(color.x * 255.0f); + pixel <<= 8; + pixel |= (uint32_t)(color.y * 255.0f); + pixel <<= 8; + pixel |= (uint32_t)(color.z * 255.0f); + + return pixel; +} + +#endif diff --git a/src/libs/ray/ray_euler.c b/src/libs/ray/ray_euler.c new file mode 100644 index 0000000..f143e25 --- /dev/null +++ b/src/libs/ray/ray_euler.c @@ -0,0 +1,90 @@ +#include +#include + +#include "ray_3f.h" +#include "ray_euler.h" + +/* produce orthonormal basis vectors from euler angles, rotated in the specified order */ +void ray_euler_basis(const ray_euler_t *e, ray_3f_t *forward, ray_3f_t *up, ray_3f_t *left) +{ + float cos_yaw = cosf(e->yaw); + float sin_yaw = sinf(e->yaw); + float cos_roll = cosf(e->roll); + float sin_roll = sinf(e->roll); + float cos_pitch = cosf(e->pitch); + float sin_pitch = sinf(e->pitch); + + /* Rotation matrices from http://www.songho.ca/opengl/gl_anglestoaxes.html */ + switch (e->order) { + case RAY_EULER_ORDER_PYR: + /* pitch, yaw, roll */ + up->x = -cos_yaw * sin_roll; + up->y = -sin_pitch * sin_yaw * sin_roll + cos_pitch * cos_roll; + up->z = cos_pitch * sin_yaw * sin_roll + sin_pitch * cos_roll; + + forward->x = sin_yaw; + forward->y = -sin_pitch * cos_yaw; + forward->z = cos_pitch * cos_yaw; + break; + + case RAY_EULER_ORDER_YRP: + /* yaw, roll, pitch */ + up->x = -cos_yaw * sin_roll * cos_pitch + sin_yaw * sin_pitch; + up->y = cos_roll * cos_pitch; + up->z = sin_yaw * sin_roll * cos_pitch + cos_yaw * sin_pitch; + + forward->x = cos_yaw * sin_roll * sin_pitch + sin_yaw * cos_pitch; + forward->y = -cos_roll * sin_pitch; + forward->z = -sin_yaw * sin_roll * sin_pitch + cos_yaw * cos_pitch; + break; + + case RAY_EULER_ORDER_RPY: + /* roll, pitch, yaw */ + up->x = -sin_roll * cos_pitch; + up->y = cos_roll * cos_pitch; + up->z = sin_pitch; + + forward->x = cos_roll * sin_yaw + sin_roll * sin_pitch * cos_yaw; + forward->y = sin_roll * sin_yaw - cos_roll * sin_pitch * cos_yaw; + forward->z = cos_pitch * cos_yaw; + break; + + case RAY_EULER_ORDER_PRY: + /* pitch, roll, yaw */ + up->x = -sin_roll; + up->y = cos_pitch * cos_roll; + up->z = sin_pitch * cos_roll; + + forward->x = cos_roll * sin_yaw; + forward->y = cos_pitch * sin_roll * sin_yaw - sin_pitch * cos_yaw; + forward->z = sin_pitch * sin_roll * sin_yaw + cos_pitch * cos_yaw; + break; + + case RAY_EULER_ORDER_RYP: + /* roll, yaw, pitch */ + up->x = -sin_roll * cos_pitch + cos_roll * sin_yaw * sin_pitch; + up->y = cos_roll * cos_pitch + sin_roll * sin_yaw * sin_pitch; + up->z = cos_yaw * sin_pitch; + + forward->x = sin_roll * sin_pitch + cos_roll * sin_yaw * cos_pitch; + forward->y = -cos_roll * sin_pitch + sin_roll * sin_yaw * cos_pitch; + forward->z = cos_yaw * cos_pitch; + break; + + case RAY_EULER_ORDER_YPR: + /* yaw, pitch, roll */ + up->x = -cos_yaw * sin_roll + sin_yaw * sin_pitch * cos_roll; + up->y = cos_pitch * cos_roll; + up->z = sin_yaw * sin_roll + cos_yaw * sin_pitch * cos_roll; + + forward->x = sin_yaw * cos_pitch; + forward->y = -sin_pitch; + forward->z = cos_yaw * cos_pitch; + break; + + default: + assert(0); + } + + *left = ray_3f_cross(up, forward); +} diff --git a/src/libs/ray/ray_euler.h b/src/libs/ray/ray_euler.h new file mode 100644 index 0000000..39da17e --- /dev/null +++ b/src/libs/ray/ray_euler.h @@ -0,0 +1,33 @@ +#ifndef _RAY_EULER_H +#define _RAY_EULER_H + +#include + +#include "ray_3f.h" + +/* Desired order to apply euler angle rotations */ +typedef enum ray_euler_order_t { + RAY_EULER_ORDER_PYR, + RAY_EULER_ORDER_YRP, + RAY_EULER_ORDER_RPY, + RAY_EULER_ORDER_PRY, + RAY_EULER_ORDER_RYP, + RAY_EULER_ORDER_YPR, +} ray_euler_order_t; + +/* euler angles are convenient for describing orientation */ +typedef struct ray_euler_t { + ray_euler_order_t order; /* order to apply rotations in */ + float pitch; /* pitch in radiasn */ + float yaw; /* yaw in radians */ + float roll; /* roll in radians */ +} ray_euler_t; + + +/* convenience macro for converting degrees to radians */ +#define RAY_EULER_DEGREES(_deg) \ + (_deg * (2 * M_PI / 360.0f)) + +void ray_euler_basis(const ray_euler_t *e, ray_3f_t *forward, ray_3f_t *up, ray_3f_t *left); + +#endif diff --git a/src/libs/ray/ray_light_emitter.h b/src/libs/ray/ray_light_emitter.h new file mode 100644 index 0000000..3b5509e --- /dev/null +++ b/src/libs/ray/ray_light_emitter.h @@ -0,0 +1,18 @@ +#ifndef _RAY_LIGHT_EMITTER_H +#define _RAY_LIGHT_EMITTER_H + +#include "ray_object_point.h" +#include "ray_object_sphere.h" + +typedef enum ray_light_emitter_type_t { + RAY_LIGHT_EMITTER_TYPE_SPHERE, + RAY_LIGHT_EMITTER_TYPE_POINT, +} ray_light_emitter_type_t; + +typedef union ray_light_emitter_t { + ray_light_emitter_type_t type; + ray_object_sphere_t sphere; + ray_object_point_t point; +} ray_light_emitter_t; + +#endif diff --git a/src/libs/ray/ray_object.h b/src/libs/ray/ray_object.h new file mode 100644 index 0000000..fc5ae1b --- /dev/null +++ b/src/libs/ray/ray_object.h @@ -0,0 +1,18 @@ +#ifndef _RAY_OBJECT_H +#define _RAY_OBJECT_H + +#include "ray_object_light.h" +#include "ray_object_plane.h" +#include "ray_object_point.h" +#include "ray_object_sphere.h" +#include "ray_object_type.h" + +typedef union ray_object_t { + ray_object_type_t type; + ray_object_sphere_t sphere; + ray_object_point_t point; + ray_object_plane_t plane; + ray_object_light_t light; +} ray_object_t; + +#endif diff --git a/src/libs/ray/ray_object_light.h b/src/libs/ray/ray_object_light.h new file mode 100644 index 0000000..ca9bac9 --- /dev/null +++ b/src/libs/ray/ray_object_light.h @@ -0,0 +1,14 @@ +#ifndef _RAY_OBJECT_LIGHT_H +#define _RAY_OBJECT_LIGHT_H + +#include "ray_light_emitter.h" +#include "ray_object_type.h" + + +typedef struct ray_object_light_t { + ray_object_type_t type; + float brightness; + ray_light_emitter_t emitter; +} ray_object_light_t; + +#endif diff --git a/src/libs/ray/ray_object_plane.h b/src/libs/ray/ray_object_plane.h new file mode 100644 index 0000000..96ed437 --- /dev/null +++ b/src/libs/ray/ray_object_plane.h @@ -0,0 +1,16 @@ +#ifndef _RAY_OBJECT_PLANE_H +#define _RAY_OBJECT_PLANE_H + +#include "ray_3f.h" +#include "ray_object_type.h" +#include "ray_surface.h" + + +typedef struct ray_object_plane_t { + ray_object_type_t type; + ray_surface_t surface; + ray_3f_t normal; + float distance; +} ray_object_plane_t; + +#endif diff --git a/src/libs/ray/ray_object_point.h b/src/libs/ray/ray_object_point.h new file mode 100644 index 0000000..5685fdc --- /dev/null +++ b/src/libs/ray/ray_object_point.h @@ -0,0 +1,15 @@ +#ifndef _RAY_OBJECT_POINT_H +#define _RAY_OBJECT_POINT_H + +#include "ray_3f.h" +#include "ray_object_type.h" +#include "ray_surface.h" + + +typedef struct ray_object_point_t { + ray_object_type_t type; + ray_surface_t surface; + ray_3f_t center; +} ray_object_point_t; + +#endif diff --git a/src/libs/ray/ray_object_sphere.h b/src/libs/ray/ray_object_sphere.h new file mode 100644 index 0000000..71b6334 --- /dev/null +++ b/src/libs/ray/ray_object_sphere.h @@ -0,0 +1,16 @@ +#ifndef _RAY_OBJECT_SPHERE_H +#define _RAY_OBJECT_SPHERE_H + +#include "ray_3f.h" +#include "ray_object_type.h" +#include "ray_surface.h" + + +typedef struct ray_object_sphere_t { + ray_object_type_t type; + ray_surface_t surface; + ray_3f_t center; + float radius; +} ray_object_sphere_t; + +#endif diff --git a/src/libs/ray/ray_object_type.h b/src/libs/ray/ray_object_type.h new file mode 100644 index 0000000..ab797d2 --- /dev/null +++ b/src/libs/ray/ray_object_type.h @@ -0,0 +1,12 @@ +#ifndef _RAY_OBJECT_TYPE_H +#define _RAY_OBJECT_TYPE_H + +typedef enum ray_object_type_t { + RAY_OBJECT_TYPE_SENTINEL, + RAY_OBJECT_TYPE_SPHERE, + RAY_OBJECT_TYPE_POINT, + RAY_OBJECT_TYPE_PLANE, + RAY_OBJECT_TYPE_LIGHT, +} ray_object_type_t; + +#endif diff --git a/src/libs/ray/ray_ray.h b/src/libs/ray/ray_ray.h new file mode 100644 index 0000000..91469a2 --- /dev/null +++ b/src/libs/ray/ray_ray.h @@ -0,0 +1,11 @@ +#ifndef _RAY_RAY_H +#define _RAY_RAY_H + +#include "ray_3f.h" + +typedef struct ray_ray_t { + ray_3f_t origin; + ray_3f_t direction; +} ray_ray_t; + +#endif diff --git a/src/libs/ray/ray_render.c b/src/libs/ray/ray_render.c new file mode 100644 index 0000000..8b930f6 --- /dev/null +++ b/src/libs/ray/ray_render.c @@ -0,0 +1,251 @@ +#include +#include + +#include "fb.h" + +#include "ray_camera.h" +#include "ray_color.h" +#include "ray_render_object.h" +#include "ray_ray.h" +#include "ray_scene.h" + +#define MAX_RECURSION_DEPTH 4 +#define MIN_RELEVANCE 0.05f + +typedef struct ray_render_t { + const ray_scene_t *scene; /* scene being rendered */ + const ray_camera_t *camera; /* camera rendering the scene */ + + ray_color_t ambient_light; + ray_camera_frame_t frame; + + ray_render_object_t objects[]; +} ray_render_t; + +/* Determine if the ray is obstructed by an object within the supplied distance, for shadows */ +static inline int ray_is_obstructed(ray_render_t *render, unsigned depth, ray_ray_t *ray, float distance) +{ + ray_render_object_t *object; + + for (object = render->objects; object->type; object++) { + float ood; + + if (ray_render_object_intersects_ray(object, depth, ray, &ood) && + ood < distance) { + return 1; + } + } + + return 0; +} + + +/* shadow test */ +static inline int point_is_shadowed(ray_render_t *render, unsigned depth, ray_3f_t *light_direction, float distance, ray_3f_t *point) +{ + ray_ray_t shadow_ray; + + shadow_ray.direction = *light_direction; + shadow_ray.origin = *point; + + if (ray_is_obstructed(render, depth + 1, &shadow_ray, distance)) + return 1; + + return 0; +} + + +/* a faster powf() that's good enough for our purposes. + * XXX: note there's a faster technique which exploits the IEEE floating point format: + * https://github.com/ekmett/approximate/blob/master/cbits/fast.c#L185 + */ +static inline float approx_powf(float x, float y) +{ + return expf(y * logf(x)); +} + + +/* Determine the color @ distance on ray on object viewed from origin */ +static inline ray_color_t shade_intersection(ray_render_t *render, ray_render_object_t *object, ray_ray_t *ray, ray_3f_t *intersection, ray_3f_t *normal, unsigned depth, float *res_reflectivity) +{ + ray_surface_t surface = ray_render_object_surface(object, intersection); + ray_color_t color = ray_3f_mult(&surface.color, &render->ambient_light); + ray_object_t *light; + + /* visit lights for shadows and illumination */ + for (light = render->scene->lights; light->type; light++) { + ray_3f_t lvec = ray_3f_sub(&light->light.emitter.point.center, intersection); + float ldist = ray_3f_length(&lvec); + float lvec_normal_dot; + + lvec = ray_3f_mult_scalar(&lvec, (1.0f / ldist)); /* normalize lvec */ +#if 1 + if (point_is_shadowed(render, depth, &lvec, ldist, intersection)) + continue; +#endif + lvec_normal_dot = ray_3f_dot(normal, &lvec); + + if (lvec_normal_dot > 0) { +#if 1 + float rvec_lvec_dot = ray_3f_dot(&ray->direction, &lvec); + float intensity = light->light.brightness * (1.0 / (ldist * ldist)); + ray_color_t diffuse; + + diffuse = ray_3f_mult_scalar(&surface.color, lvec_normal_dot); + diffuse = ray_3f_mult_scalar(&diffuse, surface.diffuse); + color = ray_3f_add(&color, &diffuse); + + if (rvec_lvec_dot > 0) { + ray_color_t specular; + + /* FIXME: assumes light is a point for its color */ + specular = ray_3f_mult_scalar(&light->light.emitter.point.surface.color, approx_powf(rvec_lvec_dot, surface.highlight_exponent)); + specular = ray_3f_mult_scalar(&specular, surface.specular); + color = ray_3f_add(&color, &specular); + } + + color = ray_3f_mult_scalar(&color, intensity); +#else + ray_color_t diffuse; + + diffuse = ray_3f_mult_scalar(&surface.color, lvec_normal_dot); + color = ray_3f_add(&color, &diffuse); +#endif + } + } + + /* for now just treat specular as the reflectivity */ + *res_reflectivity = surface.specular; + + return color; +} + + +static inline ray_render_object_t * find_nearest_intersection(ray_render_t *render, ray_render_object_t *reflector, ray_ray_t *ray, unsigned depth, float *res_distance) +{ + ray_render_object_t *nearest_object = NULL; + float nearest_object_distance = INFINITY; + ray_render_object_t *object; + + for (object = render->objects; object->type; object++) { + float distance; + + /* Don't bother checking if a reflected ray intersects the object reflecting it, + * reflector = NULL for primary rays, which will never compare as true here. */ + if (object == reflector) + continue; + + /* Does this ray intersect object? */ + if (ray_render_object_intersects_ray(object, depth, ray, &distance)) { + /* Is it the nearest intersection? */ + if (distance < nearest_object_distance) { + nearest_object = object; + nearest_object_distance = distance; + } + } + } + + if (nearest_object) + *res_distance = nearest_object_distance; + + return nearest_object; +} + + +static inline ray_color_t trace_ray(ray_render_t *render, ray_ray_t *primary_ray) +{ + ray_color_t color = { .x = 0.0f, .y = 0.0f, .z = 0.0f }; + ray_3f_t intersection, normal; + ray_render_object_t *reflector = NULL; + float relevance = 1.0f, reflectivity; + unsigned depth = 0; + ray_ray_t reflected_ray, *ray = primary_ray; + + do { + ray_render_object_t *nearest_object; + float nearest_distance; + + if (reflector) { + float dot = ray_3f_dot(&ray->direction, &normal); + ray_3f_t new_direction = ray_3f_mult_scalar(&normal, dot * 2.0f); + + new_direction = ray_3f_sub(&ray->direction, &new_direction); + + reflected_ray.origin = intersection; + reflected_ray.direction = new_direction; + + ray = &reflected_ray; + } + + nearest_object = find_nearest_intersection(render, reflector, ray, depth, &nearest_distance); + if (nearest_object) { + ray_3f_t more_color; + ray_3f_t rvec; + + rvec = ray_3f_mult_scalar(&ray->direction, nearest_distance); + intersection = ray_3f_add(&ray->origin, &rvec); + normal = ray_render_object_normal(nearest_object, &intersection); + + more_color = shade_intersection(render, nearest_object, ray, &intersection, &normal, depth, &reflectivity); + more_color = ray_3f_mult_scalar(&more_color, relevance); + color = ray_3f_add(&color, &more_color); + } + + reflector = nearest_object; + } while (reflector && (++depth < MAX_RECURSION_DEPTH) && (relevance *= reflectivity) >= MIN_RELEVANCE); + + return color; +} + + +void ray_render_trace_fragment(ray_render_t *render, fb_fragment_t *fb_fragment) +{ + uint32_t *buf = fb_fragment->buf; + ray_camera_fragment_t fragment; + ray_ray_t ray; + + ray_camera_fragment_begin(&render->frame, fb_fragment, &ray, &fragment); + do { + do { + *buf = ray_color_to_uint32_rgb(trace_ray(render, &ray)); + buf++; + } while (ray_camera_fragment_x_step(&fragment)); + + buf = ((void *)buf) + fb_fragment->stride; + } while (ray_camera_fragment_y_step(&fragment)); +} + + +/* prepare the scene for rendering with camera, must be called whenever anything in the scene+camera pair has been changed. */ +/* this is basically a time for the raytracer to precompute whatever it can which otherwise ends up occurring per-ray */ +/* the camera is included so primary rays which all have a common origin may be optimized for */ +ray_render_t * ray_render_new(const ray_scene_t *scene, const ray_camera_t *camera) +{ + ray_render_t *render; + ray_object_t *object; + unsigned i; + + for (i = 0, object = scene->objects; object->type; object++) + i++; + + render = malloc(sizeof(ray_render_t) + i * sizeof(ray_render_object_t)); + if (!render) + return NULL; + + render->scene = scene; + render->camera = camera; + + render->ambient_light = ray_3f_mult_scalar(&scene->ambient_color, scene->ambient_brightness); + ray_camera_frame_prepare(camera, &render->frame); + + for (i = 0, object = scene->objects; object->type; object++) + render->objects[i++] = ray_render_object_prepare(object, camera); + + return render; +} + + +void ray_render_free(ray_render_t *render) +{ + free(render); +} diff --git a/src/libs/ray/ray_render.h b/src/libs/ray/ray_render.h new file mode 100644 index 0000000..dfd769f --- /dev/null +++ b/src/libs/ray/ray_render.h @@ -0,0 +1,15 @@ +#ifndef _RAY_RENDER_H +#define _RAY_RENDER_H + +#include "fb.h" + +#include "ray_camera.h" +#include "ray_scene.h" + +typedef struct ray_render_t ray_render_t; + +ray_render_t * ray_render_new(const ray_scene_t *scene, const ray_camera_t *camera); +void ray_render_free(ray_render_t *render); +void ray_render_trace_fragment(ray_render_t *render, fb_fragment_t *fb_fragment); + +#endif diff --git a/src/libs/ray/ray_render_object.h b/src/libs/ray/ray_render_object.h new file mode 100644 index 0000000..1136eee --- /dev/null +++ b/src/libs/ray/ray_render_object.h @@ -0,0 +1,121 @@ +#ifndef _RAY_RENDER_OBJECT_H +#define _RAY_RENDER_OBJECT_H + +#include + +#include "ray_camera.h" +#include "ray_object.h" +#include "ray_object_type.h" +#include "ray_render_object_plane.h" +#include "ray_render_object_point.h" +#include "ray_render_object_sphere.h" +#include "ray_ray.h" +#include "ray_surface.h" + +typedef union ray_render_object_t { + ray_object_type_t type; + ray_render_object_sphere_t sphere; + ray_render_object_point_t point; + ray_render_object_plane_t plane; +} ray_render_object_t; + + + +/* Prepare an object for rendering. + * If the object has any pre-calculating to do, this is where it happens. + * The pre-calculated stuff is object-resident under a _prepared struct member. + */ +static inline ray_render_object_t ray_render_object_prepare(const ray_object_t *object, const ray_camera_t *camera) +{ + ray_render_object_t prepared = { .type = object->type }; + + switch (object->type) { + case RAY_OBJECT_TYPE_SPHERE: + prepared.sphere = ray_render_object_sphere_prepare(&object->sphere, camera); + break; + + case RAY_OBJECT_TYPE_POINT: + prepared.point = ray_render_object_point_prepare(&object->point, camera); + break; + + case RAY_OBJECT_TYPE_PLANE: + prepared.plane = ray_render_object_plane_prepare(&object->plane, camera); + break; + + case RAY_OBJECT_TYPE_LIGHT: + /* TODO */ + break; + + default: + assert(0); + } + + return prepared; +} + + +/* Determine if a ray intersects object. + * If the object is intersected, store where along the ray the intersection occurs in res_distance. + */ +static inline int ray_render_object_intersects_ray(ray_render_object_t *object, unsigned depth, ray_ray_t *ray, float *res_distance) +{ + switch (object->type) { + case RAY_OBJECT_TYPE_SPHERE: + return ray_render_object_sphere_intersects_ray(&object->sphere, depth, ray, res_distance); + + case RAY_OBJECT_TYPE_POINT: + return ray_render_object_point_intersects_ray(&object->point, depth, ray, res_distance); + + case RAY_OBJECT_TYPE_PLANE: + return ray_render_object_plane_intersects_ray(&object->plane, depth, ray, res_distance); + + case RAY_OBJECT_TYPE_LIGHT: + /* TODO */ + default: + assert(0); + } +} + + +/* Return the surface normal of object @ point */ +static inline ray_3f_t ray_render_object_normal(ray_render_object_t *object, ray_3f_t *point) +{ + switch (object->type) { + case RAY_OBJECT_TYPE_SPHERE: + return ray_render_object_sphere_normal(&object->sphere, point); + + case RAY_OBJECT_TYPE_POINT: + return ray_render_object_point_normal(&object->point, point); + + case RAY_OBJECT_TYPE_PLANE: + return ray_render_object_plane_normal(&object->plane, point); + + case RAY_OBJECT_TYPE_LIGHT: + /* TODO */ + default: + assert(0); + } +} + + +/* Return the surface of object @ point */ +static inline ray_surface_t ray_render_object_surface(ray_render_object_t *object, ray_3f_t *point) +{ + switch (object->type) { + case RAY_OBJECT_TYPE_SPHERE: + return ray_render_object_sphere_surface(&object->sphere, point); + + case RAY_OBJECT_TYPE_POINT: + return ray_render_object_point_surface(&object->point, point); + + case RAY_OBJECT_TYPE_PLANE: + return ray_render_object_plane_surface(&object->plane, point); + + case RAY_OBJECT_TYPE_LIGHT: + /* TODO */ + default: + assert(0); + } +} + +#endif diff --git a/src/libs/ray/ray_render_object_plane.h b/src/libs/ray/ray_render_object_plane.h new file mode 100644 index 0000000..6e00089 --- /dev/null +++ b/src/libs/ray/ray_render_object_plane.h @@ -0,0 +1,61 @@ +#ifndef _RAY_RENDER_OBJECT_PLANE_H +#define _RAY_RENDER_OBJECT_PLANE_H + +#include "ray_3f.h" +#include "ray_camera.h" +#include "ray_object_plane.h" +#include "ray_object_type.h" +#include "ray_ray.h" +#include "ray_surface.h" + + +typedef struct ray_render_object_plane_t { + ray_object_plane_t object; + float primary_dot_plus; +} ray_render_object_plane_t; + + +static ray_render_object_plane_t ray_render_object_plane_prepare(const ray_object_plane_t *plane, const ray_camera_t *camera) +{ + ray_render_object_plane_t prepared = { .object = *plane }; + + prepared.primary_dot_plus = ray_3f_dot(&plane->normal, &camera->position) + plane->distance; + + return prepared; +} + + +static inline int ray_render_object_plane_intersects_ray(ray_render_object_plane_t *plane, unsigned depth, ray_ray_t *ray, float *res_distance) +{ + float d = ray_3f_dot(&plane->object.normal, &ray->direction); + + if (d < 0.0f) { + float distance = plane->primary_dot_plus; + + if (depth) + distance = (ray_3f_dot(&plane->object.normal, &ray->origin) + plane->object.distance); + + distance /= -d; + if (distance > 0.0f) { + *res_distance = distance; + + return 1; + } + } + + return 0; +} + + +static inline ray_3f_t ray_render_object_plane_normal(ray_render_object_plane_t *plane, ray_3f_t *point) +{ + return plane->object.normal; +} + + +static inline ray_surface_t ray_render_object_plane_surface(ray_render_object_plane_t *plane, ray_3f_t *point) +{ + return plane->object.surface; +} + +#endif diff --git a/src/libs/ray/ray_render_object_point.h b/src/libs/ray/ray_render_object_point.h new file mode 100644 index 0000000..52c6fd6 --- /dev/null +++ b/src/libs/ray/ray_render_object_point.h @@ -0,0 +1,45 @@ +#ifndef _RAY_RENDER_OBJECT_POINT_H +#define _RAY_RENDER_OBJECT_POINT_H + +#include "ray_3f.h" +#include "ray_camera.h" +#include "ray_object_point.h" +#include "ray_object_type.h" +#include "ray_ray.h" +#include "ray_surface.h" + + +typedef struct ray_render_object_point_t { + ray_object_point_t object; +} ray_render_object_point_t; + + +static ray_render_object_point_t ray_render_object_point_prepare(const ray_object_point_t *point, const ray_camera_t *camera) +{ + ray_render_object_point_t prepared = { .object = *point }; + + return prepared; +} + + +static inline int ray_render_object_point_intersects_ray(ray_render_object_point_t *point, unsigned depth, ray_ray_t *ray, float *res_distance) +{ + /* TODO: determine a ray:point intersection */ + return 0; +} + + +static inline ray_3f_t ray_render_object_point_normal(ray_render_object_point_t *point, ray_3f_t *_point) +{ + ray_3f_t normal; + + return normal; +} + + +static inline ray_surface_t ray_render_object_point_surface(ray_render_object_point_t *point, ray_3f_t *_point) +{ + return point->object.surface; +} + +#endif diff --git a/src/libs/ray/ray_render_object_sphere.h b/src/libs/ray/ray_render_object_sphere.h new file mode 100644 index 0000000..addf1f5 --- /dev/null +++ b/src/libs/ray/ray_render_object_sphere.h @@ -0,0 +1,90 @@ +#ifndef _RAY_RENDER_OBJECT_SPHERE_H +#define _RAY_RENDER_OBJECT_SPHERE_H + +#include + +#include "ray_3f.h" +#include "ray_camera.h" +#include "ray_color.h" +#include "ray_object_sphere.h" +#include "ray_object_type.h" +#include "ray_ray.h" +#include "ray_surface.h" + + +typedef struct ray_render_object_sphere_t { + ray_object_sphere_t object; + ray_3f_t primary_v; + float primary_dot_vv; + float r2; + float r_inv; +} ray_render_object_sphere_t; + + +static ray_render_object_sphere_t ray_render_object_sphere_prepare(const ray_object_sphere_t *sphere, const ray_camera_t *camera) +{ + ray_render_object_sphere_t prepared = { .object = *sphere }; + + prepared.primary_v = ray_3f_sub(&sphere->center, &camera->position); + prepared.primary_dot_vv = ray_3f_dot(&prepared.primary_v, &prepared.primary_v); + + prepared.r2 = sphere->radius * sphere->radius; + + /* to divide by radius via multiplication in ray_object_sphere_normal() */ + prepared.r_inv = 1.0f / sphere->radius; + + return prepared; +} + + +static inline int ray_render_object_sphere_intersects_ray(ray_render_object_sphere_t *sphere, unsigned depth, ray_ray_t *ray, float *res_distance) +{ + ray_3f_t v = sphere->primary_v; + float dot_vv = sphere->primary_dot_vv; + float b, disc; + + if (depth) { + v = ray_3f_sub(&sphere->object.center, &ray->origin); + dot_vv = ray_3f_dot(&v, &v); + } + + b = ray_3f_dot(&v, &ray->direction); + disc = sphere->r2 - (dot_vv - (b * b)); + if (disc > 0) { + float i1, i2; + + disc = sqrtf(disc); + + i1 = b - disc; + i2 = b + disc; + + if (i2 > 0 && i1 > 0) { + *res_distance = i1; + return 1; + } + } + + return 0; +} + + +/* return the normal of the surface at the specified point */ +static inline ray_3f_t ray_render_object_sphere_normal(ray_render_object_sphere_t *sphere, ray_3f_t *point) +{ + ray_3f_t normal; + + normal = ray_3f_sub(point, &sphere->object.center); + normal = ray_3f_mult_scalar(&normal, sphere->r_inv); /* normalize without the sqrt() */ + + return normal; +} + + +/* return the surface of the sphere @ point */ +static inline ray_surface_t ray_render_object_sphere_surface(ray_render_object_sphere_t *sphere, ray_3f_t *point) +{ + /* uniform solids for now... */ + return sphere->object.surface; +} + +#endif diff --git a/src/libs/ray/ray_scene.h b/src/libs/ray/ray_scene.h new file mode 100644 index 0000000..ff9c440 --- /dev/null +++ b/src/libs/ray/ray_scene.h @@ -0,0 +1,16 @@ +#ifndef _RAY_SCENE_H +#define _RAY_SCENE_H + +#include "ray_color.h" + +typedef union ray_object_t ray_object_t; + +typedef struct ray_scene_t { + ray_object_t *objects; + ray_object_t *lights; + + ray_color_t ambient_color; + float ambient_brightness; +} ray_scene_t; + +#endif diff --git a/src/libs/ray/ray_surface.h b/src/libs/ray/ray_surface.h new file mode 100644 index 0000000..2e7544b --- /dev/null +++ b/src/libs/ray/ray_surface.h @@ -0,0 +1,15 @@ +#ifndef _RAY_MATERIAL_H +#define _RAY_MATERIAL_H + +#include "ray_3f.h" +#include "ray_color.h" + +/* Surface properties we expect every object to be able to introspect */ +typedef struct ray_surface_t { + ray_color_t color; + float specular; + float highlight_exponent; + float diffuse; +} ray_surface_t; + +#endif diff --git a/src/modules/ray/Makefile.am b/src/modules/ray/Makefile.am index 6c5900a..5fec057 100644 --- a/src/modules/ray/Makefile.am +++ b/src/modules/ray/Makefile.am @@ -1,4 +1,4 @@ noinst_LIBRARIES = libray.a -libray_a_SOURCES = ray_3f.h ray.c ray_camera.c ray_camera.h ray_color.h ray_euler.c ray_euler.h ray_light_emitter.h ray_object.h ray_object_light.h ray_object_plane.h ray_object_point.h ray_object_sphere.h ray_object_type.h ray_ray.h ray_render.c ray_render.h ray_render_object.h ray_render_object_plane.h ray_render_object_point.h ray_render_object_sphere.h ray_scene.h ray_surface.h +libray_a_SOURCES = ray.c libray_a_CFLAGS = -ffast-math -libray_a_CPPFLAGS = -I@top_srcdir@/src +libray_a_CPPFLAGS = -I@top_srcdir@/src -I@top_srcdir@/src/libs/ray diff --git a/src/modules/ray/ray_3f.h b/src/modules/ray/ray_3f.h deleted file mode 100644 index 2c04a5a..0000000 --- a/src/modules/ray/ray_3f.h +++ /dev/null @@ -1,154 +0,0 @@ -#ifndef _RAY_3F_H -#define _RAY_3F_H - -#include - -typedef struct ray_3f_t { - float x, y, z; -} ray_3f_t; - - -/* return the result of (a + b) */ -static inline ray_3f_t ray_3f_add(const ray_3f_t *a, const ray_3f_t *b) -{ - ray_3f_t res = { - .x = a->x + b->x, - .y = a->y + b->y, - .z = a->z + b->z, - }; - - return res; -} - - -/* return the result of (a - b) */ -static inline ray_3f_t ray_3f_sub(const ray_3f_t *a, const ray_3f_t *b) -{ - ray_3f_t res = { - .x = a->x - b->x, - .y = a->y - b->y, - .z = a->z - b->z, - }; - - return res; -} - - -/* return the result of (-v) */ -static inline ray_3f_t ray_3f_negate(const ray_3f_t *v) -{ - ray_3f_t res = { - .x = -v->x, - .y = -v->y, - .z = -v->z, - }; - - return res; -} - - -/* return the result of (a * b) */ -static inline ray_3f_t ray_3f_mult(const ray_3f_t *a, const ray_3f_t *b) -{ - ray_3f_t res = { - .x = a->x * b->x, - .y = a->y * b->y, - .z = a->z * b->z, - }; - - return res; -} - - -/* return the result of (v * scalar) */ -static inline ray_3f_t ray_3f_mult_scalar(const ray_3f_t *v, float scalar) -{ - ray_3f_t res = { - .x = v->x * scalar, - .y = v->y * scalar, - .z = v->z * scalar, - }; - - return res; -} - - -/* return the result of (uv / scalar) */ -static inline ray_3f_t ray_3f_div_scalar(const ray_3f_t *v, float scalar) -{ - ray_3f_t res = { - .x = v->x / scalar, - .y = v->y / scalar, - .z = v->z / scalar, - }; - - return res; -} - - -/* return the result of (a . b) */ -static inline float ray_3f_dot(const ray_3f_t *a, const ray_3f_t *b) -{ - return a->x * b->x + a->y * b->y + a->z * b->z; -} - - -/* return the length of the supplied vector */ -static inline float ray_3f_length(const ray_3f_t *v) -{ - return sqrtf(ray_3f_dot(v, v)); -} - - -/* return the normalized form of the supplied vector */ -static inline ray_3f_t ray_3f_normalize(const ray_3f_t *v) -{ - return ray_3f_mult_scalar(v, 1.0f / ray_3f_length(v)); -} - - -/* return the distance between two arbitrary points */ -static inline float ray_3f_distance(const ray_3f_t *a, const ray_3f_t *b) -{ - ray_3f_t delta = ray_3f_sub(a, b); - - return ray_3f_length(&delta); -} - - -/* return the cross product of two unit vectors */ -static inline ray_3f_t ray_3f_cross(const ray_3f_t *a, const ray_3f_t *b) -{ - ray_3f_t product; - - product.x = a->y * b->z - a->z * b->y; - product.y = a->z * b->x - a->x * b->z; - product.z = a->x * b->y - a->y * b->x; - - return product; -} - - -/* return the linearly interpolated vector between the two vectors at point alpha (0-1.0) */ -static inline ray_3f_t ray_3f_lerp(const ray_3f_t *a, const ray_3f_t *b, float alpha) -{ - ray_3f_t lerp_a, lerp_b; - - lerp_a = ray_3f_mult_scalar(a, 1.0f - alpha); - lerp_b = ray_3f_mult_scalar(b, alpha); - - return ray_3f_add(&lerp_a, &lerp_b); -} - - -/* return the normalized linearly interpolated vector between the two vectors at point alpha (0-1.0) */ -static inline ray_3f_t ray_3f_nlerp(const ray_3f_t *a, const ray_3f_t *b, float alpha) -{ - ray_3f_t lerp; - - lerp = ray_3f_lerp(a, b, alpha); - - return ray_3f_normalize(&lerp); -} - -#endif diff --git a/src/modules/ray/ray_camera.c b/src/modules/ray/ray_camera.c deleted file mode 100644 index b942cf3..0000000 --- a/src/modules/ray/ray_camera.c +++ /dev/null @@ -1,70 +0,0 @@ -#include "fb.h" - -#include "ray_camera.h" -#include "ray_euler.h" - - -/* Produce a vector from the provided orientation vectors and proportions. */ -static ray_3f_t project_corner(ray_3f_t *forward, ray_3f_t *left, ray_3f_t *up, float focal_length, float horiz, float vert) -{ - ray_3f_t tmp; - ray_3f_t corner; - - corner = ray_3f_mult_scalar(forward, focal_length); - tmp = ray_3f_mult_scalar(left, horiz); - corner = ray_3f_add(&corner, &tmp); - tmp = ray_3f_mult_scalar(up, vert); - corner = ray_3f_add(&corner, &tmp); - - return ray_3f_normalize(&corner); -} - - -/* Produce vectors for the corners of the entire camera frame, used for interpolation. */ -static void project_corners(const ray_camera_t *camera, ray_camera_frame_t *frame) -{ - ray_3f_t forward, left, up, right, down; - float half_horiz = (float)camera->width * 0.5f; - float half_vert = (float)camera->height * 0.5f; - - ray_euler_basis(&camera->orientation, &forward, &up, &left); - right = ray_3f_negate(&left); - down = ray_3f_negate(&up); - - frame->nw = project_corner(&forward, &left, &up, camera->focal_length, half_horiz, half_vert); - frame->ne = project_corner(&forward, &right, &up, camera->focal_length, half_horiz, half_vert); - frame->se = project_corner(&forward, &right, &down, camera->focal_length, half_horiz, half_vert); - frame->sw = project_corner(&forward, &left, &down, camera->focal_length, half_horiz, half_vert); -} - - -/* Prepare a frame of camera projection, initializing res_frame. */ -void ray_camera_frame_prepare(const ray_camera_t *camera, ray_camera_frame_t *res_frame) -{ - res_frame->camera = camera; - - project_corners(camera, res_frame); - - res_frame->x_delta = 1.0f / (float)camera->width; - res_frame->y_delta = 1.0f / (float)camera->height; -} - - -/* Begin a frame's fragment, initializing frame and ray. */ -void ray_camera_fragment_begin(ray_camera_frame_t *frame, fb_fragment_t *fb_fragment, ray_ray_t *res_ray, ray_camera_fragment_t *res_fragment) -{ - res_fragment->frame = frame; - res_fragment->fb_fragment = fb_fragment; - res_fragment->ray = res_ray; - - res_fragment->x = res_fragment->y = 0; - - res_fragment->x_alpha = frame->x_delta * (float)fb_fragment->x; - res_fragment->y_alpha = frame->y_delta * (float)fb_fragment->y; - - res_fragment->cur_w = ray_3f_lerp(&frame->nw, &frame->sw, res_fragment->y_alpha); - res_fragment->cur_e = ray_3f_lerp(&frame->ne, &frame->se, res_fragment->y_alpha); - - res_ray->origin = frame->camera->position; - res_ray->direction = ray_3f_nlerp(&res_fragment->cur_w, &res_fragment->cur_e, res_fragment->x_alpha); -} diff --git a/src/modules/ray/ray_camera.h b/src/modules/ray/ray_camera.h deleted file mode 100644 index e393beb..0000000 --- a/src/modules/ray/ray_camera.h +++ /dev/null @@ -1,84 +0,0 @@ -#ifndef _RAY_CAMERA_H -#define _RAY_CAMERA_H - -#include - -#include "fb.h" - -#include "ray_3f.h" -#include "ray_euler.h" -#include "ray_ray.h" - - -typedef struct ray_camera_t { - ray_3f_t position; /* position of camera, the origin of all its rays */ - ray_euler_t orientation; /* orientation of the camera */ - float focal_length; /* controls the field of view */ - unsigned width; /* width of camera viewport in pixels */ - unsigned height; /* height of camera viewport in pixels */ -} ray_camera_t; - - -typedef struct ray_camera_frame_t { - const ray_camera_t *camera; /* the camera supplied to frame_begin() */ - - ray_3f_t nw, ne, sw, se; /* directions pointing through the corners of the frame fragment */ - float x_delta, y_delta; /* interpolation step delta along the x and y axis */ -} ray_camera_frame_t; - - -typedef struct ray_camera_fragment_t { - ray_camera_frame_t *frame; /* the frame supplied to fragment_begin() */ - fb_fragment_t *fb_fragment; /* the fragment supplied to fragment_begin() */ - ray_ray_t *ray; /* the ray supplied to frame_begin(), which gets updated as we step through the frame. */ - - ray_3f_t cur_w, cur_e; /* current row's west and east ends */ - float x_alpha, y_alpha; /* interpolation position along the x and y axis */ - unsigned x, y; /* integral position within frame fragment */ -} ray_camera_fragment_t; - - -void ray_camera_frame_prepare(const ray_camera_t *camera, ray_camera_frame_t *res_frame); -void ray_camera_fragment_begin(ray_camera_frame_t *frame, fb_fragment_t *fb_fragment, ray_ray_t *res_ray, ray_camera_fragment_t *res_fragment); - - -/* Step the ray through the fragment on the x axis, returns 1 when rays remain on this axis, 0 at the end. */ -/* When 1 is returned, fragment->ray is left pointing through the new coordinate. */ -static inline int ray_camera_fragment_x_step(ray_camera_fragment_t *fragment) -{ - fragment->x++; - - if (fragment->x >= fragment->fb_fragment->width) { - fragment->x = 0; - fragment->x_alpha = fragment->frame->x_delta * (float)fragment->fb_fragment->x; - return 0; - } - - fragment->x_alpha += fragment->frame->x_delta; - fragment->ray->direction = ray_3f_nlerp(&fragment->cur_w, &fragment->cur_e, fragment->x_alpha); - - return 1; -} - - -/* Step the ray through the fragment on the y axis, returns 1 when rays remain on this axis, 0 at the end. */ -/* When 1 is returned, fragment->ray is left pointing through the new coordinate. */ -static inline int ray_camera_fragment_y_step(ray_camera_fragment_t *fragment) -{ - fragment->y++; - - if (fragment->y >= fragment->fb_fragment->height) { - fragment->y = 0; - fragment->y_alpha = fragment->frame->y_delta * (float)fragment->fb_fragment->y; - return 0; - } - - fragment->y_alpha += fragment->frame->y_delta; - fragment->cur_w = ray_3f_lerp(&fragment->frame->nw, &fragment->frame->sw, fragment->y_alpha); - fragment->cur_e = ray_3f_lerp(&fragment->frame->ne, &fragment->frame->se, fragment->y_alpha); - fragment->ray->direction = ray_3f_nlerp(&fragment->cur_w, &fragment->cur_e, fragment->x_alpha); - - return 1; -} - -#endif diff --git a/src/modules/ray/ray_color.h b/src/modules/ray/ray_color.h deleted file mode 100644 index 9fe62c1..0000000 --- a/src/modules/ray/ray_color.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef _RAY_COLOR_H -#define _RAY_COLOR_H - -#include - -#include "ray_3f.h" - -typedef ray_3f_t ray_color_t; - -/* convert a vector into a packed, 32-bit rgb pixel value */ -static inline uint32_t ray_color_to_uint32_rgb(ray_color_t color) { - uint32_t pixel; - - /* doing this all per-pixel, ugh. */ - - if (color.x > 1.0f) color.x = 1.0f; - if (color.y > 1.0f) color.y = 1.0f; - if (color.z > 1.0f) color.z = 1.0f; - - pixel = (uint32_t)(color.x * 255.0f); - pixel <<= 8; - pixel |= (uint32_t)(color.y * 255.0f); - pixel <<= 8; - pixel |= (uint32_t)(color.z * 255.0f); - - return pixel; -} - -#endif diff --git a/src/modules/ray/ray_euler.c b/src/modules/ray/ray_euler.c deleted file mode 100644 index f143e25..0000000 --- a/src/modules/ray/ray_euler.c +++ /dev/null @@ -1,90 +0,0 @@ -#include -#include - -#include "ray_3f.h" -#include "ray_euler.h" - -/* produce orthonormal basis vectors from euler angles, rotated in the specified order */ -void ray_euler_basis(const ray_euler_t *e, ray_3f_t *forward, ray_3f_t *up, ray_3f_t *left) -{ - float cos_yaw = cosf(e->yaw); - float sin_yaw = sinf(e->yaw); - float cos_roll = cosf(e->roll); - float sin_roll = sinf(e->roll); - float cos_pitch = cosf(e->pitch); - float sin_pitch = sinf(e->pitch); - - /* Rotation matrices from http://www.songho.ca/opengl/gl_anglestoaxes.html */ - switch (e->order) { - case RAY_EULER_ORDER_PYR: - /* pitch, yaw, roll */ - up->x = -cos_yaw * sin_roll; - up->y = -sin_pitch * sin_yaw * sin_roll + cos_pitch * cos_roll; - up->z = cos_pitch * sin_yaw * sin_roll + sin_pitch * cos_roll; - - forward->x = sin_yaw; - forward->y = -sin_pitch * cos_yaw; - forward->z = cos_pitch * cos_yaw; - break; - - case RAY_EULER_ORDER_YRP: - /* yaw, roll, pitch */ - up->x = -cos_yaw * sin_roll * cos_pitch + sin_yaw * sin_pitch; - up->y = cos_roll * cos_pitch; - up->z = sin_yaw * sin_roll * cos_pitch + cos_yaw * sin_pitch; - - forward->x = cos_yaw * sin_roll * sin_pitch + sin_yaw * cos_pitch; - forward->y = -cos_roll * sin_pitch; - forward->z = -sin_yaw * sin_roll * sin_pitch + cos_yaw * cos_pitch; - break; - - case RAY_EULER_ORDER_RPY: - /* roll, pitch, yaw */ - up->x = -sin_roll * cos_pitch; - up->y = cos_roll * cos_pitch; - up->z = sin_pitch; - - forward->x = cos_roll * sin_yaw + sin_roll * sin_pitch * cos_yaw; - forward->y = sin_roll * sin_yaw - cos_roll * sin_pitch * cos_yaw; - forward->z = cos_pitch * cos_yaw; - break; - - case RAY_EULER_ORDER_PRY: - /* pitch, roll, yaw */ - up->x = -sin_roll; - up->y = cos_pitch * cos_roll; - up->z = sin_pitch * cos_roll; - - forward->x = cos_roll * sin_yaw; - forward->y = cos_pitch * sin_roll * sin_yaw - sin_pitch * cos_yaw; - forward->z = sin_pitch * sin_roll * sin_yaw + cos_pitch * cos_yaw; - break; - - case RAY_EULER_ORDER_RYP: - /* roll, yaw, pitch */ - up->x = -sin_roll * cos_pitch + cos_roll * sin_yaw * sin_pitch; - up->y = cos_roll * cos_pitch + sin_roll * sin_yaw * sin_pitch; - up->z = cos_yaw * sin_pitch; - - forward->x = sin_roll * sin_pitch + cos_roll * sin_yaw * cos_pitch; - forward->y = -cos_roll * sin_pitch + sin_roll * sin_yaw * cos_pitch; - forward->z = cos_yaw * cos_pitch; - break; - - case RAY_EULER_ORDER_YPR: - /* yaw, pitch, roll */ - up->x = -cos_yaw * sin_roll + sin_yaw * sin_pitch * cos_roll; - up->y = cos_pitch * cos_roll; - up->z = sin_yaw * sin_roll + cos_yaw * sin_pitch * cos_roll; - - forward->x = sin_yaw * cos_pitch; - forward->y = -sin_pitch; - forward->z = cos_yaw * cos_pitch; - break; - - default: - assert(0); - } - - *left = ray_3f_cross(up, forward); -} diff --git a/src/modules/ray/ray_euler.h b/src/modules/ray/ray_euler.h deleted file mode 100644 index 39da17e..0000000 --- a/src/modules/ray/ray_euler.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef _RAY_EULER_H -#define _RAY_EULER_H - -#include - -#include "ray_3f.h" - -/* Desired order to apply euler angle rotations */ -typedef enum ray_euler_order_t { - RAY_EULER_ORDER_PYR, - RAY_EULER_ORDER_YRP, - RAY_EULER_ORDER_RPY, - RAY_EULER_ORDER_PRY, - RAY_EULER_ORDER_RYP, - RAY_EULER_ORDER_YPR, -} ray_euler_order_t; - -/* euler angles are convenient for describing orientation */ -typedef struct ray_euler_t { - ray_euler_order_t order; /* order to apply rotations in */ - float pitch; /* pitch in radiasn */ - float yaw; /* yaw in radians */ - float roll; /* roll in radians */ -} ray_euler_t; - - -/* convenience macro for converting degrees to radians */ -#define RAY_EULER_DEGREES(_deg) \ - (_deg * (2 * M_PI / 360.0f)) - -void ray_euler_basis(const ray_euler_t *e, ray_3f_t *forward, ray_3f_t *up, ray_3f_t *left); - -#endif diff --git a/src/modules/ray/ray_light_emitter.h b/src/modules/ray/ray_light_emitter.h deleted file mode 100644 index 3b5509e..0000000 --- a/src/modules/ray/ray_light_emitter.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef _RAY_LIGHT_EMITTER_H -#define _RAY_LIGHT_EMITTER_H - -#include "ray_object_point.h" -#include "ray_object_sphere.h" - -typedef enum ray_light_emitter_type_t { - RAY_LIGHT_EMITTER_TYPE_SPHERE, - RAY_LIGHT_EMITTER_TYPE_POINT, -} ray_light_emitter_type_t; - -typedef union ray_light_emitter_t { - ray_light_emitter_type_t type; - ray_object_sphere_t sphere; - ray_object_point_t point; -} ray_light_emitter_t; - -#endif diff --git a/src/modules/ray/ray_object.h b/src/modules/ray/ray_object.h deleted file mode 100644 index fc5ae1b..0000000 --- a/src/modules/ray/ray_object.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef _RAY_OBJECT_H -#define _RAY_OBJECT_H - -#include "ray_object_light.h" -#include "ray_object_plane.h" -#include "ray_object_point.h" -#include "ray_object_sphere.h" -#include "ray_object_type.h" - -typedef union ray_object_t { - ray_object_type_t type; - ray_object_sphere_t sphere; - ray_object_point_t point; - ray_object_plane_t plane; - ray_object_light_t light; -} ray_object_t; - -#endif diff --git a/src/modules/ray/ray_object_light.h b/src/modules/ray/ray_object_light.h deleted file mode 100644 index ca9bac9..0000000 --- a/src/modules/ray/ray_object_light.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef _RAY_OBJECT_LIGHT_H -#define _RAY_OBJECT_LIGHT_H - -#include "ray_light_emitter.h" -#include "ray_object_type.h" - - -typedef struct ray_object_light_t { - ray_object_type_t type; - float brightness; - ray_light_emitter_t emitter; -} ray_object_light_t; - -#endif diff --git a/src/modules/ray/ray_object_plane.h b/src/modules/ray/ray_object_plane.h deleted file mode 100644 index 96ed437..0000000 --- a/src/modules/ray/ray_object_plane.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef _RAY_OBJECT_PLANE_H -#define _RAY_OBJECT_PLANE_H - -#include "ray_3f.h" -#include "ray_object_type.h" -#include "ray_surface.h" - - -typedef struct ray_object_plane_t { - ray_object_type_t type; - ray_surface_t surface; - ray_3f_t normal; - float distance; -} ray_object_plane_t; - -#endif diff --git a/src/modules/ray/ray_object_point.h b/src/modules/ray/ray_object_point.h deleted file mode 100644 index 5685fdc..0000000 --- a/src/modules/ray/ray_object_point.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef _RAY_OBJECT_POINT_H -#define _RAY_OBJECT_POINT_H - -#include "ray_3f.h" -#include "ray_object_type.h" -#include "ray_surface.h" - - -typedef struct ray_object_point_t { - ray_object_type_t type; - ray_surface_t surface; - ray_3f_t center; -} ray_object_point_t; - -#endif diff --git a/src/modules/ray/ray_object_sphere.h b/src/modules/ray/ray_object_sphere.h deleted file mode 100644 index 71b6334..0000000 --- a/src/modules/ray/ray_object_sphere.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef _RAY_OBJECT_SPHERE_H -#define _RAY_OBJECT_SPHERE_H - -#include "ray_3f.h" -#include "ray_object_type.h" -#include "ray_surface.h" - - -typedef struct ray_object_sphere_t { - ray_object_type_t type; - ray_surface_t surface; - ray_3f_t center; - float radius; -} ray_object_sphere_t; - -#endif diff --git a/src/modules/ray/ray_object_type.h b/src/modules/ray/ray_object_type.h deleted file mode 100644 index ab797d2..0000000 --- a/src/modules/ray/ray_object_type.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _RAY_OBJECT_TYPE_H -#define _RAY_OBJECT_TYPE_H - -typedef enum ray_object_type_t { - RAY_OBJECT_TYPE_SENTINEL, - RAY_OBJECT_TYPE_SPHERE, - RAY_OBJECT_TYPE_POINT, - RAY_OBJECT_TYPE_PLANE, - RAY_OBJECT_TYPE_LIGHT, -} ray_object_type_t; - -#endif diff --git a/src/modules/ray/ray_ray.h b/src/modules/ray/ray_ray.h deleted file mode 100644 index 91469a2..0000000 --- a/src/modules/ray/ray_ray.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef _RAY_RAY_H -#define _RAY_RAY_H - -#include "ray_3f.h" - -typedef struct ray_ray_t { - ray_3f_t origin; - ray_3f_t direction; -} ray_ray_t; - -#endif diff --git a/src/modules/ray/ray_render.c b/src/modules/ray/ray_render.c deleted file mode 100644 index 8b930f6..0000000 --- a/src/modules/ray/ray_render.c +++ /dev/null @@ -1,251 +0,0 @@ -#include -#include - -#include "fb.h" - -#include "ray_camera.h" -#include "ray_color.h" -#include "ray_render_object.h" -#include "ray_ray.h" -#include "ray_scene.h" - -#define MAX_RECURSION_DEPTH 4 -#define MIN_RELEVANCE 0.05f - -typedef struct ray_render_t { - const ray_scene_t *scene; /* scene being rendered */ - const ray_camera_t *camera; /* camera rendering the scene */ - - ray_color_t ambient_light; - ray_camera_frame_t frame; - - ray_render_object_t objects[]; -} ray_render_t; - -/* Determine if the ray is obstructed by an object within the supplied distance, for shadows */ -static inline int ray_is_obstructed(ray_render_t *render, unsigned depth, ray_ray_t *ray, float distance) -{ - ray_render_object_t *object; - - for (object = render->objects; object->type; object++) { - float ood; - - if (ray_render_object_intersects_ray(object, depth, ray, &ood) && - ood < distance) { - return 1; - } - } - - return 0; -} - - -/* shadow test */ -static inline int point_is_shadowed(ray_render_t *render, unsigned depth, ray_3f_t *light_direction, float distance, ray_3f_t *point) -{ - ray_ray_t shadow_ray; - - shadow_ray.direction = *light_direction; - shadow_ray.origin = *point; - - if (ray_is_obstructed(render, depth + 1, &shadow_ray, distance)) - return 1; - - return 0; -} - - -/* a faster powf() that's good enough for our purposes. - * XXX: note there's a faster technique which exploits the IEEE floating point format: - * https://github.com/ekmett/approximate/blob/master/cbits/fast.c#L185 - */ -static inline float approx_powf(float x, float y) -{ - return expf(y * logf(x)); -} - - -/* Determine the color @ distance on ray on object viewed from origin */ -static inline ray_color_t shade_intersection(ray_render_t *render, ray_render_object_t *object, ray_ray_t *ray, ray_3f_t *intersection, ray_3f_t *normal, unsigned depth, float *res_reflectivity) -{ - ray_surface_t surface = ray_render_object_surface(object, intersection); - ray_color_t color = ray_3f_mult(&surface.color, &render->ambient_light); - ray_object_t *light; - - /* visit lights for shadows and illumination */ - for (light = render->scene->lights; light->type; light++) { - ray_3f_t lvec = ray_3f_sub(&light->light.emitter.point.center, intersection); - float ldist = ray_3f_length(&lvec); - float lvec_normal_dot; - - lvec = ray_3f_mult_scalar(&lvec, (1.0f / ldist)); /* normalize lvec */ -#if 1 - if (point_is_shadowed(render, depth, &lvec, ldist, intersection)) - continue; -#endif - lvec_normal_dot = ray_3f_dot(normal, &lvec); - - if (lvec_normal_dot > 0) { -#if 1 - float rvec_lvec_dot = ray_3f_dot(&ray->direction, &lvec); - float intensity = light->light.brightness * (1.0 / (ldist * ldist)); - ray_color_t diffuse; - - diffuse = ray_3f_mult_scalar(&surface.color, lvec_normal_dot); - diffuse = ray_3f_mult_scalar(&diffuse, surface.diffuse); - color = ray_3f_add(&color, &diffuse); - - if (rvec_lvec_dot > 0) { - ray_color_t specular; - - /* FIXME: assumes light is a point for its color */ - specular = ray_3f_mult_scalar(&light->light.emitter.point.surface.color, approx_powf(rvec_lvec_dot, surface.highlight_exponent)); - specular = ray_3f_mult_scalar(&specular, surface.specular); - color = ray_3f_add(&color, &specular); - } - - color = ray_3f_mult_scalar(&color, intensity); -#else - ray_color_t diffuse; - - diffuse = ray_3f_mult_scalar(&surface.color, lvec_normal_dot); - color = ray_3f_add(&color, &diffuse); -#endif - } - } - - /* for now just treat specular as the reflectivity */ - *res_reflectivity = surface.specular; - - return color; -} - - -static inline ray_render_object_t * find_nearest_intersection(ray_render_t *render, ray_render_object_t *reflector, ray_ray_t *ray, unsigned depth, float *res_distance) -{ - ray_render_object_t *nearest_object = NULL; - float nearest_object_distance = INFINITY; - ray_render_object_t *object; - - for (object = render->objects; object->type; object++) { - float distance; - - /* Don't bother checking if a reflected ray intersects the object reflecting it, - * reflector = NULL for primary rays, which will never compare as true here. */ - if (object == reflector) - continue; - - /* Does this ray intersect object? */ - if (ray_render_object_intersects_ray(object, depth, ray, &distance)) { - /* Is it the nearest intersection? */ - if (distance < nearest_object_distance) { - nearest_object = object; - nearest_object_distance = distance; - } - } - } - - if (nearest_object) - *res_distance = nearest_object_distance; - - return nearest_object; -} - - -static inline ray_color_t trace_ray(ray_render_t *render, ray_ray_t *primary_ray) -{ - ray_color_t color = { .x = 0.0f, .y = 0.0f, .z = 0.0f }; - ray_3f_t intersection, normal; - ray_render_object_t *reflector = NULL; - float relevance = 1.0f, reflectivity; - unsigned depth = 0; - ray_ray_t reflected_ray, *ray = primary_ray; - - do { - ray_render_object_t *nearest_object; - float nearest_distance; - - if (reflector) { - float dot = ray_3f_dot(&ray->direction, &normal); - ray_3f_t new_direction = ray_3f_mult_scalar(&normal, dot * 2.0f); - - new_direction = ray_3f_sub(&ray->direction, &new_direction); - - reflected_ray.origin = intersection; - reflected_ray.direction = new_direction; - - ray = &reflected_ray; - } - - nearest_object = find_nearest_intersection(render, reflector, ray, depth, &nearest_distance); - if (nearest_object) { - ray_3f_t more_color; - ray_3f_t rvec; - - rvec = ray_3f_mult_scalar(&ray->direction, nearest_distance); - intersection = ray_3f_add(&ray->origin, &rvec); - normal = ray_render_object_normal(nearest_object, &intersection); - - more_color = shade_intersection(render, nearest_object, ray, &intersection, &normal, depth, &reflectivity); - more_color = ray_3f_mult_scalar(&more_color, relevance); - color = ray_3f_add(&color, &more_color); - } - - reflector = nearest_object; - } while (reflector && (++depth < MAX_RECURSION_DEPTH) && (relevance *= reflectivity) >= MIN_RELEVANCE); - - return color; -} - - -void ray_render_trace_fragment(ray_render_t *render, fb_fragment_t *fb_fragment) -{ - uint32_t *buf = fb_fragment->buf; - ray_camera_fragment_t fragment; - ray_ray_t ray; - - ray_camera_fragment_begin(&render->frame, fb_fragment, &ray, &fragment); - do { - do { - *buf = ray_color_to_uint32_rgb(trace_ray(render, &ray)); - buf++; - } while (ray_camera_fragment_x_step(&fragment)); - - buf = ((void *)buf) + fb_fragment->stride; - } while (ray_camera_fragment_y_step(&fragment)); -} - - -/* prepare the scene for rendering with camera, must be called whenever anything in the scene+camera pair has been changed. */ -/* this is basically a time for the raytracer to precompute whatever it can which otherwise ends up occurring per-ray */ -/* the camera is included so primary rays which all have a common origin may be optimized for */ -ray_render_t * ray_render_new(const ray_scene_t *scene, const ray_camera_t *camera) -{ - ray_render_t *render; - ray_object_t *object; - unsigned i; - - for (i = 0, object = scene->objects; object->type; object++) - i++; - - render = malloc(sizeof(ray_render_t) + i * sizeof(ray_render_object_t)); - if (!render) - return NULL; - - render->scene = scene; - render->camera = camera; - - render->ambient_light = ray_3f_mult_scalar(&scene->ambient_color, scene->ambient_brightness); - ray_camera_frame_prepare(camera, &render->frame); - - for (i = 0, object = scene->objects; object->type; object++) - render->objects[i++] = ray_render_object_prepare(object, camera); - - return render; -} - - -void ray_render_free(ray_render_t *render) -{ - free(render); -} diff --git a/src/modules/ray/ray_render.h b/src/modules/ray/ray_render.h deleted file mode 100644 index dfd769f..0000000 --- a/src/modules/ray/ray_render.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef _RAY_RENDER_H -#define _RAY_RENDER_H - -#include "fb.h" - -#include "ray_camera.h" -#include "ray_scene.h" - -typedef struct ray_render_t ray_render_t; - -ray_render_t * ray_render_new(const ray_scene_t *scene, const ray_camera_t *camera); -void ray_render_free(ray_render_t *render); -void ray_render_trace_fragment(ray_render_t *render, fb_fragment_t *fb_fragment); - -#endif diff --git a/src/modules/ray/ray_render_object.h b/src/modules/ray/ray_render_object.h deleted file mode 100644 index 1136eee..0000000 --- a/src/modules/ray/ray_render_object.h +++ /dev/null @@ -1,121 +0,0 @@ -#ifndef _RAY_RENDER_OBJECT_H -#define _RAY_RENDER_OBJECT_H - -#include - -#include "ray_camera.h" -#include "ray_object.h" -#include "ray_object_type.h" -#include "ray_render_object_plane.h" -#include "ray_render_object_point.h" -#include "ray_render_object_sphere.h" -#include "ray_ray.h" -#include "ray_surface.h" - -typedef union ray_render_object_t { - ray_object_type_t type; - ray_render_object_sphere_t sphere; - ray_render_object_point_t point; - ray_render_object_plane_t plane; -} ray_render_object_t; - - - -/* Prepare an object for rendering. - * If the object has any pre-calculating to do, this is where it happens. - * The pre-calculated stuff is object-resident under a _prepared struct member. - */ -static inline ray_render_object_t ray_render_object_prepare(const ray_object_t *object, const ray_camera_t *camera) -{ - ray_render_object_t prepared = { .type = object->type }; - - switch (object->type) { - case RAY_OBJECT_TYPE_SPHERE: - prepared.sphere = ray_render_object_sphere_prepare(&object->sphere, camera); - break; - - case RAY_OBJECT_TYPE_POINT: - prepared.point = ray_render_object_point_prepare(&object->point, camera); - break; - - case RAY_OBJECT_TYPE_PLANE: - prepared.plane = ray_render_object_plane_prepare(&object->plane, camera); - break; - - case RAY_OBJECT_TYPE_LIGHT: - /* TODO */ - break; - - default: - assert(0); - } - - return prepared; -} - - -/* Determine if a ray intersects object. - * If the object is intersected, store where along the ray the intersection occurs in res_distance. - */ -static inline int ray_render_object_intersects_ray(ray_render_object_t *object, unsigned depth, ray_ray_t *ray, float *res_distance) -{ - switch (object->type) { - case RAY_OBJECT_TYPE_SPHERE: - return ray_render_object_sphere_intersects_ray(&object->sphere, depth, ray, res_distance); - - case RAY_OBJECT_TYPE_POINT: - return ray_render_object_point_intersects_ray(&object->point, depth, ray, res_distance); - - case RAY_OBJECT_TYPE_PLANE: - return ray_render_object_plane_intersects_ray(&object->plane, depth, ray, res_distance); - - case RAY_OBJECT_TYPE_LIGHT: - /* TODO */ - default: - assert(0); - } -} - - -/* Return the surface normal of object @ point */ -static inline ray_3f_t ray_render_object_normal(ray_render_object_t *object, ray_3f_t *point) -{ - switch (object->type) { - case RAY_OBJECT_TYPE_SPHERE: - return ray_render_object_sphere_normal(&object->sphere, point); - - case RAY_OBJECT_TYPE_POINT: - return ray_render_object_point_normal(&object->point, point); - - case RAY_OBJECT_TYPE_PLANE: - return ray_render_object_plane_normal(&object->plane, point); - - case RAY_OBJECT_TYPE_LIGHT: - /* TODO */ - default: - assert(0); - } -} - - -/* Return the surface of object @ point */ -static inline ray_surface_t ray_render_object_surface(ray_render_object_t *object, ray_3f_t *point) -{ - switch (object->type) { - case RAY_OBJECT_TYPE_SPHERE: - return ray_render_object_sphere_surface(&object->sphere, point); - - case RAY_OBJECT_TYPE_POINT: - return ray_render_object_point_surface(&object->point, point); - - case RAY_OBJECT_TYPE_PLANE: - return ray_render_object_plane_surface(&object->plane, point); - - case RAY_OBJECT_TYPE_LIGHT: - /* TODO */ - default: - assert(0); - } -} - -#endif diff --git a/src/modules/ray/ray_render_object_plane.h b/src/modules/ray/ray_render_object_plane.h deleted file mode 100644 index 6e00089..0000000 --- a/src/modules/ray/ray_render_object_plane.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef _RAY_RENDER_OBJECT_PLANE_H -#define _RAY_RENDER_OBJECT_PLANE_H - -#include "ray_3f.h" -#include "ray_camera.h" -#include "ray_object_plane.h" -#include "ray_object_type.h" -#include "ray_ray.h" -#include "ray_surface.h" - - -typedef struct ray_render_object_plane_t { - ray_object_plane_t object; - float primary_dot_plus; -} ray_render_object_plane_t; - - -static ray_render_object_plane_t ray_render_object_plane_prepare(const ray_object_plane_t *plane, const ray_camera_t *camera) -{ - ray_render_object_plane_t prepared = { .object = *plane }; - - prepared.primary_dot_plus = ray_3f_dot(&plane->normal, &camera->position) + plane->distance; - - return prepared; -} - - -static inline int ray_render_object_plane_intersects_ray(ray_render_object_plane_t *plane, unsigned depth, ray_ray_t *ray, float *res_distance) -{ - float d = ray_3f_dot(&plane->object.normal, &ray->direction); - - if (d < 0.0f) { - float distance = plane->primary_dot_plus; - - if (depth) - distance = (ray_3f_dot(&plane->object.normal, &ray->origin) + plane->object.distance); - - distance /= -d; - if (distance > 0.0f) { - *res_distance = distance; - - return 1; - } - } - - return 0; -} - - -static inline ray_3f_t ray_render_object_plane_normal(ray_render_object_plane_t *plane, ray_3f_t *point) -{ - return plane->object.normal; -} - - -static inline ray_surface_t ray_render_object_plane_surface(ray_render_object_plane_t *plane, ray_3f_t *point) -{ - return plane->object.surface; -} - -#endif diff --git a/src/modules/ray/ray_render_object_point.h b/src/modules/ray/ray_render_object_point.h deleted file mode 100644 index 52c6fd6..0000000 --- a/src/modules/ray/ray_render_object_point.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef _RAY_RENDER_OBJECT_POINT_H -#define _RAY_RENDER_OBJECT_POINT_H - -#include "ray_3f.h" -#include "ray_camera.h" -#include "ray_object_point.h" -#include "ray_object_type.h" -#include "ray_ray.h" -#include "ray_surface.h" - - -typedef struct ray_render_object_point_t { - ray_object_point_t object; -} ray_render_object_point_t; - - -static ray_render_object_point_t ray_render_object_point_prepare(const ray_object_point_t *point, const ray_camera_t *camera) -{ - ray_render_object_point_t prepared = { .object = *point }; - - return prepared; -} - - -static inline int ray_render_object_point_intersects_ray(ray_render_object_point_t *point, unsigned depth, ray_ray_t *ray, float *res_distance) -{ - /* TODO: determine a ray:point intersection */ - return 0; -} - - -static inline ray_3f_t ray_render_object_point_normal(ray_render_object_point_t *point, ray_3f_t *_point) -{ - ray_3f_t normal; - - return normal; -} - - -static inline ray_surface_t ray_render_object_point_surface(ray_render_object_point_t *point, ray_3f_t *_point) -{ - return point->object.surface; -} - -#endif diff --git a/src/modules/ray/ray_render_object_sphere.h b/src/modules/ray/ray_render_object_sphere.h deleted file mode 100644 index addf1f5..0000000 --- a/src/modules/ray/ray_render_object_sphere.h +++ /dev/null @@ -1,90 +0,0 @@ -#ifndef _RAY_RENDER_OBJECT_SPHERE_H -#define _RAY_RENDER_OBJECT_SPHERE_H - -#include - -#include "ray_3f.h" -#include "ray_camera.h" -#include "ray_color.h" -#include "ray_object_sphere.h" -#include "ray_object_type.h" -#include "ray_ray.h" -#include "ray_surface.h" - - -typedef struct ray_render_object_sphere_t { - ray_object_sphere_t object; - ray_3f_t primary_v; - float primary_dot_vv; - float r2; - float r_inv; -} ray_render_object_sphere_t; - - -static ray_render_object_sphere_t ray_render_object_sphere_prepare(const ray_object_sphere_t *sphere, const ray_camera_t *camera) -{ - ray_render_object_sphere_t prepared = { .object = *sphere }; - - prepared.primary_v = ray_3f_sub(&sphere->center, &camera->position); - prepared.primary_dot_vv = ray_3f_dot(&prepared.primary_v, &prepared.primary_v); - - prepared.r2 = sphere->radius * sphere->radius; - - /* to divide by radius via multiplication in ray_object_sphere_normal() */ - prepared.r_inv = 1.0f / sphere->radius; - - return prepared; -} - - -static inline int ray_render_object_sphere_intersects_ray(ray_render_object_sphere_t *sphere, unsigned depth, ray_ray_t *ray, float *res_distance) -{ - ray_3f_t v = sphere->primary_v; - float dot_vv = sphere->primary_dot_vv; - float b, disc; - - if (depth) { - v = ray_3f_sub(&sphere->object.center, &ray->origin); - dot_vv = ray_3f_dot(&v, &v); - } - - b = ray_3f_dot(&v, &ray->direction); - disc = sphere->r2 - (dot_vv - (b * b)); - if (disc > 0) { - float i1, i2; - - disc = sqrtf(disc); - - i1 = b - disc; - i2 = b + disc; - - if (i2 > 0 && i1 > 0) { - *res_distance = i1; - return 1; - } - } - - return 0; -} - - -/* return the normal of the surface at the specified point */ -static inline ray_3f_t ray_render_object_sphere_normal(ray_render_object_sphere_t *sphere, ray_3f_t *point) -{ - ray_3f_t normal; - - normal = ray_3f_sub(point, &sphere->object.center); - normal = ray_3f_mult_scalar(&normal, sphere->r_inv); /* normalize without the sqrt() */ - - return normal; -} - - -/* return the surface of the sphere @ point */ -static inline ray_surface_t ray_render_object_sphere_surface(ray_render_object_sphere_t *sphere, ray_3f_t *point) -{ - /* uniform solids for now... */ - return sphere->object.surface; -} - -#endif diff --git a/src/modules/ray/ray_scene.h b/src/modules/ray/ray_scene.h deleted file mode 100644 index ff9c440..0000000 --- a/src/modules/ray/ray_scene.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef _RAY_SCENE_H -#define _RAY_SCENE_H - -#include "ray_color.h" - -typedef union ray_object_t ray_object_t; - -typedef struct ray_scene_t { - ray_object_t *objects; - ray_object_t *lights; - - ray_color_t ambient_color; - float ambient_brightness; -} ray_scene_t; - -#endif diff --git a/src/modules/ray/ray_surface.h b/src/modules/ray/ray_surface.h deleted file mode 100644 index 2e7544b..0000000 --- a/src/modules/ray/ray_surface.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef _RAY_MATERIAL_H -#define _RAY_MATERIAL_H - -#include "ray_3f.h" -#include "ray_color.h" - -/* Surface properties we expect every object to be able to introspect */ -typedef struct ray_surface_t { - ray_color_t color; - float specular; - float highlight_exponent; - float diffuse; -} ray_surface_t; - -#endif -- cgit v1.2.3