commit 4be9372fc60560c4474e17b91f165d96186a62e3
parent cf4f816ae2023f193c4adec925ff10b419024e23
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Mon, 23 Mar 2015 13:39:46 +0100
Change the API of a sampled/ray-traced primitive indentifier
Take into account the instance transformation in the
s3d_shape_get_attrib function
Diffstat:
5 files changed, 90 insertions(+), 40 deletions(-)
diff --git a/src/s3d.h b/src/s3d.h
@@ -110,8 +110,7 @@ static const struct s3d_vertex_data S3D_VERTEX_DATA_NULL =
/* Intersection point */
struct s3d_hit {
struct s3d_shape* shape; /* Hit shape */
- struct s3d_scene* scene; /* Hit scene */
- unsigned iprim; /* Index of the intersected primitive */
+ unsigned iprim[2]; /* Indentifiers of the intersected primitive */
float normal[3]; /* Unormalized geometry normal */
float uv[2]; /* Barycentric coordinates of the hit onto `iprim' */
float distance; /* Hit distance from the ray origin */
@@ -119,7 +118,7 @@ struct s3d_hit {
/* Constant defining a NULL intersection. Should be used to initialize a hit */
static const struct s3d_hit S3D_HIT_NULL =
-{NULL, NULL, 0, {0.f,0.f,0.f}, {0.f,0.f}, FLT_MAX};
+{NULL, {(unsigned)-1, (unsigned)-1}, {0.f,0.f,0.f}, {0.f,0.f}, FLT_MAX};
/* Helper macro that defines whether or not the hit is valid, i.e. the ray
* intersects a shape or not */
@@ -264,16 +263,16 @@ s3d_shape_sample
(struct s3d_shape* shape,
/* Uniform random variables in [0, 1) */
const float u, const float v, const float w,
- unsigned* iprim, /* Sampled primitive */
+ unsigned iprim[2], /* Sampled primitive */
float uv[2]); /* Sampled barycentric coordinate onto `iprim' */
/* Retrieve the attribute of the shape prim `iprim' at the barycentric
* coordinates `uv' */
S3D_API res_T
-s3d_mesh_get_attrib
+s3d_shape_get_attrib
(struct s3d_shape* shape,
const enum s3d_attrib_usage attr, /* Attribute to retrieve */
- const unsigned iprim, /* Id of the primitive on which `attr' is retrieved */
+ const unsigned iprim[2], /* Id of the primitive on which `attr' is retrieved */
const float uv[2], /* Barycentric coordinates of `attr' on `iprim' */
struct s3d_attrib* attrib); /* Resulting attrib */
diff --git a/src/s3d_scene.c b/src/s3d_scene.c
@@ -223,6 +223,36 @@ scene_release(ref_T* ref)
}
/*******************************************************************************
+ * Local function
+ ******************************************************************************/
+struct s3d_shape*
+scene_shape_from_rtc_geom(struct s3d_scene* scn, const unsigned igeom)
+{
+ struct s3d_shape* shape = NULL;
+ res_T res = RES_OK;
+ ASSERT(scn);
+
+ mutex_lock(scn->lock);
+ if(darray_geom2shape_size_get(&scn->geom2shape) <= igeom)
+ goto error;
+ shape = darray_geom2shape_data_get(&scn->geom2shape)[igeom];
+error:
+ mutex_unlock(scn->lock);
+ return shape;
+exit:
+ goto error;
+}
+
+void
+scene_remove_shape(struct s3d_scene* scn, struct s3d_shape* shape)
+{
+ ASSERT(scn);
+ mutex_lock(scn->lock);
+ scene_remove_shape_unsafe(scn, shape);
+ mutex_unlock(scn->lock);
+}
+
+/*******************************************************************************
* Exported s3d_scene functions
******************************************************************************/
res_T
@@ -425,7 +455,6 @@ s3d_scene_trace_ray
/* Prevent concurrent modifications on the Embree scene */
mutex_rw_rlock(scn->lock_rtc);
rtcIntersect(scn->rtc_scn, ray);
- mutex_rw_unlock(scn->lock_rtc);
if((unsigned)ray.geomID == RTC_INVALID_GEOMETRY_ID) {
*hit = S3D_HIT_NULL;
@@ -434,47 +463,29 @@ s3d_scene_trace_ray
hit->uv[0] = ray.u;
hit->uv[1] = ray.v;
hit->distance = ray.tfar;
- hit->iprim = ray.primID;
+ hit->iprim[TRIANGLE_ID] = ray.primID;
if((unsigned)ray.instID == RTC_INVALID_GEOMETRY_ID) {
ASSERT((unsigned)ray.geomID
< darray_geom2shape_size_get(&scn->geom2shape));
- hit->shape = darray_geom2shape_data_get
- (&scn->geom2shape)[ray.geomID];
+ hit->shape = darray_geom2shape_data_get(&scn->geom2shape)[ray.geomID];
ASSERT(hit->shape != NULL && (unsigned)ray.geomID == hit->shape->rtc_geom);
ASSERT(hit->shape->type == SHAPE_MESH);
- hit->scene = scn;
+ hit->iprim[GEOMETRY_ID] = RTC_INVALID_GEOMETRY_ID;
} else { /* The hit shape is instantiated */
/* Retrieve the hit instance */
ASSERT((unsigned)ray.instID
< darray_geom2shape_size_get(&scn->geom2shape));
- hit->shape = darray_geom2shape_data_get
- (&scn->geom2shape)[ray.instID];
- ASSERT(hit->shape != NULL && (unsigned)ray.instID == hit->shape->rtc_geom);
+ hit->shape = darray_geom2shape_data_get(&scn->geom2shape)[ray.instID];
ASSERT(hit->shape->type == SHAPE_INSTANCE);
- hit->scene = hit->shape->data.instance.scene;
-
- /* Retrieve the hit geometry into the instance */
+ ASSERT(hit->shape != NULL && (unsigned)ray.instID == hit->shape->rtc_geom);
ASSERT((unsigned)ray.geomID
- < darray_geom2shape_size_get(&hit->scene->geom2shape));
- hit->shape = darray_geom2shape_data_get
- (&hit->scene->geom2shape)[ray.geomID];
- ASSERT(hit->shape != NULL && (unsigned)ray.geomID == hit->shape->rtc_geom);
- ASSERT(hit->shape->type == SHAPE_MESH);
+ < darray_geom2shape_size_get(&hit->shape->data.instance.scene->geom2shape));
+ hit->iprim[GEOMETRY_ID] = ray.geomID;
}
}
+ mutex_rw_unlock(scn->lock_rtc);
return RES_OK;
}
-/*******************************************************************************
- * Local function
- ******************************************************************************/
-void
-scene_remove_shape(struct s3d_scene* scn, struct s3d_shape* shape)
-{
- ASSERT(scn);
- mutex_lock(scn->lock);
- scene_remove_shape_unsafe(scn, shape);
- mutex_unlock(scn->lock);
-}
diff --git a/src/s3d_scene_c.h b/src/s3d_scene_c.h
@@ -56,6 +56,12 @@ struct s3d_scene {
ref_T ref;
};
+/* Return NULL if `rtc_geom' is not registered into `scn' */
+extern LOCAL_SYM struct s3d_shape*
+scene_shape_from_rtc_geom
+ (struct s3d_scene* scn,
+ const unsigned rtc_geom);
+
extern LOCAL_SYM void
scene_remove_shape
(struct s3d_scene* scn,
diff --git a/src/s3d_shape.c b/src/s3d_shape.c
@@ -381,20 +381,20 @@ res_T
s3d_shape_get_attrib
(const struct s3d_shape* shape,
const enum s3d_attrib_usage usage,
- const unsigned iprim,
+ const unsigned iprim[2],
const float uv[2],
struct s3d_attrib* attrib)
{
const uint32_t* ids;
+ unsigned itri;
+ const struct s3d_shape* mesh = NULL;
+ const float* transform = NULL;
float w;
res_T res = RES_OK;
if(!shape || !usage == S3D_ATTRIBS_COUNT__ || !uv || !attrib)
return RES_BAD_ARG;
- /* Unsupported mesh type */
- if(shape->type != SHAPE_MESH)
- return RES_BAD_ARG;
/* Unormalized barycentric coordinates */
w = 1.f - uv[0] - uv[1];
if(uv[0] < 0.f || uv[1] < 0.f || !eq_eps(w, 1.f, 1.e-6f))
@@ -402,6 +402,25 @@ s3d_shape_get_attrib
mutex_rw_rlock(shape->lock);
+ switch(shape->type) {
+ case SHAPE_INSTANCE:
+ mesh = scene_shape_from_rtc_geom
+ (shape->data.instance.scene, iprim[GEOMETRY_ID]);
+ if(!mesh) {
+ res = RES_BAD_ARG;
+ goto error;
+ }
+ ASSERT(mesh->type == SHAPE_MESH);
+ transform = shape->data.instance.transform;
+ break;
+ case SHAPE_MESH:
+ mesh = shape;
+ break;
+ default: /* Unsupported primitive type */
+ res = RES_BAD_ARG;
+ goto error;
+ }
+
/* The mesh haven't the required mesh attrib */
if(usage != S3D_GEOMETRY_NORMAL
&& !darray_float_size_get(shape->data.mesh.attribs + usage)) {
@@ -409,15 +428,15 @@ s3d_shape_get_attrib
goto error;
}
/* Out of bound primitive index */
- if(iprim >= darray_u32_size_get(&shape->data.mesh.indices) / 3/*# prim ids*/) {
+ itri = iprim[TRIANGLE_ID];
+ if(itri >= darray_u32_size_get(&shape->data.mesh.indices) / 3/*# prim ids*/) {
res = RES_BAD_ARG;
goto error;
}
- ids = darray_u32_cdata_get(&shape->data.mesh.indices) + iprim * 3;
+ ids = darray_u32_cdata_get(&shape->data.mesh.indices) + itri * 3;
attrib->usage = usage;
if(usage == S3D_POSITION || usage == S3D_GEOMETRY_NORMAL) {
- /* TODO take into account the instance transformation */
const float* v0, *v1, *v2;
const float* pos;
attrib->type = S3D_FLOAT3;
@@ -429,11 +448,20 @@ s3d_shape_get_attrib
if(usage == S3D_GEOMETRY_NORMAL) { /* Compute the geometry normal */
float e0[3], e1[3];
f3_cross(attrib->value, f3_sub(e0, v1, v0), f3_sub(e1, v2, v0));
+ if(transform) { /* Transform the normal from local to world space */
+ float transform_invtrans[9];
+ f33_invtrans(transform_invtrans, transform);
+ f33_mulf3(attrib->value, transform_invtrans, attrib->value);
+ }
} else { /* Interpolate the vertex position */
float tmp[3];
f3_mulf(attrib->value, v0, uv[0]);
f3_add(attrib->value, attrib->value, f3_mulf(tmp, v1, uv[1]));
f3_add(attrib->value, attrib->value, f3_mulf(tmp, v2, w));
+ if(transform) { /* Transform the position from local to world space */
+ f33_mulf3(attrib->value, transform, attrib->value); /* Rotation */
+ f3_add(attrib->value, attrib->value, transform + 9); /* Translation */
+ }
}
} else {
const float* attr;
diff --git a/src/s3d_shape_c.h b/src/s3d_shape_c.h
@@ -55,6 +55,12 @@ enum shape_type {
SHAPE_NONE = SHAPE_TYPES_COUNT__
};
+/* Helper constants use as synthactic sugar to index the primitive identifiers */
+enum {
+ GEOMETRY_ID, /* Index toward the Embree Geometry ID of the primtive */
+ TRIANGLE_ID /* Index toward the Embree triangle ID of the primitive*/
+};
+
struct mesh { /* Triangular mesh */
darray_u32 indices;
darray_float attribs[S3D_ATTRIBS_COUNT__];