star-3d

Surface structuring for efficient 3D geometric queries
git clone git://git.meso-star.com/star-3d.git
Log | Files | Refs | README | LICENSE

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 }