commit c91dba27d066e9bb411b9d36af7db68cf7a5c82c
parent 8cca97983601296a007b151131168ea2e9e66563
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Tue, 22 Nov 2022 18:11:48 +0100
Add and test the scam_perspective_get_solid_angle function
Diffstat:
5 files changed, 78 insertions(+), 28 deletions(-)
diff --git a/src/scam.h b/src/scam.h
@@ -161,6 +161,11 @@ scam_field_of_view_to_focal_length
const double field_of_view,
double* focal_length);
+SCAM_API res_T
+scam_perspective_get_solid_angle
+ (const struct scam* camera,
+ double* solid_angle); /* In sr */
+
END_DECLS
#endif /* SCAM_H */
diff --git a/src/scam_c.h b/src/scam_c.h
@@ -27,6 +27,7 @@ struct perspective {
double position[3]; /* Lens position */
+ double solid_angle; /* In sr */
double rcp_tan_half_fov; /* 1 / tan(vertical_fov / 2) */
double aspect_ratio; /* width / height */
double lens_radius; /* 0 <=> pinhole camera */
@@ -36,6 +37,7 @@ struct perspective {
{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 */ \
+ 0.60111772988434627069, /* horizontal_fov * 2*sin(vertical_fov/2) */ \
1.0, /* 1/tan(vertical_fov/2) */ \
1.0, /* Aspect ratio */ \
0.0, /* Lens radius */ \
diff --git a/src/scam_perspective.c b/src/scam_perspective.c
@@ -26,48 +26,55 @@
* Helper functions
******************************************************************************/
static res_T
-setup_perspective(struct scam* cam, const struct scam_perspective_args* args)
+check_perspective_args
+ (struct scam* cam,
+ const struct scam_perspective_args* args)
{
- double x[3], y[3], z[3];
- int pinhole = 0;
- res_T res = RES_OK;
- ASSERT(cam && args && cam->type == SCAM_PERSPECTIVE);
-
- cam->param.persp = PERSPECTIVE_DEFAULT;
- pinhole = args->lens_radius == 0;
+ if(!args) return RES_BAD_ARG;
+ /* Invalid aspect ratio */
if(args->aspect_ratio <= 0) {
- log_err(cam,
- "perspective camera: invalid aspect ratio: %g\n",
+ log_err(cam,"perspective camera: invalid aspect ratio: %g\n",
args->aspect_ratio);
- res = RES_BAD_ARG;
- goto error;
+ return RES_BAD_ARG;
}
+ /* Invalid lens radius */
if(args->lens_radius < 0) {
- log_err(cam,
- "perspective camera: invalid negative lens radius: %g\n",
+ log_err(cam,"perspective camera: invalid negative lens radius: %g\n",
args->lens_radius);
- res = RES_BAD_ARG;
- goto error;
+ return RES_BAD_ARG;
}
- if(!pinhole && args->focal_distance < 0) {
- log_err(cam,
- "perspective camera: invalid negative focal distance: %g\n",
+ /* Invalid focal distance */
+ if(args->lens_radius > 0 && args->focal_distance < 0) {
+ log_err(cam, "perspective camera: invalid negative focal distance: %g\n",
args->focal_distance);
- res = RES_BAD_ARG;
- goto error;
+ return RES_BAD_ARG;
}
+ /* Invalid field of view */
if(args->field_of_view <= 0 || args->field_of_view >= PI) {
- log_err(cam,
- "perspective camera: invalid vertical field of view: %g\n",
+ log_err(cam, "perspective camera: invalid vertical field of view: %g\n",
args->field_of_view);
- res = RES_BAD_ARG;
- goto error;
+ return RES_BAD_ARG;
}
+ return RES_OK;
+}
+
+static res_T
+setup_perspective(struct scam* cam, const struct scam_perspective_args* args)
+{
+ double hfov; /* Horizotal field of view */
+ double half_vfov; /* (Vertical vield of view) / 2 */
+ double tan_half_vfov;
+ double x[3], y[3], z[3];
+ res_T res = RES_OK;
+ ASSERT(cam && args && cam->type == SCAM_PERSPECTIVE);
+
+ cam->param.persp = PERSPECTIVE_DEFAULT;
+
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) {
@@ -81,7 +88,10 @@ setup_perspective(struct scam* cam, const struct scam_perspective_args* args)
goto error;
}
- cam->param.persp.rcp_tan_half_fov = 1.0/tan(args->field_of_view*0.5);
+ half_vfov = args->field_of_view*0.5;
+ tan_half_vfov = tan(half_vfov);
+
+ cam->param.persp.rcp_tan_half_fov = 1.0/tan_half_vfov;
cam->param.persp.aspect_ratio = args->aspect_ratio;
cam->param.persp.lens_radius = args->lens_radius;
cam->param.persp.focal_distance = args->focal_distance;
@@ -96,6 +106,10 @@ setup_perspective(struct scam* cam, const struct scam_perspective_args* args)
d3_set(cam->param.persp.camera2world+3, y);
d3_set(cam->param.persp.camera2world+6, z);
+ /* Compute the solid angle of the camera */
+ hfov = 2*atan(args->aspect_ratio * tan_half_vfov);
+ cam->param.persp.solid_angle = hfov * 2*sin(half_vfov);
+
exit:
return res;
error:
@@ -215,9 +229,10 @@ scam_create_perspective
res = RES_BAD_ARG;
goto error;
}
-
res = camera_create(logger, allocator, verbose, SCAM_PERSPECTIVE, &cam);
if(res != RES_OK) goto error;
+ res = check_perspective_args(cam, args);
+ if(res != RES_OK) goto error;
res = setup_perspective(cam, args);
if(res != RES_OK) goto error;
@@ -233,6 +248,16 @@ error:
}
res_T
+scam_perspective_get_solid_angle(const struct scam* camera, double* solid_angle)
+{
+ if(!camera || camera->type != SCAM_PERSPECTIVE || !solid_angle)
+ return RES_BAD_ARG;
+
+ *solid_angle = camera->param.persp.solid_angle;
+ return RES_OK;
+}
+
+res_T
scam_focal_length_to_field_of_view
(const double lens_radius,
const double focal_length,
diff --git a/src/test_scam_orthographic.c b/src/test_scam_orthographic.c
@@ -40,6 +40,7 @@ main(int argc, char** argv)
double axis_x[3];
double axis_y[3];
double axis_z[3];
+ double solid_angle;
size_t i;
enum scam_type type = SCAM_NONE;
(void)argc, (void)argv;
@@ -92,6 +93,7 @@ main(int argc, char** argv)
args.aspect_ratio = 16.0/9.0;
CHK(scam_create_orthographic(NULL, NULL, 1, &args, &cam) == RES_OK);
+ CHK(scam_perspective_get_solid_angle(cam, &solid_angle) == RES_BAD_ARG);
/* Precompute camera parameters */
d3_normalize(axis_z, d3_sub(axis_z, args.target, args.position));
diff --git a/src/test_scam_perspective_pinhole.c b/src/test_scam_perspective_pinhole.c
@@ -48,6 +48,8 @@ main(int argc, char** argv)
double sin_hori_hfov; /* Sinus of the horizontal half field of view */
double sin_vert_hfov; /* Sinos of the vertical half field of view */
double img_depth;
+ double solid_angle;
+ double ref;
size_t i = 0;
enum scam_type type = SCAM_NONE;
(void)argc, (void)argv;
@@ -112,9 +114,23 @@ main(int argc, char** argv)
args.up[1] = rand_canonical();
args.up[2] = rand_canonical();
args.field_of_view = PI/2.0;
- args.aspect_ratio = 4.0/3.0;
+ args.aspect_ratio = 1.0;
CHK(scam_create_perspective(NULL, NULL, 1, &args, &cam) == RES_OK);
+ CHK(scam_perspective_get_solid_angle(NULL, &solid_angle) == RES_BAD_ARG);
+ CHK(scam_perspective_get_solid_angle(cam, NULL) == RES_BAD_ARG);
+ CHK(scam_perspective_get_solid_angle(cam, &solid_angle) == RES_OK);
+
+ ref = args.field_of_view * 2*sin(args.field_of_view/2);
+ CHK(eq_eps(solid_angle, ref, 1.e-6));
+ CHK(scam_ref_put(cam) == RES_OK);
+
+ args.aspect_ratio = 4.0/3.0;
+ CHK(scam_create_perspective(NULL, NULL, 1, &args, &cam) == RES_OK);
+
+ CHK(scam_perspective_get_solid_angle(cam, &solid_angle) == RES_OK);
+ ref = 2.6227869472431911;
+ CHK(eq_eps(solid_angle, ref, 1.e-6));
/* Precompute some view frustum constants */
d3_normalize(axis_z, d3_sub(axis_z, args.target, args.position));