commit b721aaa2cb44aab8efc5835d3cdec769e32f9651
parent 9f0d3be7042c3d74306d64e9d1581e3bc607dee7
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Wed, 9 Sep 2015 15:37:31 +0200
Begin the implementation of the scene sampling
Compute the CDF of the scene surface area
Diffstat:
6 files changed, 177 insertions(+), 40 deletions(-)
diff --git a/src/s3d_instance.c b/src/s3d_instance.c
@@ -50,6 +50,7 @@ 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));
}
@@ -72,6 +73,7 @@ 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;
@@ -135,19 +137,52 @@ instance_compute_area(struct instance* inst)
LIST_FOR_EACH(node, &inst->scene->shapes) {
struct s3d_shape* shape = CONTAINER_OF
(node, struct s3d_shape, scene_attachment);
- switch(shape->type) {
- case GEOM_INSTANCE:
- area += instance_compute_area(shape->data.instance);
- break;
- case GEOM_MESH:
- area += mesh_compute_area(shape->data.mesh);
- break;
- default: FATAL("Unreachable code\n"); break;
- }
+ ASSERT(shape->type == GEOM_MESH); /* One instancing level is supported */
+ area += mesh_compute_area(shape->data.mesh);
}
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)
{
@@ -160,15 +195,8 @@ instance_compute_volume(struct instance* inst, const char flip_surface)
struct s3d_shape* shape = CONTAINER_OF
(node, struct s3d_shape, scene_attachment);
const char flip = flip_surface ^ shape->flip_surface;
- switch(shape->type) {
- case GEOM_INSTANCE:
- volume += instance_compute_volume(shape->data.instance, flip);
- break;
- case GEOM_MESH:
- volume += mesh_compute_volume(shape->data.mesh, flip);
- break;
- default: FATAL("Unreachable code\n"); break;
- }
+ ASSERT(shape->type == GEOM_MESH); /* One instancing level is supported */
+ volume += mesh_compute_volume(shape->data.mesh, flip);
}
return volume;
}
diff --git a/src/s3d_instance.h b/src/s3d_instance.h
@@ -34,12 +34,15 @@
#define S3D_INSTANCE_H
#include "s3d_geometry.h"
+#include <rsys/dynamic_array_float.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;
};
@@ -64,6 +67,12 @@ 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
@@ -207,6 +207,28 @@ mesh_setup_attribs
}
}
+static FINLINE float
+mesh_compute_triangle_2area(struct mesh* mesh, const size_t itri)
+{
+ const uint32_t* ids;
+ const float* pos;
+ const float* v0, *v1, *v2;
+ const size_t id = itri * 3/*#ids per faces*/;
+ float E0[3], E1[3], N[3];
+ ASSERT(mesh && itri < mesh_get_ntris(mesh));
+
+ ids = mesh_get_ids(mesh);
+ pos = mesh_get_pos(mesh);
+
+ v0 = pos + ids[id+0]*3/*#coords*/;
+ v1 = pos + ids[id+1]*3/*#coords*/;
+ v2 = pos + ids[id+2]*3/*#coords*/;
+ f3_sub(E0, v1, v0);
+ f3_sub(E1, v2, v0);
+
+ return f3_len(f3_cross(N, E0, E1));
+}
+
static void
mesh_release(ref_T* ref)
{
@@ -217,6 +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);
MEM_RM(dev->allocator, mesh);
S3D(device_ref_put(dev));
}
@@ -239,6 +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);
exit:
*out_mesh = mesh;
@@ -280,6 +304,9 @@ mesh_clear(struct mesh* mesh)
mesh->attribs[iattr] = NULL;
}
}
+ mesh->resize_mask = 0;
+ mesh->update_mask = 0;
+ darray_float_clear(&mesh->triangle_2area_ucdf);
}
size_t
@@ -333,8 +360,6 @@ mesh_get_attr(struct mesh* mesh, const enum s3d_attrib_usage usage)
float
mesh_compute_area(struct mesh* mesh)
{
- const uint32_t* ids;
- const float* pos;
size_t itri, ntris;
float area = 0.f;
ASSERT(mesh);
@@ -342,20 +367,36 @@ mesh_compute_area(struct mesh* mesh)
ntris = mesh_get_ntris(mesh);
if(!ntris) return 0.f;
- ids = mesh_get_ids(mesh);
- pos = mesh_get_pos(mesh);
+ FOR_EACH(itri, 0, ntris)
+ area += mesh_compute_triangle_2area(mesh, itri);
+ return area * 0.5f;
+}
+
+res_T
+mesh_compute_triangle_2area_ucdf(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);
+
+ ntris = mesh_get_ntris(mesh);
+ if(!ntris) goto exit;
+
+ res = darray_float_resize(&mesh->triangle_2area_ucdf, ntris);
+ if(res != RES_OK) goto error;
FOR_EACH(itri, 0, ntris) {
- float E0[3], E1[3], N[3];
- const size_t id = itri * 3/*#ids per faces*/;
- const float* v0 = pos + ids[id+0]*3/*#coords*/;
- const float* v1 = pos + ids[id+1]*3/*#coords*/;
- const float* v2 = pos + ids[id+2]*3/*#coords*/;
- f3_sub(E0, v1, v0);
- f3_sub(E1, v2, v0);
- area += f3_len(f3_cross(N, E0, E1)) * 0.5f;
+ area += mesh_compute_triangle_2area(mesh, itri);
+ darray_float_data_get(&mesh->triangle_2area_ucdf)[itri] = area;
}
- return area;
+exit:
+ return res;
+error:
+ darray_float_clear(&mesh->triangle_2area_ucdf);
+ goto exit;
}
float
diff --git a/src/s3d_mesh.h b/src/s3d_mesh.h
@@ -61,6 +61,10 @@ 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;
+
int resize_mask; /* Combination of buffer_type */
int update_mask; /* Combination of buffer_type */
struct s3d_device* dev;
@@ -109,6 +113,11 @@ extern LOCAL_SYM float
mesh_compute_area
(struct mesh* mesh);
+/* Compute the *unormalized* CDF of the mesh triangles */
+extern LOCAL_SYM res_T
+mesh_compute_triangle_2area_ucdf
+ (struct mesh* mesh);
+
extern LOCAL_SYM float
mesh_compute_volume
(struct mesh* mesh,
diff --git a/src/s3d_scene.c b/src/s3d_scene.c
@@ -132,8 +132,7 @@ scene_session_clear(struct s3d_scene* scn)
static res_T
scene_register_mesh
(struct s3d_scene* scn,
- struct s3d_shape* shape,
- const int session_mask)
+ struct s3d_shape* shape)
{
struct geometry** pgeom = NULL;
struct geometry* geom = NULL;
@@ -169,11 +168,11 @@ scene_register_mesh
goto exit;
}
- /* Define which Embree geometry buffer must be updated */
+ /* Define which geometry buffers were updated */
upd_ids = geom->data.mesh->indices != shape->data.mesh->indices
|| ((shape->data.mesh->update_mask & INDEX_BUFFER) != 0);
upd_pos = geom->data.mesh->attribs[S3D_POSITION] != shape->data.mesh->attribs[S3D_POSITION]
- || ((shape->data.mesh->update_mask == VERTEX_BUFFER) != 0);
+ || ((shape->data.mesh->update_mask & VERTEX_BUFFER) != 0);
/* Get a reference onto the shape mesh indices */
if(geom->data.mesh->indices != shape->data.mesh->indices) {
@@ -313,6 +312,7 @@ scene_detach_shape(struct s3d_scene* scn, struct s3d_shape* shape)
struct geometry** pgeom;
ASSERT(scn && shape && !is_list_empty(&shape->scene_attachment));
ASSERT(shape->type == GEOM_MESH || shape->type == GEOM_INSTANCE);
+ ASSERT(scn->session_mask == S3D_SESSION_NONE);
pgeom = htable_geom_find(&scn->cached_geoms, &shape);
if(pgeom) { /* Remove the cached shape mesh */
@@ -335,9 +335,52 @@ scene_detach_shape(struct s3d_scene* scn, struct s3d_shape* shape)
}
static res_T
+scene_compute_2area_ucdf(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;
+ res_T res = RES_OK;
+ ASSERT(scn);
+
+ scn->area = 0.f;
+
+ 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;
+
+ 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);
+ 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);
+ break;
+ default: FATAL("Unreachable code\n"); break;
+ }
+ if(res != RES_OK) goto error;
+ if(ucdf_len) scn->area += ucdf[ucdf_len - 1];
+ }
+exit:
+ return res;
+error:
+ goto exit;
+}
+
+static res_T
scene_sync(struct s3d_scene* scn, const int session_mask)
{
struct list_node* node;
+ struct s3d_shape* shape;
res_T res = RES_OK;
ASSERT(scn);
@@ -347,24 +390,30 @@ scene_sync(struct s3d_scene* scn, const int session_mask)
}
LIST_FOR_EACH(node, &scn->shapes) {
- struct s3d_shape* shape = CONTAINER_OF
- (node, struct s3d_shape, scene_attachment);
+ shape = CONTAINER_OF(node, struct s3d_shape, scene_attachment);
switch(shape->type) {
case GEOM_INSTANCE:
res = scene_register_instance(scn, shape, session_mask);
break;
case GEOM_MESH:
- res = scene_register_mesh(scn, shape, session_mask);
+ res = scene_register_mesh(scn, shape);
break;
default: FATAL("Unreachable code\n"); break;
}
if(res != RES_OK)
goto error;
}
- if(scn->is_rtc_scn_outdated) {
+
+ if((session_mask & S3D_SESSION_SAMPLE) != 0) {
+ res = scene_compute_2area_ucdf(scn);
+ if(res != RES_OK) goto error;
+ }
+
+ if((session_mask & S3D_SESSION_TRACE) != 0 && scn->is_rtc_scn_outdated) {
rtcCommit(scn->rtc_scn);
scn->is_rtc_scn_outdated = 0;
}
+
scn->session_mask = session_mask;
exit:
@@ -579,7 +628,7 @@ s3d_scene_trace_ray
return RES_BAD_ARG;
if(!f3_is_normalized(dir))
return RES_BAD_ARG;
- if(scn->session_mask == S3D_SESSION_NONE)
+ if((scn->session_mask & S3D_SESSION_TRACE) == 0)
return RES_BAD_OP;
if(range[0] > range[1]) {
*hit = S3D_HIT_NULL;
diff --git a/src/s3d_scene_c.h b/src/s3d_scene_c.h
@@ -73,6 +73,7 @@ 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;