commit 7b7d005583773071edb3a1b58d8fb572a0e77db0
parent 3aecf0499972bd03c9f3ba2becde012eb669049e
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Wed, 25 Mar 2015 18:19:34 +0100
Test the s3d_primitive_get_attrib function
Ensure that the hit uv parameter map to the first and second triangle
vertices, respectively. Fix the geometry normal computation to
ensure that for a given triangle, its direction is the same as its hit
geometry normal.
Diffstat:
5 files changed, 60 insertions(+), 15 deletions(-)
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
@@ -49,6 +49,10 @@ find_package(RSys 0.1.1 REQUIRED)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${RCMAKE_SOURCE_DIR})
include(rcmake)
+if(CMAKE_COMPILER_IS_GNUCXX)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-long-long")
+endif()
+
include_directories(${Embree_INCLUDE_DIR} ${RSys_INCLUDE_DIR})
################################################################################
diff --git a/src/s3d.h b/src/s3d.h
@@ -276,7 +276,7 @@ s3d_shape_sample
* coordinates `uv' */
S3D_API res_T
s3d_primitive_get_attrib
- (struct s3d_primitive* prim,
+ (const struct s3d_primitive* prim,
const enum s3d_attrib_usage attr, /* Attribute to retrieve */
const float uv[2], /* Barycentric coordinates of `attr' on `iprim' */
struct s3d_attrib* attrib); /* Resulting attrib */
diff --git a/src/s3d_primitive.c b/src/s3d_primitive.c
@@ -44,7 +44,6 @@ res_T
s3d_primitive_get_attrib
(const struct s3d_primitive* prim,
const enum s3d_attrib_usage usage,
- const unsigned iprim[2],
const float uv[2],
struct s3d_attrib* attrib)
{
@@ -59,13 +58,14 @@ s3d_primitive_get_attrib
/* 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))
+ if(uv[0] < 0.f || uv[1] < 0.f || w < 0.f || w > 1.f)
return RES_BAD_ARG;
if(prim->igeom__ == RTC_INVALID_GEOMETRY_ID) {
mesh = (struct mesh*)prim->ptr__;
} else {
const struct instance* inst = (const struct instance*)prim->ptr__;
+ transform = inst->transform;
mesh = scene_get_mesh(inst->scene, prim->igeom__);
if(!mesh) {
res = RES_BAD_ARG;
@@ -98,7 +98,7 @@ s3d_primitive_get_attrib
v2 = pos + ids[2] * 3;
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));
+ f3_cross(attrib->value, f3_sub(e0, v2, v0), f3_sub(e1, v1, v0));
if(transform) { /* Transform the normal from local to world space */
float transform_invtrans[9];
f33_invtrans(transform_invtrans, transform);
diff --git a/src/s3d_scene.c b/src/s3d_scene.c
@@ -244,7 +244,10 @@ scene_setup_shape_instance(struct s3d_scene* scn, struct s3d_shape* shape)
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 ... */
+ /* It is not necessary to get a reference onto the instantiated scene since
+ * the scene get a reference onto its shape. Anyway it is actually more
+ * consistent */
+ S3D(scene_ref_get(shape->data.instance.scene));
inst->scene = shape->data.instance.scene;
}
ASSERT(inst->scene == shape->data.instance.scene);
@@ -378,7 +381,7 @@ s3d_scene_create(struct s3d_device* dev, struct s3d_scene** out_scn)
S3D(device_ref_get(dev));
scn->dev = dev;
scn->rtc_scn = rtcNewScene
- (RTC_SCENE_DYNAMIC | RTC_SCENE_INCOHERENT,
+ (RTC_SCENE_DYNAMIC | RTC_SCENE_INCOHERENT | RTC_SCENE_ROBUST,
RTC_INTERSECT1 | RTC_INTERSECT4);
if(!scn->rtc_scn) {
res = RES_MEM_ERR;
@@ -551,10 +554,25 @@ s3d_scene_trace_ray
if((unsigned)ray.geomID == RTC_INVALID_GEOMETRY_ID) { /* No hit */
*hit = S3D_HIT_NULL;
} else {
+ float w;
f3_set(hit->normal, ray.Ng);
+ hit->distance = ray.tfar;
+
hit->uv[0] = ray.u;
hit->uv[1] = ray.v;
- hit->distance = ray.tfar;
+ w = 1.f - hit->uv[0] - hit->uv[1];
+ ASSERT(w <= 1.f); /* This may not occurs */
+ if(w < 0.f) { /* Handle precision error */
+ if(hit->uv[0] > hit->uv[1]) hit->uv[0] += w;
+ else hit->uv[1] += w;
+ w = 0.f;
+ }
+ /* Embree stores on the u and v parameters the barycentric coordinate of
+ * the hit intersection with respect to the second and third triangle
+ * vertices, respectively. The following code maps the u and v coordinate
+ * to the first and second triangle vertices */
+ hit->uv[1] = hit->uv[0];
+ hit->uv[0] = w;
if((unsigned)ray.instID == RTC_INVALID_GEOMETRY_ID) {
ASSERT((unsigned)ray.geomID < darray_geom2mesh_size_get(&scn->geom2mesh));
@@ -564,7 +582,7 @@ s3d_scene_trace_ray
} else { /* The hit shape is instantiated */
/* Retrieve the hit instance */
ASSERT((unsigned)ray.instID < darray_geom2inst_size_get(&scn->geom2inst));
- hit->prim.ptr__ = darray_geom2inst_data_get(&scn->geom2inst);
+ hit->prim.ptr__ = darray_geom2inst_data_get(&scn->geom2inst)[ray.instID];
hit->prim.igeom__ = ray.geomID;
hit->prim.iprim__ = ray.primID;
}
diff --git a/src/test_s3d_trace_ray.c b/src/test_s3d_trace_ray.c
@@ -159,25 +159,25 @@ main(int argc, char** argv)
CHECK(s3d_scene_create(dev, &scn2), RES_OK);
- f3(org, -555.f, 0.f, -551.f);
+ f3(org, -560.f, 0.f, -556.f);
CHECK(s3d_shape_ref_put(shape), RES_OK);
CHECK(s3d_scene_instantiate(scn, &shape), RES_OK);
CHECK(s3d_scene_attach_shape(scn2, shape), RES_OK);
CHECK(s3d_instance_set_position(shape, org), RES_OK);
- f3(org, 3.f, 0.f, -551.f);
+ f3(org, 7.f, 0.f, -556.f);
CHECK(s3d_shape_ref_put(shape), RES_OK);
CHECK(s3d_scene_instantiate(scn, &shape), RES_OK);
CHECK(s3d_scene_attach_shape(scn2, shape), RES_OK);
CHECK(s3d_instance_set_position(shape, org), RES_OK);
- f3(org, -555.f, 0.f, 3.f);
+ f3(org, -560.f, 0.f, 7.f);
CHECK(s3d_shape_ref_put(shape), RES_OK);
CHECK(s3d_scene_instantiate(scn, &shape), RES_OK);
CHECK(s3d_scene_attach_shape(scn2, shape), RES_OK);
CHECK(s3d_instance_set_position(shape, org), RES_OK);
- f3(org, 3.f, 0.f, 3.f);
+ f3(org, 7.f, 0.f, 7.f);
CHECK(s3d_shape_ref_put(shape), RES_OK);
CHECK(s3d_scene_instantiate(scn, &shape), RES_OK);
CHECK(s3d_scene_attach_shape(scn2, shape), RES_OK);
@@ -196,16 +196,38 @@ main(int argc, char** argv)
pixel[0] = (float)ix/(float)IMG_WIDTH;
camera_ray(&cam, pixel, org, dir);
CHECK(s3d_scene_trace_ray(scn2, org, dir, range, &hit), RES_OK);
- if(!img)
- continue;
if(S3D_HIT_NONE(&hit)) {
- img[ipix+0] = img[ipix+1] = img[ipix+2] = 0;
+ if(img) {
+ img[ipix+0] = img[ipix+1] = img[ipix+2] = 0;
+ }
} else {
float wi[3], N[3], cos_theta, len;
unsigned char color;
+ struct s3d_attrib attr;
+ float pos[3];
+
+ CHECK(s3d_primitive_get_attrib
+ (&hit.prim, S3D_POSITION, hit.uv, &attr), RES_OK);
+ CHECK(attr.type, S3D_FLOAT3);
+ CHECK(attr.usage, S3D_POSITION);
+ f3_add(pos, f3_mulf(pos, dir, hit.distance), org);
+ CHECK(f3_eq_eps
+ (pos, attr.value, 1.e-2f/*Sic O_o!! Really bad precision!*/), 1);
+
len = f3_normalize(N, hit.normal);
NCHECK(len, 0);
+
+ CHECK(s3d_primitive_get_attrib
+ (&hit.prim, S3D_GEOMETRY_NORMAL, hit.uv, &attr), RES_OK);
+ CHECK(attr.type, S3D_FLOAT3);
+ CHECK(attr.usage, S3D_GEOMETRY_NORMAL);
+ f3_normalize(attr.value, attr.value);
+ CHECK(f3_eq_eps(attr.value, N, 1.e-6f), 1);
+
+ if(!img)
+ continue;
+
cos_theta = f3_dot(f3_minus(wi, dir), N);
color = (unsigned char)(cos_theta * 255.f);
img[ipix+0] = color;
@@ -232,3 +254,4 @@ main(int argc, char** argv)
return 0;
}
+