commit b33a8c751dc1ac008d96f7d6e6ff41bd1fe7cf78
parent b721aaa2cb44aab8efc5835d3cdec769e32f9651
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Wed, 9 Sep 2015 17:38:03 +0200
Implement the s3d_scene_sample function
Diffstat:
7 files changed, 155 insertions(+), 115 deletions(-)
diff --git a/src/s3d.h b/src/s3d.h
@@ -167,7 +167,6 @@ enum s3d_session_flag {
/* Forward declaration of s3d opaque data types */
struct s3d_device; /* Entry point of the library */
-struct s3d_sampler; /* Random distribution of shape positions */
struct s3d_scene; /* Collection of shapes */
struct s3d_shape; /* Untyped geometry */
@@ -298,6 +297,14 @@ s3d_scene_trace_rays
const float* ranges, /* List of 2D ray ranges. in [0, INF)^2 */
struct s3d_hit* hits);
+/* TODO comment */
+S3D_API res_T
+s3d_scene_sample
+ (struct s3d_scene* scene,
+ const float u, const float v, const float w,
+ struct s3d_primitive* primitive, /* sampled primitive */
+ float uv[2]);
+
/*******************************************************************************
* Shape API - A shape defines a geometry that can be attached to *one* scene.
******************************************************************************/
@@ -366,43 +373,6 @@ s3d_shape_compute_volume
float* volume);
/*******************************************************************************
- * Sampler API
- ******************************************************************************/
-S3D_API res_T
-s3d_sampler_create
- (struct s3d_shape* shape,
- struct s3d_sampler** sampler);
-
-S3D_API res_T
-s3d_sampler_ref_get
- (struct s3d_sampler* sampler);
-
-S3D_API res_T
-s3d_sampler_ref_put
- (struct s3d_sampler* sampler);
-
-/* Synchronize the sampler geometry with the geometry of its attached shape. If
- * a s3d_sampler_begin_sampling is already active on `sample' a RES_BAD_OP
- * error is returned. On success no other begin samping can be invoked on
- * `sampler' until s3d_sampler_end_sampling is called. A s3d_sampler_get
- * operation can be invoked on `sampler' only between a
- * s3d_sampler_begin_sampling and s3d_sampler_end_sampling call. */
-S3D_API res_T
-s3d_sampler_begin_sampling
- (struct s3d_sampler* sampler);
-
-S3D_API res_T
-s3d_sampler_end_sampling
- (struct s3d_sampler* sampler);
-
-S3D_API res_T
-s3d_sampler_get
- (struct s3d_sampler* sampler,
- const float u, const float v, const float w,
- struct s3d_primitive* primitive, /* sampled primitive */
- float uv[2]);
-
-/*******************************************************************************
* Primitive API - Define a geometric primitive of a shape
******************************************************************************/
/* Retrieve the attribute of the shape primitive `iprim' at the barycentric
diff --git a/src/s3d_instance.c b/src/s3d_instance.c
@@ -50,7 +50,6 @@ instance_release(ref_T* ref)
ASSERT(ref);
inst = CONTAINER_OF(ref, struct instance, ref);
scn = inst->scene;
- darray_float_release(&inst->shape_2area_ucdf);
MEM_RM(scn->dev->allocator, inst);
S3D(scene_ref_put(scn));
}
@@ -73,7 +72,6 @@ instance_create
res = RES_MEM_ERR;
goto error;
}
- darray_float_init(scn->dev->allocator, &inst->shape_2area_ucdf);
f33_set_identity(inst->transform); /* rotation */
f3_splat(inst->transform + 9, 0.f); /* Translation */
inst->update_transform = 0;
@@ -143,46 +141,6 @@ instance_compute_area(struct instance* inst)
return area;
}
-res_T
-instance_compute_shape_2area_ucdf
- (struct instance* inst, const char use_cached_data)
-{
- struct list_node* node;
- size_t ntris;
- float area = 0.f;
- res_T res = RES_OK;
- ASSERT(inst);
-
- /* TODO take into account the scale factor of the instance */
- LIST_FOR_EACH(node, &inst->scene->shapes) {
- struct s3d_shape* shape = CONTAINER_OF
- (node, struct s3d_shape, scene_attachment);
- struct mesh* mesh;
- ASSERT(shape->type == GEOM_MESH); /* One instancing level is supported */
-
- if(!use_cached_data) {
- mesh = shape->data.mesh;
- } else {
- struct geometry** pgeom;
- pgeom = htable_geom_find(&inst->scene->cached_geoms, &shape);
- ASSERT(pgeom);
- mesh = (*pgeom)->data.mesh;
- }
-
- res = mesh_compute_triangle_2area_ucdf(mesh);
- if(res != RES_OK) goto error;
-
- ntris = mesh_get_ntris(mesh);
- if(ntris)
- area += darray_float_data_get(&mesh->triangle_2area_ucdf)[ntris-1];
- }
-exit:
- return res;
-error:
- darray_float_clear(&inst->shape_2area_ucdf);
- goto exit;
-}
-
float
instance_compute_volume(struct instance* inst, const char flip_surface)
{
diff --git a/src/s3d_instance.h b/src/s3d_instance.h
@@ -34,15 +34,13 @@
#define S3D_INSTANCE_H
#include "s3d_geometry.h"
-#include <rsys/dynamic_array_float.h>
+#include <rsys/dynamic_array.h>
#include <rsys/ref_count.h>
struct instance {
float transform[12]; /* local to world 3x4 column major matrix */
char update_transform;
struct s3d_scene* scene;
- /* Unormalized CDF of 2 times the instance shapes area */
- struct darray_float shape_2area_ucdf;
ref_T ref;
};
@@ -67,12 +65,6 @@ extern LOCAL_SYM float
instance_compute_area
(struct instance* inst);
-/* Compute the *unormalized* CDF of 2 times the instantiated shapes area */
-extern LOCAL_SYM res_T
-instance_compute_shape_2area_ucdf
- (struct instance* inst,
- const char use_session); /* Use session data */
-
extern LOCAL_SYM float
instance_compute_volume
(struct instance* inst,
diff --git a/src/s3d_mesh.c b/src/s3d_mesh.c
@@ -239,7 +239,7 @@ mesh_release(ref_T* ref)
mesh = CONTAINER_OF(ref, struct mesh, ref);
mesh_clear(mesh);
dev = mesh->dev;
- darray_float_release(&mesh->triangle_2area_ucdf);
+ darray_float_release(&mesh->cdf);
MEM_RM(dev->allocator, mesh);
S3D(device_ref_put(dev));
}
@@ -262,7 +262,7 @@ mesh_create(struct s3d_device* dev, struct mesh** out_mesh)
ref_init(&mesh->ref);
S3D(device_ref_get(dev));
mesh->dev = dev;
- darray_float_init(dev->allocator, &mesh->triangle_2area_ucdf);
+ darray_float_init(dev->allocator, &mesh->cdf);
exit:
*out_mesh = mesh;
@@ -306,7 +306,7 @@ mesh_clear(struct mesh* mesh)
}
mesh->resize_mask = 0;
mesh->update_mask = 0;
- darray_float_clear(&mesh->triangle_2area_ucdf);
+ darray_float_clear(&mesh->cdf);
}
size_t
@@ -373,29 +373,29 @@ mesh_compute_area(struct mesh* mesh)
}
res_T
-mesh_compute_triangle_2area_ucdf(struct mesh* mesh)
+mesh_compute_cdf(struct mesh* mesh)
{
size_t itri, ntris;
float area = 0.f;
res_T res = RES_OK;
ASSERT(mesh);
- darray_float_clear(&mesh->triangle_2area_ucdf);
+ darray_float_clear(&mesh->cdf);
ntris = mesh_get_ntris(mesh);
if(!ntris) goto exit;
- res = darray_float_resize(&mesh->triangle_2area_ucdf, ntris);
+ res = darray_float_resize(&mesh->cdf, ntris);
if(res != RES_OK) goto error;
FOR_EACH(itri, 0, ntris) {
area += mesh_compute_triangle_2area(mesh, itri);
- darray_float_data_get(&mesh->triangle_2area_ucdf)[itri] = area;
+ darray_float_data_get(&mesh->cdf)[itri] = area;
}
exit:
return res;
error:
- darray_float_clear(&mesh->triangle_2area_ucdf);
+ darray_float_clear(&mesh->cdf);
goto exit;
}
diff --git a/src/s3d_mesh.h b/src/s3d_mesh.h
@@ -61,9 +61,7 @@ struct mesh { /* Triangular mesh */
struct index_buffer* indices;
struct vertex_buffer* attribs[S3D_ATTRIBS_COUNT__];
enum s3d_type attribs_type[S3D_ATTRIBS_COUNT__];
-
- /* Unormalized CDF of 2 times the triangles area */
- struct darray_float triangle_2area_ucdf;
+ struct darray_float cdf;
int resize_mask; /* Combination of buffer_type */
int update_mask; /* Combination of buffer_type */
@@ -113,9 +111,9 @@ extern LOCAL_SYM float
mesh_compute_area
(struct mesh* mesh);
-/* Compute the *unormalized* CDF of the mesh triangles */
+/* Compute mesh CDF */
extern LOCAL_SYM res_T
-mesh_compute_triangle_2area_ucdf
+mesh_compute_cdf
(struct mesh* mesh);
extern LOCAL_SYM float
diff --git a/src/s3d_scene.c b/src/s3d_scene.c
@@ -40,6 +40,8 @@
#include <rsys/mem_allocator.h>
#include <rsys/mutex.h>
+#include <algorithm>
+
/* Flag used to define session of enabled on instantiated scene */
#define S3D_SESSION_INSTANCE (BIT(sizeof(int)*8 - 1))
@@ -335,40 +337,52 @@ scene_detach_shape(struct s3d_scene* scn, struct s3d_shape* shape)
}
static res_T
-scene_compute_2area_ucdf(struct s3d_scene* scn)
+scene_compute_cdf(struct s3d_scene* scn)
{
struct list_node* node;
struct s3d_shape* shape;
struct geometry** pgeom;
struct geometry* geom;
- const float* ucdf;
- size_t ucdf_len;
+ size_t len;
+ float area = 0.f;
res_T res = RES_OK;
ASSERT(scn);
- scn->area = 0.f;
+ darray_fltui_clear(&scn->cdf);
LIST_FOR_EACH(node, &scn->shapes) {
shape = CONTAINER_OF(node, struct s3d_shape, scene_attachment);
pgeom = htable_geom_find(&scn->cached_geoms, &shape);
ASSERT(pgeom != NULL);
geom = *pgeom;
+ struct fltui fltui;
switch(geom->type) {
case GEOM_MESH:
- res = mesh_compute_triangle_2area_ucdf(geom->data.mesh);
- ucdf = darray_float_cdata_get(&geom->data.mesh->triangle_2area_ucdf);
- ucdf_len = darray_float_size_get(&geom->data.mesh->triangle_2area_ucdf);
+ res = mesh_compute_cdf(geom->data.mesh);
+ if(res != RES_OK) goto error;
+ len = darray_float_size_get(&geom->data.mesh->cdf);
+ if(len) {
+ area += darray_float_cdata_get(&geom->data.mesh->cdf)[len - 1];
+ fltui.ui = geom->irtc;
+ fltui.flt = area;
+ }
break;
case GEOM_INSTANCE:
- res = instance_compute_shape_2area_ucdf(geom->data.instance, 1);
- ucdf = darray_float_cdata_get(&geom->data.instance->shape_2area_ucdf);
- ucdf_len = darray_float_size_get(&geom->data.instance->shape_2area_ucdf);
+ res = scene_compute_cdf(geom->data.instance->scene);
+ if(res != RES_OK) goto error;
+ len = darray_fltui_size_get(&geom->data.instance->scene->cdf);
+ if(len) {
+ area += darray_fltui_cdata_get
+ (&geom->data.instance->scene->cdf)[len - 1].flt;
+ fltui.ui = geom->irtc;
+ fltui.flt = area;
+ }
break;
default: FATAL("Unreachable code\n"); break;
}
+ res = darray_fltui_push_back(&scn->cdf, &fltui);
if(res != RES_OK) goto error;
- if(ucdf_len) scn->area += ucdf[ucdf_len - 1];
}
exit:
return res;
@@ -376,6 +390,12 @@ error:
goto exit;
}
+static FINLINE bool
+operator < (const struct fltui& it, const float val)
+{
+ return it.flt < val;
+}
+
static res_T
scene_sync(struct s3d_scene* scn, const int session_mask)
{
@@ -405,7 +425,7 @@ scene_sync(struct s3d_scene* scn, const int session_mask)
}
if((session_mask & S3D_SESSION_SAMPLE) != 0) {
- res = scene_compute_2area_ucdf(scn);
+ res = scene_compute_cdf(scn);
if(res != RES_OK) goto error;
}
@@ -435,6 +455,7 @@ scene_release(ref_T* ref)
if(scn->rtc_scn) rtcDeleteScene(scn->rtc_scn);
htable_geom_release(&scn->cached_geoms);
darray_geom_release(&scn->embree2geoms);
+ darray_fltui_release(&scn->cdf);
MEM_RM(dev->allocator, scn);
S3D(device_ref_put(dev));
}
@@ -461,6 +482,7 @@ s3d_scene_create(struct s3d_device* dev, struct s3d_scene** out_scn)
list_init(&scn->shapes);
htable_geom_init(dev->allocator, &scn->cached_geoms);
darray_geom_init(dev->allocator, &scn->embree2geoms);
+ darray_fltui_init(dev->allocator, &scn->cdf);
ref_init(&scn->ref);
S3D(device_ref_get(dev));
scn->dev = dev;
@@ -737,3 +759,97 @@ s3d_scene_trace_rays
return res;
}
+res_T
+s3d_scene_sample
+ (struct s3d_scene* scn,
+ const float u,
+ const float v,
+ const float w,
+ struct s3d_primitive* primitive, /* sampled primitive */
+ float uv[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) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ /* Expecting canonic numbers */
+ if(u < 0.f || u >= 1.f || v < 0.f || v >= 1.f || w < 0.f || w >= 1.f) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ if((scn->session_mask & S3D_SESSION_SAMPLE) == 0) {
+ res = RES_BAD_OP;
+ goto error;
+ }
+
+ /* Find the sampled geometry */
+ if(darray_fltui_size_get(&scn->cdf) == 1) {
+ igeom = darray_fltui_cdata_get(&scn->cdf)[0].ui;
+ } else {
+ fltui_begin = darray_fltui_cdata_get(&scn->cdf);
+ fltui_end = fltui_begin + darray_fltui_size_get(&scn->cdf);
+ f = u * fltui_end[-1].flt;
+ fltui_found = std::lower_bound(fltui_begin, fltui_end, f);
+ ASSERT(fltui_found != fltui_end);
+ igeom = fltui_found->ui;
+
+ if(fltui_found != fltui_begin)
+ f -= fltui_found[-1].flt;
+ }
+ geom = darray_geom_data_get(&scn->embree2geoms)[igeom];
+ ASSERT(geom);
+
+ if(geom->type != GEOM_INSTANCE) {
+ primitive->inst__ = NULL;
+ primitive->inst_id = S3D_INVALID_ID;
+ } else {
+ /* Find the sampled instantiated geometry */
+ primitive->inst__ = geom;
+ primitive->inst_id = geom->name;
+ if(darray_fltui_size_get(&geom->data.instance->scene->cdf) == 1) {
+ igeom = darray_fltui_cdata_get(&geom->data.instance->scene->cdf)[0].ui;
+ } else {
+ fltui_begin = darray_fltui_cdata_get(&geom->data.instance->scene->cdf);
+ fltui_end = fltui_begin + darray_fltui_size_get(&geom->data.instance->scene->cdf);
+ fltui_found = std::lower_bound(fltui_begin, fltui_end, f);
+ ASSERT(fltui_found != fltui_end);
+ igeom = fltui_found->ui;
+
+ if(fltui_found != fltui_begin)
+ f -= fltui_found[-1].flt;
+ }
+ geom = darray_geom_data_get
+ (&geom->data.instance->scene->embree2geoms)[igeom];
+ ASSERT(geom);
+ }
+ ASSERT(geom->type == GEOM_MESH);
+
+ /* Find the sampled triangle */
+ primitive->mesh__ = geom;
+ primitive->geom_id = geom->name;
+ flt_begin = darray_float_cdata_get(&geom->data.mesh->cdf);
+ flt_end = flt_begin + darray_float_size_get(&geom->data.mesh->cdf);
+ flt_found = std::lower_bound(flt_begin, flt_end, f);
+ 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);
+
+exit:
+ return res;
+error:
+ goto exit;
+}
+
diff --git a/src/s3d_scene_c.h b/src/s3d_scene_c.h
@@ -62,10 +62,17 @@ geom_ptr_init__(struct mem_allocator* alloc, struct geometry** geom)
#define HTABLE_KEY struct s3d_shape*
#include <rsys/hash_table.h>
+/* Generate the darray_fltui dynamic array */
+struct fltui { float flt; unsigned ui; };
+#define DARRAY_NAME fltui
+#define DARRAY_DATA struct fltui
+#include <rsys/dynamic_array.h>
+
struct s3d_scene {
struct list_node shapes; /* List of attached shapes */
struct htable_geom cached_geoms; /* Cached shape geometries */
struct darray_geom embree2geoms; /* Shape geometries index by embree id */
+ struct darray_fltui cdf; /* Unormalized CDF */
size_t instances_count; /* # instances in the scene */
@@ -73,7 +80,6 @@ struct s3d_scene {
char is_rtc_scn_outdated; /* Must the embree scene rebuild */
int session_mask; /* Combination of enum s3d_session_flag */
- float area; /* Overall scene surface area */
struct s3d_device* dev;
ref_T ref;