star-camera

Camera models
git clone git://git.meso-star.fr/star-camera.git
Log | Files | Refs | README | LICENSE

test_scam_perspective_thin_lens.c (5875B)


      1 /* Copyright (C) 2021-2023 |Méso|Star> (contact@meso-star.com)
      2  *
      3  * This program is free software: you can redistribute it and/or modify
      4  * it under the terms of the GNU General Public License as published by
      5  * the Free Software Foundation, either version 3 of the License, or
      6  * (at your option) any later version.
      7  *
      8  * This program is distributed in the hope that it will be useful,
      9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
     11  * GNU General Public License for more details.
     12  *
     13  * You should have received a copy of the GNU General Public License
     14  * along with this program. If not, see <http://www.gnu.org/licenses/>. */
     15 
     16 #define _POSIX_C_SOURCE 200112L /* nextafterf */
     17 
     18 #include "scam.h"
     19 #include "test_scam_utils.h"
     20 
     21 #include <rsys/double2.h>
     22 #include <rsys/double3.h>
     23 #include <rsys/double33.h>
     24 #include <rsys/math.h>
     25 #include <rsys/mem_allocator.h>
     26 
     27 int
     28 main(int argc, char** argv)
     29 {
     30   struct scam* cam = NULL;
     31   struct scam_perspective_args args = SCAM_PERSPECTIVE_ARGS_DEFAULT;
     32   struct scam_sample sample = SCAM_SAMPLE_NULL;
     33   struct scam_ray ray = SCAM_RAY_NULL;
     34   const size_t nsamps = 10000;
     35   size_t i;
     36   double transform[9];
     37   double axis_x[3];
     38   double axis_y[3];
     39   double axis_z[3];
     40   double hori_hfov; /* horizontal half field of view */
     41   double sin_hori_hfov; /* Sinus of the horizontal half field of view */
     42   double sin_vert_hfov; /* Sinos of the vertical half field of view */
     43   double depth;
     44   double fov;
     45   double length;
     46   double radius;
     47   double ref;
     48   (void)argc, (void)argv;
     49 
     50   args.lens_radius = -1;
     51   CHK(scam_create_perspective(NULL, NULL, 1, &args, &cam) == RES_BAD_ARG);
     52   args.lens_radius = 1;
     53   args.focal_distance = -1;
     54   CHK(scam_create_perspective(NULL, NULL, 1, &args, &cam) == RES_BAD_ARG);
     55   args.focal_distance = 1;
     56   CHK(scam_create_perspective(NULL, NULL, 1, &args, &cam) == RES_OK);
     57   CHK(scam_ref_put(cam) == RES_OK);
     58 
     59   length = 1.2;
     60   radius = 0.01;
     61   CHK(scam_focal_length_to_field_of_view(-1, length, &fov) == RES_BAD_ARG);
     62   CHK(scam_focal_length_to_field_of_view(radius, 0, &fov) == RES_BAD_ARG);
     63   CHK(scam_focal_length_to_field_of_view(radius, length, &fov) == RES_OK);
     64 
     65   ref = 2*atan(radius/length);
     66   CHK(eq_eps(fov, ref, ref*1.e-6));
     67 
     68   ref = length;
     69   CHK(scam_field_of_view_to_focal_length(-1, fov, &length) == RES_BAD_ARG);
     70   CHK(scam_field_of_view_to_focal_length(radius, 0, &length) == RES_BAD_ARG);
     71   CHK(scam_field_of_view_to_focal_length(radius, PI, &length) == RES_BAD_ARG);
     72   CHK(scam_field_of_view_to_focal_length(radius, fov, &length) == RES_OK);
     73 
     74   CHK(eq_eps(length, ref, ref*1.e-6));
     75 
     76   args.position[0] = rand_canonical();
     77   args.position[1] = rand_canonical();
     78   args.position[2] = rand_canonical();
     79   args.target[0] = rand_canonical();
     80   args.target[1] = rand_canonical();
     81   args.target[2] = rand_canonical();
     82   args.up[0] = rand_canonical();
     83   args.up[1] = rand_canonical();
     84   args.up[2] = rand_canonical();
     85   args.field_of_view = PI/2.0;
     86   args.aspect_ratio = 4.0/3.0;
     87   args.lens_radius = 0.01;
     88   args.focal_distance = 12.34;
     89 
     90   CHK(scam_create_perspective(NULL, NULL, 1, &args, &cam) == RES_OK);
     91 
     92   /* Precompute some view frustum constants */
     93   d3_normalize(axis_z, d3_sub(axis_z, args.target, args.position));
     94   d3_normalize(axis_x, d3_cross(axis_x, axis_z, args.up));
     95   d3_normalize(axis_y, d3_cross(axis_y, axis_z, axis_x));
     96   depth = 1.0/tan(args.field_of_view*0.5);
     97   hori_hfov = atan(args.aspect_ratio / depth);
     98   sin_hori_hfov = sin(hori_hfov);
     99   sin_vert_hfov = sin(args.field_of_view*0.5);
    100 
    101   /* Compute the world to camera space transformation */
    102   d3_set(transform + 0, axis_x);
    103   d3_set(transform + 3, axis_y);
    104   d3_set(transform + 6, axis_z);
    105   d33_transpose(transform, transform);
    106 
    107   sample.lens[0] = nextafterf(0, -1);
    108   CHK(scam_generate_ray(cam, &sample, &ray) == RES_BAD_ARG);
    109   sample.lens[0] = 1;
    110   CHK(scam_generate_ray(cam, &sample, &ray) == RES_BAD_ARG);
    111   sample.lens[0] = 0;
    112   sample.lens[1] = nextafterf(0, -1);
    113   CHK(scam_generate_ray(cam, &sample, &ray) == RES_BAD_ARG);
    114   sample.lens[1] = 1;
    115   CHK(scam_generate_ray(cam, &sample, &ray) == RES_BAD_ARG);
    116   sample.film[0] = sample.lens[0] = 0;
    117   sample.film[1] = sample.lens[1] = nextafterf(1, 0);
    118   CHK(scam_generate_ray(cam, &sample, &ray) == RES_OK);
    119 
    120   FOR_EACH(i, 0, nsamps) {
    121     double cos_ray_axis_x;
    122     double cos_ray_axis_y;
    123     double cos_ray_axis_z;
    124     double dir[3];
    125     double pos[3];
    126     double dst;
    127 
    128     sample.film[0] = rand_canonical();
    129     sample.film[1] = rand_canonical();
    130     sample.lens[0] = rand_canonical();
    131     sample.lens[1] = rand_canonical();
    132     CHK(scam_generate_ray(cam, &sample, &ray) == RES_OK);
    133 
    134     /* Transform the position in camera space */
    135     d3_sub(pos, ray.org, args.position);
    136     d33_muld3(pos, transform, pos);
    137 
    138     /* Check that the sampled position lies onto the thin lens */
    139     dst = d2_len(pos);
    140     CHK(eq_eps(pos[2], 0, 1.e-6));
    141     CHK(dst < args.lens_radius
    142      || eq_eps(dst, args.lens_radius, args.lens_radius*1.e-6));
    143 
    144     /* Compute the ray starting from the lens center and intersecting the focal
    145      * plane at the same position of the generated ray */
    146     pos[0] = ray.org[0] + ray.dir[0]*args.focal_distance;
    147     pos[1] = ray.org[1] + ray.dir[1]*args.focal_distance;
    148     pos[2] = ray.org[2] + ray.dir[2]*args.focal_distance;
    149     CHK(d3_is_normalized(ray.dir));
    150     d3_add(pos, ray.org, ray.dir);
    151     d3_sub(dir, pos, args.position);
    152     d3_normalize(dir, dir);
    153 
    154     /* Check that the computed direction is in the view frustum */
    155     cos_ray_axis_x = d3_dot(dir, axis_x);
    156     cos_ray_axis_y = d3_dot(dir, axis_y);
    157     cos_ray_axis_z = d3_dot(dir, axis_z);
    158     CHK(cos_ray_axis_z >= 0);
    159     CHK(cos_ray_axis_y <= sin_vert_hfov);
    160     CHK(cos_ray_axis_x <= sin_hori_hfov);
    161   }
    162 
    163   CHK(scam_ref_put(cam) == RES_OK);
    164   CHK(mem_allocated_size() == 0);
    165   return 0;
    166 }