commit 860b5418492f3bab4cb091cd356ba02ce123c64d
parent 1fd7e0a80b08065608d2884c6d72a180bb1ed137
Author: Vincent Forest <vincent.forest@meso-star.com>
Date: Thu, 4 Mar 2021 16:57:38 +0100
Fix precomputed normals on tetrahedra with wrong orientation
Diffstat:
| M | src/suvm_volume.c | | | 97 | +++++++++++++++++++++++++++++++++---------------------------------------------- |
1 file changed, 40 insertions(+), 57 deletions(-)
diff --git a/src/suvm_volume.c b/src/suvm_volume.c
@@ -179,38 +179,6 @@ error:
}
static res_T
-compute_tetrahedral_mesh_normals(struct suvm_volume* vol)
-{
- size_t itetra;
- size_t ntetrahedra;
- res_T res = RES_OK;
- ASSERT(vol);
-
- ntetrahedra = volume_get_primitives_count(vol);
-
- res = darray_float_resize(&vol->normals,
- ntetrahedra * 4/*#facets per tetrahedron*/ * 3/*#coords per normal*/);
- if(res != RES_OK) goto error;
-
- FOR_EACH(itetra, 0, ntetrahedra) {
- float* n0 = darray_float_data_get(&vol->normals) + (itetra*4 + 0)*3;
- float* n1 = darray_float_data_get(&vol->normals) + (itetra*4 + 1)*3;
- float* n2 = darray_float_data_get(&vol->normals) + (itetra*4 + 2)*3;
- float* n3 = darray_float_data_get(&vol->normals) + (itetra*4 + 3)*3;
- volume_primitive_compute_facet_normal(vol, itetra, 0, n0);
- volume_primitive_compute_facet_normal(vol, itetra, 1, n1);
- volume_primitive_compute_facet_normal(vol, itetra, 2, n2);
- volume_primitive_compute_facet_normal(vol, itetra, 3, n3);
- }
-
-exit:
- return res;
-error:
- darray_float_purge(&vol->normals);
- goto exit;
-}
-
-static res_T
setup_tetrahedral_mesh
(struct suvm_volume* vol, const struct suvm_tetrahedral_mesh_args* args)
{
@@ -222,12 +190,6 @@ setup_tetrahedral_mesh
res = setup_tetrahedral_mesh_position(vol, args);
if(res != RES_OK) goto error;
- /* Precompute the facet normals */
- if(args->precompute_normals) {
- res = compute_tetrahedral_mesh_normals(vol);
- if(res != RES_OK) goto error;
- }
-
/* Store the per tetrahedron data */
if(args->tetrahedron_data.get) {
res = buffer_init_from_data(vol->dev->allocator, &vol->prim_data,
@@ -444,20 +406,30 @@ error:
}
static res_T
-fixup_tetrahedra_normals(struct suvm_volume* vol)
+setup_tetrahedra_normals
+ (struct suvm_volume* vol,
+ const int precompute_normals)
{
size_t itetra, ntetra;
int fixup = 0;
+ res_T res = RES_OK;
ASSERT(vol);
ntetra = volume_get_primitives_count(vol);
+ if(precompute_normals) {
+ res = darray_float_resize(&vol->normals,
+ ntetra * 4/*#facets per tetrahedron*/ * 3/*#coords per normal*/);
+ if(res != RES_OK) goto error;
+ }
+
FOR_EACH(itetra, 0, ntetra) {
uint32_t* ids = NULL;
const float* vert0 = NULL;
const float* vert3 = NULL;
float normal0[3];
float v0[3];
+ int flip = 0;
/* Fetch tetrahedron indices */
ids = darray_u32_data_get(&vol->indices) + itetra*4;
@@ -470,27 +442,33 @@ fixup_tetrahedra_normals(struct suvm_volume* vol)
vert0 = darray_float_cdata_get(&vol->positions) + ids[0]*3/*#coords*/;
vert3 = darray_float_cdata_get(&vol->positions) + ids[3]*3/*#coords*/;
- /* Fetch the normal of the 1st facet */
- volume_primitive_get_facet_normal(vol, itetra, 0, normal0);
+ /* Compute the normal of the 1st facet */
+ volume_primitive_compute_facet_normal(vol, itetra, 0, normal0);
/* Check that the normal of the 1st facet looks the fourth vertex */
if(f3_dot(normal0, f3_sub(v0, vert3, vert0)) < 0) {
- fixup = 1;
-
- /* Revert tetrahedron orientation, i.e. the vertices of the 1st facet*/
+ fixup = flip = 1;
+ /* Revert tetrahedron orientation */
SWAP(uint32_t, ids[1], ids[2]);
+ }
- /* Revert precomputed normals if any */
- if(darray_float_size_get(&vol->normals)) {
- size_t ifacet;
- FOR_EACH(ifacet, 0, 4) {
- const size_t id = (itetra*4/*#facets*/ + ifacet)*3/*#coords*/;
- float* N = darray_float_data_get(&vol->normals) + id;
- N[0] = -N[0];
- N[1] = -N[1];
- N[2] = -N[2];
- }
+ /* Precompute the normals */
+ if(precompute_normals) {
+ float* n0 = darray_float_data_get(&vol->normals) + (itetra*4 + 0)*3;
+ float* n1 = darray_float_data_get(&vol->normals) + (itetra*4 + 1)*3;
+ float* n2 = darray_float_data_get(&vol->normals) + (itetra*4 + 2)*3;
+ float* n3 = darray_float_data_get(&vol->normals) + (itetra*4 + 3)*3;
+ if(!flip) {
+ f3_set(n0, normal0);
+ } else {
+ /* Do not simply negate the normal of the facet 0 if the tetrahedron
+ * vertices wer flipped but recompute it from scratch. This ensure that
+ * precomputed normals are strictly the same of non-precomputed ones */
+ volume_primitive_compute_facet_normal(vol, itetra, 0, n0);
}
+ volume_primitive_compute_facet_normal(vol, itetra, 1, n1);
+ volume_primitive_compute_facet_normal(vol, itetra, 2, n2);
+ volume_primitive_compute_facet_normal(vol, itetra, 3, n3);
}
#ifndef NDEBUG
@@ -529,7 +507,12 @@ fixup_tetrahedra_normals(struct suvm_volume* vol)
if(fixup) {
log_warn(vol->dev, "Tetrahedra were not correctly orientated.\n");
}
- return RES_OK;
+
+exit:
+ return res;
+error:
+ darray_float_purge(&vol->normals);
+ goto exit;
}
static void
@@ -618,8 +601,8 @@ suvm_tetrahedral_mesh_create
if(res != RES_OK) goto error;
/* Ensure that the vertices of the tetrahedra are well ordered regarding the
- * normal convention */
- res = fixup_tetrahedra_normals(vol);
+ * normal convention and store them if required */
+ res = setup_tetrahedra_normals(vol, args->precompute_normals);
if(res != RES_OK) goto error;
/* Build the BVH of the volumetric mesh */