From 121846b0e35607bf8b48d5ce304a65e2657be455 Mon Sep 17 00:00:00 2001 From: Vito Caputo Date: Wed, 13 Sep 2017 13:55:22 -0700 Subject: ray: cleanup ray_camera_frame_t fragments Previously every fb_fragment_t (and thus thread) was constructing its own ray_camera_frame_t view into the scene, duplicating some work. Instead introduce ray_camera_fragment_t to encapsulate the truly per-fragment state and make ray_scene_render_fragment() operate on just this stuff with a reference to a shared ray_camera_frame_t prepared once per-frame. Some minor ray_camera.c cleanups sneak in as well (prefer multiply instead of divide, whitespace cleanups...) --- src/modules/ray/ray.c | 2 +- src/modules/ray/ray_camera.c | 83 ++++++++++++++++++-------------------------- src/modules/ray/ray_camera.h | 59 +++++++++++++++++-------------- src/modules/ray/ray_scene.c | 15 ++++---- src/modules/ray/ray_scene.h | 5 +-- 5 files changed, 79 insertions(+), 85 deletions(-) (limited to 'src/modules/ray') diff --git a/src/modules/ray/ray.c b/src/modules/ray/ray.c index ac00806..60784db 100644 --- a/src/modules/ray/ray.c +++ b/src/modules/ray/ray.c @@ -154,7 +154,7 @@ static void ray_prepare_frame(void *context, unsigned n_cpus, fb_fragment_t *fra /* ray trace a simple scene into the fragment */ static void ray_render_fragment(void *context, fb_fragment_t *fragment) { - ray_scene_render_fragment(&scene, &camera, fragment); + ray_scene_render_fragment(&scene, fragment); } diff --git a/src/modules/ray/ray_camera.c b/src/modules/ray/ray_camera.c index e7792f2..a709d6f 100644 --- a/src/modules/ray/ray_camera.c +++ b/src/modules/ray/ray_camera.c @@ -24,62 +24,47 @@ static ray_3f_t project_corner(ray_3f_t *forward, ray_3f_t *left, ray_3f_t *up, static void project_corners(ray_camera_t *camera, ray_camera_frame_t *frame) { ray_3f_t forward, left, up, right, down; - float half_horiz = (float)camera->width / 2.0f; - float half_vert = (float)camera->height / 2.0f; + 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); + 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); } -/* Begin a frame for the fragment of camera projection, initializing frame and ray. */ -void ray_camera_frame_begin(ray_camera_t *camera, fb_fragment_t *fragment, ray_ray_t *ray, ray_camera_frame_t *frame) +/* Prepare a frame of camera projection, initializing res_frame. */ +void ray_camera_frame_prepare(ray_camera_t *camera, ray_camera_frame_t *res_frame) { - /* References are kept to the camera, fragment, and ray to be traced. - * The ray is maintained as we step through the frame, that is the - * purpose of this api. - * - * Since the ray direction should be a normalized vector, the obvious - * implementation is a bit costly. The camera frame api hides this - * detail so we can explore interpolation techniques to potentially - * lessen the per-pixel cost. - */ - frame->camera = camera; - frame->fragment = fragment; - frame->ray = ray; - - frame->x = frame->y = 0; - - /* From camera->orientation and camera->focal_length compute the vectors - * through the viewport's corners, and place these normalized vectors - * in frame->(nw,ne,sw,se). - * - * These can than be interpolated between to produce the ray vectors - * throughout the frame's fragment. The efficient option of linear - * interpolation will not maintain the unit vector length, so to - * produce normalized interpolated directions will require the costly - * normalize function. - * - * I'm hoping a simple length correction table can be used to fixup the - * linearly interpolated vectors to make them unit vectors with just - * scalar multiplication instead of the sqrt of normalize. - */ - project_corners(camera, frame); - - frame->x_delta = 1.0f / (float)camera->width; - frame->y_delta = 1.0f / (float)camera->height; - frame->x_alpha = frame->x_delta * (float)fragment->x; - frame->y_alpha = frame->y_delta * (float)fragment->y; - - frame->cur_w = ray_3f_lerp(&frame->nw, &frame->sw, frame->y_alpha); - frame->cur_e = ray_3f_lerp(&frame->ne, &frame->se, frame->y_alpha); - - ray->origin = camera->position; - ray->direction = ray_3f_nlerp(&frame->cur_w, &frame->cur_e, frame->x_alpha); + 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 index 191d614..889beb9 100644 --- a/src/modules/ray/ray_camera.h +++ b/src/modules/ray/ray_camera.h @@ -21,55 +21,62 @@ typedef struct ray_camera_t { typedef struct ray_camera_frame_t { ray_camera_t *camera; /* the camera supplied to frame_begin() */ - fb_fragment_t *fragment; /* the fragment supplied to frame_begin() */ - ray_ray_t *ray; /* the ray supplied to frame_begin(), which gets updated as we step through the frame. */ ray_3f_t nw, ne, sw, se; /* directions pointing through the corners of the frame fragment */ - 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 */ float x_delta, y_delta; /* interpolation step delta along the x and y axis */ - unsigned x, y; /* integral position within frame fragment */ } ray_camera_frame_t; -void ray_camera_frame_begin(ray_camera_t *camera, fb_fragment_t *fragment, ray_ray_t *ray, ray_camera_frame_t *frame); +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; -/* Step the ray through the frame on the x axis, returns 1 when rays remain on this axis, 0 at the end. */ -/* When 1 is returned, frame->ray is left pointing through the new coordinate. */ -static inline int ray_camera_frame_x_step(ray_camera_frame_t *frame) + +void ray_camera_frame_prepare(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) { - frame->x++; + fragment->x++; - if (frame->x >= frame->fragment->width) { - frame->x = 0; - frame->x_alpha = frame->x_delta * (float)frame->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; } - frame->x_alpha += frame->x_delta; - frame->ray->direction = ray_3f_nlerp(&frame->cur_w, &frame->cur_e, frame->x_alpha); + 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 frame on the y axis, returns 1 when rays remain on this axis, 0 at the end. */ -/* When 1 is returned, frame->ray is left pointing through the new coordinate. */ -static inline int ray_camera_frame_y_step(ray_camera_frame_t *frame) +/* 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) { - frame->y++; + fragment->y++; - if (frame->y >= frame->fragment->height) { - frame->y = 0; - frame->y_alpha = frame->y_delta * (float)frame->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; } - frame->y_alpha += frame->y_delta; - frame->cur_w = ray_3f_lerp(&frame->nw, &frame->sw, frame->y_alpha); - frame->cur_e = ray_3f_lerp(&frame->ne, &frame->se, frame->y_alpha); - frame->ray->direction = ray_3f_nlerp(&frame->cur_w, &frame->cur_e, frame->x_alpha); + 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; } diff --git a/src/modules/ray/ray_scene.c b/src/modules/ray/ray_scene.c index 2026f6d..cf8fb44 100644 --- a/src/modules/ray/ray_scene.c +++ b/src/modules/ray/ray_scene.c @@ -189,22 +189,22 @@ static inline ray_color_t trace_ray(ray_scene_t *scene, ray_ray_t *primary_ray) } -void ray_scene_render_fragment(ray_scene_t *scene, ray_camera_t *camera, fb_fragment_t *fragment) +void ray_scene_render_fragment(ray_scene_t *scene, fb_fragment_t *fb_fragment) { - ray_camera_frame_t frame; + unsigned stride = fb_fragment->stride / 4; + uint32_t *buf = fb_fragment->buf; + ray_camera_fragment_t fragment; ray_ray_t ray; - uint32_t *buf = fragment->buf; - unsigned stride = fragment->stride / 4; - ray_camera_frame_begin(camera, fragment, &ray, &frame); + ray_camera_fragment_begin(&scene->_prepared.frame, fb_fragment, &ray, &fragment); do { do { *buf = ray_color_to_uint32_rgb(trace_ray(scene, &ray)); buf++; - } while (ray_camera_frame_x_step(&frame)); + } while (ray_camera_fragment_x_step(&fragment)); buf += stride; - } while (ray_camera_frame_y_step(&frame)); + } while (ray_camera_fragment_y_step(&fragment)); } @@ -216,6 +216,7 @@ void ray_scene_prepare(ray_scene_t *scene, ray_camera_t *camera) unsigned i; scene->_prepared.ambient_light = ray_3f_mult_scalar(&scene->ambient_color, scene->ambient_brightness); + ray_camera_frame_prepare(camera, &scene->_prepared.frame); for (i = 0; i < scene->n_objects; i++) ray_object_prepare(&scene->objects[i], camera); diff --git a/src/modules/ray/ray_scene.h b/src/modules/ray/ray_scene.h index 98928ee..1fe736c 100644 --- a/src/modules/ray/ray_scene.h +++ b/src/modules/ray/ray_scene.h @@ -20,11 +20,12 @@ typedef struct ray_scene_t { float ambient_brightness; struct { - ray_color_t ambient_light; + ray_color_t ambient_light; + ray_camera_frame_t frame; } _prepared; } ray_scene_t; void ray_scene_prepare(ray_scene_t *scene, ray_camera_t *camera); -void ray_scene_render_fragment(ray_scene_t *scene, ray_camera_t *camera, fb_fragment_t *fragment); +void ray_scene_render_fragment(ray_scene_t *scene, fb_fragment_t *fb_fragment); #endif -- cgit v1.2.1