commit 11aad71d1da267c450f985bc8d69f0ef89340cb7
parent 57605ea5785e9e384689d9519b280a5af8a7a0e2
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Wed, 28 Jul 2021 16:58:36 +0200
Implement the orthographic camera model
Diffstat:
6 files changed, 302 insertions(+), 11 deletions(-)
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
@@ -44,6 +44,7 @@ set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH})
set(SCAM_FILES_SRC
scam.c
scam_log.c
+ scam_orthographic.c
scam_perspective.c)
set(SCAM_FILES_INC
scam_c.h
diff --git a/src/scam.c b/src/scam.c
@@ -74,6 +74,9 @@ scam_generate_ray
}
switch(cam->type) {
+ case SCAM_ORTHOGRAPHIC:
+ orthographic_generate_ray(cam, sample, ray);
+ break;
case SCAM_PERSPECTIVE:
perspective_generate_ray(cam, sample, ray);
break;
diff --git a/src/scam.h b/src/scam.h
@@ -37,6 +37,7 @@
#endif
enum scam_type {
+ SCAM_ORTHOGRAPHIC,
SCAM_PERSPECTIVE,
SCAM_TYPES_COUNT__,
SCAM_NONE = SCAM_TYPES_COUNT__
@@ -57,10 +58,33 @@ struct scam_ray {
#define SCAM_RAY_NULL__ {{0,0,0},{0,0,0}}
static const struct scam_ray SCAM_RAY_NULL = SCAM_RAY_NULL__;
+struct scam_orthographic_args {
+ double position[3]; /* Lens position */
+ double target[3]; /* Targeted point. target-position = image plane normal */
+ double up[3]; /* Vector defining the upward orientation */
+ double height; /* Height of the image plane */
+ double aspect_ratio; /* Image plane aspect ratio (width / height) */
+ double lens_radius; /* Radius of 0 <=> pinhole */
+
+ /* Distance to focus on. Used when lens_radius != 0 */
+ double focal_distance;
+};
+#define SCAM_ORTHOGRAPHIC_ARGS_DEFAULT__ { \
+ {0,0,0}, /* Position */ \
+ {0,1,0}, /* Target */ \
+ {0,0,1}, /* Up */ \
+ 1.0, /* Height of the image plane */ \
+ 1.0, /* Aspect ratio */ \
+ 0.0, /* Lens radius */ \
+ 1.0 /* Focal distance. Unused for radius == 0 */ \
+}
+static const struct scam_orthographic_args SCAM_ORTHOGRAPHIC_ARGS_DEFAULT =
+ SCAM_ORTHOGRAPHIC_ARGS_DEFAULT__;
+
struct scam_perspective_args {
double position[3]; /* Lens position */
double target[3]; /* Targeted point. target-position = image plane normal */
- double up[3]; /* Vector defining the upward orientation */
+ double up[3]; /* Vector defining the upward orientation */
double aspect_ratio; /* Image plane aspect ratio (width / height) */
double lens_radius; /* Radius of 0 <=> pinhole */
@@ -79,9 +103,9 @@ struct scam_perspective_args {
1.0, /* Aspect ratio */ \
0.0, /* Lens radius */ \
1.22173047639603070383, /* Fov ~70 degrees */ \
- 1.0, /* Focal distance. Unused for radius == 0 */ \
+ 1.0 /* Focal distance. Unused for radius == 0 */ \
}
-static const struct scam_perspective_args SCAM_PERSPECTIVE_ARGS_DEFAULT =
+static const struct scam_perspective_args SCAM_PERSPECTIVE_ARGS_DEFAULT =
SCAM_PERSPECTIVE_ARGS_DEFAULT__;
/* Forward declaration of external data types */
@@ -105,6 +129,14 @@ scam_create_perspective
struct scam** camera);
SCAM_API res_T
+scam_create_orthographic
+ (struct logger* logger, /* NULL <=> use builtin logger */
+ struct mem_allocator* allocator, /* NULL <=> use default allocator */
+ const int verbose, /* Verbosity level */
+ struct scam_orthographic_args* args,
+ struct scam** camera);
+
+SCAM_API res_T
scam_generate_ray
(const struct scam* cam,
const struct scam_sample* sample,
diff --git a/src/scam_c.h b/src/scam_c.h
@@ -43,10 +43,33 @@ struct perspective {
}
static const struct perspective PERSPECTIVE_DEFAULT = PERSPECTIVE_DEFAULT__;
+struct orthographic {
+ double screen2world[9];
+ double camera2world[9];
+
+ double position[3]; /* Lens position */
+
+ double height; /* Height of the image plane */
+ double aspect_ratio; /* width / height */
+ double lens_radius; /* 0 <=> pinhole camera */
+ double focal_distance; /* Unused when lens_radius == 0 */
+};
+#define ORTHOGRAPHIC_DEFAULT__ { \
+ {1,0,0, 0,1,0, 0,0,1}, /* Screen to world transformation */ \
+ {1,0,0, 0,1,0, 0,0,1}, /* Camera to world transformation */ \
+ {0,0,0}, /* Lens position */ \
+ 1.0, /* Height */ \
+ 1.0, /* Aspect ratio */ \
+ 0.0, /* Lens radius */ \
+ -1.0 /* Focal distance */ \
+}
+static const struct orthographic ORTHOGRAPHIC_DEFAULT = ORTHOGRAPHIC_DEFAULT__;
+
struct scam {
enum scam_type type;
union {
struct perspective persp;
+ struct orthographic ortho;
} param;
int verbose;
@@ -66,6 +89,12 @@ camera_create
struct scam** scam);
extern LOCAL_SYM void
+orthographic_generate_ray
+ (const struct scam* cam,
+ const struct scam_sample* sample,
+ struct scam_ray* ray);
+
+extern LOCAL_SYM void
perspective_generate_ray
(const struct scam* cam,
const struct scam_sample* sample,
diff --git a/src/scam_orthographic.c b/src/scam_orthographic.c
@@ -0,0 +1,230 @@
+/* Copyright (C) 2021 |Meso|Star> (contact@meso-star.com)
+ *
+ * Tyhis program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+#include "scam_c.h"
+#include "scam_log.h"
+
+#include <rsys/double3.h>
+#include <rsys/double33.h>
+#include <rsys/math.h>
+
+#include <math.h>
+
+/*******************************************************************************
+ * Helper functions
+ ******************************************************************************/
+static res_T
+setup_orthographic(struct scam* cam, const struct scam_orthographic_args* args)
+{
+ double x[3], y[3], z[3];
+ int pinhole = 0;
+ res_T res = RES_OK;
+ ASSERT(cam && args && cam->type == SCAM_ORTHOGRAPHIC);
+
+ cam->param.ortho = ORTHOGRAPHIC_DEFAULT;
+ pinhole = args->lens_radius == 0;
+
+ if(args->aspect_ratio <= 0) {
+ log_err(cam,
+ "orthographic camera: invalid aspect ratio: %g\n",
+ args->aspect_ratio);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ if(args->height <= 0) {
+ log_err(cam,
+ "orthographic camera: invalid height: %g\n",
+ args->height);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ if(args->lens_radius < 0) {
+ log_err(cam,
+ "orthographic camera: invalid negative lens radius: %g\n",
+ args->lens_radius);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ if(!pinhole && args->focal_distance < 0) {
+ log_err(cam,
+ "orthographic camera: invalid negative focal distance: %g\n",
+ args->focal_distance);
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ if(d3_normalize(z, d3_sub(z, args->target, args->position)) <= 0
+ || d3_normalize(x, d3_cross(x, z, args->up)) <= 0
+ || d3_normalize(y, d3_cross(y, z, x)) <= 0) {
+ log_err(cam,
+ "orthographic camera: invalid point of view:\n"
+ " position = %g %g %g\n"
+ " target = %g %g %g\n"
+ " up = %g %g %g\n",
+ SPLIT3(args->position), SPLIT3(args->target), SPLIT3(args->up));
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ cam->param.ortho.height = args->height;
+ cam->param.ortho.aspect_ratio = args->aspect_ratio;
+ cam->param.ortho.lens_radius= args->lens_radius;
+ cam->param.ortho.focal_distance = args->focal_distance;
+
+ d3_set(cam->param.ortho.position, args->position);
+
+ d3_muld(cam->param.ortho.screen2world+0, x, 0.5*args->height*args->aspect_ratio);
+ d3_muld(cam->param.ortho.screen2world+3, y, 0.5*args->height);
+ d3_set (cam->param.ortho.screen2world+6, z);
+
+ d3_set(cam->param.ortho.camera2world+0, x);
+ d3_set(cam->param.ortho.camera2world+3, y);
+ d3_set(cam->param.ortho.camera2world+6, z);
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+static INLINE void
+pinhole_generate_ray
+ (const struct scam* cam,
+ const struct scam_sample* sample,
+ struct scam_ray* ray)
+{
+ double x[3], y[3];
+ double pos[3];
+
+ ASSERT(cam && sample && ray);
+ ASSERT(cam->param.ortho.lens_radius == 0);
+ ASSERT(cam->type == SCAM_ORTHOGRAPHIC);
+ ASSERT(0 <= sample->film[0] && sample->film[0] < 1);
+ ASSERT(0 <= sample->film[1] && sample->film[1] < 1);
+
+ /* Transform the sampled position in screen space */
+ pos[0] = sample->film[0]*2-1;
+ pos[1] = sample->film[1]*2-1;
+ pos[2] = 0;
+
+ /* Transform the sampled position in world space */
+ d3_muld(x, cam->param.ortho.screen2world+0, pos[0]);
+ d3_muld(y, cam->param.ortho.screen2world+3, pos[1]);
+ d3_add(ray->org, x, y);
+ d3_add(ray->org, ray->org, cam->param.ortho.position);
+
+ /* Setup the ray direction to the image plane normal, i.e. the z axis of the
+ * camera */
+ d3_set(ray->dir, cam->param.ortho.camera2world+9);
+}
+
+static INLINE void
+thin_lens_generate_ray
+ (const struct scam* cam,
+ const struct scam_sample* sample,
+ struct scam_ray* ray)
+{
+ double focus_pt[3];
+ double theta;
+ double len;
+ double r;
+ (void)len;
+
+ ASSERT(cam && sample && ray);
+ ASSERT(cam->param.ortho.lens_radius > 0);
+ ASSERT(cam->type == SCAM_PERSPECTIVE);
+ ASSERT(0 <= sample->film[0] && sample->film[0] < 1);
+ ASSERT(0 <= sample->film[1] && sample->film[1] < 1);
+ ASSERT(0 <= sample->lens[0] && sample->lens[0] < 1);
+ ASSERT(0 <= sample->lens[1] && sample->lens[1] < 1);
+
+ /* find the focus point by intersecting the image plane normal with the focus
+ * plane in camera space */
+ focus_pt[0] = 0;
+ focus_pt[1] = 0;
+ focus_pt[2] = cam->param.ortho.focal_distance;
+
+ /* Uniformly sample a position onto the lens in camera space */
+ theta = 2 * PI * sample->lens[0];
+ r = cam->param.ortho.lens_radius * sqrt(sample->lens[1]);
+ ray->org[0] = r * cos(theta);
+ ray->org[1] = r * sin(theta);
+ ray->org[2] = 0;
+
+ /* Compute the ray direction in camera space */
+ d3_sub(ray->dir, focus_pt, ray->org);
+ len = d3_normalize(ray->dir, ray->dir);
+ ASSERT(len >= 1.e-6);
+
+ /* Transform the ray from camera space to world space */
+ d33_muld3(ray->dir, cam->param.ortho.camera2world, ray->dir);
+ d33_muld3(ray->org, cam->param.ortho.camera2world, ray->org);
+ d3_add(ray->org, cam->param.persp.position, ray->org);
+}
+
+/*******************************************************************************
+ * Exported function
+ ******************************************************************************/
+SCAM_API res_T
+scam_create_orthographic
+ (struct logger* logger, /* NULL <=> use builtin logger */
+ struct mem_allocator* allocator, /* NULL <=> use default allocator */
+ const int verbose, /* Verbosity level */
+ struct scam_orthographic_args* args,
+ struct scam** out_cam)
+{
+ struct scam* cam = NULL;
+ res_T res = RES_OK;
+
+ if(!args || !out_cam) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
+ res = camera_create(logger, allocator, verbose, SCAM_ORTHOGRAPHIC, &cam);
+ if(res != RES_OK) goto error;
+ res = setup_orthographic(cam, args);
+ if(res != RES_OK) goto error;
+
+exit:
+ if(out_cam) *out_cam = cam;
+ return res;
+error:
+ if(cam) {
+ SCAM(ref_put(cam));
+ cam = NULL;
+ }
+ goto exit;
+}
+
+/*******************************************************************************
+ * Local function
+ ******************************************************************************/
+void
+orthographic_generate_ray
+ (const struct scam* cam,
+ const struct scam_sample* sample,
+ struct scam_ray* ray)
+{
+ ASSERT(cam && cam->type == SCAM_ORTHOGRAPHIC);
+ if(cam->param.ortho.lens_radius == 0) {
+ pinhole_generate_ray(cam, sample, ray);
+ } else {
+ thin_lens_generate_ray(cam, sample, ray);
+ }
+}
diff --git a/src/scam_perspective.c b/src/scam_perspective.c
@@ -23,7 +23,7 @@
#include <math.h>
/*******************************************************************************
- * Helper function
+ * Helper functions
******************************************************************************/
static res_T
setup_perspective(struct scam* cam, const struct scam_perspective_args* args)
@@ -60,7 +60,7 @@ setup_perspective(struct scam* cam, const struct scam_perspective_args* args)
goto error;
}
- if(pinhole && (args->field_of_view <= 0 || args->field_of_view >= PI)) {
+ if(args->field_of_view <= 0 || args->field_of_view >= PI) {
log_err(cam,
"perspective camera: invalid vertical field of view: %g\n",
args->field_of_view);
@@ -198,7 +198,7 @@ thin_lens_generate_ray
}
/*******************************************************************************
- * Exported function
+ * Exported functions
******************************************************************************/
SCAM_API res_T
scam_create_perspective
@@ -265,11 +265,7 @@ perspective_generate_ray
const struct scam_sample* sample,
struct scam_ray* ray)
{
- ASSERT(cam && sample && ray);
- ASSERT(cam->type == SCAM_PERSPECTIVE);
- ASSERT(0 <= sample->film[0] && sample->film[0] < 1);
- ASSERT(0 <= sample->film[1] && sample->film[1] < 1);
-
+ ASSERT(cam && cam->type == SCAM_PERSPECTIVE);
if(cam->param.persp.lens_radius == 0) {
pinhole_generate_ray(cam, sample, ray);
} else {