star-uvm

Spatial structuring of unstructured volumetric meshes
git clone git://git.meso-star.fr/star-uvm.git
Log | Files | Refs | README | LICENSE

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:
Msrc/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 */