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:
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);