test_scam_perspective_pinhole.c (6642B)
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/double3.h> 22 #include <rsys/logger.h> 23 #include <rsys/mem_allocator.h> 24 25 #include <math.h> 26 27 static void 28 log_stream(const char* msg, void* ctx) 29 { 30 ASSERT(msg); 31 (void)msg, (void)ctx; 32 printf("%s", msg); 33 } 34 35 int 36 main(int argc, char** argv) 37 { 38 struct logger logger; 39 struct scam_perspective_args args = SCAM_PERSPECTIVE_ARGS_DEFAULT; 40 struct scam_sample sample = SCAM_SAMPLE_NULL; 41 struct scam_ray ray = SCAM_RAY_NULL; 42 struct scam* cam = NULL; 43 const size_t nsamps = 10000; 44 double axis_x[3]; 45 double axis_y[3]; 46 double axis_z[3]; 47 double hori_hfov; /* horizontal half field of view */ 48 double sin_hori_hfov; /* Sinus of the horizontal half field of view */ 49 double sin_vert_hfov; /* Sinos of the vertical half field of view */ 50 double img_depth; 51 double solid_angle; 52 double ref; 53 size_t i = 0; 54 enum scam_type type = SCAM_NONE; 55 (void)argc, (void)argv; 56 57 CHK(scam_create_perspective(NULL, NULL, 0, NULL, &cam) == RES_BAD_ARG); 58 CHK(scam_create_perspective(NULL, NULL, 0, &args, NULL) == RES_BAD_ARG); 59 CHK(scam_create_perspective(NULL, NULL, 0, &args, &cam) == RES_OK); 60 61 CHK(scam_get_type(NULL, &type) == RES_BAD_ARG); 62 CHK(scam_get_type(cam, NULL) == RES_BAD_ARG); 63 CHK(scam_get_type(cam, &type) == RES_OK); 64 CHK(type == SCAM_PERSPECTIVE); 65 66 CHK(scam_ref_get(NULL) == RES_BAD_ARG); 67 CHK(scam_ref_get(cam) == RES_OK); 68 CHK(scam_ref_put(NULL) == RES_BAD_ARG); 69 CHK(scam_ref_put(cam) == RES_OK); 70 CHK(scam_ref_put(cam) == RES_OK); 71 72 CHK(logger_init(&mem_default_allocator, &logger) == RES_OK); 73 logger_set_stream(&logger, LOG_OUTPUT, log_stream, NULL); 74 logger_set_stream(&logger, LOG_ERROR, log_stream, NULL); 75 logger_set_stream(&logger, LOG_WARNING, log_stream, NULL); 76 77 CHK(scam_create_perspective(&logger, NULL, 0, &args, &cam) == RES_OK); 78 CHK(scam_ref_put(cam) == RES_OK); 79 80 CHK(scam_create_perspective(NULL, &mem_default_allocator, 0, &args, &cam) == RES_OK); 81 CHK(scam_ref_put(cam) == RES_OK); 82 83 d3_set(args.target, args.position); 84 CHK(scam_create_perspective(NULL, NULL, 1, &args, &cam) == RES_BAD_ARG); 85 86 d3(args.position, 0, 0, 0); 87 d3(args.target, 0, 1, 0); 88 d3(args.up, 0, 1, 0); 89 CHK(scam_create_perspective(NULL, NULL, 1, &args, &cam) == RES_BAD_ARG); 90 91 args = SCAM_PERSPECTIVE_ARGS_DEFAULT; 92 args.aspect_ratio = 0; 93 CHK(scam_create_perspective(NULL, NULL, 1, &args, &cam) == RES_BAD_ARG); 94 95 args = SCAM_PERSPECTIVE_ARGS_DEFAULT; 96 args.field_of_view = 0; 97 CHK(scam_create_perspective(NULL, NULL, 1, &args, &cam) == RES_BAD_ARG); 98 args.field_of_view = PI; 99 CHK(scam_create_perspective(NULL, NULL, 1, &args, &cam) == RES_BAD_ARG); 100 args.field_of_view = nextafter(0, PI); 101 CHK(scam_create_perspective(NULL, NULL, 1, &args, &cam) == RES_OK); 102 CHK(scam_ref_put(cam) == RES_OK); 103 args.field_of_view = nextafter(PI, 0); 104 CHK(scam_create_perspective(NULL, NULL, 1, &args, &cam) == RES_OK); 105 CHK(scam_ref_put(cam) == RES_OK); 106 107 args.position[0] = rand_canonical(); 108 args.position[1] = rand_canonical(); 109 args.position[2] = rand_canonical(); 110 args.target[0] = rand_canonical(); 111 args.target[1] = rand_canonical(); 112 args.target[2] = rand_canonical(); 113 args.up[0] = rand_canonical(); 114 args.up[1] = rand_canonical(); 115 args.up[2] = rand_canonical(); 116 args.field_of_view = PI/2.0; 117 args.aspect_ratio = 1.0; 118 119 CHK(scam_create_perspective(NULL, NULL, 1, &args, &cam) == RES_OK); 120 CHK(scam_perspective_get_solid_angle(NULL, &solid_angle) == RES_BAD_ARG); 121 CHK(scam_perspective_get_solid_angle(cam, NULL) == RES_BAD_ARG); 122 CHK(scam_perspective_get_solid_angle(cam, &solid_angle) == RES_OK); 123 124 ref = args.field_of_view * 2*sin(args.field_of_view/2); 125 CHK(eq_eps(solid_angle, ref, 1.e-6)); 126 CHK(scam_ref_put(cam) == RES_OK); 127 128 args.aspect_ratio = 4.0/3.0; 129 CHK(scam_create_perspective(NULL, NULL, 1, &args, &cam) == RES_OK); 130 131 CHK(scam_perspective_get_solid_angle(cam, &solid_angle) == RES_OK); 132 ref = 2.6227869472431911; 133 CHK(eq_eps(solid_angle, ref, 1.e-6)); 134 135 /* Precompute some view frustum constants */ 136 d3_normalize(axis_z, d3_sub(axis_z, args.target, args.position)); 137 d3_normalize(axis_x, d3_cross(axis_x, axis_z, args.up)); 138 d3_normalize(axis_y, d3_cross(axis_y, axis_z, axis_x)); 139 img_depth = 1.0/tan(args.field_of_view*0.5); 140 hori_hfov = atan(args.aspect_ratio / img_depth); 141 sin_hori_hfov = sin(hori_hfov); 142 sin_vert_hfov = sin(args.field_of_view*0.5); 143 144 CHK(scam_generate_ray(NULL, &sample, &ray) == RES_BAD_ARG); 145 CHK(scam_generate_ray(cam, NULL, &ray) == RES_BAD_ARG); 146 CHK(scam_generate_ray(cam, &sample, NULL) == RES_BAD_ARG); 147 148 sample.film[0] = nextafterf(0, -1); 149 CHK(scam_generate_ray(cam, &sample, &ray) == RES_BAD_ARG); 150 sample.film[0] = 1; 151 CHK(scam_generate_ray(cam, &sample, &ray) == RES_BAD_ARG); 152 sample.film[0] = 0; 153 sample.film[1] = nextafterf(0, -1); 154 CHK(scam_generate_ray(cam, &sample, &ray) == RES_BAD_ARG); 155 sample.film[1] = 1; 156 CHK(scam_generate_ray(cam, &sample, &ray) == RES_BAD_ARG); 157 sample.film[0] = 0; 158 sample.film[1] = nextafterf(1, 0); 159 CHK(scam_generate_ray(cam, &sample, &ray) == RES_OK); 160 161 FOR_EACH(i, 0, nsamps) { 162 double cos_ray_axis_x; 163 double cos_ray_axis_y; 164 double cos_ray_axis_z; 165 sample.film[0] = rand_canonical(); 166 sample.film[1] = rand_canonical(); 167 CHK(scam_generate_ray(cam, &sample, &ray) == RES_OK); 168 169 /* Check the ray origin */ 170 CHK(d3_eq(ray.org, args.position)); 171 172 /* Check that the generated ray is in the view frustum */ 173 CHK(d3_is_normalized(ray.dir)); 174 cos_ray_axis_x = d3_dot(ray.dir, axis_x); 175 cos_ray_axis_y = d3_dot(ray.dir, axis_y); 176 cos_ray_axis_z = d3_dot(ray.dir, axis_z); 177 CHK(cos_ray_axis_z >= 0); 178 CHK(cos_ray_axis_y <= sin_vert_hfov); 179 CHK(cos_ray_axis_x <= sin_hori_hfov); 180 } 181 CHK(scam_ref_put(cam) == RES_OK); 182 183 logger_release(&logger); 184 CHK(mem_allocated_size() == 0); 185 return 0; 186 }