diff options
Diffstat (limited to 'source/blender/blenkernel/intern/mesh_evaluate.c')
-rw-r--r-- | source/blender/blenkernel/intern/mesh_evaluate.c | 150 |
1 files changed, 113 insertions, 37 deletions
diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c index a334951c772..a65ac5151a8 100644 --- a/source/blender/blenkernel/intern/mesh_evaluate.c +++ b/source/blender/blenkernel/intern/mesh_evaluate.c @@ -51,6 +51,7 @@ #include "BLI_task.h" #include "BKE_customdata.h" +#include "BKE_global.h" #include "BKE_mesh.h" #include "BKE_multires.h" #include "BKE_report.h" @@ -132,7 +133,7 @@ void BKE_mesh_calc_normals_mapping_ex( if (only_face_normals == false) { /* vertex normals are optional, they require some extra calculations, * so make them optional */ - BKE_mesh_calc_normals_poly(mverts, numVerts, mloop, mpolys, numLoops, numPolys, pnors, false); + BKE_mesh_calc_normals_poly(mverts, NULL, numVerts, mloop, mpolys, numLoops, numPolys, pnors, false); } else { /* only calc poly normals */ @@ -221,18 +222,20 @@ static void mesh_calc_normals_poly_accum( } void BKE_mesh_calc_normals_poly( - MVert *mverts, int numVerts, + MVert *mverts, float (*r_vertnors)[3], int numVerts, const MLoop *mloop, const MPoly *mpolys, int UNUSED(numLoops), int numPolys, float (*r_polynors)[3], const bool only_face_normals) { float (*pnors)[3] = r_polynors; - float (*tnorms)[3]; + float (*vnors)[3] = r_vertnors; + bool free_vnors = false; int i; const MPoly *mp; if (only_face_normals) { BLI_assert((pnors != NULL) || (numPolys == 0)); + BLI_assert(r_vertnors == NULL); #pragma omp parallel for if (numPolys > BKE_MESH_OMP_LIMIT) for (i = 0; i < numPolys; i++) { @@ -242,25 +245,30 @@ void BKE_mesh_calc_normals_poly( } /* first go through and calculate normals for all the polys */ - tnorms = MEM_callocN(sizeof(*tnorms) * (size_t)numVerts, __func__); + if (vnors == NULL) { + vnors = MEM_callocN(sizeof(*vnors) * (size_t)numVerts, __func__); + free_vnors = true; + } + else { + memset(vnors, 0, sizeof(*vnors) * (size_t)numVerts); + } + mp = mpolys; if (pnors) { - mp = mpolys; for (i = 0; i < numPolys; i++, mp++) { - mesh_calc_normals_poly_accum(mp, mloop + mp->loopstart, mverts, pnors[i], tnorms); + mesh_calc_normals_poly_accum(mp, mloop + mp->loopstart, mverts, pnors[i], vnors); } } else { float tpnor[3]; /* temp poly normal */ - mp = mpolys; for (i = 0; i < numPolys; i++, mp++) { - mesh_calc_normals_poly_accum(mp, mloop + mp->loopstart, mverts, tpnor, tnorms); + mesh_calc_normals_poly_accum(mp, mloop + mp->loopstart, mverts, tpnor, vnors); } } for (i = 0; i < numVerts; i++) { MVert *mv = &mverts[i]; - float *no = tnorms[i]; + float *no = vnors[i]; if (UNLIKELY(normalize_v3(no) == 0.0f)) { /* following Mesh convention; we use vertex coordinate itself for normal in this case */ @@ -270,7 +278,9 @@ void BKE_mesh_calc_normals_poly( normal_float_to_short_v3(mv->no, no); } - MEM_freeN(tnorms); + if (free_vnors) { + MEM_freeN(vnors); + } } void BKE_mesh_calc_normals(Mesh *mesh) @@ -278,7 +288,7 @@ void BKE_mesh_calc_normals(Mesh *mesh) #ifdef DEBUG_TIME TIMEIT_START(BKE_mesh_calc_normals); #endif - BKE_mesh_calc_normals_poly(mesh->mvert, mesh->totvert, + BKE_mesh_calc_normals_poly(mesh->mvert, NULL, mesh->totvert, mesh->mloop, mesh->mpoly, mesh->totloop, mesh->totpoly, NULL, false); #ifdef DEBUG_TIME @@ -883,7 +893,9 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, LoopSpli clnors_avg[0] /= clnors_nbr; clnors_avg[1] /= clnors_nbr; /* Fix/update all clnors of this fan with computed average value. */ - printf("Invalid clnors in this fan!\n"); + if (G.debug & G_DEBUG) { + printf("Invalid clnors in this fan!\n"); + } while ((clnor = BLI_SMALLSTACK_POP(clnors))) { //print_v2("org clnor", clnor); clnor[0] = (short)clnors_avg[0]; @@ -1338,12 +1350,14 @@ void BKE_mesh_normals_loop_split( * Compute internal representation of given custom normals (as an array of float[2]). * It also makes sure the mesh matches those custom normals, by setting sharp edges flag as needed to get a * same custom lnor for all loops sharing a same smooth fan. - * If use_vertices if true, custom_loopnors is assumed to be per-vertex, not per-loop + * If use_vertices if true, r_custom_loopnors is assumed to be per-vertex, not per-loop * (this allows to set whole vert's normals at once, useful in some cases). + * r_custom_loopnors is expected to have normalized normals, or zero ones, in which case they will be replaced + * by default loop/vertex normal. */ static void mesh_normals_loop_custom_set( const MVert *mverts, const int numVerts, MEdge *medges, const int numEdges, - MLoop *mloops, float (*custom_loopnors)[3], const int numLoops, + MLoop *mloops, float (*r_custom_loopnors)[3], const int numLoops, MPoly *mpolys, const float (*polynors)[3], const int numPolys, short (*r_clnors_data)[2], const bool use_vertices) { @@ -1369,6 +1383,22 @@ static void mesh_normals_loop_custom_set( mpolys, polynors, numPolys, use_split_normals, split_angle, &lnors_spacearr, NULL, loop_to_poly); + /* Set all given zero vectors to their default value. */ + if (use_vertices) { + for (i = 0; i < numVerts; i++) { + if (is_zero_v3(r_custom_loopnors[i])) { + normal_short_to_float_v3(r_custom_loopnors[i], mverts[i].no); + } + } + } + else { + for (i = 0; i < numLoops; i++) { + if (is_zero_v3(r_custom_loopnors[i])) { + copy_v3_v3(r_custom_loopnors[i], lnors[i]); + } + } + } + /* Now, check each current smooth fan (one lnor space per smooth fan!), and if all its matching custom lnors * are not (enough) equal, add sharp edges as needed. * This way, next time we run BKE_mesh_normals_loop_split(), we'll get lnor spacearr/smooth fans matching @@ -1384,7 +1414,9 @@ static void mesh_normals_loop_custom_set( * Maybe we should set those loops' edges as sharp? */ BLI_BITMAP_ENABLE(done_loops, i); - printf("WARNING! Getting invalid NULL loop space for loop %d!\n", i); + if (G.debug & G_DEBUG) { + printf("WARNING! Getting invalid NULL loop space for loop %d!\n", i); + } continue; } @@ -1406,11 +1438,7 @@ static void mesh_normals_loop_custom_set( const int lidx = GET_INT_FROM_POINTER(loops->link); MLoop *ml = &mloops[lidx]; const int nidx = lidx; - float *nor = custom_loopnors[nidx]; - - if (is_zero_v3(nor)) { - nor = lnors[nidx]; - } + float *nor = r_custom_loopnors[nidx]; if (!org_nor) { org_nor = nor; @@ -1432,7 +1460,26 @@ static void mesh_normals_loop_custom_set( loops = loops->next; BLI_BITMAP_ENABLE(done_loops, lidx); } - BLI_BITMAP_ENABLE(done_loops, i); /* For single loops, where lnors_spacearr.lspacearr[i]->loops is NULL. */ + + /* We also have to check between last and first loops, otherwise we may miss some sharp edges here! + * This is just a simplified version of above while loop. + * See T45984. */ + loops = lnors_spacearr.lspacearr[i]->loops; + if (loops && org_nor) { + const int lidx = GET_INT_FROM_POINTER(loops->link); + MLoop *ml = &mloops[lidx]; + const int nidx = lidx; + float *nor = r_custom_loopnors[nidx]; + + if (dot_v3v3(org_nor, nor) < LNOR_SPACE_TRIGO_THRESHOLD) { + const MPoly *mp = &mpolys[loop_to_poly[lidx]]; + const MLoop *mlp = &mloops[(lidx == mp->loopstart) ? mp->loopstart + mp->totloop - 1 : lidx - 1]; + medges[(prev_ml->e == mlp->e) ? prev_ml->e : ml->e].flag |= ME_SHARP; + } + } + + /* For single loops, where lnors_spacearr.lspacearr[i]->loops is NULL. */ + BLI_BITMAP_ENABLE(done_loops, i); } } @@ -1450,7 +1497,9 @@ static void mesh_normals_loop_custom_set( for (i = 0; i < numLoops; i++) { if (!lnors_spacearr.lspacearr[i]) { BLI_BITMAP_DISABLE(done_loops, i); - printf("WARNING! Still getting invalid NULL loop space in second loop for loop %d!\n", i); + if (G.debug & G_DEBUG) { + printf("WARNING! Still getting invalid NULL loop space in second loop for loop %d!\n", i); + } continue; } @@ -1469,11 +1518,7 @@ static void mesh_normals_loop_custom_set( while (loops) { const int lidx = GET_INT_FROM_POINTER(loops->link); const int nidx = use_vertices ? (int)mloops[lidx].v : lidx; - float *nor = custom_loopnors[nidx]; - - if (is_zero_v3(nor)) { - nor = lnors[nidx]; - } + float *nor = r_custom_loopnors[nidx]; nbr_nors++; add_v3_v3(avg_nor, nor); @@ -1493,7 +1538,7 @@ static void mesh_normals_loop_custom_set( } else { const int nidx = use_vertices ? (int)mloops[i].v : i; - float *nor = custom_loopnors[nidx]; + float *nor = r_custom_loopnors[nidx]; BKE_lnor_space_custom_normal_to_data(lnors_spacearr.lspacearr[i], nor, r_clnors_data[i]); BLI_BITMAP_DISABLE(done_loops, i); @@ -1509,24 +1554,56 @@ static void mesh_normals_loop_custom_set( void BKE_mesh_normals_loop_custom_set( const MVert *mverts, const int numVerts, MEdge *medges, const int numEdges, - MLoop *mloops, float (*custom_loopnors)[3], const int numLoops, + MLoop *mloops, float (*r_custom_loopnors)[3], const int numLoops, MPoly *mpolys, const float (*polynors)[3], const int numPolys, short (*r_clnors_data)[2]) { - mesh_normals_loop_custom_set(mverts, numVerts, medges, numEdges, mloops, custom_loopnors, numLoops, + mesh_normals_loop_custom_set(mverts, numVerts, medges, numEdges, mloops, r_custom_loopnors, numLoops, mpolys, polynors, numPolys, r_clnors_data, false); } void BKE_mesh_normals_loop_custom_from_vertices_set( - const MVert *mverts, float (*custom_vertnors)[3], const int numVerts, + const MVert *mverts, float (*r_custom_vertnors)[3], const int numVerts, MEdge *medges, const int numEdges, MLoop *mloops, const int numLoops, MPoly *mpolys, const float (*polynors)[3], const int numPolys, short (*r_clnors_data)[2]) { - mesh_normals_loop_custom_set(mverts, numVerts, medges, numEdges, mloops, custom_vertnors, numLoops, + mesh_normals_loop_custom_set(mverts, numVerts, medges, numEdges, mloops, r_custom_vertnors, numLoops, mpolys, polynors, numPolys, r_clnors_data, true); } +/** + * Computes average per-vertex normals from given custom loop normals. + * + * @param clnors The computed custom loop normals. + * @param r_vert_clnors The (already allocated) array where to store averaged per-vertex normals. + */ +void BKE_mesh_normals_loop_to_vertex( + const int numVerts, const MLoop *mloops, const int numLoops, + const float (*clnors)[3], float (*r_vert_clnors)[3]) +{ + const MLoop *ml; + int i; + + int *vert_loops_nbr = MEM_callocN(sizeof(*vert_loops_nbr) * (size_t)numVerts, __func__); + + copy_vn_fl((float *)r_vert_clnors, 3 * numVerts, 0.0f); + + for (i = 0, ml = mloops; i < numLoops; i++, ml++) { + const unsigned int v = ml->v; + + add_v3_v3(r_vert_clnors[v], clnors[i]); + vert_loops_nbr[v]++; + } + + for (i = 0; i < numVerts; i++) { + mul_v3_fl(r_vert_clnors[i], 1.0f / (float)vert_loops_nbr[i]); + } + + MEM_freeN(vert_loops_nbr); +} + + #undef LNOR_SPACE_TRIGO_THRESHOLD /** \} */ @@ -2121,8 +2198,7 @@ void BKE_mesh_calc_volume( totvol += vol; } if (r_center) { - /* averaging factor 1/4 is applied in the end */ - madd_v3_v3fl(r_center, center, vol); /* XXX could extract this */ + /* averaging factor 1/3 is applied in the end */ madd_v3_v3fl(r_center, v1->co, vol); madd_v3_v3fl(r_center, v2->co, vol); madd_v3_v3fl(r_center, v3->co, vol); @@ -2137,11 +2213,11 @@ void BKE_mesh_calc_volume( *r_volume = fabsf(totvol); } if (r_center) { - /* Note: Factor 1/4 is applied once for all vertices here. + /* Note: Factor 1/3 is applied once for all vertices here. * This also automatically negates the vector if totvol is negative. */ if (totvol != 0.0f) - mul_v3_fl(r_center, 0.25f / totvol); + mul_v3_fl(r_center, (1.0f / 3.0f) / totvol); } } @@ -3180,7 +3256,7 @@ void BKE_mesh_flush_hidden_from_polys_ex(MVert *mvert, j = mp->totloop; for (ml = &mloop[mp->loopstart]; j--; ml++) { mvert[ml->v].flag &= (char)~ME_HIDE; - medge[ml->e].flag &= (char)~ME_HIDE; + medge[ml->e].flag &= (short)~ME_HIDE; } } } |