star-3d

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

test_s3d_trace_ray_instance.c (10326B)


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