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 f3314a3c58b2c85403b549e2dfc10631cb68d9af
parent 35b39239804a82cf3d209c75c339a35930666b88
Author: Vincent Forest <vincent.forest@meso-star.com>
Date:   Wed, 25 Mar 2015 12:10:01 +0100

Major refactoring of the instance data management

Diffstat:
Mcmake/CMakeLists.txt | 16++++++++++++++--
Asrc/s3d_instance.c | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/s3d_instance.h | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/s3d_scene.c | 156+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------
Msrc/s3d_scene_c.h | 13++++++++++++-
Msrc/s3d_shape.c | 2+-
Msrc/s3d_shape_c.h | 7+------
Msrc/test_s3d_trace_ray.c | 11+++++------
8 files changed, 274 insertions(+), 43 deletions(-)

diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt @@ -59,8 +59,20 @@ set(VERSION_MINOR 0) set(VERSION_PATCH 0) set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}) -set(S3D_FILES_SRC s3d_device.c s3d_mesh.c s3d_scene.c s3d_shape.c) -set(S3D_FILES_INC s3d.h s3d_buffer.h s3d_device_c.h s3d_mesh.h s3d_shape_c.h) +set(S3D_FILES_SRC + s3d_device.c + s3d_instance.c + s3d_mesh.c + s3d_scene.c + s3d_shape.c) +set(S3D_FILES_INC + s3d.h + s3d_backend.h + s3d_buffer.h + s3d_device_c.h + s3d_instance.h + s3d_mesh.h + s3d_shape_c.h) # Prepend each file in the `S3D_FILES_<SRC|INC>' list by `S3D_SOURCE_DIR' rcmake_prepend_path(S3D_FILES_SRC ${S3D_SOURCE_DIR}) diff --git a/src/s3d_instance.c b/src/s3d_instance.c @@ -0,0 +1,60 @@ +/* Copyright (C) |Meso|Star> 2015 (contact@meso-star.com) + * + * This software is a computer program whose purpose is to describe a + * virtual 3D environment that can be ray-traced and sampled both robustly + * and efficiently. + * + * This software is governed by the CeCILL license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/or redistribute the software under the terms of the CeCILL + * license as circulated by CEA, CNRS and INRIA at the following URL + * "http://www.cecill.info". + * + * As a counterpart to the access to the source code and rights to copy, + * modify and redistribute granted by the license, users are provided only + * with a limited warranty and the software's author, the holder of the + * economic rights, and the successive licensors have only limited + * liability. + * + * In this respect, the user's attention is drawn to the risks associated + * with loading, using, modifying and/or developing or reproducing the + * software by the user in light of its specific status of free software, + * that may mean that it is complicated to manipulate, and that also + * therefore means that it is reserved for developers and experienced + * professionals having in-depth computer knowledge. Users are therefore + * encouraged to load and test the software's suitability as regards their + * requirements in conditions enabling the security of their systems and/or + * data to be ensured and, more generally, to use and operate it in the + * same conditions as regards security. + * + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL license and that you accept its terms. */ + +#include "s3d.h" +#include "s3d_backend.h" +#include "s3d_instance.h" + +#include <rsys/float33.h> + +void +instance_init(struct instance* inst) +{ + ASSERT(inst); + inst->scene = NULL; + f33_set_identity(inst->transform); /* rotation */ + f3_splat(inst->transform + 9, 0.f); /* Translation */ + inst->update_transform = 0; + inst->rtc_geom = RTC_INVALID_GEOMETRY_ID; +} + +void +instance_clear(struct instance* inst) +{ + ASSERT(inst); + if(inst->scene) { + S3D(scene_ref_put(inst->scene)); + inst->scene = NULL; + } +} + + diff --git a/src/s3d_instance.h b/src/s3d_instance.h @@ -0,0 +1,52 @@ +/* Copyright (C) |Meso|Star> 2015 (contact@meso-star.com) + * + * This software is a computer program whose purpose is to describe a + * virtual 3D environment that can be ray-traced and sampled both robustly + * and efficiently. + * + * This software is governed by the CeCILL license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/or redistribute the software under the terms of the CeCILL + * license as circulated by CEA, CNRS and INRIA at the following URL + * "http://www.cecill.info". + * + * As a counterpart to the access to the source code and rights to copy, + * modify and redistribute granted by the license, users are provided only + * with a limited warranty and the software's author, the holder of the + * economic rights, and the successive licensors have only limited + * liability. + * + * In this respect, the user's attention is drawn to the risks associated + * with loading, using, modifying and/or developing or reproducing the + * software by the user in light of its specific status of free software, + * that may mean that it is complicated to manipulate, and that also + * therefore means that it is reserved for developers and experienced + * professionals having in-depth computer knowledge. Users are therefore + * encouraged to load and test the software's suitability as regards their + * requirements in conditions enabling the security of their systems and/or + * data to be ensured and, more generally, to use and operate it in the + * same conditions as regards security. + * + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL license and that you accept its terms. */ + +#ifndef S3D_INSTANCE_H +#define S3D_INSTANCE_H + +struct instance { + struct s3d_scene* scene; + float transform[12]; /* local to world 3x4 column major matrix */ + char update_transform; + unsigned rtc_geom; +}; + +extern LOCAL_SYM void +instance_init + (struct instance* inst); + +extern LOCAL_SYM void +instance_clear + (struct instance* inst); + +#endif /* S3D_INSTANCE_H */ + diff --git a/src/s3d_scene.c b/src/s3d_scene.c @@ -79,6 +79,41 @@ scene_delete_mesh_rtc_geometry(struct s3d_scene* scn, struct mesh* mesh) } static res_T +scene_create_instance_rtc_geometry(struct s3d_scene* scn, struct instance* inst) +{ + ASSERT(scn && inst && inst->scene && inst->rtc_geom == RTC_INVALID_GEOMETRY_ID); + /* The instance should not contain instances */ + ASSERT(!darray_geom2inst_size_get(&inst->scene->geom2inst)); + + inst->rtc_geom = rtcNewInstance(scn->rtc_scn, inst->scene->rtc_scn); + if(inst->rtc_geom >= darray_geom2inst_size_get(&scn->geom2inst)) { + res_T res = darray_geom2inst_resize(&scn->geom2inst, inst->rtc_geom + 1); + if(res != RES_OK) { + rtcDeleteGeometry(scn->rtc_scn, inst->rtc_geom); + inst->rtc_geom = RTC_INVALID_GEOMETRY_ID; + return res; + } else { + /* Check that no other scene is mapped to this Embree geometry */ + ASSERT(!darray_geom2inst_data_get(&scn->geom2inst)[inst->rtc_geom]); + } + darray_geom2inst_data_get(&scn->geom2inst)[inst->rtc_geom] = inst; + scn->is_rtc_scn_outdated = 1; + } + return RES_OK; +} + +static void +scene_delete_instance_rtc_geometry(struct s3d_scene* scn, struct instance* inst) +{ + ASSERT(scn && inst && inst->rtc_geom != RTC_INVALID_GEOMETRY_ID); + ASSERT(darray_geom2inst_size_get(&scn->geom2inst) > inst->rtc_geom); + darray_geom2inst_data_get(&scn->geom2inst)[inst->rtc_geom] = NULL; + rtcDeleteGeometry(scn->rtc_scn, inst->rtc_geom); + inst->rtc_geom = RTC_INVALID_GEOMETRY_ID; + scn->is_rtc_scn_outdated = 1; +} + +static res_T scene_setup_shape_mesh (struct s3d_scene* scn, struct s3d_shape* shape) @@ -182,41 +217,76 @@ error: goto exit; } -#if 0 static res_T -shape_instance_setup(struct s3d_scene* scn, struct s3d_shape* shape) +scene_setup_shape_instance(struct s3d_scene* scn, struct s3d_shape* shape) { - res_T res; + struct instance** pinst = NULL; + struct instance* inst = NULL; + res_T res = RES_OK; ASSERT(scn && shape && shape->type == SHAPE_INSTANCE); - /* Recursuvely update the scene */ - S3D(scene_build(shape->data.instance.scene)); - if(shape->rtc_geom == RTC_INVALID_GEOMETRY_ID) { - shape->rtc_geom = rtcNewInstance - (scn->rtc_scn, shape->data.instance.scene->rtc_scn); + /* Recursuvely update the scene */ + res = s3d_scene_build(shape->data.instance.scene); + if(res != RES_OK) goto error; - res = shape_register_rtc_geom(scn, shape); - if(res != RES_OK) { - return res; + pinst = htable_inst_find(&scn->instances, &shape); + /* Create the scene instance of the shape if necessary */ + if(pinst) { + inst = *pinst; + } else { + inst = (struct instance*) + MEM_ALLOC(scn->dev->allocator, sizeof(struct instance)); + if(!inst) { + res = RES_MEM_ERR; + goto error; } + instance_init(inst); + res = htable_inst_set(&scn->instances, &shape, &inst); + if(res != RES_OK) goto error; + + S3D(scene_ref_get(shape->data.instance.scene)); /* Not necessary but ... */ + inst->scene = shape->data.instance.scene; + } + ASSERT(inst->scene == shape->data.instance.scene); + f33_set(inst->transform, shape->data.instance.transform); + f3_set(inst->transform + 9, shape->data.instance.transform + 9); + + /* The instance cannot contain instances */ + if(darray_geom2inst_size_get(&inst->scene->geom2inst)) { + res = RES_BAD_ARG; + goto error; + } + + /* Create the Embree instance */ + if(inst->rtc_geom == RTC_INVALID_GEOMETRY_ID) { + res = scene_create_instance_rtc_geometry(scn, inst); + if(res != RES_OK) goto error; } + + /* Update the Embree instance transformation */ if(shape->data.instance.update_transform) { rtcSetTransform (scn->rtc_scn, - shape->rtc_geom, + inst->rtc_geom, RTC_MATRIX_COLUMN_MAJOR, - shape->data.instance.transform); - shape->data.instance.update_transform = 1; + inst->transform); + scn->is_rtc_scn_outdated = 1; } - return RES_OK; + + shape->data.instance.update_transform = 0; /* Flush instance state */ + +exit: + return res; +error: + goto exit; } -#endif -static INLINE void -scene_remove_shape(struct s3d_scene* scn, struct s3d_shape* shape) +static void +scene_detach_shape_mesh(struct s3d_scene* scn, struct s3d_shape* shape) { struct mesh** pmesh; ASSERT(scn && shape && !is_list_empty(&shape->scene_attachment)); + ASSERT(shape->type == SHAPE_MESH); pmesh = htable_mesh_find(&scn->meshes, &shape); if(pmesh) { /* The shape mesh is registered into the scene */ @@ -232,6 +302,37 @@ scene_remove_shape(struct s3d_scene* scn, struct s3d_shape* shape) } static void +scene_detach_shape_instance(struct s3d_scene* scn, struct s3d_shape* shape) +{ + struct instance** pinst; + ASSERT(scn && shape && !is_list_empty(&shape->scene_attachment)); + ASSERT(shape->type == SHAPE_INSTANCE); + + pinst = htable_inst_find(&scn->instances, &shape); + if(pinst) { /* The shape instance is registered into the scene */ + struct instance* inst = *pinst; + if(inst->rtc_geom != RTC_INVALID_GEOMETRY_ID) + scene_delete_instance_rtc_geometry(scn, inst); + instance_clear(inst); + MEM_FREE(scn->dev->allocator, inst); + htable_inst_erase(&scn->instances, &shape); + } + list_del(&shape->scene_attachment); + S3D(shape_ref_put(shape)); +} + +static void +scene_detach_shape(struct s3d_scene* scn, struct s3d_shape* shape) +{ + ASSERT(scn && shape); + switch(shape->type) { + case SHAPE_INSTANCE: scene_detach_shape_instance(scn, shape); break; + case SHAPE_MESH: scene_detach_shape_mesh(scn, shape); break; + default: FATAL("Unreachable code\n"); break; + } +} + +static void scene_release(ref_T* ref) { struct s3d_scene* scn; @@ -242,7 +343,9 @@ scene_release(ref_T* ref) dev = scn->dev; if(scn->rtc_scn) rtcDeleteScene(scn->rtc_scn); htable_mesh_release(&scn->meshes); + htable_inst_release(&scn->instances); darray_geom2mesh_release(&scn->geom2mesh); + darray_geom2inst_release(&scn->geom2inst); MEM_FREE(dev->allocator, scn); S3D(device_ref_put(dev)); } @@ -268,7 +371,9 @@ s3d_scene_create(struct s3d_device* dev, struct s3d_scene** out_scn) } list_init(&scn->shapes); htable_mesh_init(dev->allocator, &scn->meshes); + htable_inst_init(dev->allocator, &scn->instances); darray_geom2mesh_init(dev->allocator, &scn->geom2mesh); + darray_geom2inst_init(dev->allocator, &scn->geom2inst); ref_init(&scn->ref); S3D(device_ref_get(dev)); scn->dev = dev; @@ -323,11 +428,9 @@ s3d_scene_instantiate(struct s3d_scene* scn, struct s3d_shape** out_shape) return res; shape->type = SHAPE_INSTANCE; + instance_init(&shape->data.instance); S3D(scene_ref_get(scn)); - f33_set_identity(shape->data.instance.transform); /* Rotation */ - f3_splat(shape->data.instance.transform + 9, 0); /* Translation */ shape->data.instance.scene = scn; - shape->data.instance.update_transform = 0; *out_shape = shape; return RES_OK; } @@ -363,7 +466,7 @@ s3d_scene_detach_shape(struct s3d_scene* scn, struct s3d_shape* shape) ASSERT(is_found); } #endif - scene_remove_shape(scn, shape); + scene_detach_shape(scn, shape); return RES_OK; } @@ -374,11 +477,10 @@ s3d_scene_clear(struct s3d_scene* scn) if(!scn) return RES_BAD_ARG; - /* Prevent the scene_<attach_shape|remove_shape|build> operations */ LIST_FOR_EACH_SAFE(node, tmp, &scn->shapes) { struct s3d_shape* shape = CONTAINER_OF (node, struct s3d_shape, scene_attachment); - scene_remove_shape(scn, shape); + scene_detach_shape(scn, shape); } return RES_OK; } @@ -398,7 +500,7 @@ s3d_scene_build(struct s3d_scene* scn) struct s3d_shape* shape = CONTAINER_OF (node, struct s3d_shape, scene_attachment); switch(shape->type) { - case SHAPE_INSTANCE: /*res = shape_instance_setup(scn, shape);*/ break; + case SHAPE_INSTANCE: res = scene_setup_shape_instance(scn, shape); break; case SHAPE_MESH: res = scene_setup_shape_mesh(scn, shape); break; default: FATAL("Unreachable code\n"); break; } @@ -461,8 +563,8 @@ s3d_scene_trace_ray hit->prim.igeom = RTC_INVALID_GEOMETRY_ID; } else { /* The hit shape is instantiated */ /* Retrieve the hit instance */ - ASSERT((unsigned)ray.instID < darray_geom2mesh_size_get(&scn->geom2mesh)); - /*hit->prim.ptr = TODO */ + ASSERT((unsigned)ray.instID < darray_geom2inst_size_get(&scn->geom2inst)); + hit->prim.ptr = darray_geom2inst_data_get(&scn->geom2inst); hit->prim.igeom = ray.geomID; hit->prim.iprim = ray.primID; } diff --git a/src/s3d_scene_c.h b/src/s3d_scene_c.h @@ -44,15 +44,26 @@ #define DARRAY_DATA struct mesh* #include <rsys/dynamic_array.h> +#define DARRAY_NAME geom2inst +#define DARRAY_DATA struct instance* +#include <rsys/dynamic_array.h> + #define HTABLE_NAME mesh #define HTABLE_DATA struct mesh* #define HTABLE_KEY struct s3d_shape* #include <rsys/hash_table.h> +#define HTABLE_NAME inst +#define HTABLE_DATA struct instance* +#define HTABLE_KEY struct s3d_shape* +#include <rsys/hash_table.h> + struct s3d_scene { struct list_node shapes; /* List of attached shapes */ struct htable_mesh meshes; /* List of meshes associated to a shape */ - struct darray_geom2mesh geom2mesh; + struct htable_inst instances; /* List of instances associated to a shape */ + struct darray_geom2mesh geom2mesh; /* Map an Embree geometry to a mesh */ + struct darray_geom2inst geom2inst; /* Map an Embree geometry to an instance */ RTCScene rtc_scn; char is_rtc_scn_outdated; diff --git a/src/s3d_shape.c b/src/s3d_shape.c @@ -48,7 +48,7 @@ shape_release_data(struct s3d_shape* shape) switch(shape->type) { case SHAPE_MESH: mesh_clear(&shape->data.mesh); break; case SHAPE_NONE: /* Do nothing */ break; - case SHAPE_INSTANCE: S3D(scene_ref_put(shape->data.instance.scene)); break; + case SHAPE_INSTANCE: instance_clear(&shape->data.instance); break; default: FATAL("Unreachable code\n"); break; } shape->type = SHAPE_NONE; diff --git a/src/s3d_shape_c.h b/src/s3d_shape_c.h @@ -34,6 +34,7 @@ #define S3D_SHAPE_C_H #include "s3d_mesh.h" +#include "s3d_instance.h" #include <rsys/dynamic_array_u32.h> #include <rsys/dynamic_array_float.h> @@ -50,12 +51,6 @@ enum shape_type { SHAPE_NONE = SHAPE_TYPES_COUNT__ }; -struct instance { - struct s3d_scene* scene; - float transform[12]; /* local to world 3x4 column major matrix */ - char update_transform; -}; - struct s3d_shape { struct list_node scene_attachment; enum shape_type type; diff --git a/src/test_s3d_trace_ray.c b/src/test_s3d_trace_ray.c @@ -48,8 +48,8 @@ struct camera { static void camera_init(struct camera* cam) { - const float pos[3] = { 178.f, -1000.f, 273.f }; - const float tgt[3] = { 178.f, 0.f, 273.f }; + const float pos[3] = { 0.f, -1500.f, 0.f }; + const float tgt[3] = { 0.f, 0.f, 0.f }; const float up[3] = { 0.f, 0.f, 1.f }; const float proj_ratio = (float)IMG_WIDTH/(float)IMG_HEIGHT; const float fov_x = (float)PI * 0.25f; @@ -157,7 +157,6 @@ main(int argc, char** argv) CHECK(s3d_scene_trace_ray(scn, org, dir, range, &hit), RES_BAD_ARG); - /* CHECK(s3d_scene_create(dev, &scn2), RES_OK); f3(org, -555.f, 0.f, -551.f); @@ -184,7 +183,7 @@ main(int argc, char** argv) CHECK(s3d_scene_attach_shape(scn2, shape), RES_OK); CHECK(s3d_instance_set_position(shape, org), RES_OK); - CHECK(s3d_scene_build(scn2), RES_OK);*/ + CHECK(s3d_scene_build(scn2), RES_OK); camera_init(&cam); FOR_EACH(iy, 0, IMG_HEIGHT) { @@ -196,7 +195,7 @@ main(int argc, char** argv) pixel[0] = (float)ix/(float)IMG_WIDTH; camera_ray(&cam, pixel, org, dir); - CHECK(s3d_scene_trace_ray(scn, org, dir, range, &hit), RES_OK); + CHECK(s3d_scene_trace_ray(scn2, org, dir, range, &hit), RES_OK); if(!img) continue; @@ -225,7 +224,7 @@ main(int argc, char** argv) CHECK(s3d_device_ref_put(dev), RES_OK); CHECK(s3d_shape_ref_put(shape), RES_OK); CHECK(s3d_scene_ref_put(scn), RES_OK); - /*CHECK(s3d_scene_ref_put(scn2), RES_OK);*/ + CHECK(s3d_scene_ref_put(scn2), RES_OK); check_memory_allocator(&allocator); mem_shutdown_proxy_allocator(&allocator);