test_s3d_sphere_instance.c (6374B)
1 /* Copyright (C) 2015-2023, 2026 |Méso|Star> (contact@meso-star.com) 2 * 3 * This file is part of Star-3D. 4 * 5 * Star-3D is free software: you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation, either version 3 of the License, or 8 * (at your option) any later version. 9 * 10 * Star-3D is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with Star-3D. If not, see <http://www.gnu.org/licenses/>. */ 17 18 #include "s3d.h" 19 #include "test_s3d_camera.h" 20 #include "test_s3d_utils.h" 21 22 #include <rsys/image.h> 23 #include <rsys/float2.h> 24 #include <rsys/float3.h> 25 26 #include <string.h> 27 28 static int 29 filter_front_face 30 (const struct s3d_hit* hit, 31 const float pos[3], 32 const float dir[3], 33 const float range[2], 34 void* ray_data, 35 void* filter_data) 36 { 37 CHK(hit != NULL); 38 CHK(pos != NULL); 39 CHK(dir != NULL); 40 CHK(range != NULL); 41 CHK(range[0] < range[1]); 42 CHK(filter_data == NULL); 43 CHK(ray_data == NULL); 44 CHK(S3D_HIT_NONE(hit) == 0); 45 return f3_dot(hit->normal, dir) < 0; 46 } 47 48 static void 49 test_sampling 50 (struct s3d_scene_view* view, 51 const unsigned geom_id, 52 const unsigned inst0_id) 53 { 54 struct s3d_attrib attr0; 55 struct s3d_attrib attr1; 56 struct s3d_primitive prim; 57 int N = 10000; 58 int i; 59 float center[3]; 60 float sum; 61 float st[2]; 62 float E, V, SE; 63 64 /* Check that 50 percents of samples lie onto the 1st instance */ 65 sum = 0; 66 FOR_EACH(i, 0, N) { 67 const float u = rand_canonic(); 68 const float v = rand_canonic(); 69 const float w = rand_canonic(); 70 71 CHK(s3d_scene_view_sample(view, u, v, w, &prim, st) == RES_OK); 72 CHK(prim.geom_id == geom_id); 73 if(prim.inst_id == inst0_id) { 74 sum += 1; 75 } 76 77 CHK(s3d_primitive_get_attrib(&prim, S3D_POSITION, st, &attr0) == RES_OK); 78 CHK(s3d_primitive_get_attrib 79 (&prim, S3D_GEOMETRY_NORMAL, st, &attr1) == RES_OK); 80 81 if(prim.inst_id == inst0_id) { 82 f3_sub(attr0.value, attr0.value, f3(center,-1.5, 0, 0)); 83 } else { 84 f3_sub(attr0.value, attr0.value, f3(center, 1.5, 0, 0)); 85 } 86 f3_mulf(attr1.value, attr1.value, 2.f); 87 CHK(f3_eq_eps(attr0.value, attr1.value, 1.e-3f)); 88 } 89 E = sum / (float)N; 90 V = sum / (float)N - E*E; 91 SE = (float)sqrt(V/(float)N); 92 CHK(eq_epsf(E, 0.5, 2*SE)); 93 } 94 95 static void 96 test_ray_tracing(struct s3d_scene_view* view) 97 { 98 struct image img; 99 struct camera cam; 100 const size_t img_sz[2] = {640, 480}; 101 float pos[3] = {0, 0, 0}; 102 float tgt[3] = {0, 0, 0}; 103 float up[3] = {0, 1, 0}; 104 float proj_ratio; 105 size_t x, y; 106 107 image_init(NULL, &img); 108 CHK(image_setup 109 (&img, img_sz[0], img_sz[1], img_sz[0]*3, IMAGE_RGB8, NULL) == RES_OK); 110 111 f3(pos, 0, 0, -10); 112 f3(tgt, 0, 0, 0); 113 f3(up, 0, 1, 0); 114 proj_ratio = (float)img_sz[0] / (float)img_sz[1]; 115 camera_init(&cam, pos, tgt, up, (float)PI*0.25f, proj_ratio); 116 117 FOR_EACH(y, 0, img_sz[1]) { 118 float pixel[2]; 119 pixel[1] = (float)y / (float)img_sz[1]; 120 FOR_EACH(x, 0, img_sz[0]) { 121 const size_t ipix = (y*img_sz[0] + x)*3/*RGB*/; 122 struct s3d_hit hit; 123 const float range[2] = {0, FLT_MAX}; 124 float org[3]; 125 float dir[3]; 126 127 pixel[0] = (float)x/(float)img_sz[0]; 128 camera_ray(&cam, pixel, org, dir); 129 CHK(s3d_scene_view_trace_ray(view, org, dir, range, NULL, &hit) == RES_OK); 130 if(S3D_HIT_NONE(&hit)) { 131 ((uint8_t*)img.pixels)[ipix+0] = 0; 132 ((uint8_t*)img.pixels)[ipix+1] = 0; 133 ((uint8_t*)img.pixels)[ipix+2] = 0; 134 } else { 135 float normal[3] = {0.f, 0.f, 0.f}; 136 f3_normalize(normal, hit.normal); 137 ((uint8_t*)img.pixels)[ipix+0] = (uint8_t)(fabs(normal[0])*255.f); 138 ((uint8_t*)img.pixels)[ipix+1] = (uint8_t)(fabs(normal[1])*255.f); 139 ((uint8_t*)img.pixels)[ipix+2] = (uint8_t)(fabs(normal[2])*255.f); 140 } 141 } 142 } 143 144 /* Write image */ 145 CHK(image_write_ppm_stream(&img, 0, stdout) == RES_OK); 146 image_release(&img); 147 } 148 149 int 150 main(int argc, char** argv) 151 { 152 struct mem_allocator allocator; 153 struct s3d_device* dev; 154 struct s3d_shape* sphere; 155 struct s3d_shape* sphere0; 156 struct s3d_shape* sphere1; 157 struct s3d_scene* scn; 158 struct s3d_scene_view* view; 159 unsigned geom_id; 160 unsigned inst0_id; 161 unsigned inst1_id; 162 float center[3]; 163 char filter = 0; 164 (void)argc, (void)argv; 165 166 if(argc > 1 && !strcmp(argv[1], "filter")) { 167 filter = 1; 168 } 169 170 CHK(mem_init_proxy_allocator(&allocator, &mem_default_allocator) == RES_OK); 171 CHK(s3d_device_create(NULL, &allocator, 0, &dev) == RES_OK); 172 CHK(s3d_scene_create(dev, &scn) == RES_OK); 173 174 CHK(s3d_shape_create_sphere(dev, &sphere) == RES_OK); 175 CHK(s3d_sphere_setup(sphere, f3_splat(center, 0), 2) == RES_OK); 176 CHK(s3d_shape_get_id(sphere, &geom_id) == RES_OK); 177 CHK(s3d_scene_attach_shape(scn, sphere) == RES_OK); 178 179 CHK(s3d_scene_instantiate(scn, &sphere0) == RES_OK); 180 CHK(s3d_scene_instantiate(scn, &sphere1) == RES_OK); 181 CHK(s3d_shape_get_id(sphere0, &inst0_id) == RES_OK); 182 CHK(s3d_shape_get_id(sphere0, &inst1_id) == RES_OK); 183 CHK(s3d_scene_ref_put(scn) == RES_OK); 184 185 CHK(s3d_scene_create(dev, &scn) == RES_OK); 186 CHK(s3d_scene_attach_shape(scn, sphere0) == RES_OK); 187 CHK(s3d_scene_attach_shape(scn, sphere1) == RES_OK); 188 CHK(s3d_instance_set_position(sphere0, f3(center,-1.5, 0, 0)) == RES_OK); 189 CHK(s3d_instance_set_position(sphere1, f3(center, 1.5, 0, 0)) == RES_OK); 190 191 if(filter) { 192 CHK(s3d_sphere_set_hit_filter_function 193 (NULL, filter_front_face, NULL) == RES_BAD_ARG); 194 CHK(s3d_sphere_set_hit_filter_function 195 (sphere, filter_front_face, NULL) == RES_OK); 196 } 197 198 CHK(s3d_scene_view_create 199 (scn, S3D_TRACE|S3D_GET_PRIMITIVE|S3D_SAMPLE, &view) == RES_OK); 200 201 test_sampling(view, geom_id, inst0_id); 202 test_ray_tracing(view); 203 204 CHK(s3d_device_ref_put(dev) == RES_OK); 205 CHK(s3d_scene_ref_put(scn) == RES_OK); 206 CHK(s3d_shape_ref_put(sphere) == RES_OK); 207 CHK(s3d_shape_ref_put(sphere0) == RES_OK); 208 CHK(s3d_shape_ref_put(sphere1) == RES_OK); 209 CHK(s3d_scene_view_ref_put(view) == RES_OK); 210 211 check_memory_allocator(&allocator); 212 mem_shutdown_proxy_allocator(&allocator); 213 CHK(mem_allocated_size() == 0); 214 return 0; 215 } 216