star-3d

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

commit 46b98bcb8106c08106a3566d978f481170025a53
parent 9a3eeb57fdb532847e1a6fab02fa76d3c26baed7
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Fri, 11 Sep 2015 11:58:23 +0200

Add and test the s3d_primitive_sample function

Uniformly sample a given primitive.

Diffstat:
Msrc/s3d.h | 25++++++++++++++++++-------
Msrc/s3d_primitive.c | 27++++++++++++++++++++++++++-
Msrc/s3d_scene.c | 11+++--------
Msrc/test_s3d_primitive.c | 92+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Msrc/test_s3d_scene.c | 3+--
5 files changed, 138 insertions(+), 20 deletions(-)

diff --git a/src/s3d.h b/src/s3d.h @@ -301,31 +301,35 @@ s3d_scene_trace_rays S3D_API res_T s3d_scene_sample (struct s3d_scene* scn, - const float u, const float v, const float w, /* in [0, 1) */ - struct s3d_primitive* primitive, /* sampled primitive */ - float uv[2]); + const float u, const float v, const float w, /* Random numbers in [0, 1) */ + struct s3d_primitive* primitive, /* Sampled primitive */ + float st[2]); /* Sampled parametric coordinates on the primitive */ /* Retrieve a primitive from the scene. Can be called only if an S3D_SAMPLE - * session is active on `scn'*/ + * session is active on `scn' */ S3D_API res_T s3d_scene_get_primitive (struct s3d_scene* scn, const unsigned iprim, /* in [0, #prims) */ struct s3d_primitive* prim); -/* Retrieve the number of scene primitives */ +/* Retrieve the number of scene primitives. Can be called only if a sessio is + * active on `scn' */ S3D_API res_T s3d_scene_primitives_count (struct s3d_scene* scn, size_t* primitives_count); +/* Compute the overall scene surface area. Can be called only if a session is + * active on `scn' */ S3D_API res_T s3d_scene_compute_area (struct s3d_scene* scn, float* area); /* This function assumes that the scene defines a closed volume and that the - * normals point into the volume */ + * normals point into the volume. Can be called only if a session is active on + * `scn' */ S3D_API res_T s3d_scene_compute_volume (struct s3d_scene* scn, @@ -388,9 +392,16 @@ S3D_API res_T s3d_primitive_get_attrib (const struct s3d_primitive* prim, const enum s3d_attrib_usage attr, /* Attribute to retrieve */ - const float uv[2], /* Barycentric coordinates of `attr' on `iprim' */ + const float st[2], /* Parametric coordinates of `attr' on `iprim' */ struct s3d_attrib* attrib); /* Resulting attrib */ +/* Uniform sampling of the primitive */ +S3D_API res_T +s3d_primitive_sample + (const struct s3d_primitive* prim, + const float u, const float v, /* Random numbers in [0, 1) */ + float st[2]); /* Sampled parametric coordinates on prim */ + /******************************************************************************* * Mesh API - Manage a triangular meshes ******************************************************************************/ diff --git a/src/s3d_primitive.c b/src/s3d_primitive.c @@ -66,7 +66,8 @@ s3d_primitive_get_attrib /* Unormalized barycentric coordinates */ w = CLAMP(1.f - uv[0] - uv[1], 0.f, 1.f); - if(uv[0] < 0.f || uv[1] < 0.f) + if(uv[0] < 0.f || uv[1] < 0.f || uv[0] > 1.f || uv[1] > 1.f + || !eq_epsf(w + uv[0] + uv[1], 1.f, 1.e-3f)) return RES_BAD_ARG; if(prim->inst__ == NULL) { @@ -156,3 +157,27 @@ error: goto exit; } +res_T +s3d_primitive_sample + (const struct s3d_primitive *prim, + const float u, + const float v, + float st[2]) +{ + double sqrt_u; + + if(!prim || S3D_PRIMITIVE_EQ(prim, &S3D_PRIMITIVE_NULL) || !st) + return RES_BAD_ARG; + + /* Expecting canonic numbers */ + if(u < 0.f || u >= 1.f || v < 0.f || v >= 1.f) + return RES_BAD_ARG; + + /* Only triangular primitives are currently supported. So simply compute the + * barycentric coordinates of an uniform triangle sampling. */ + sqrt_u = sqrt(u); + st[0] = (float)(1.0 - sqrt_u); + st[1] = (float)(v * sqrt_u); + return RES_OK;; +} + diff --git a/src/s3d_scene.c b/src/s3d_scene.c @@ -852,17 +852,16 @@ s3d_scene_sample const float v, const float w, struct s3d_primitive* primitive, /* sampled primitive */ - float uv[2]) + float st[2]) { struct geometry* geom; const struct fltui* fltui_begin, *fltui_end, *fltui_found; const float* flt_begin, *flt_end, *flt_found; size_t igeom; - double sqrt_v; float f; res_T res = RES_OK; - if(!scn || !primitive || !uv) { + if(!scn || !primitive || !st) { res = RES_BAD_ARG; goto error; } @@ -935,11 +934,7 @@ s3d_scene_sample ASSERT(flt_found != flt_end); primitive->prim_id = (unsigned)(flt_found - flt_begin); - - /* Compute the sampled barycentric coordinate of the sampled primitive */ - sqrt_v = sqrt(v); - uv[0] = (float)(1.0 - sqrt_v); - uv[1] = (float)(w * sqrt_v); + S3D(primitive_sample(primitive, v, w, st)); exit: return res; diff --git a/src/test_s3d_primitive.c b/src/test_s3d_primitive.c @@ -34,6 +34,49 @@ #include "test_s3d_cbox.h" #include "test_s3d_utils.h" +static const float plane_verts[] = { + 0.f, 0.f, 0.f, + 1.f, 0.f, 0.f, + 1.f, 1.f, 0.f, + 0.f, 1.f, 0.f +}; +static const unsigned plane_nverts = sizeof(plane_verts) / sizeof(float[3]); + +static const unsigned plane_ids[] = { 0, 1, 2, 2, 3, 0 }; +static const unsigned plane_ntris = sizeof(plane_ids) / sizeof(unsigned[3]); + +static float +rand_canonic(void) +{ + int r; + while((r = rand()) == RAND_MAX); + return (float)r / (float)RAND_MAX; +} + +static void +plane_get_ids(const unsigned itri, unsigned ids[3], void* data) +{ + const unsigned id = itri * 3; + (void)data; + NCHECK(ids, NULL); + CHECK(itri < plane_ntris, 1); + ids[0] = plane_ids[id + 0]; + ids[1] = plane_ids[id + 1]; + ids[2] = plane_ids[id + 2]; +} + +static void +plane_get_pos(const unsigned ivert, float pos[3], void* data) +{ + const unsigned i = ivert*3; + (void)data; + NCHECK(pos, NULL); + CHECK(ivert < plane_nverts, 1); + pos[0] = plane_verts[i + 0]; + pos[1] = plane_verts[i + 1]; + pos[2] = plane_verts[i + 2]; +} + int main(int argc, char** argv) { @@ -41,10 +84,13 @@ main(int argc, char** argv) struct s3d_device* dev; struct s3d_scene* scn; struct s3d_shape* walls; + struct s3d_shape* plane; struct s3d_attrib attr; struct s3d_primitive prim = S3D_PRIMITIVE_NULL; struct s3d_vertex_data attribs[2]; struct cbox_desc desc; + size_t nprims; + size_t i; unsigned ntris, nverts; float uv[2]; unsigned walls_id; @@ -55,6 +101,7 @@ main(int argc, char** argv) CHECK(s3d_device_create(NULL, &allocator, 1, &dev), RES_OK); CHECK(s3d_scene_create(dev, &scn), RES_OK); CHECK(s3d_shape_create_mesh(dev, &walls), RES_OK); + CHECK(s3d_shape_create_mesh(dev, &plane), RES_OK); CHECK(s3d_shape_get_id(walls, &walls_id), RES_OK); CHECK(s3d_scene_attach_shape(scn, walls), RES_OK); @@ -63,13 +110,17 @@ main(int argc, char** argv) attribs[0].get = cbox_get_position; attribs[1] = S3D_VERTEX_DATA_NULL; - ntris = sizeof(cbox_walls_ids)/sizeof(unsigned[3]); - nverts = sizeof(cbox_walls)/sizeof(float[3]); + ntris = cbox_walls_ntris; + nverts = cbox_walls_nverts; desc.vertices = cbox_walls; desc.indices = cbox_walls_ids; CHECK(s3d_mesh_setup_indexed_vertices (walls, ntris, cbox_get_ids, nverts, attribs, &desc), RES_OK); + attribs[0].get = plane_get_pos; + CHECK(s3d_mesh_setup_indexed_vertices + (plane, plane_ntris, plane_get_ids, plane_nverts, attribs, NULL), RES_OK); + CHECK(s3d_scene_begin_session(scn, S3D_SAMPLE), RES_OK); CHECK(s3d_scene_sample(scn, 0, 0, 0, &prim, uv), RES_OK); CHECK(s3d_scene_end_session(scn), RES_OK); @@ -99,12 +150,49 @@ main(int argc, char** argv) CHECK(s3d_primitive_get_attrib(&prim, S3D_ATTRIB_0, uv, &attr), RES_BAD_ARG); CHECK(s3d_primitive_get_attrib(&S3D_PRIMITIVE_NULL, S3D_POSITION, uv, &attr), RES_BAD_ARG); + CHECK(s3d_scene_clear(scn), RES_OK); + CHECK(s3d_scene_attach_shape(scn, plane), RES_OK); + CHECK(s3d_scene_begin_session(scn, S3D_GET_PRIMITIVE), RES_OK); + CHECK(s3d_scene_primitives_count(scn, &nprims), RES_OK); + CHECK(nprims, 2); + CHECK(s3d_scene_get_primitive(scn, 0, &prim), RES_OK); + CHECK(S3D_PRIMITIVE_EQ(&prim, &S3D_PRIMITIVE_NULL), 0); + CHECK(s3d_scene_end_session(scn), RES_OK); + + CHECK(s3d_primitive_sample(NULL, 1.f, 1.f, NULL), RES_BAD_ARG); + CHECK(s3d_primitive_sample(&prim, 1.f, 1.f, NULL), RES_BAD_ARG); + CHECK(s3d_primitive_sample(NULL, 0.f, 1.f, NULL), RES_BAD_ARG); + CHECK(s3d_primitive_sample(&prim, 0.f, 1.f, NULL), RES_BAD_ARG); + CHECK(s3d_primitive_sample(NULL, 1.f, 0.f, NULL), RES_BAD_ARG); + CHECK(s3d_primitive_sample(&prim, 1.f, 0.f, NULL), RES_BAD_ARG); + CHECK(s3d_primitive_sample(NULL, 0.f, 0.f, NULL), RES_BAD_ARG); + CHECK(s3d_primitive_sample(&prim, 0.f, 0.f, NULL), RES_BAD_ARG); + CHECK(s3d_primitive_sample(NULL, 1.f, 1.f, uv), RES_BAD_ARG); + CHECK(s3d_primitive_sample(&prim, 1.f, 1.f, uv), RES_BAD_ARG); + CHECK(s3d_primitive_sample(NULL, 0.f, 1.f, uv), RES_BAD_ARG); + CHECK(s3d_primitive_sample(&prim, 0.f, 1.f, uv), RES_BAD_ARG); + CHECK(s3d_primitive_sample(NULL, 1.f, 0.f, uv), RES_BAD_ARG); + CHECK(s3d_primitive_sample(&prim, 1.f, 0.f, uv), RES_BAD_ARG); + CHECK(s3d_primitive_sample(NULL, 0.f, 0.f, uv), RES_BAD_ARG); + CHECK(s3d_primitive_sample(&prim, 0.f, 0.f, uv), RES_OK); + + FOR_EACH(i, 0, 4096) { + CHECK(s3d_primitive_sample + (&prim, rand_canonic(), rand_canonic(), uv), RES_OK); + CHECK(uv[0] >= 0.f, 1); + CHECK(uv[0] <= 1.f, 1); + CHECK(uv[1] >= 0.f, 1); + CHECK(uv[1] <= 1.f, 1); + } + CHECK(s3d_device_ref_put(dev), RES_OK); CHECK(s3d_scene_ref_put(scn), RES_OK); CHECK(s3d_shape_ref_put(walls), RES_OK); + CHECK(s3d_shape_ref_put(plane), RES_OK); check_memory_allocator(&allocator); mem_shutdown_proxy_allocator(&allocator); CHECK(mem_allocated_size(), 0); return 0; } + diff --git a/src/test_s3d_scene.c b/src/test_s3d_scene.c @@ -46,7 +46,7 @@ static const float cube_verts[] = { 5.f, 6.f, 6.f, 6.f, 6.f, 6.f }; -static const unsigned cube_nverts= sizeof(cube_verts) / sizeof(float[3]); +static const unsigned cube_nverts = sizeof(cube_verts) / sizeof(float[3]); /* Front faces are CW. The normals point into the cube */ static const unsigned cube_ids[] = { @@ -75,7 +75,6 @@ static void cube_get_pos(const unsigned ivert, float pos[3], void* data) { const unsigned i = ivert*3; - (void)data; CHECK(data, NULL); NCHECK(pos, NULL); CHECK(ivert < cube_nverts, 1);