test_s3d_trace_ray_instance.c (10353B)
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_cbox.h" 21 #include "test_s3d_utils.h" 22 23 #include <rsys/float2.h> 24 #include <rsys/float3.h> 25 #include <rsys/float33.h> 26 #include <rsys/image.h> 27 28 static const float quad_verts[] = { 29 -1.f, -1.f, 0.f, 30 -1.f, 1.f, 0.f, 31 1.f, 1.f, 0.f, 32 1.f, -1.f, 0.f 33 }; 34 static const unsigned quad_nverts = sizeof(quad_verts)/(sizeof(float)*3); 35 static const unsigned quad_ids[] = { 0, 1, 3, 3, 1, 2 }; 36 static const unsigned quad_ntris = sizeof(quad_ids)/(sizeof(unsigned)*3); 37 38 struct ray { 39 float org[3]; 40 float dir[3]; 41 }; 42 43 static int 44 filter 45 (const struct s3d_hit* hit, 46 const float ray_org[3], 47 const float ray_dir[3], 48 const float ray_range[2], 49 void* ray_data, 50 void* filter_data) 51 { 52 struct ray* ray = ray_data; 53 54 CHK(hit != NULL); 55 CHK(ray_org != NULL); 56 CHK(ray_dir != NULL); 57 CHK(ray_data != NULL); 58 CHK(ray_range != NULL); 59 CHK(filter_data == NULL); 60 CHK(f3_eq(ray_org, ray->org) == 1); 61 CHK(f3_eq(ray_dir, ray->dir) == 1); 62 return 0; 63 } 64 65 static void 66 quad_get_ids(const unsigned itri, unsigned ids[3], void* data) 67 { 68 const unsigned id = itri * 3; 69 CHK(ids != NULL); 70 CHK(itri < quad_ntris); 71 (void)data; 72 ids[0] = quad_ids[id + 0]; 73 ids[1] = quad_ids[id + 1]; 74 ids[2] = quad_ids[id + 2]; 75 } 76 77 static void 78 quad_get_pos(const unsigned ivert, float pos[3], void* data) 79 { 80 const unsigned i = ivert*3; 81 CHK(pos != NULL); 82 CHK(ivert < quad_nverts); 83 (void)data; 84 pos[0] = quad_verts[i+0]; 85 pos[1] = quad_verts[i+1]; 86 pos[2] = quad_verts[i+2]; 87 } 88 89 static void 90 test_quad(struct s3d_device* dev) 91 { 92 struct ray ray; 93 struct s3d_attrib attr; 94 struct s3d_hit hit[2]; 95 struct s3d_scene* scn; 96 struct s3d_scene_view* view[2]; 97 struct s3d_shape* quad; 98 struct s3d_shape* quad_inst; 99 struct s3d_vertex_data vdata; 100 unsigned quad_id; 101 unsigned quad_inst_id; 102 float transform[12]; 103 float dir[3]; 104 float range[2]; 105 106 f33_rotation_pitch(transform, (float)PI); 107 f3_splat(transform+9, 0); 108 109 vdata.type = S3D_FLOAT3; 110 vdata.usage = S3D_POSITION; 111 vdata.get = quad_get_pos; 112 CHK(s3d_shape_create_mesh(dev, &quad) == RES_OK); 113 CHK(s3d_mesh_set_hit_filter_function(quad, filter, NULL) == RES_OK); 114 CHK(s3d_mesh_setup_indexed_vertices 115 (quad, quad_ntris, quad_get_ids, quad_nverts, &vdata, 1, NULL) == RES_OK); 116 117 CHK(s3d_scene_create(dev, &scn) == RES_OK); 118 CHK(s3d_scene_attach_shape(scn, quad) == RES_OK); 119 CHK(s3d_scene_instantiate(scn, &quad_inst) == RES_OK); 120 CHK(s3d_instance_set_transform(quad_inst, transform) == RES_OK); 121 CHK(s3d_scene_ref_put(scn) == RES_OK); 122 123 CHK(s3d_scene_create(dev, &scn) == RES_OK); 124 CHK(s3d_scene_attach_shape(scn, quad_inst) == RES_OK); 125 CHK(s3d_scene_view_create(scn, S3D_TRACE, &view[0]) == RES_OK); 126 127 CHK(s3d_scene_clear(scn) == RES_OK); 128 CHK(s3d_scene_attach_shape(scn, quad) == RES_OK); 129 CHK(s3d_scene_view_create(scn, S3D_TRACE, &view[1]) == RES_OK); 130 131 CHK(s3d_shape_get_id(quad, &quad_id) == RES_OK); 132 CHK(s3d_shape_get_id(quad_inst, &quad_inst_id) == RES_OK); 133 134 f3(ray.org, 0.f, 0.5f, -1.f); 135 f3(ray.dir, 0.f, 0.f, 1.f); 136 f2(range, 0.f, FLT_MAX); 137 CHK(s3d_scene_view_trace_ray 138 (view[0], ray.org, ray.dir, range, &ray, &hit[0]) == RES_OK); 139 CHK(s3d_scene_view_trace_ray 140 (view[1], ray.org, ray.dir, range, &ray, &hit[1]) == RES_OK); 141 142 CHK(hit[0].prim.prim_id == 0); 143 CHK(hit[1].prim.prim_id == 1); 144 CHK(hit[0].prim.geom_id == quad_id); 145 CHK(hit[1].prim.geom_id == quad_id); 146 CHK(hit[0].prim.inst_id == quad_inst_id); 147 CHK(hit[1].prim.inst_id == S3D_INVALID_ID); 148 CHK(f3_eq_eps(hit[0].normal, f3_minus(dir, hit[1].normal), 1.e-6f) == 1); 149 CHK(eq_epsf(hit[0].distance, hit[1].distance, 1.e-6f) == 1); 150 151 CHK(s3d_primitive_get_attrib 152 (&hit[0].prim, S3D_GEOMETRY_NORMAL, hit[0].uv, &attr) == RES_OK); 153 f3_normalize(attr.value, attr.value); 154 f3_normalize(hit[0].normal, hit[0].normal); 155 CHK(f3_eq_eps(hit[0].normal, attr.value, 1.e-6f) == 1); 156 157 CHK(s3d_primitive_get_attrib 158 (&hit[1].prim, S3D_GEOMETRY_NORMAL, hit[1].uv, &attr) == RES_OK); 159 f3_normalize(attr.value, attr.value); 160 f3_normalize(hit[1].normal, hit[1].normal); 161 CHK(f3_eq_eps(hit[1].normal, attr.value, 1.e-6f) == 1); 162 163 CHK(s3d_scene_view_ref_put(view[0]) == RES_OK); 164 CHK(s3d_scene_view_ref_put(view[1]) == RES_OK); 165 166 CHK(s3d_shape_ref_put(quad_inst) == RES_OK); 167 CHK(s3d_shape_ref_put(quad) == RES_OK); 168 CHK(s3d_scene_ref_put(scn) == RES_OK); 169 } 170 171 static void 172 test_cbox(struct s3d_device* dev) 173 { 174 struct image img; 175 struct camera cam; 176 struct cbox_desc cbox_desc; 177 struct s3d_scene* scn; 178 struct s3d_scene* cbox; 179 struct s3d_shape* shape; 180 struct s3d_vertex_data vdata; 181 struct s3d_scene_view* view; 182 float lower[3], upper[3], extend[3]; 183 float size[2]; 184 float pos[3], tgt[3], up[3]; 185 float org[3], dir[3], range[2]; 186 float proj_ratio; 187 unsigned walls_id; 188 const size_t img_sz[2] = { 640, 480 }; 189 const size_t N = 8; 190 size_t x, y; 191 192 CHK(s3d_scene_create(dev, &cbox) == RES_OK); 193 CHK(s3d_scene_create(dev, &scn) == RES_OK); 194 195 vdata.usage = S3D_POSITION; 196 vdata.type = S3D_FLOAT3; 197 vdata.get = cbox_get_position; 198 199 /* Walls */ 200 cbox_desc.vertices = cbox_walls; 201 cbox_desc.indices = cbox_walls_ids; 202 CHK(s3d_shape_create_mesh(dev, &shape) == RES_OK); 203 CHK(s3d_mesh_setup_indexed_vertices(shape, cbox_walls_ntris, cbox_get_ids, 204 cbox_walls_nverts, &vdata, 1, &cbox_desc) == RES_OK); 205 CHK(s3d_scene_attach_shape(cbox, shape) == RES_OK); 206 CHK(s3d_shape_get_id(shape, &walls_id) == RES_OK); 207 CHK(s3d_shape_ref_put(shape) == RES_OK); 208 209 /* Short block */ 210 cbox_desc.vertices = cbox_short_block; 211 cbox_desc.indices = cbox_block_ids; 212 CHK(s3d_shape_create_mesh(dev, &shape) == RES_OK); 213 CHK(s3d_mesh_setup_indexed_vertices(shape, cbox_block_ntris, cbox_get_ids, 214 cbox_block_nverts, &vdata, 1, &cbox_desc) == RES_OK); 215 CHK(s3d_scene_attach_shape(cbox, shape) == RES_OK); 216 CHK(s3d_shape_ref_put(shape) == RES_OK); 217 218 /* Tall block */ 219 cbox_desc.vertices = cbox_tall_block; 220 cbox_desc.indices = cbox_block_ids; 221 CHK(s3d_shape_create_mesh(dev, &shape) == RES_OK); 222 CHK(s3d_mesh_setup_indexed_vertices(shape, cbox_block_ntris, cbox_get_ids, 223 cbox_block_nverts, &vdata, 1, &cbox_desc) == RES_OK); 224 CHK(s3d_scene_attach_shape(cbox, shape) == RES_OK); 225 CHK(s3d_shape_ref_put(shape) == RES_OK); 226 227 /* Compute the cbox extends */ 228 CHK(s3d_scene_view_create(cbox, S3D_GET_PRIMITIVE, &view) == RES_OK); 229 CHK(s3d_scene_view_get_aabb(view, lower, upper) == RES_OK); 230 CHK(s3d_scene_view_ref_put(view) == RES_OK); 231 f3_sub(extend, upper, lower); 232 233 /* Create instances */ 234 size[0] = extend[0]*(float)N + (extend[0]*0.05f) * (float)(N-1); 235 size[1] = extend[2]*(float)N + (extend[2]*0.05f) * (float)(N-1); 236 pos[0] = -size[0] * 0.5f; 237 pos[1] = 0; 238 FOR_EACH(x, 0, N) { 239 pos[2] = -size[1] * 0.5f; 240 FOR_EACH(y, 0, N) { 241 CHK(s3d_scene_instantiate(cbox, &shape) == RES_OK); 242 CHK(s3d_instance_set_position(shape, pos) == RES_OK); 243 CHK(s3d_scene_attach_shape(scn, shape) == RES_OK); 244 CHK(s3d_shape_ref_put(shape) == RES_OK); 245 pos[2] += extend[2] * 1.05f; 246 } 247 pos[0] += extend[0] * 1.05f; 248 } 249 250 /* Setup point of view */ 251 f3(pos, 0.f, -3000.f, 0.f); 252 f3(tgt, 0.f, 0.f, 0.f); 253 f3(up, 0.f, 0.f, 1.f); 254 proj_ratio = (float)img_sz[0] / (float)img_sz[1]; 255 camera_init(&cam, pos, tgt, up, (float)PI*0.5f, proj_ratio); 256 257 image_init(NULL, &img); 258 CHK(image_setup 259 (&img, img_sz[0], img_sz[1], img_sz[0]*3, IMAGE_RGB8, NULL) == RES_OK); 260 261 /* Trace rays */ 262 CHK(s3d_scene_view_create(scn, S3D_TRACE, &view) == RES_OK); 263 range[0] = 0.f; 264 range[1] = FLT_MAX; 265 FOR_EACH(y, 0, img_sz[1]) { 266 float pixel[2]; 267 pixel[1] = (float)y / (float)img_sz[1]; 268 FOR_EACH(x, 0, img_sz[0]) { 269 const size_t ipix = (y*img_sz[0] + x)*3/*RGB*/; 270 struct s3d_hit hit; 271 272 pixel[0] = (float)x/(float)img_sz[0]; 273 camera_ray(&cam, pixel, org, dir); 274 CHK(s3d_scene_view_trace_ray(view, org, dir, range, NULL, &hit) == RES_OK); 275 276 if(S3D_HIT_NONE(&hit)) { 277 ((uint8_t*)img.pixels)[ipix+0] = 0; 278 ((uint8_t*)img.pixels)[ipix+1] = 0; 279 ((uint8_t*)img.pixels)[ipix+2] = 0; 280 } else { 281 float normal[3] = {0.f, 0.f, 0.f}; 282 float col[3], dot; 283 float f = (float)hit.prim.inst_id / (float)(N*N); 284 f3(col, f, MMAX(0.f, 1.f-f), MMAX(0.f, 1.f-f)); 285 286 if(hit.prim.geom_id == walls_id) { 287 if(hit.prim.prim_id == 4 || hit.prim.prim_id == 5) { 288 f3(col, col[0], 0.f, 0.f); 289 } else if(hit.prim.prim_id == 6 || hit.prim.prim_id == 7) { 290 f3(col, 0.f, col[1], 0.f); 291 } 292 } 293 294 f3_normalize(normal, hit.normal); 295 dot = absf(f3_dot(normal, dir)); 296 ((uint8_t*)img.pixels)[ipix+0] = (uint8_t)(dot * col[0] * 255.f); 297 ((uint8_t*)img.pixels)[ipix+1] = (uint8_t)(dot * col[1] * 255.f); 298 ((uint8_t*)img.pixels)[ipix+2] = (uint8_t)(dot * col[2] * 255.f); 299 } 300 } 301 } 302 CHK(s3d_scene_view_ref_put(view) == RES_OK); 303 304 /* Write image */ 305 CHK(image_write_ppm_stream(&img, 0, stdout) == RES_OK); 306 image_release(&img); 307 308 /* Release data */ 309 CHK(s3d_scene_ref_put(cbox) == RES_OK); 310 CHK(s3d_scene_ref_put(scn) == RES_OK); 311 } 312 313 int 314 main(int argc, char** argv) 315 { 316 struct mem_allocator allocator; 317 struct s3d_device* dev; 318 (void)argc, (void)argv; 319 320 mem_init_proxy_allocator(&allocator, &mem_default_allocator); 321 CHK(s3d_device_create(NULL, &allocator, 0, &dev) == RES_OK); 322 323 test_quad(dev); 324 test_cbox(dev); 325 326 CHK(s3d_device_ref_put(dev) == RES_OK); 327 328 check_memory_allocator(&allocator); 329 mem_shutdown_proxy_allocator(&allocator); 330 CHK(mem_allocated_size() == 0); 331 return 0; 332 }