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 }