diff options
author | Vito Caputo <vcaputo@pengaru.com> | 2020-01-12 16:32:59 -0800 |
---|---|---|
committer | Vito Caputo <vcaputo@pengaru.com> | 2020-01-12 16:43:57 -0800 |
commit | 179341f758ca86d0f8d820713cf35bd281f01755 (patch) | |
tree | ebce00ed744bca69754b0d04498e1f17d6d4c3d2 /src | |
parent | 14a6d7be88955affdfbdbb8293bf5bca191ee7ff (diff) |
libs/ray: decouple film and frame dimensions
The existing code conflated the rendered frame dimensions with
what's essentially the virtual camera's film dimensions. That
resulted in a viewing frustum depending on the rendered frame
dimensions. Smaller frames (like in the montage module) would
show a smaller viewport into the same scene.
Now the view into the scene always shows the same viewport in
terms of the frustum dimensions for a given combination of
focal_length and film_{width,height}.
The rendered frame is essentially a sampling of the 2D plane
(the virtual film) intersecting the frustum.
Nothing is done to try enforce a specific aspect ratio or any
such magic. The caller is expected to manage this for now, or
just ignore it and let the output be stretched when the aspect
ratio of the output doesn't match the virtual film's aspect
ratio.
In the future it might be interesting to support letter boxing or
such things for preserving the film's aspect ratio.
For now the ray module just lets things be stretched, with
hard-coded film dimensions of something approximately consistent
with the past viewport.
The ray module could make some effort to fit the hard-coded film
dimensions to the runtime aspect ratio for the frame to be
rendered, tweaking things as needed but generally preserving the
general hard-coded dimensions. Allowing the frustum to be
minimally adjusted to fit the circumstances... that might also be
worth shoving into libray. Something of a automatic fitting
mode for the camera.
Diffstat (limited to 'src')
-rw-r--r-- | src/libs/ray/ray_camera.c | 10 | ||||
-rw-r--r-- | src/libs/ray/ray_camera.h | 16 | ||||
-rw-r--r-- | src/libs/ray/ray_render.c | 4 | ||||
-rw-r--r-- | src/libs/ray/ray_render.h | 2 | ||||
-rw-r--r-- | src/modules/ray/ray.c | 12 |
5 files changed, 28 insertions, 16 deletions
diff --git a/src/libs/ray/ray_camera.c b/src/libs/ray/ray_camera.c index b942cf3..a0e3d02 100644 --- a/src/libs/ray/ray_camera.c +++ b/src/libs/ray/ray_camera.c @@ -24,8 +24,8 @@ static ray_3f_t project_corner(ray_3f_t *forward, ray_3f_t *left, ray_3f_t *up, 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; + float half_horiz = camera->film_width * 0.5f; + float half_vert = camera->film_height * 0.5f; ray_euler_basis(&camera->orientation, &forward, &up, &left); right = ray_3f_negate(&left); @@ -39,14 +39,14 @@ static void project_corners(const ray_camera_t *camera, ray_camera_frame_t *fram /* 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) +void ray_camera_frame_prepare(const ray_camera_t *camera, unsigned frame_width, unsigned frame_height, 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; + res_frame->x_delta = 1.0f / (float)frame_width; + res_frame->y_delta = 1.0f / (float)frame_height; } diff --git a/src/libs/ray/ray_camera.h b/src/libs/ray/ray_camera.h index e393beb..0a8af2a 100644 --- a/src/libs/ray/ray_camera.h +++ b/src/libs/ray/ray_camera.h @@ -13,9 +13,19 @@ 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 */ + + /* Units for focal_length, width, and height, are undefined in absolute terms or any + * kind of SI unit - they're the same units of the virtual scene shared + * with the objects. + */ float focal_length; /* controls the field of view */ - unsigned width; /* width of camera viewport in pixels */ - unsigned height; /* height of camera viewport in pixels */ + + /* XXX: Note these are not the same as the rendered frame width and height in pixels, + * these influence the frustum size and shape in the 3D world by controlling the 2D + * plane size and shape that frustum intersects. + */ + float film_width; /* width of camera's virtual "film" */ + float film_height; /* height of camera's virtual "film" */ } ray_camera_t; @@ -38,7 +48,7 @@ typedef struct ray_camera_fragment_t { } ray_camera_fragment_t; -void ray_camera_frame_prepare(const ray_camera_t *camera, ray_camera_frame_t *res_frame); +void ray_camera_frame_prepare(const ray_camera_t *camera, unsigned frame_width, unsigned frame_height, 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); diff --git a/src/libs/ray/ray_render.c b/src/libs/ray/ray_render.c index 1c7c79c..dbbfb47 100644 --- a/src/libs/ray/ray_render.c +++ b/src/libs/ray/ray_render.c @@ -221,7 +221,7 @@ void ray_render_trace_fragment(ray_render_t *render, fb_fragment_t *fb_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 * ray_render_new(const ray_scene_t *scene, const ray_camera_t *camera, unsigned frame_width, unsigned frame_height) { ray_render_t *render; ray_object_t *object; @@ -239,7 +239,7 @@ ray_render_t * ray_render_new(const ray_scene_t *scene, const ray_camera_t *came render->ambient_light = ray_3f_mult_scalar(&scene->ambient_color, scene->ambient_brightness); ray_gamma_prepare(scene->gamma, &render->gamma); - ray_camera_frame_prepare(camera, &render->frame); + ray_camera_frame_prepare(camera, frame_width, frame_height, &render->frame); for (i = 0, object = scene->objects; object->type; object++) render->objects[i++] = ray_render_object_prepare(object, camera); diff --git a/src/libs/ray/ray_render.h b/src/libs/ray/ray_render.h index dfd769f..69daf86 100644 --- a/src/libs/ray/ray_render.h +++ b/src/libs/ray/ray_render.h @@ -8,7 +8,7 @@ typedef struct ray_render_t ray_render_t; -ray_render_t * ray_render_new(const ray_scene_t *scene, const ray_camera_t *camera); +ray_render_t * ray_render_new(const ray_scene_t *scene, const ray_camera_t *camera, unsigned frame_width, unsigned frame_height); void ray_render_free(ray_render_t *render); void ray_render_trace_fragment(ray_render_t *render, fb_fragment_t *fb_fragment); diff --git a/src/modules/ray/ray.c b/src/modules/ray/ray.c index dd33b19..a9d78c4 100644 --- a/src/modules/ray/ray.c +++ b/src/modules/ray/ray.c @@ -106,6 +106,12 @@ static ray_camera_t camera = { .roll = RAY_EULER_DEGREES(0.0f), }, .focal_length = 700.0f, + + /* TODO: these should probably be adjusted @ runtime to at least fit the aspect ratio + * of the frame being rendered. + */ + .film_width = 1000.f, + .film_height = 900.f, }; static ray_scene_t scene = { @@ -148,10 +154,6 @@ static void ray_prepare_frame(void *context, unsigned n_cpus, fb_fragment_t *fra ray_context_t *ctxt = context; *res_fragmenter = ray_fragmenter; - - /* TODO: the camera doesn't need the width and height anymore, the fragment has the frame_width/frame_height */ - camera.width = fragment->frame_width, - camera.height = fragment->frame_height, #if 1 /* animated point light source */ @@ -174,7 +176,7 @@ static void ray_prepare_frame(void *context, unsigned n_cpus, fb_fragment_t *fra /* tilt camera pitch in time with up and down movements, phase shifted appreciably */ camera.orientation.pitch = -(sinf((M_PI * 1.5f) + r * 1.3f) * .6f + -.35f); #endif - ctxt->render = ray_render_new(&scene, &camera); + ctxt->render = ray_render_new(&scene, &camera, fragment->frame_width, fragment->frame_height); } |