summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorVito Caputo <vcaputo@pengaru.com>2017-09-13 13:55:22 -0700
committerVito Caputo <vcaputo@pengaru.com>2017-09-13 13:59:19 -0700
commit121846b0e35607bf8b48d5ce304a65e2657be455 (patch)
tree7877e16b4b4949d65f3fc46373c5850cb72b4f88 /src
parentcf586253932e04f3c5a2be2c3d6d3ff5b1301ce0 (diff)
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...)
Diffstat (limited to 'src')
-rw-r--r--src/modules/ray/ray.c2
-rw-r--r--src/modules/ray/ray_camera.c83
-rw-r--r--src/modules/ray/ray_camera.h59
-rw-r--r--src/modules/ray/ray_scene.c15
-rw-r--r--src/modules/ray/ray_scene.h5
5 files changed, 79 insertions, 85 deletions
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
© All Rights Reserved