From 9446225670d9f303e02f0acc642817d8709c9bfb Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Thu, 27 Apr 2023 16:23:42 -0400 Subject: [PATCH 01/22] Cleanup: Remove global mesh threading size macro The grain size depends on the algorithm, it doesn't make sense to use the same value for multiple areas just because they relate to `Mesh`. The comment mentions OpenMP which isn't used anymore. Also remove an unused forward declaration. --- source/blender/blenkernel/BKE_mesh.h | 8 -------- source/blender/blenkernel/intern/shrinkwrap.cc | 6 +++--- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index 80d2c3e0549..e9f91715650 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -16,7 +16,6 @@ #include "BKE_customdata.h" #include "BKE_mesh_types.h" -struct BLI_Stack; struct BMesh; struct BMeshCreateParams; struct BMeshFromMeshParams; @@ -44,13 +43,6 @@ struct Scene; extern "C" { #endif -/* setting zero so we can catch bugs in OpenMP/BMesh */ -#ifdef DEBUG -# define BKE_MESH_OMP_LIMIT 0 -#else -# define BKE_MESH_OMP_LIMIT 10000 -#endif - /* mesh_runtime.cc */ /** diff --git a/source/blender/blenkernel/intern/shrinkwrap.cc b/source/blender/blenkernel/intern/shrinkwrap.cc index c24e83615f5..b7a2ddf725f 100644 --- a/source/blender/blenkernel/intern/shrinkwrap.cc +++ b/source/blender/blenkernel/intern/shrinkwrap.cc @@ -412,7 +412,7 @@ static void shrinkwrap_calc_nearest_vertex(ShrinkwrapCalcData *calc) data.tree = calc->tree; TaskParallelSettings settings; BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = (calc->numVerts > BKE_MESH_OMP_LIMIT); + settings.use_threading = (calc->numVerts > 10000); settings.userdata_chunk = &nearest; settings.userdata_chunk_size = sizeof(nearest); BLI_task_parallel_range( @@ -691,7 +691,7 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc) data.local2aux = &local2aux; TaskParallelSettings settings; BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = (calc->numVerts > BKE_MESH_OMP_LIMIT); + settings.use_threading = (calc->numVerts > 10000); settings.userdata_chunk = &hit; settings.userdata_chunk_size = sizeof(hit); BLI_task_parallel_range( @@ -1363,7 +1363,7 @@ static void shrinkwrap_calc_nearest_surface_point(ShrinkwrapCalcData *calc) data.tree = calc->tree; TaskParallelSettings settings; BLI_parallel_range_settings_defaults(&settings); - settings.use_threading = (calc->numVerts > BKE_MESH_OMP_LIMIT); + settings.use_threading = (calc->numVerts > 10000); settings.userdata_chunk = &nearest; settings.userdata_chunk_size = sizeof(nearest); BLI_task_parallel_range( -- 2.30.2 From a9903e16526f99a6a43ca630922350abf07d0306 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Thu, 27 Apr 2023 22:45:55 -0400 Subject: [PATCH 02/22] Mesh: Reduce memory usage calculating face corner normals --- source/blender/blenkernel/BKE_mesh.hh | 100 +++-- .../blender/blenkernel/intern/mesh_mirror.cc | 13 +- .../blender/blenkernel/intern/mesh_normals.cc | 349 ++++++++++-------- .../modifiers/intern/MOD_weighted_normal.cc | 44 +-- 4 files changed, 305 insertions(+), 201 deletions(-) diff --git a/source/blender/blenkernel/BKE_mesh.hh b/source/blender/blenkernel/BKE_mesh.hh index d543baa04a7..8419ed2f52a 100644 --- a/source/blender/blenkernel/BKE_mesh.hh +++ b/source/blender/blenkernel/BKE_mesh.hh @@ -50,6 +50,81 @@ void poly_angles_calc(Span vert_positions, /** \} */ +/* -------------------------------------------------------------------- */ +/** \name Face Corner Normal Calculation + * \{ */ + +/** + * Combined with the automatically calculated face corner normal, this gives a dimentional + * coordinate space used to convert normals between the "custom normal" #short2 representation and + * a regular #float3 format. + */ +struct NormalFanSpace { + /** Reference vector, orthogonal to vec_lnor. */ + float3 vec_ref; + /** Third vector, orthogonal to vec_lnor and vec_ref. */ + float3 vec_ortho; + /** Reference angle, around vec_ortho, in [0, pi] range (0.0 marks that space as invalid). */ + float ref_alpha; + /** Reference angle, around vec_lnor, in [0, 2pi] range (0.0 marks that space as invalid). */ + float ref_beta; +}; + +/** + * Storage for coordinate spaces and connection information during normal calculation. + */ +struct MeshNormalFanSpaces { + /** + * The normal coordinate spaces, potentially shared between multiple face corners in a smooth fan + * connected to a vertex. Depending on the geometry (the amount of sharing / size of each fan), + * there may be many fewer spaces than face corners, so they are stored in a separate array. + */ + Array spaces; + + /** The index in #spaces for each face corner. */ + Array corner_space_indices; + + /** + * An index-based linked list of the face corners in each smooth fan, starting at each corner. + * Each index stores the index of the next corner in the fan, or -1 if it is the last. "Single" + * fans with only a single corner store -1 at that corner index directly. + */ + Array corner_group_lists; +}; + +short2 fan_space_custom_normal_to_data(const NormalFanSpace &space, + float3 corner_normal_no_custom, + float3 custom_lnor); + +/** + * Compute split normals, i.e. vertex normals associated with each poly (hence 'loop normals'). + * Useful to materialize sharp edges (or non-smooth faces) without actually modifying the geometry + * (splitting edges). + * + * \param loop_to_poly_map: Optional pre-created map from corners to their polygon. + * \param sharp_edges: Optional array of sharp edge tags, used to split the evaluated normals on + * each side of the edge. + * \param r_lnors_spacearr: Optional return data filled with information about the custom normals + * spaces for each grouped fan of face corners. + */ +void normals_calc_loop(Span vert_positions, + Span edges, + OffsetIndices polys, + Span corner_verts, + Span corner_edges, + Span loop_to_poly_map, + Span vert_normals, + Span poly_normals, + const bool *sharp_edges, + const bool *sharp_faces, + bool use_split_normals, + float split_angle, + short (*clnors_data)[2], + MeshNormalFanSpaces *r_lnors_spacearr, + MutableSpan r_loop_normals); + +/** \} */ + /* -------------------------------------------------------------------- */ /** \name Medium-Level Normals Calculation * \{ */ @@ -77,31 +152,6 @@ void normals_calc_poly_vert(Span vert_positions, MutableSpan poly_normals, MutableSpan vert_normals); -/** - * Compute split normals, i.e. vertex normals associated with each poly (hence 'loop normals'). - * Useful to materialize sharp edges (or non-smooth faces) without actually modifying the geometry - * (splitting edges). - * - * \param loop_to_poly_map: Optional pre-created map from corners to their polygon. - * \param sharp_edges: Optional array of sharp edge tags, used to split the evaluated normals on - * each side of the edge. - */ -void normals_calc_loop(Span vert_positions, - Span edges, - OffsetIndices polys, - Span corner_verts, - Span corner_edges, - Span loop_to_poly_map, - Span vert_normals, - Span poly_normals, - const bool *sharp_edges, - const bool *sharp_faces, - bool use_split_normals, - float split_angle, - short (*clnors_data)[2], - MLoopNorSpaceArray *r_lnors_spacearr, - MutableSpan r_loop_normals); - void normals_loop_custom_set(Span vert_positions, Span edges, OffsetIndices polys, diff --git a/source/blender/blenkernel/intern/mesh_mirror.cc b/source/blender/blenkernel/intern/mesh_mirror.cc index 7ad5b5d2907..6ae3f840985 100644 --- a/source/blender/blenkernel/intern/mesh_mirror.cc +++ b/source/blender/blenkernel/intern/mesh_mirror.cc @@ -380,7 +380,7 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd, CustomData *ldata = &result->ldata; short(*clnors)[2] = static_cast( CustomData_get_layer_for_write(ldata, CD_CUSTOMLOOPNORMAL, result->totloop)); - MLoopNorSpaceArray lnors_spacearr = {nullptr}; + blender::bke::mesh::MeshNormalFanSpaces lnors_spacearr; /* The transform matrix of a normal must be * the transpose of inverse of transform matrix of the geometry... */ @@ -422,12 +422,15 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd, } copy_v3_v3(loop_normals[mirrorj], loop_normals[j]); mul_m4_v3(mtx_nor, loop_normals[mirrorj]); - BKE_lnor_space_custom_normal_to_data( - lnors_spacearr.lspacearr[mirrorj], loop_normals[mirrorj], clnors[mirrorj]); + + const int space_index = lnors_spacearr.corner_space_indices[mirrorj]; + const blender::bke::mesh::NormalFanSpace &space = lnors_spacearr.spaces[space_index]; + + copy_v2_v2_short(clnors[mirrorj], + blender::bke::mesh::fan_space_custom_normal_to_data( + space, loop_normals[mirrorj], loop_normals[mirrorj])); } } - - BKE_lnor_spacearr_free(&lnors_spacearr); } /* handle vgroup stuff */ diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc index 4e59ac434be..dbea53160ca 100644 --- a/source/blender/blenkernel/intern/mesh_normals.cc +++ b/source/blender/blenkernel/intern/mesh_normals.cc @@ -36,7 +36,7 @@ #include "atomic_ops.h" -// #define DEBUG_TIME +#define DEBUG_TIME #ifdef DEBUG_TIME # include "BLI_timeit.hh" @@ -467,12 +467,13 @@ MLoopNorSpace *BKE_lnor_space_create(MLoopNorSpaceArray *lnors_spacearr) /* This threshold is a bit touchy (usual float precision issue), this value seems OK. */ #define LNOR_SPACE_TRIGO_THRESHOLD (1.0f - 1e-4f) -void BKE_lnor_space_define(MLoopNorSpace *lnor_space, - const float lnor[3], - float vec_ref[3], - float vec_other[3], - const blender::Span edge_vectors) +namespace blender::bke::mesh { +static NormalFanSpace normal_fan_space_define(const float lnor[3], + float vec_ref[3], + float vec_other[3], + const Span edge_vectors) { + NormalFanSpace lnor_space{}; const float pi2 = float(M_PI) * 2.0f; float tvec[3], dtp; const float dtp_ref = dot_v3v3(vec_ref, lnor); @@ -482,16 +483,14 @@ void BKE_lnor_space_define(MLoopNorSpace *lnor_space, fabsf(dtp_other) >= LNOR_SPACE_TRIGO_THRESHOLD)) { /* If vec_ref or vec_other are too much aligned with lnor, we can't build lnor space, * tag it as invalid and abort. */ - lnor_space->ref_alpha = lnor_space->ref_beta = 0.0f; - return; + lnor_space.ref_alpha = lnor_space.ref_beta = 0.0f; + return lnor_space; } - copy_v3_v3(lnor_space->vec_lnor, lnor); - /* Compute ref alpha, average angle of all available edge vectors to lnor. */ if (!edge_vectors.is_empty()) { float alpha = 0.0f; - for (const blender::float3 &vec : edge_vectors) { + for (const float3 &vec : edge_vectors) { alpha += saacosf(dot_v3v3(vec, lnor)); } /* This piece of code shall only be called for more than one loop. */ @@ -500,21 +499,21 @@ void BKE_lnor_space_define(MLoopNorSpace *lnor_space, * a smooth vertex with only two edges and two faces (our Monkey's nose has that, e.g.). */ BLI_assert(edge_vectors.size() >= 2); - lnor_space->ref_alpha = alpha / float(edge_vectors.size()); + lnor_space.ref_alpha = alpha / float(edge_vectors.size()); } else { - lnor_space->ref_alpha = (saacosf(dot_v3v3(vec_ref, lnor)) + - saacosf(dot_v3v3(vec_other, lnor))) / - 2.0f; + lnor_space.ref_alpha = (saacosf(dot_v3v3(vec_ref, lnor)) + + saacosf(dot_v3v3(vec_other, lnor))) / + 2.0f; } /* Project vec_ref on lnor's ortho plane. */ mul_v3_v3fl(tvec, lnor, dtp_ref); sub_v3_v3(vec_ref, tvec); - normalize_v3_v3(lnor_space->vec_ref, vec_ref); + normalize_v3_v3(lnor_space.vec_ref, vec_ref); - cross_v3_v3v3(tvec, lnor, lnor_space->vec_ref); - normalize_v3_v3(lnor_space->vec_ortho, tvec); + cross_v3_v3v3(tvec, lnor, lnor_space.vec_ref); + normalize_v3_v3(lnor_space.vec_ortho, tvec); /* Project vec_other on lnor's ortho plane. */ mul_v3_v3fl(tvec, lnor, dtp_other); @@ -522,15 +521,43 @@ void BKE_lnor_space_define(MLoopNorSpace *lnor_space, normalize_v3(vec_other); /* Beta is angle between ref_vec and other_vec, around lnor. */ - dtp = dot_v3v3(lnor_space->vec_ref, vec_other); + dtp = dot_v3v3(lnor_space.vec_ref, vec_other); if (LIKELY(dtp < LNOR_SPACE_TRIGO_THRESHOLD)) { const float beta = saacos(dtp); - lnor_space->ref_beta = (dot_v3v3(lnor_space->vec_ortho, vec_other) < 0.0f) ? pi2 - beta : beta; + lnor_space.ref_beta = (dot_v3v3(lnor_space.vec_ortho, vec_other) < 0.0f) ? pi2 - beta : beta; } else { - lnor_space->ref_beta = pi2; + lnor_space.ref_beta = pi2; } + + return lnor_space; } +} // namespace blender::bke::mesh + +void BKE_lnor_space_define(MLoopNorSpace *lnor_space, + const float lnor[3], + float vec_ref[3], + float vec_other[3], + const blender::Span edge_vectors) +{ + using namespace blender::bke::mesh; + const NormalFanSpace space = normal_fan_space_define(lnor, vec_ref, vec_other, edge_vectors); + copy_v3_v3(lnor_space->vec_lnor, lnor); + copy_v3_v3(lnor_space->vec_ref, space.vec_ref); + copy_v3_v3(lnor_space->vec_ortho, space.vec_ortho); + lnor_space->ref_alpha = space.ref_alpha; + lnor_space->ref_beta = space.ref_beta; +} + +namespace blender::bke::mesh { +static void fan_space_add_corners(MeshNormalFanSpaces &fan_spaces, const Span corners) +{ + for (const int i : corners.index_range().drop_back(1)) { + fan_spaces.corner_group_lists[corners[i]] = corners[i + 1]; + } + fan_spaces.corner_group_lists[corners.last()] = -1; +} +} // namespace blender::bke::mesh void BKE_lnor_space_add_loop(MLoopNorSpaceArray *lnors_spacearr, MLoopNorSpace *lnor_space, @@ -567,91 +594,126 @@ MINLINE short unit_float_to_short(const float val) return short(floorf(val * float(SHRT_MAX) + 0.5f)); } +namespace blender::bke::mesh { +static float3 fan_space_custom_data_to_normal(const NormalFanSpace &lnor_space, + const float3 lnor_no_custom, + const short2 clnor_data) +{ + /* NOP custom normal data or invalid lnor space, return. */ + if (clnor_data[0] == 0 || lnor_space.ref_alpha == 0.0f || lnor_space.ref_beta == 0.0f) { + return lnor_no_custom; + } + + float3 r_custom_lnor(0.0f); + + /* TODO: Check whether using #sincosf() gives any noticeable benefit + * (could not even get it working under linux though)! */ + const float pi2 = float(M_PI * 2.0); + const float alphafac = unit_short_to_float(clnor_data[0]); + const float alpha = (alphafac > 0.0f ? lnor_space.ref_alpha : pi2 - lnor_space.ref_alpha) * + alphafac; + const float betafac = unit_short_to_float(clnor_data[1]); + + mul_v3_v3fl(r_custom_lnor, lnor_no_custom, cosf(alpha)); + + if (betafac == 0.0f) { + madd_v3_v3fl(r_custom_lnor, lnor_space.vec_ref, sinf(alpha)); + } + else { + const float sinalpha = sinf(alpha); + const float beta = (betafac > 0.0f ? lnor_space.ref_beta : pi2 - lnor_space.ref_beta) * + betafac; + madd_v3_v3fl(r_custom_lnor, lnor_space.vec_ref, sinalpha * cosf(beta)); + madd_v3_v3fl(r_custom_lnor, lnor_space.vec_ortho, sinalpha * sinf(beta)); + } + + return r_custom_lnor; +} + +} // namespace blender::bke::mesh + void BKE_lnor_space_custom_data_to_normal(const MLoopNorSpace *lnor_space, const short clnor_data[2], float r_custom_lnor[3]) { - /* NOP custom normal data or invalid lnor space, return. */ - if (clnor_data[0] == 0 || lnor_space->ref_alpha == 0.0f || lnor_space->ref_beta == 0.0f) { - copy_v3_v3(r_custom_lnor, lnor_space->vec_lnor); - return; + using namespace blender::bke::mesh; + NormalFanSpace space; + space.vec_ref = lnor_space->vec_ref; + space.vec_ortho = lnor_space->vec_ortho; + space.ref_alpha = lnor_space->ref_alpha; + space.ref_beta = lnor_space->ref_beta; + copy_v3_v3(r_custom_lnor, + fan_space_custom_data_to_normal(space, lnor_space->vec_lnor, clnor_data)); +} + +namespace blender::bke::mesh { +short2 fan_space_custom_normal_to_data(const NormalFanSpace &lnor_space, + const float3 lnor_no_custom, + const float3 custom_lnor) +{ + /* We use nullptr vector as NOP custom normal (can be simpler than giving auto-computed `lnor`). + */ + if (is_zero_v3(custom_lnor) || compare_v3v3(lnor_no_custom, custom_lnor, 1e-4f)) { + return short2(0, 0); } - { - /* TODO: Check whether using #sincosf() gives any noticeable benefit - * (could not even get it working under linux though)! */ - const float pi2 = float(M_PI * 2.0); - const float alphafac = unit_short_to_float(clnor_data[0]); - const float alpha = (alphafac > 0.0f ? lnor_space->ref_alpha : pi2 - lnor_space->ref_alpha) * - alphafac; - const float betafac = unit_short_to_float(clnor_data[1]); + const float pi2 = float(M_PI * 2.0); + const float cos_alpha = dot_v3v3(lnor_no_custom, custom_lnor); + float vec[3], cos_beta; + float alpha; - mul_v3_v3fl(r_custom_lnor, lnor_space->vec_lnor, cosf(alpha)); + short2 r_clnor_data; - if (betafac == 0.0f) { - madd_v3_v3fl(r_custom_lnor, lnor_space->vec_ref, sinf(alpha)); + alpha = saacosf(cos_alpha); + if (alpha > lnor_space.ref_alpha) { + /* Note we could stick to [0, pi] range here, + * but makes decoding more complex, not worth it. */ + r_clnor_data[0] = unit_float_to_short(-(pi2 - alpha) / (pi2 - lnor_space.ref_alpha)); + } + else { + r_clnor_data[0] = unit_float_to_short(alpha / lnor_space.ref_alpha); + } + + /* Project custom lnor on (vec_ref, vec_ortho) plane. */ + mul_v3_v3fl(vec, lnor_no_custom, -cos_alpha); + add_v3_v3(vec, custom_lnor); + normalize_v3(vec); + + cos_beta = dot_v3v3(lnor_space.vec_ref, vec); + + if (cos_beta < LNOR_SPACE_TRIGO_THRESHOLD) { + float beta = saacosf(cos_beta); + if (dot_v3v3(lnor_space.vec_ortho, vec) < 0.0f) { + beta = pi2 - beta; + } + + if (beta > lnor_space.ref_beta) { + r_clnor_data[1] = unit_float_to_short(-(pi2 - beta) / (pi2 - lnor_space.ref_beta)); } else { - const float sinalpha = sinf(alpha); - const float beta = (betafac > 0.0f ? lnor_space->ref_beta : pi2 - lnor_space->ref_beta) * - betafac; - madd_v3_v3fl(r_custom_lnor, lnor_space->vec_ref, sinalpha * cosf(beta)); - madd_v3_v3fl(r_custom_lnor, lnor_space->vec_ortho, sinalpha * sinf(beta)); + r_clnor_data[1] = unit_float_to_short(beta / lnor_space.ref_beta); } } + else { + r_clnor_data[1] = 0; + } + + return r_clnor_data; } +} // namespace blender::bke::mesh void BKE_lnor_space_custom_normal_to_data(const MLoopNorSpace *lnor_space, const float custom_lnor[3], short r_clnor_data[2]) { - /* We use nullptr vector as NOP custom normal (can be simpler than giving auto-computed `lnor`). - */ - if (is_zero_v3(custom_lnor) || compare_v3v3(lnor_space->vec_lnor, custom_lnor, 1e-4f)) { - r_clnor_data[0] = r_clnor_data[1] = 0; - return; - } - - { - const float pi2 = float(M_PI * 2.0); - const float cos_alpha = dot_v3v3(lnor_space->vec_lnor, custom_lnor); - float vec[3], cos_beta; - float alpha; - - alpha = saacosf(cos_alpha); - if (alpha > lnor_space->ref_alpha) { - /* Note we could stick to [0, pi] range here, - * but makes decoding more complex, not worth it. */ - r_clnor_data[0] = unit_float_to_short(-(pi2 - alpha) / (pi2 - lnor_space->ref_alpha)); - } - else { - r_clnor_data[0] = unit_float_to_short(alpha / lnor_space->ref_alpha); - } - - /* Project custom lnor on (vec_ref, vec_ortho) plane. */ - mul_v3_v3fl(vec, lnor_space->vec_lnor, -cos_alpha); - add_v3_v3(vec, custom_lnor); - normalize_v3(vec); - - cos_beta = dot_v3v3(lnor_space->vec_ref, vec); - - if (cos_beta < LNOR_SPACE_TRIGO_THRESHOLD) { - float beta = saacosf(cos_beta); - if (dot_v3v3(lnor_space->vec_ortho, vec) < 0.0f) { - beta = pi2 - beta; - } - - if (beta > lnor_space->ref_beta) { - r_clnor_data[1] = unit_float_to_short(-(pi2 - beta) / (pi2 - lnor_space->ref_beta)); - } - else { - r_clnor_data[1] = unit_float_to_short(beta / lnor_space->ref_beta); - } - } - else { - r_clnor_data[1] = 0; - } - } + using namespace blender::bke::mesh; + NormalFanSpace space; + space.vec_ref = lnor_space->vec_ref; + space.vec_ortho = lnor_space->vec_ortho; + space.ref_alpha = lnor_space->ref_alpha; + space.ref_beta = lnor_space->ref_beta; + copy_v2_v2_short(r_clnor_data, + fan_space_custom_normal_to_data(space, lnor_space->vec_lnor, custom_lnor)); } namespace blender::bke::mesh { @@ -660,7 +722,7 @@ struct LoopSplitTaskDataCommon { /* Read/write. * Note we do not need to protect it, though, since two different tasks will *always* affect * different elements in the arrays. */ - MLoopNorSpaceArray *lnors_spacearr; + MeshNormalFanSpaces *lnors_spacearr; MutableSpan loop_normals; MutableSpan clnors_data; @@ -830,7 +892,7 @@ static void loop_manifold_fan_around_vert_next(const Span corner_verts, static void lnor_space_for_single_fan(LoopSplitTaskDataCommon *common_data, const int ml_curr_index, - MLoopNorSpace *lnor_space) + NormalFanSpace *lnor_space) { const Span loop_to_poly = common_data->loop_to_poly; const Span poly_normals = common_data->poly_normals; @@ -838,7 +900,7 @@ static void lnor_space_for_single_fan(LoopSplitTaskDataCommon *common_data, loop_normals[ml_curr_index] = poly_normals[loop_to_poly[ml_curr_index]]; - if (MLoopNorSpaceArray *lnors_spacearr = common_data->lnors_spacearr) { + if (lnor_space) { const Span positions = common_data->positions; const Span edges = common_data->edges; const OffsetIndices polys = common_data->polys; @@ -860,23 +922,22 @@ static void lnor_space_for_single_fan(LoopSplitTaskDataCommon *common_data, sub_v3_v3v3(vec_prev, positions[vert_3], positions[vert_pivot]); normalize_v3(vec_prev); - BKE_lnor_space_define(lnor_space, loop_normals[ml_curr_index], vec_curr, vec_prev, {}); + *lnor_space = normal_fan_space_define(loop_normals[ml_curr_index], vec_curr, vec_prev, {}); /* We know there is only one loop in this space, no need to create a link-list in this case. */ - BKE_lnor_space_add_loop(lnors_spacearr, lnor_space, ml_curr_index, nullptr, true); if (!clnors_data.is_empty()) { - BKE_lnor_space_custom_data_to_normal( - lnor_space, clnors_data[ml_curr_index], loop_normals[ml_curr_index]); + loop_normals[ml_curr_index] = fan_space_custom_data_to_normal( + *lnor_space, loop_normals[ml_curr_index], clnors_data[ml_curr_index]); } } } static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, const int ml_curr_index, - MLoopNorSpace *lnor_space, + NormalFanSpace *lnor_space, Vector *edge_vectors) { - MLoopNorSpaceArray *lnors_spacearr = common_data->lnors_spacearr; + MeshNormalFanSpaces *lnors_spacearr = common_data->lnors_spacearr; MutableSpan loop_normals = common_data->loop_normals; MutableSpan clnors_data = common_data->clnors_data; @@ -978,8 +1039,6 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, processed_corners.append(mlfan_vert_index); if (lnors_spacearr) { - /* Assign current lnor space to current 'vertex' loop. */ - BKE_lnor_space_add_loop(lnors_spacearr, lnor_space, mlfan_vert_index, nullptr, false); if (edge != edge_orig) { /* We store here all edges-normalized vectors processed. */ edge_vectors->append(vec_curr); @@ -1013,13 +1072,15 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, * and optionally compute final lnor from custom data too! */ if (lnors_spacearr) { + processed_corners.as_mutable_span().reverse(); + fan_space_add_corners(*lnors_spacearr, processed_corners); if (UNLIKELY(lnor_len == 0.0f)) { /* Use vertex normal as fallback! */ copy_v3_v3(lnor, loop_normals[mlfan_vert_index]); lnor_len = 1.0f; } - BKE_lnor_space_define(lnor_space, lnor, vec_org, vec_curr, *edge_vectors); + *lnor_space = normal_fan_space_define(lnor, vec_org, vec_curr, *edge_vectors); edge_vectors->clear(); if (!clnors_data.is_empty()) { @@ -1037,7 +1098,7 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, /* Extra bonus: since small-stack is local to this function, * no more need to empty it at all cost! */ - BKE_lnor_space_custom_data_to_normal(lnor_space, *clnor_ref, lnor); + lnor = fan_space_custom_data_to_normal(*lnor_space, lnor, *clnor_ref); } } @@ -1213,7 +1274,7 @@ void normals_calc_loop(const Span vert_positions, bool use_split_normals, float split_angle, short (*clnors_data)[2], - MLoopNorSpaceArray *r_lnors_spacearr, + MeshNormalFanSpaces *r_lnors_spacearr, MutableSpan r_loop_normals) { /* For now this is not supported. @@ -1271,7 +1332,7 @@ void normals_calc_loop(const Span vert_positions, /* When using custom loop normals, disable the angle feature! */ const bool check_angle = (split_angle < float(M_PI)) && (clnors_data == nullptr); - MLoopNorSpaceArray _lnors_spacearr = {nullptr}; + MeshNormalFanSpaces _lnors_spacearr; #ifdef DEBUG_TIME SCOPED_TIMER_AVERAGED(__func__); @@ -1281,9 +1342,6 @@ void normals_calc_loop(const Span vert_positions, /* We need to compute lnor spacearr if some custom lnor data are given to us! */ r_lnors_spacearr = &_lnors_spacearr; } - if (r_lnors_spacearr) { - BKE_lnor_spacearr_init(r_lnors_spacearr, corner_verts.size(), MLNOR_SPACEARR_LOOP_INDEX); - } /* Init data common to all tasks. */ LoopSplitTaskDataCommon common_data; @@ -1322,17 +1380,21 @@ void normals_calc_loop(const Span vert_positions, Vector fan_corners; loop_split_generator(&common_data, single_corners, fan_corners); - MLoopNorSpace *lnor_spaces = nullptr; if (r_lnors_spacearr) { - r_lnors_spacearr->spaces_num = single_corners.size() + fan_corners.size(); - lnor_spaces = static_cast(BLI_memarena_calloc( - r_lnors_spacearr->mem, sizeof(MLoopNorSpace) * r_lnors_spacearr->spaces_num)); + r_lnors_spacearr->spaces.reinitialize(single_corners.size() + fan_corners.size()); + r_lnors_spacearr->corner_group_lists.reinitialize(corner_verts.size()); + r_lnors_spacearr->corner_space_indices = Array(corner_verts.size(), -1); } threading::parallel_for(single_corners.index_range(), 1024, [&](const IndexRange range) { for (const int i : range) { const int corner = single_corners[i]; - lnor_space_for_single_fan(&common_data, corner, lnor_spaces ? &lnor_spaces[i] : nullptr); + lnor_space_for_single_fan( + &common_data, corner, r_lnors_spacearr ? &r_lnors_spacearr->spaces[i] : nullptr); + if (r_lnors_spacearr) { + r_lnors_spacearr->corner_space_indices[corner] = i; + r_lnors_spacearr->corner_group_lists[corner] = -1; + } } }); @@ -1340,18 +1402,16 @@ void normals_calc_loop(const Span vert_positions, Vector edge_vectors; for (const int i : range) { const int corner = fan_corners[i]; + const int space_index = single_corners.size() + i; split_loop_nor_fan_do(&common_data, corner, - lnor_spaces ? &lnor_spaces[single_corners.size() + i] : nullptr, + r_lnors_spacearr ? &r_lnors_spacearr->spaces[space_index] : nullptr, &edge_vectors); + if (r_lnors_spacearr) { + r_lnors_spacearr->corner_space_indices[corner] = space_index; + } } }); - - if (r_lnors_spacearr) { - if (r_lnors_spacearr == &_lnors_spacearr) { - BKE_lnor_spacearr_free(r_lnors_spacearr); - } - } } #undef INDEX_UNSET @@ -1386,7 +1446,7 @@ static void mesh_normals_loop_custom_set(Span positions, * function *is not* performance-critical, since it is mostly expected to be called by io add-ons * when importing custom normals, and modifier (and perhaps from some editing tools later?). So * better to keep some simplicity here, and just call #bke::mesh::normals_calc_loop() twice! */ - MLoopNorSpaceArray lnors_spacearr = {nullptr}; + MeshNormalFanSpaces lnors_spacearr; BitVector<> done_loops(corner_verts.size(), false); Array loop_normals(corner_verts.size()); const Array loop_to_poly = mesh_topology::build_loop_to_poly_map(polys); @@ -1430,8 +1490,6 @@ static void mesh_normals_loop_custom_set(Span positions, } } - BLI_assert(lnors_spacearr.data_type == MLNOR_SPACEARR_LOOP_INDEX); - /* Now, check each current smooth fan (one lnor space per smooth fan!), * and if all its matching custom loop_normals are not (enough) equal, add sharp edges as needed. * This way, next time we run bke::mesh::normals_calc_loop(), we'll get lnor spacearr/smooth fans @@ -1443,9 +1501,9 @@ static void mesh_normals_loop_custom_set(Span positions, } else { for (const int i : corner_verts.index_range()) { - if (!lnors_spacearr.lspacearr[i]) { + if (lnors_spacearr.corner_space_indices[i] == -1) { /* This should not happen in theory, but in some rare case (probably ugly geometry) - * we can get some nullptr loopspacearr at this point. :/ + * we can get some missing loopspacearr at this point. :/ * Maybe we should set those loops' edges as sharp? */ done_loops[i].set(); if (G.debug & G_DEBUG) { @@ -1466,17 +1524,17 @@ static void mesh_normals_loop_custom_set(Span positions, * - In smooth fan case, we compare each clnor against a ref one, * to avoid small differences adding up into a real big one in the end! */ - if (lnors_spacearr.lspacearr[i]->flags & MLNOR_SPACE_IS_SINGLE) { + int corner_link = lnors_spacearr.corner_group_lists[i]; + if (corner_link == -1) { done_loops[i].set(); continue; } - LinkNode *loop_link = lnors_spacearr.lspacearr[i]->loops; int prev_corner = -1; const float *org_nor = nullptr; - while (loop_link) { - const int lidx = POINTER_AS_INT(loop_link->link); + while (corner_link != -1) { + const int lidx = corner_link; float *nor = r_custom_loop_normals[lidx]; if (!org_nor) { @@ -1498,7 +1556,7 @@ static void mesh_normals_loop_custom_set(Span positions, } prev_corner = lidx; - loop_link = loop_link->next; + corner_link = lnors_spacearr.corner_group_lists[corner_link]; done_loops[lidx].set(); } @@ -1506,9 +1564,9 @@ static void mesh_normals_loop_custom_set(Span positions, * otherwise we may miss some sharp edges here! * This is just a simplified version of above while loop. * See #45984. */ - loop_link = lnors_spacearr.lspacearr[i]->loops; - if (loop_link && org_nor) { - const int lidx = POINTER_AS_INT(loop_link->link); + corner_link = lnors_spacearr.corner_group_lists[i]; + if (corner_link != -1 && org_nor) { + const int lidx = corner_link; float *nor = r_custom_loop_normals[lidx]; if (dot_v3v3(org_nor, nor) < LNOR_SPACE_TRIGO_THRESHOLD) { @@ -1523,7 +1581,7 @@ static void mesh_normals_loop_custom_set(Span positions, } /* And now, recompute our new auto `loop_normals` and lnor spacearr! */ - BKE_lnor_spacearr_clear(&lnors_spacearr); + lnors_spacearr = {}; normals_calc_loop(positions, edges, polys, @@ -1544,7 +1602,7 @@ static void mesh_normals_loop_custom_set(Span positions, /* And we just have to convert plain object-space custom normals to our * lnor space-encoded ones. */ for (const int i : corner_verts.index_range()) { - if (!lnors_spacearr.lspacearr[i]) { + if (lnors_spacearr.corner_space_indices[i] == -1) { done_loops[i].reset(); if (G.debug & G_DEBUG) { printf("WARNING! Still getting invalid nullptr loop space in second loop for loop %d!\n", @@ -1557,23 +1615,24 @@ static void mesh_normals_loop_custom_set(Span positions, /* Note we accumulate and average all custom normals in current smooth fan, * to avoid getting different clnors data (tiny differences in plain custom normals can * give rather huge differences in computed 2D factors). */ - LinkNode *loop_link = lnors_spacearr.lspacearr[i]->loops; - if (lnors_spacearr.lspacearr[i]->flags & MLNOR_SPACE_IS_SINGLE) { - BLI_assert(POINTER_AS_INT(loop_link) == i); + int corner_link = lnors_spacearr.corner_group_lists[i]; + if (corner_link == -1) { const int nidx = use_vertices ? corner_verts[i] : i; float *nor = r_custom_loop_normals[nidx]; - BKE_lnor_space_custom_normal_to_data(lnors_spacearr.lspacearr[i], nor, r_clnors_data[i]); + const int space_index = lnors_spacearr.corner_space_indices[i]; + copy_v2_v2_short(r_clnors_data[i], + fan_space_custom_normal_to_data( + lnors_spacearr.spaces[space_index], loop_normals[i], nor)); done_loops[i].reset(); } else { int avg_nor_count = 0; float avg_nor[3]; - short clnor_data_tmp[2]; zero_v3(avg_nor); - while (loop_link) { - const int lidx = POINTER_AS_INT(loop_link->link); + while (corner_link != -1) { + const int lidx = corner_link; const int nidx = use_vertices ? corner_verts[lidx] : lidx; float *nor = r_custom_loop_normals[nidx]; @@ -1581,12 +1640,16 @@ static void mesh_normals_loop_custom_set(Span positions, add_v3_v3(avg_nor, nor); clnors_data.append(r_clnors_data[lidx]); - loop_link = loop_link->next; + corner_link = lnors_spacearr.corner_group_lists[corner_link]; done_loops[lidx].reset(); } mul_v3_fl(avg_nor, 1.0f / float(avg_nor_count)); - BKE_lnor_space_custom_normal_to_data(lnors_spacearr.lspacearr[i], avg_nor, clnor_data_tmp); + const int space_index = lnors_spacearr.corner_space_indices[i]; + const short2 clnor_data_tmp = fan_space_custom_normal_to_data( + lnors_spacearr.spaces[space_index], loop_normals[i], avg_nor); + + std::cout << float3(avg_nor) << '\n'; while (!clnors_data.is_empty()) { short *clnor_data = clnors_data.pop_last(); @@ -1596,8 +1659,6 @@ static void mesh_normals_loop_custom_set(Span positions, } } } - - BKE_lnor_spacearr_free(&lnors_spacearr); } void normals_loop_custom_set(const Span vert_positions, diff --git a/source/blender/modifiers/intern/MOD_weighted_normal.cc b/source/blender/modifiers/intern/MOD_weighted_normal.cc index d47b0847226..b422483f513 100644 --- a/source/blender/modifiers/intern/MOD_weighted_normal.cc +++ b/source/blender/modifiers/intern/MOD_weighted_normal.cc @@ -204,7 +204,7 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd, const bool has_clnors = wn_data->has_clnors; const float split_angle = wn_data->split_angle; - MLoopNorSpaceArray lnors_spacearr = {nullptr}; + bke::mesh::MeshNormalFanSpaces lnors_spacearr; const bool keep_sharp = (wnmd->flag & MOD_WEIGHTEDNORMAL_KEEP_SHARP) != 0; const bool use_face_influence = (wnmd->flag & MOD_WEIGHTEDNORMAL_FACE_INFLUENCE) != 0 && @@ -214,7 +214,6 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd, blender::Array loop_normals; WeightedNormalDataAggregateItem *items_data = nullptr; - Array item_index_per_corner(corner_verts.size(), 0); int items_num = 0; if (keep_sharp) { BLI_bitmap *done_loops = BLI_BITMAP_NEW(corner_verts.size(), __func__); @@ -238,13 +237,12 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd, &lnors_spacearr, loop_normals); - items_num = lnors_spacearr.spaces_num; + items_num = lnors_spacearr.spaces.size(); items_data = static_cast( MEM_calloc_arrayN(size_t(items_num), sizeof(*items_data), __func__)); /* In this first loop, we assign each WeightedNormalDataAggregateItem * to its smooth fan of loops (aka lnor space). */ - int item_index = 0; for (const int i : polys.index_range()) { for (const int ml_index : polys[i]) { if (BLI_BITMAP_TEST(done_loops, ml_index)) { @@ -252,23 +250,15 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd, continue; } - WeightedNormalDataAggregateItem *itdt = &items_data[item_index]; + const int space_index = lnors_spacearr.corner_space_indices[ml_index]; + WeightedNormalDataAggregateItem *itdt = &items_data[space_index]; itdt->curr_strength = FACE_STRENGTH_WEAK; - MLoopNorSpace *lnor_space = lnors_spacearr.lspacearr[ml_index]; - item_index_per_corner[ml_index] = item_index; - - if (!(lnor_space->flags & MLNOR_SPACE_IS_SINGLE)) { - for (LinkNode *lnode = lnor_space->loops; lnode; lnode = lnode->next) { - const int ml_fan_index = POINTER_AS_INT(lnode->link); - BLI_BITMAP_ENABLE(done_loops, ml_fan_index); - } + int fan_corner = lnors_spacearr.corner_group_lists[ml_index]; + while (fan_corner != -1) { + BLI_BITMAP_ENABLE(done_loops, fan_corner); + fan_corner = lnors_spacearr.corner_group_lists[fan_corner]; } - else { - BLI_BITMAP_ENABLE(done_loops, ml_index); - } - - item_index++; } } @@ -294,8 +284,10 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd, for (const int ml_index : polys[poly_index]) { const int mv_index = corner_verts[ml_index]; - WeightedNormalDataAggregateItem *item_data = - keep_sharp ? &items_data[item_index_per_corner[ml_index]] : &items_data[mv_index]; + const int space_index = lnors_spacearr.corner_space_indices[ml_index]; + + WeightedNormalDataAggregateItem *item_data = keep_sharp ? &items_data[space_index] : + &items_data[mv_index]; aggregate_item_normal( wnmd, wn_data, item_data, mv_index, poly_index, mp_val, use_face_influence); @@ -307,11 +299,12 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd, for (int i = 0; i < corner_verts.size(); i++) { const int ml_index = mode_pair[i].index; const float ml_val = mode_pair[i].val; + const int space_index = lnors_spacearr.corner_space_indices[ml_index]; const int poly_index = loop_to_poly[ml_index]; const int mv_index = corner_verts[ml_index]; - WeightedNormalDataAggregateItem *item_data = - keep_sharp ? &items_data[item_index_per_corner[ml_index]] : &items_data[mv_index]; + WeightedNormalDataAggregateItem *item_data = keep_sharp ? &items_data[space_index] : + &items_data[mv_index]; aggregate_item_normal( wnmd, wn_data, item_data, mv_index, poly_index, ml_val, use_face_influence); @@ -334,7 +327,8 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd, * (before this modifier is applied, at start of this function), * so no need to recompute them here. */ for (int ml_index = 0; ml_index < corner_verts.size(); ml_index++) { - WeightedNormalDataAggregateItem *item_data = &items_data[item_index_per_corner[ml_index]]; + const int space_index = lnors_spacearr.corner_space_indices[ml_index]; + WeightedNormalDataAggregateItem *item_data = &items_data[space_index]; if (!is_zero_v3(item_data->normal)) { copy_v3_v3(loop_normals[ml_index], item_data->normal); } @@ -418,10 +412,6 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd, clnors); } } - - if (keep_sharp) { - BKE_lnor_spacearr_free(&lnors_spacearr); - } } static void wn_face_area(WeightedNormalModifierData *wnmd, WeightedNormalData *wn_data) -- 2.30.2 From c6d5019ebd09d34f9b4073afa7a50a630e56d768 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Fri, 28 Apr 2023 15:15:40 -0400 Subject: [PATCH 03/22] Cleanup --- source/blender/blenkernel/intern/mesh_normals.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc index 9c25f4429db..bc02acb11b4 100644 --- a/source/blender/blenkernel/intern/mesh_normals.cc +++ b/source/blender/blenkernel/intern/mesh_normals.cc @@ -1621,9 +1621,8 @@ static void mesh_normals_loop_custom_set(Span positions, float *nor = r_custom_loop_normals[nidx]; const int space_index = lnors_spacearr.corner_space_indices[i]; - copy_v2_v2_short(r_clnors_data[i], - fan_space_custom_normal_to_data( - lnors_spacearr.spaces[space_index], loop_normals[i], nor)); + r_clnors_data[i] = fan_space_custom_normal_to_data( + lnors_spacearr.spaces[space_index], loop_normals[i], nor); done_loops[i].reset(); } else { -- 2.30.2 From 236846507c8cdc48e63080dcb078da60a84dbea2 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Fri, 28 Apr 2023 15:18:50 -0400 Subject: [PATCH 04/22] Cleanup: Make diff smaller --- source/blender/blenkernel/BKE_mesh.hh | 2 +- .../blender/blenkernel/intern/mesh_mirror.cc | 5 +-- .../blender/blenkernel/intern/mesh_normals.cc | 38 +++++++++---------- 3 files changed, 22 insertions(+), 23 deletions(-) diff --git a/source/blender/blenkernel/BKE_mesh.hh b/source/blender/blenkernel/BKE_mesh.hh index a3554b1b1c6..f90b9984ef3 100644 --- a/source/blender/blenkernel/BKE_mesh.hh +++ b/source/blender/blenkernel/BKE_mesh.hh @@ -92,7 +92,7 @@ struct MeshNormalFanSpaces { Array corner_group_lists; }; -short2 fan_space_custom_normal_to_data(const NormalFanSpace &space, +short2 fan_space_custom_normal_to_data(const NormalFanSpace *space, float3 corner_normal_no_custom, float3 custom_lnor); diff --git a/source/blender/blenkernel/intern/mesh_mirror.cc b/source/blender/blenkernel/intern/mesh_mirror.cc index 9415f40b2b3..963a91397a0 100644 --- a/source/blender/blenkernel/intern/mesh_mirror.cc +++ b/source/blender/blenkernel/intern/mesh_mirror.cc @@ -434,9 +434,8 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd, const int space_index = lnors_spacearr.corner_space_indices[mirrorj]; const blender::bke::mesh::NormalFanSpace &space = lnors_spacearr.spaces[space_index]; - copy_v2_v2_short(clnors[mirrorj], - blender::bke::mesh::fan_space_custom_normal_to_data( - space, loop_normals[mirrorj], loop_normals[mirrorj])); + clnors[mirrorj] = blender::bke::mesh::fan_space_custom_normal_to_data( + &space, loop_normals[mirrorj], loop_normals[mirrorj]); } } } diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc index bc02acb11b4..30c5340877d 100644 --- a/source/blender/blenkernel/intern/mesh_normals.cc +++ b/source/blender/blenkernel/intern/mesh_normals.cc @@ -595,12 +595,12 @@ MINLINE short unit_float_to_short(const float val) } namespace blender::bke::mesh { -static float3 fan_space_custom_data_to_normal(const NormalFanSpace &lnor_space, +static float3 fan_space_custom_data_to_normal(const NormalFanSpace *lnor_space, const float3 lnor_no_custom, const short2 clnor_data) { /* NOP custom normal data or invalid lnor space, return. */ - if (clnor_data[0] == 0 || lnor_space.ref_alpha == 0.0f || lnor_space.ref_beta == 0.0f) { + if (clnor_data[0] == 0 || lnor_space->ref_alpha == 0.0f || lnor_space->ref_beta == 0.0f) { return lnor_no_custom; } @@ -610,21 +610,21 @@ static float3 fan_space_custom_data_to_normal(const NormalFanSpace &lnor_space, * (could not even get it working under linux though)! */ const float pi2 = float(M_PI * 2.0); const float alphafac = unit_short_to_float(clnor_data[0]); - const float alpha = (alphafac > 0.0f ? lnor_space.ref_alpha : pi2 - lnor_space.ref_alpha) * + const float alpha = (alphafac > 0.0f ? lnor_space->ref_alpha : pi2 - lnor_space->ref_alpha) * alphafac; const float betafac = unit_short_to_float(clnor_data[1]); mul_v3_v3fl(r_custom_lnor, lnor_no_custom, cosf(alpha)); if (betafac == 0.0f) { - madd_v3_v3fl(r_custom_lnor, lnor_space.vec_ref, sinf(alpha)); + madd_v3_v3fl(r_custom_lnor, lnor_space->vec_ref, sinf(alpha)); } else { const float sinalpha = sinf(alpha); - const float beta = (betafac > 0.0f ? lnor_space.ref_beta : pi2 - lnor_space.ref_beta) * + const float beta = (betafac > 0.0f ? lnor_space->ref_beta : pi2 - lnor_space->ref_beta) * betafac; - madd_v3_v3fl(r_custom_lnor, lnor_space.vec_ref, sinalpha * cosf(beta)); - madd_v3_v3fl(r_custom_lnor, lnor_space.vec_ortho, sinalpha * sinf(beta)); + madd_v3_v3fl(r_custom_lnor, lnor_space->vec_ref, sinalpha * cosf(beta)); + madd_v3_v3fl(r_custom_lnor, lnor_space->vec_ortho, sinalpha * sinf(beta)); } return r_custom_lnor; @@ -643,11 +643,11 @@ void BKE_lnor_space_custom_data_to_normal(const MLoopNorSpace *lnor_space, space.ref_alpha = lnor_space->ref_alpha; space.ref_beta = lnor_space->ref_beta; copy_v3_v3(r_custom_lnor, - fan_space_custom_data_to_normal(space, lnor_space->vec_lnor, clnor_data)); + fan_space_custom_data_to_normal(&space, lnor_space->vec_lnor, clnor_data)); } namespace blender::bke::mesh { -short2 fan_space_custom_normal_to_data(const NormalFanSpace &lnor_space, +short2 fan_space_custom_normal_to_data(const NormalFanSpace *lnor_space, const float3 lnor_no_custom, const float3 custom_lnor) { @@ -665,13 +665,13 @@ short2 fan_space_custom_normal_to_data(const NormalFanSpace &lnor_space, short2 r_clnor_data; alpha = saacosf(cos_alpha); - if (alpha > lnor_space.ref_alpha) { + if (alpha > lnor_space->ref_alpha) { /* Note we could stick to [0, pi] range here, * but makes decoding more complex, not worth it. */ - r_clnor_data[0] = unit_float_to_short(-(pi2 - alpha) / (pi2 - lnor_space.ref_alpha)); + r_clnor_data[0] = unit_float_to_short(-(pi2 - alpha) / (pi2 - lnor_space->ref_alpha)); } else { - r_clnor_data[0] = unit_float_to_short(alpha / lnor_space.ref_alpha); + r_clnor_data[0] = unit_float_to_short(alpha / lnor_space->ref_alpha); } /* Project custom lnor on (vec_ref, vec_ortho) plane. */ @@ -679,19 +679,19 @@ short2 fan_space_custom_normal_to_data(const NormalFanSpace &lnor_space, add_v3_v3(vec, custom_lnor); normalize_v3(vec); - cos_beta = dot_v3v3(lnor_space.vec_ref, vec); + cos_beta = dot_v3v3(lnor_space->vec_ref, vec); if (cos_beta < LNOR_SPACE_TRIGO_THRESHOLD) { float beta = saacosf(cos_beta); - if (dot_v3v3(lnor_space.vec_ortho, vec) < 0.0f) { + if (dot_v3v3(lnor_space->vec_ortho, vec) < 0.0f) { beta = pi2 - beta; } - if (beta > lnor_space.ref_beta) { - r_clnor_data[1] = unit_float_to_short(-(pi2 - beta) / (pi2 - lnor_space.ref_beta)); + if (beta > lnor_space->ref_beta) { + r_clnor_data[1] = unit_float_to_short(-(pi2 - beta) / (pi2 - lnor_space->ref_beta)); } else { - r_clnor_data[1] = unit_float_to_short(beta / lnor_space.ref_beta); + r_clnor_data[1] = unit_float_to_short(beta / lnor_space->ref_beta); } } else { @@ -927,7 +927,7 @@ static void lnor_space_for_single_fan(LoopSplitTaskDataCommon *common_data, if (!clnors_data.is_empty()) { loop_normals[ml_curr_index] = fan_space_custom_data_to_normal( - *lnor_space, loop_normals[ml_curr_index], clnors_data[ml_curr_index]); + lnor_space, loop_normals[ml_curr_index], clnors_data[ml_curr_index]); } } } @@ -1098,7 +1098,7 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, /* Extra bonus: since small-stack is local to this function, * no more need to empty it at all cost! */ - lnor = fan_space_custom_data_to_normal(*lnor_space, lnor, *clnor_ref); + lnor = fan_space_custom_data_to_normal(lnor_space, lnor, *clnor_ref); } } -- 2.30.2 From 50a96baf7313f5c174ea5c63f1014aadd92c0e7f Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Fri, 28 Apr 2023 15:41:58 -0400 Subject: [PATCH 05/22] Cleanup --- source/blender/blenkernel/intern/mesh_normals.cc | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc index 30c5340877d..39b1de0686d 100644 --- a/source/blender/blenkernel/intern/mesh_normals.cc +++ b/source/blender/blenkernel/intern/mesh_normals.cc @@ -713,7 +713,7 @@ void BKE_lnor_space_custom_normal_to_data(const MLoopNorSpace *lnor_space, space.ref_alpha = lnor_space->ref_alpha; space.ref_beta = lnor_space->ref_beta; copy_v2_v2_short(r_clnor_data, - fan_space_custom_normal_to_data(space, lnor_space->vec_lnor, custom_lnor)); + fan_space_custom_normal_to_data(&space, lnor_space->vec_lnor, custom_lnor)); } namespace blender::bke::mesh { @@ -1622,7 +1622,7 @@ static void mesh_normals_loop_custom_set(Span positions, const int space_index = lnors_spacearr.corner_space_indices[i]; r_clnors_data[i] = fan_space_custom_normal_to_data( - lnors_spacearr.spaces[space_index], loop_normals[i], nor); + &lnors_spacearr.spaces[space_index], loop_normals[i], nor); done_loops[i].reset(); } else { @@ -1644,9 +1644,7 @@ static void mesh_normals_loop_custom_set(Span positions, mul_v3_fl(avg_nor, 1.0f / float(avg_nor_count)); const int space_index = lnors_spacearr.corner_space_indices[i]; const short2 clnor_data_tmp = fan_space_custom_normal_to_data( - lnors_spacearr.spaces[space_index], loop_normals[i], avg_nor); - - std::cout << float3(avg_nor) << '\n'; + &lnors_spacearr.spaces[space_index], loop_normals[i], avg_nor); r_clnors_data.fill_indices(processed_corners.as_span(), clnor_data_tmp); processed_corners.clear(); -- 2.30.2 From 08e7b1e404b629037c0354387b1af33b5ec25106 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Fri, 28 Apr 2023 15:59:03 -0400 Subject: [PATCH 06/22] Add debug printing --- source/blender/blenkernel/intern/mesh_normals.cc | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc index 39b1de0686d..33b4ccdc583 100644 --- a/source/blender/blenkernel/intern/mesh_normals.cc +++ b/source/blender/blenkernel/intern/mesh_normals.cc @@ -1412,6 +1412,20 @@ void normals_calc_loop(const Span vert_positions, } } }); + + for (const int i : corner_verts.index_range()) { + std::cout << "Corner " << i << '\n'; + std::cout << " Vert: " << corner_verts[i] << '\n'; + std::cout << " Normal: " << r_loop_normals[i] << '\n'; + if (r_lnors_spacearr) { + const NormalFanSpace &space = + r_lnors_spacearr->spaces[r_lnors_spacearr->corner_space_indices[i]]; + std::cout << " vec_ref: " << space.vec_ref << '\n'; + std::cout << " vec_ortho: " << space.vec_ortho << '\n'; + std::cout << " ref_alpha: " << space.ref_alpha << '\n'; + std::cout << " ref_beta: " << space.ref_beta << '\n'; + } + } } #undef INDEX_UNSET -- 2.30.2 From 6c29232dc297a8f84c093c8f4828f0f49421d468 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Fri, 28 Apr 2023 16:27:45 -0400 Subject: [PATCH 07/22] Fixes --- source/blender/blenkernel/intern/mesh_normals.cc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc index 33b4ccdc583..cb3b6b72996 100644 --- a/source/blender/blenkernel/intern/mesh_normals.cc +++ b/source/blender/blenkernel/intern/mesh_normals.cc @@ -934,6 +934,7 @@ static void lnor_space_for_single_fan(LoopSplitTaskDataCommon *common_data, static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, const int ml_curr_index, + Vector &processed_corners, NormalFanSpace *lnor_space, Vector *edge_vectors) { @@ -973,8 +974,6 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, int clnors_count = 0; bool clnors_invalid = false; - Vector processed_corners; - /* `mlfan_vert_index` the loop of our current edge might not be the loop of our current vertex! */ int mlfan_curr_index = ml_prev_index; @@ -1399,17 +1398,21 @@ void normals_calc_loop(const Span vert_positions, }); threading::parallel_for(fan_corners.index_range(), 1024, [&](const IndexRange range) { + Vector processed_corners; Vector edge_vectors; for (const int i : range) { const int corner = fan_corners[i]; const int space_index = single_corners.size() + i; split_loop_nor_fan_do(&common_data, corner, + processed_corners, r_lnors_spacearr ? &r_lnors_spacearr->spaces[space_index] : nullptr, &edge_vectors); if (r_lnors_spacearr) { - r_lnors_spacearr->corner_space_indices[corner] = space_index; + r_lnors_spacearr->corner_space_indices.as_mutable_span().fill_indices( + processed_corners.as_span(), space_index); } + processed_corners.clear(); } }); -- 2.30.2 From b69e744e97ec96dc14b22bcc1bf8cf5922e74e19 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Sun, 30 Apr 2023 17:30:22 -0400 Subject: [PATCH 08/22] Cleanup: Make diff smaller --- source/blender/blenkernel/BKE_mesh.hh | 11 +- .../blender/blenkernel/intern/mesh_mirror.cc | 8 +- .../blender/blenkernel/intern/mesh_normals.cc | 282 +++++++++--------- 3 files changed, 145 insertions(+), 156 deletions(-) diff --git a/source/blender/blenkernel/BKE_mesh.hh b/source/blender/blenkernel/BKE_mesh.hh index f90b9984ef3..f4bcf2c6968 100644 --- a/source/blender/blenkernel/BKE_mesh.hh +++ b/source/blender/blenkernel/BKE_mesh.hh @@ -92,9 +92,10 @@ struct MeshNormalFanSpaces { Array corner_group_lists; }; -short2 fan_space_custom_normal_to_data(const NormalFanSpace *space, - float3 corner_normal_no_custom, - float3 custom_lnor); +void fan_space_custom_normal_to_data(const NormalFanSpace *lnor_space, + const float3 lnor_no_custom, + const float custom_lnor[3], + short r_clnor_data[2]); /** * Compute split normals, i.e. vertex normals associated with each poly (hence 'loop normals'). @@ -104,8 +105,8 @@ short2 fan_space_custom_normal_to_data(const NormalFanSpace *space, * \param loop_to_poly_map: Optional pre-created map from corners to their polygon. * \param sharp_edges: Optional array of sharp edge tags, used to split the evaluated normals on * each side of the edge. - * \param r_lnors_spacearr: Optional return data filled with information about the custom normals - * spaces for each grouped fan of face corners. + * \param r_lnors_spacearr: Optional return data filled with information about the custom + * normals spaces for each grouped fan of face corners. */ void normals_calc_loop(Span vert_positions, Span edges, diff --git a/source/blender/blenkernel/intern/mesh_mirror.cc b/source/blender/blenkernel/intern/mesh_mirror.cc index 963a91397a0..74466985016 100644 --- a/source/blender/blenkernel/intern/mesh_mirror.cc +++ b/source/blender/blenkernel/intern/mesh_mirror.cc @@ -432,10 +432,10 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd, mul_m4_v3(mtx_nor, loop_normals[mirrorj]); const int space_index = lnors_spacearr.corner_space_indices[mirrorj]; - const blender::bke::mesh::NormalFanSpace &space = lnors_spacearr.spaces[space_index]; - - clnors[mirrorj] = blender::bke::mesh::fan_space_custom_normal_to_data( - &space, loop_normals[mirrorj], loop_normals[mirrorj]); + blender::bke::mesh::fan_space_custom_normal_to_data(&lnors_spacearr.spaces[space_index], + loop_normals[mirrorj], + loop_normals[mirrorj], + clnors[mirrorj]); } } } diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc index cb3b6b72996..9e4c3974496 100644 --- a/source/blender/blenkernel/intern/mesh_normals.cc +++ b/source/blender/blenkernel/intern/mesh_normals.cc @@ -468,12 +468,12 @@ MLoopNorSpace *BKE_lnor_space_create(MLoopNorSpaceArray *lnors_spacearr) #define LNOR_SPACE_TRIGO_THRESHOLD (1.0f - 1e-4f) namespace blender::bke::mesh { -static NormalFanSpace normal_fan_space_define(const float lnor[3], - float vec_ref[3], - float vec_other[3], - const Span edge_vectors) +static void normal_fan_space_define(NormalFanSpace *lnor_space, + const float lnor[3], + float vec_ref[3], + float vec_other[3], + const blender::Span edge_vectors) { - NormalFanSpace lnor_space{}; const float pi2 = float(M_PI) * 2.0f; float tvec[3], dtp; const float dtp_ref = dot_v3v3(vec_ref, lnor); @@ -483,14 +483,14 @@ static NormalFanSpace normal_fan_space_define(const float lnor[3], fabsf(dtp_other) >= LNOR_SPACE_TRIGO_THRESHOLD)) { /* If vec_ref or vec_other are too much aligned with lnor, we can't build lnor space, * tag it as invalid and abort. */ - lnor_space.ref_alpha = lnor_space.ref_beta = 0.0f; - return lnor_space; + lnor_space->ref_alpha = lnor_space->ref_beta = 0.0f; + return; } /* Compute ref alpha, average angle of all available edge vectors to lnor. */ if (!edge_vectors.is_empty()) { float alpha = 0.0f; - for (const float3 &vec : edge_vectors) { + for (const blender::float3 &vec : edge_vectors) { alpha += saacosf(dot_v3v3(vec, lnor)); } /* This piece of code shall only be called for more than one loop. */ @@ -499,21 +499,21 @@ static NormalFanSpace normal_fan_space_define(const float lnor[3], * a smooth vertex with only two edges and two faces (our Monkey's nose has that, e.g.). */ BLI_assert(edge_vectors.size() >= 2); - lnor_space.ref_alpha = alpha / float(edge_vectors.size()); + lnor_space->ref_alpha = alpha / float(edge_vectors.size()); } else { - lnor_space.ref_alpha = (saacosf(dot_v3v3(vec_ref, lnor)) + - saacosf(dot_v3v3(vec_other, lnor))) / - 2.0f; + lnor_space->ref_alpha = (saacosf(dot_v3v3(vec_ref, lnor)) + + saacosf(dot_v3v3(vec_other, lnor))) / + 2.0f; } /* Project vec_ref on lnor's ortho plane. */ mul_v3_v3fl(tvec, lnor, dtp_ref); sub_v3_v3(vec_ref, tvec); - normalize_v3_v3(lnor_space.vec_ref, vec_ref); + normalize_v3_v3(lnor_space->vec_ref, vec_ref); - cross_v3_v3v3(tvec, lnor, lnor_space.vec_ref); - normalize_v3_v3(lnor_space.vec_ortho, tvec); + cross_v3_v3v3(tvec, lnor, lnor_space->vec_ref); + normalize_v3_v3(lnor_space->vec_ortho, tvec); /* Project vec_other on lnor's ortho plane. */ mul_v3_v3fl(tvec, lnor, dtp_other); @@ -521,16 +521,14 @@ static NormalFanSpace normal_fan_space_define(const float lnor[3], normalize_v3(vec_other); /* Beta is angle between ref_vec and other_vec, around lnor. */ - dtp = dot_v3v3(lnor_space.vec_ref, vec_other); + dtp = dot_v3v3(lnor_space->vec_ref, vec_other); if (LIKELY(dtp < LNOR_SPACE_TRIGO_THRESHOLD)) { const float beta = saacos(dtp); - lnor_space.ref_beta = (dot_v3v3(lnor_space.vec_ortho, vec_other) < 0.0f) ? pi2 - beta : beta; + lnor_space->ref_beta = (dot_v3v3(lnor_space->vec_ortho, vec_other) < 0.0f) ? pi2 - beta : beta; } else { - lnor_space.ref_beta = pi2; + lnor_space->ref_beta = pi2; } - - return lnor_space; } } // namespace blender::bke::mesh @@ -541,7 +539,8 @@ void BKE_lnor_space_define(MLoopNorSpace *lnor_space, const blender::Span edge_vectors) { using namespace blender::bke::mesh; - const NormalFanSpace space = normal_fan_space_define(lnor, vec_ref, vec_other, edge_vectors); + NormalFanSpace space{}; + normal_fan_space_define(&space, lnor, vec_ref, vec_other, edge_vectors); copy_v3_v3(lnor_space->vec_lnor, lnor); copy_v3_v3(lnor_space->vec_ref, space.vec_ref); copy_v3_v3(lnor_space->vec_ortho, space.vec_ortho); @@ -549,16 +548,6 @@ void BKE_lnor_space_define(MLoopNorSpace *lnor_space, lnor_space->ref_beta = space.ref_beta; } -namespace blender::bke::mesh { -static void fan_space_add_corners(MeshNormalFanSpaces &fan_spaces, const Span corners) -{ - for (const int i : corners.index_range().drop_back(1)) { - fan_spaces.corner_group_lists[corners[i]] = corners[i + 1]; - } - fan_spaces.corner_group_lists[corners.last()] = -1; -} -} // namespace blender::bke::mesh - void BKE_lnor_space_add_loop(MLoopNorSpaceArray *lnors_spacearr, MLoopNorSpace *lnor_space, const int ml_index, @@ -595,41 +584,40 @@ MINLINE short unit_float_to_short(const float val) } namespace blender::bke::mesh { -static float3 fan_space_custom_data_to_normal(const NormalFanSpace *lnor_space, - const float3 lnor_no_custom, - const short2 clnor_data) +static void fan_space_custom_data_to_normal(const NormalFanSpace *lnor_space, + const float3 lnor_no_custom, + const short clnor_data[2], + float r_custom_lnor[3]) { /* NOP custom normal data or invalid lnor space, return. */ if (clnor_data[0] == 0 || lnor_space->ref_alpha == 0.0f || lnor_space->ref_beta == 0.0f) { - return lnor_no_custom; + copy_v3_v3(r_custom_lnor, lnor_no_custom); + return; } - float3 r_custom_lnor(0.0f); + { + /* TODO: Check whether using #sincosf() gives any noticeable benefit + * (could not even get it working under linux though)! */ + const float pi2 = float(M_PI * 2.0); + const float alphafac = unit_short_to_float(clnor_data[0]); + const float alpha = (alphafac > 0.0f ? lnor_space->ref_alpha : pi2 - lnor_space->ref_alpha) * + alphafac; + const float betafac = unit_short_to_float(clnor_data[1]); - /* TODO: Check whether using #sincosf() gives any noticeable benefit - * (could not even get it working under linux though)! */ - const float pi2 = float(M_PI * 2.0); - const float alphafac = unit_short_to_float(clnor_data[0]); - const float alpha = (alphafac > 0.0f ? lnor_space->ref_alpha : pi2 - lnor_space->ref_alpha) * - alphafac; - const float betafac = unit_short_to_float(clnor_data[1]); + mul_v3_v3fl(r_custom_lnor, lnor_no_custom, cosf(alpha)); - mul_v3_v3fl(r_custom_lnor, lnor_no_custom, cosf(alpha)); - - if (betafac == 0.0f) { - madd_v3_v3fl(r_custom_lnor, lnor_space->vec_ref, sinf(alpha)); + if (betafac == 0.0f) { + madd_v3_v3fl(r_custom_lnor, lnor_space->vec_ref, sinf(alpha)); + } + else { + const float sinalpha = sinf(alpha); + const float beta = (betafac > 0.0f ? lnor_space->ref_beta : pi2 - lnor_space->ref_beta) * + betafac; + madd_v3_v3fl(r_custom_lnor, lnor_space->vec_ref, sinalpha * cosf(beta)); + madd_v3_v3fl(r_custom_lnor, lnor_space->vec_ortho, sinalpha * sinf(beta)); + } } - else { - const float sinalpha = sinf(alpha); - const float beta = (betafac > 0.0f ? lnor_space->ref_beta : pi2 - lnor_space->ref_beta) * - betafac; - madd_v3_v3fl(r_custom_lnor, lnor_space->vec_ref, sinalpha * cosf(beta)); - madd_v3_v3fl(r_custom_lnor, lnor_space->vec_ortho, sinalpha * sinf(beta)); - } - - return r_custom_lnor; } - } // namespace blender::bke::mesh void BKE_lnor_space_custom_data_to_normal(const MLoopNorSpace *lnor_space, @@ -642,63 +630,62 @@ void BKE_lnor_space_custom_data_to_normal(const MLoopNorSpace *lnor_space, space.vec_ortho = lnor_space->vec_ortho; space.ref_alpha = lnor_space->ref_alpha; space.ref_beta = lnor_space->ref_beta; - copy_v3_v3(r_custom_lnor, - fan_space_custom_data_to_normal(&space, lnor_space->vec_lnor, clnor_data)); + fan_space_custom_data_to_normal(&space, lnor_space->vec_lnor, clnor_data, r_custom_lnor); } namespace blender::bke::mesh { -short2 fan_space_custom_normal_to_data(const NormalFanSpace *lnor_space, - const float3 lnor_no_custom, - const float3 custom_lnor) +void fan_space_custom_normal_to_data(const NormalFanSpace *lnor_space, + const float3 lnor_no_custom, + const float custom_lnor[3], + short r_clnor_data[2]) { /* We use nullptr vector as NOP custom normal (can be simpler than giving auto-computed `lnor`). */ if (is_zero_v3(custom_lnor) || compare_v3v3(lnor_no_custom, custom_lnor, 1e-4f)) { - return short2(0, 0); + r_clnor_data[0] = r_clnor_data[1] = 0; + return; } - const float pi2 = float(M_PI * 2.0); - const float cos_alpha = dot_v3v3(lnor_no_custom, custom_lnor); - float vec[3], cos_beta; - float alpha; + { + const float pi2 = float(M_PI * 2.0); + const float cos_alpha = dot_v3v3(lnor_no_custom, custom_lnor); + float vec[3], cos_beta; + float alpha; - short2 r_clnor_data; - - alpha = saacosf(cos_alpha); - if (alpha > lnor_space->ref_alpha) { - /* Note we could stick to [0, pi] range here, - * but makes decoding more complex, not worth it. */ - r_clnor_data[0] = unit_float_to_short(-(pi2 - alpha) / (pi2 - lnor_space->ref_alpha)); - } - else { - r_clnor_data[0] = unit_float_to_short(alpha / lnor_space->ref_alpha); - } - - /* Project custom lnor on (vec_ref, vec_ortho) plane. */ - mul_v3_v3fl(vec, lnor_no_custom, -cos_alpha); - add_v3_v3(vec, custom_lnor); - normalize_v3(vec); - - cos_beta = dot_v3v3(lnor_space->vec_ref, vec); - - if (cos_beta < LNOR_SPACE_TRIGO_THRESHOLD) { - float beta = saacosf(cos_beta); - if (dot_v3v3(lnor_space->vec_ortho, vec) < 0.0f) { - beta = pi2 - beta; - } - - if (beta > lnor_space->ref_beta) { - r_clnor_data[1] = unit_float_to_short(-(pi2 - beta) / (pi2 - lnor_space->ref_beta)); + alpha = saacosf(cos_alpha); + if (alpha > lnor_space->ref_alpha) { + /* Note we could stick to [0, pi] range here, + * but makes decoding more complex, not worth it. */ + r_clnor_data[0] = unit_float_to_short(-(pi2 - alpha) / (pi2 - lnor_space->ref_alpha)); } else { - r_clnor_data[1] = unit_float_to_short(beta / lnor_space->ref_beta); + r_clnor_data[0] = unit_float_to_short(alpha / lnor_space->ref_alpha); + } + + /* Project custom lnor on (vec_ref, vec_ortho) plane. */ + mul_v3_v3fl(vec, lnor_no_custom, -cos_alpha); + add_v3_v3(vec, custom_lnor); + normalize_v3(vec); + + cos_beta = dot_v3v3(lnor_space->vec_ref, vec); + + if (cos_beta < LNOR_SPACE_TRIGO_THRESHOLD) { + float beta = saacosf(cos_beta); + if (dot_v3v3(lnor_space->vec_ortho, vec) < 0.0f) { + beta = pi2 - beta; + } + + if (beta > lnor_space->ref_beta) { + r_clnor_data[1] = unit_float_to_short(-(pi2 - beta) / (pi2 - lnor_space->ref_beta)); + } + else { + r_clnor_data[1] = unit_float_to_short(beta / lnor_space->ref_beta); + } + } + else { + r_clnor_data[1] = 0; } } - else { - r_clnor_data[1] = 0; - } - - return r_clnor_data; } } // namespace blender::bke::mesh @@ -712,8 +699,7 @@ void BKE_lnor_space_custom_normal_to_data(const MLoopNorSpace *lnor_space, space.vec_ortho = lnor_space->vec_ortho; space.ref_alpha = lnor_space->ref_alpha; space.ref_beta = lnor_space->ref_beta; - copy_v2_v2_short(r_clnor_data, - fan_space_custom_normal_to_data(&space, lnor_space->vec_lnor, custom_lnor)); + fan_space_custom_normal_to_data(&space, lnor_space->vec_lnor, custom_lnor, r_clnor_data); } namespace blender::bke::mesh { @@ -890,9 +876,20 @@ static void loop_manifold_fan_around_vert_next(const Span corner_verts, } } +static void fan_space_add_corners(MeshNormalFanSpaces &fan_spaces, + const Span corners, + const int space_index) +{ + for (const int i : corners.index_range().drop_back(1)) { + fan_spaces.corner_group_lists[corners[i]] = corners[i + 1]; + } + fan_spaces.corner_group_lists[corners.last()] = -1; + fan_spaces.corner_space_indices.as_mutable_span().fill_indices(corners, space_index); +} + static void lnor_space_for_single_fan(LoopSplitTaskDataCommon *common_data, const int ml_curr_index, - NormalFanSpace *lnor_space) + const int space_index) { const Span loop_to_poly = common_data->loop_to_poly; const Span poly_normals = common_data->poly_normals; @@ -900,7 +897,7 @@ static void lnor_space_for_single_fan(LoopSplitTaskDataCommon *common_data, loop_normals[ml_curr_index] = poly_normals[loop_to_poly[ml_curr_index]]; - if (lnor_space) { + if (MeshNormalFanSpaces *lnors_spacearr = common_data->lnors_spacearr) { const Span positions = common_data->positions; const Span edges = common_data->edges; const OffsetIndices polys = common_data->polys; @@ -922,20 +919,23 @@ static void lnor_space_for_single_fan(LoopSplitTaskDataCommon *common_data, sub_v3_v3v3(vec_prev, positions[vert_3], positions[vert_pivot]); normalize_v3(vec_prev); - *lnor_space = normal_fan_space_define(loop_normals[ml_curr_index], vec_curr, vec_prev, {}); + NormalFanSpace *lnor_space = &lnors_spacearr->spaces[space_index]; + normal_fan_space_define(lnor_space, loop_normals[ml_curr_index], vec_curr, vec_prev, {}); /* We know there is only one loop in this space, no need to create a link-list in this case. */ + fan_space_add_corners(*lnors_spacearr, {ml_curr_index}, space_index); if (!clnors_data.is_empty()) { - loop_normals[ml_curr_index] = fan_space_custom_data_to_normal( - lnor_space, loop_normals[ml_curr_index], clnors_data[ml_curr_index]); + fan_space_custom_data_to_normal(lnor_space, + loop_normals[ml_curr_index], + clnors_data[ml_curr_index], + loop_normals[ml_curr_index]); } } } static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, const int ml_curr_index, - Vector &processed_corners, - NormalFanSpace *lnor_space, + const int space_index, Vector *edge_vectors) { MeshNormalFanSpaces *lnors_spacearr = common_data->lnors_spacearr; @@ -974,6 +974,8 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, int clnors_count = 0; bool clnors_invalid = false; + Vector processed_corners; + /* `mlfan_vert_index` the loop of our current edge might not be the loop of our current vertex! */ int mlfan_curr_index = ml_prev_index; @@ -1071,15 +1073,15 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, * and optionally compute final lnor from custom data too! */ if (lnors_spacearr) { - processed_corners.as_mutable_span().reverse(); - fan_space_add_corners(*lnors_spacearr, processed_corners); + fan_space_add_corners(*lnors_spacearr, processed_corners, space_index); if (UNLIKELY(lnor_len == 0.0f)) { /* Use vertex normal as fallback! */ copy_v3_v3(lnor, loop_normals[mlfan_vert_index]); lnor_len = 1.0f; } - *lnor_space = normal_fan_space_define(lnor, vec_org, vec_curr, *edge_vectors); + NormalFanSpace *lnor_space = &lnors_spacearr->spaces[space_index]; + normal_fan_space_define(lnor_space, lnor, vec_org, vec_curr, *edge_vectors); edge_vectors->clear(); if (!clnors_data.is_empty()) { @@ -1097,7 +1099,7 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, /* Extra bonus: since small-stack is local to this function, * no more need to empty it at all cost! */ - lnor = fan_space_custom_data_to_normal(lnor_space, lnor, *clnor_ref); + fan_space_custom_data_to_normal(lnor_space, lnor, *clnor_ref, lnor); } } @@ -1388,31 +1390,16 @@ void normals_calc_loop(const Span vert_positions, threading::parallel_for(single_corners.index_range(), 1024, [&](const IndexRange range) { for (const int i : range) { const int corner = single_corners[i]; - lnor_space_for_single_fan( - &common_data, corner, r_lnors_spacearr ? &r_lnors_spacearr->spaces[i] : nullptr); - if (r_lnors_spacearr) { - r_lnors_spacearr->corner_space_indices[corner] = i; - r_lnors_spacearr->corner_group_lists[corner] = -1; - } + lnor_space_for_single_fan(&common_data, corner, i); } }); threading::parallel_for(fan_corners.index_range(), 1024, [&](const IndexRange range) { - Vector processed_corners; Vector edge_vectors; for (const int i : range) { const int corner = fan_corners[i]; const int space_index = single_corners.size() + i; - split_loop_nor_fan_do(&common_data, - corner, - processed_corners, - r_lnors_spacearr ? &r_lnors_spacearr->spaces[space_index] : nullptr, - &edge_vectors); - if (r_lnors_spacearr) { - r_lnors_spacearr->corner_space_indices.as_mutable_span().fill_indices( - processed_corners.as_span(), space_index); - } - processed_corners.clear(); + split_loop_nor_fan_do(&common_data, corner, space_index, &edge_vectors); } }); @@ -1539,8 +1526,8 @@ static void mesh_normals_loop_custom_set(Span positions, * - In smooth fan case, we compare each clnor against a ref one, * to avoid small differences adding up into a real big one in the end! */ - int corner_link = lnors_spacearr.corner_group_lists[i]; - if (corner_link == -1) { + int loop_link = lnors_spacearr.corner_group_lists[i]; + if (loop_link == -1) { done_loops[i].set(); continue; } @@ -1548,8 +1535,8 @@ static void mesh_normals_loop_custom_set(Span positions, int prev_corner = -1; const float *org_nor = nullptr; - while (corner_link != -1) { - const int lidx = corner_link; + while (loop_link != -1) { + const int lidx = loop_link; float *nor = r_custom_loop_normals[lidx]; if (!org_nor) { @@ -1571,7 +1558,7 @@ static void mesh_normals_loop_custom_set(Span positions, } prev_corner = lidx; - corner_link = lnors_spacearr.corner_group_lists[corner_link]; + loop_link = lnors_spacearr.corner_group_lists[loop_link]; done_loops[lidx].set(); } @@ -1579,9 +1566,9 @@ static void mesh_normals_loop_custom_set(Span positions, * otherwise we may miss some sharp edges here! * This is just a simplified version of above while loop. * See #45984. */ - corner_link = lnors_spacearr.corner_group_lists[i]; - if (corner_link != -1 && org_nor) { - const int lidx = corner_link; + loop_link = lnors_spacearr.corner_group_lists[i]; + if (loop_link != -1 && org_nor) { + const int lidx = loop_link; float *nor = r_custom_loop_normals[lidx]; if (dot_v3v3(org_nor, nor) < LNOR_SPACE_TRIGO_THRESHOLD) { @@ -1632,21 +1619,21 @@ static void mesh_normals_loop_custom_set(Span positions, /* Note we accumulate and average all custom normals in current smooth fan, * to avoid getting different clnors data (tiny differences in plain custom normals can * give rather huge differences in computed 2D factors). */ - int corner_link = lnors_spacearr.corner_group_lists[i]; - if (corner_link == -1) { + int loop_link = lnors_spacearr.corner_group_lists[i]; + if (loop_link == -1) { const int nidx = use_vertices ? corner_verts[i] : i; float *nor = r_custom_loop_normals[nidx]; const int space_index = lnors_spacearr.corner_space_indices[i]; - r_clnors_data[i] = fan_space_custom_normal_to_data( - &lnors_spacearr.spaces[space_index], loop_normals[i], nor); + fan_space_custom_normal_to_data( + &lnors_spacearr.spaces[space_index], loop_normals[i], nor, r_clnors_data[i]); done_loops[i].reset(); } else { int avg_nor_count = 0; float3 avg_nor(0.0f); - while (corner_link != -1) { - const int lidx = corner_link; + while (loop_link != -1) { + const int lidx = loop_link; const int nidx = use_vertices ? corner_verts[lidx] : lidx; float *nor = r_custom_loop_normals[nidx]; @@ -1654,14 +1641,15 @@ static void mesh_normals_loop_custom_set(Span positions, add_v3_v3(avg_nor, nor); processed_corners.append(lidx); - corner_link = lnors_spacearr.corner_group_lists[corner_link]; + loop_link = lnors_spacearr.corner_group_lists[loop_link]; done_loops[lidx].reset(); } mul_v3_fl(avg_nor, 1.0f / float(avg_nor_count)); + short2 clnor_data_tmp; const int space_index = lnors_spacearr.corner_space_indices[i]; - const short2 clnor_data_tmp = fan_space_custom_normal_to_data( - &lnors_spacearr.spaces[space_index], loop_normals[i], avg_nor); + fan_space_custom_normal_to_data( + &lnors_spacearr.spaces[space_index], loop_normals[i], avg_nor, clnor_data_tmp); r_clnors_data.fill_indices(processed_corners.as_span(), clnor_data_tmp); processed_corners.clear(); -- 2.30.2 From ec4ebb869171e4b83ee74ab535b618e0c8599354 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Wed, 3 May 2023 12:47:01 -0400 Subject: [PATCH 09/22] More debug printing --- .../blender/blenkernel/intern/mesh_normals.cc | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc index 83bc95793cb..b84915204af 100644 --- a/source/blender/blenkernel/intern/mesh_normals.cc +++ b/source/blender/blenkernel/intern/mesh_normals.cc @@ -1408,17 +1408,24 @@ void normals_calc_loop(const Span vert_positions, } }); - for (const int i : corner_verts.index_range()) { - std::cout << "Corner " << i << '\n'; - std::cout << " Vert: " << corner_verts[i] << '\n'; - std::cout << " Normal: " << r_loop_normals[i] << '\n'; + for (const int corner : corner_verts.index_range()) { + std::cout << "Corner " << corner << '\n'; + std::cout << " Vert: " << corner_verts[corner] << '\n'; + std::cout << " Normal: " << r_loop_normals[corner] << '\n'; if (r_lnors_spacearr) { const NormalFanSpace &space = - r_lnors_spacearr->spaces[r_lnors_spacearr->corner_space_indices[i]]; + r_lnors_spacearr->spaces[r_lnors_spacearr->corner_space_indices[corner]]; std::cout << " vec_ref: " << space.vec_ref << '\n'; std::cout << " vec_ortho: " << space.vec_ortho << '\n'; std::cout << " ref_alpha: " << space.ref_alpha << '\n'; std::cout << " ref_beta: " << space.ref_beta << '\n'; + std::cout << " fan indices: ("; + int iter = r_lnors_spacearr->corner_group_lists[corner]; + while (iter != -1) { + std::cout << iter << ", "; + iter = r_lnors_spacearr->corner_group_lists[iter]; + } + std::cout << ")\n"; } } } -- 2.30.2 From a882816358df3763e58fccab72cc4886b1fe1e9e Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Wed, 3 May 2023 16:06:47 -0400 Subject: [PATCH 10/22] Cleanup --- source/blender/blenkernel/BKE_mesh.hh | 1 + .../blender/blenkernel/intern/mesh_normals.cc | 1 + .../modifiers/intern/MOD_weighted_normal.cc | 39 +++---------------- 3 files changed, 8 insertions(+), 33 deletions(-) diff --git a/source/blender/blenkernel/BKE_mesh.hh b/source/blender/blenkernel/BKE_mesh.hh index f4bcf2c6968..7ccdedc08d4 100644 --- a/source/blender/blenkernel/BKE_mesh.hh +++ b/source/blender/blenkernel/BKE_mesh.hh @@ -68,6 +68,7 @@ struct NormalFanSpace { float ref_alpha; /** Reference angle, around vec_lnor, in [0, 2pi] range (0.0 marks that space as invalid). */ float ref_beta; + Vector corners; }; /** diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc index b84915204af..c462f74ca69 100644 --- a/source/blender/blenkernel/intern/mesh_normals.cc +++ b/source/blender/blenkernel/intern/mesh_normals.cc @@ -1085,6 +1085,7 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, NormalFanSpace *lnor_space = &lnors_spacearr->spaces[space_index]; normal_fan_space_define(lnor_space, lnor, vec_org, vec_curr, *edge_vectors); + lnor_space->corners = std::move(processed_corners); edge_vectors->clear(); if (!clnors_data.is_empty()) { diff --git a/source/blender/modifiers/intern/MOD_weighted_normal.cc b/source/blender/modifiers/intern/MOD_weighted_normal.cc index 7bbb63828ed..947e5214acb 100644 --- a/source/blender/modifiers/intern/MOD_weighted_normal.cc +++ b/source/blender/modifiers/intern/MOD_weighted_normal.cc @@ -216,8 +216,6 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd, Array items_data; if (keep_sharp) { - BLI_bitmap *done_loops = BLI_BITMAP_NEW(corner_verts.size(), __func__); - /* This will give us loop normal spaces, * we do not actually care about computed loop_normals for now... */ loop_normals.reinitialize(corner_verts.size()); @@ -237,40 +235,15 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd, &lnors_spacearr, loop_normals); - items_data = Array(lnors_spacearr.spaces.size(), - WeightedNormalDataAggregateItem{}); + WeightedNormalDataAggregateItem start_item{}; + start_item.curr_strength = FACE_STRENGTH_WEAK; - /* In this first loop, we assign each WeightedNormalDataAggregateItem - * to its smooth fan of loops (aka lnor space). */ - for (const int i : polys.index_range()) { - for (const int ml_index : polys[i]) { - if (BLI_BITMAP_TEST(done_loops, ml_index)) { - /* Smooth fan of this loop has already been processed, skip it. */ - continue; - } - - const int space_index = lnors_spacearr.corner_space_indices[ml_index]; - WeightedNormalDataAggregateItem *itdt = &items_data[space_index]; - itdt->curr_strength = FACE_STRENGTH_WEAK; - - int fan_corner = lnors_spacearr.corner_group_lists[ml_index]; - while (fan_corner != -1) { - BLI_BITMAP_ENABLE(done_loops, fan_corner); - fan_corner = lnors_spacearr.corner_group_lists[fan_corner]; - } - } - } - - MEM_freeN(done_loops); + items_data = Array(lnors_spacearr.spaces.size(), start_item); } else { - items_data = Array(verts_num, - WeightedNormalDataAggregateItem{}); - if (use_face_influence) { - for (int item_index : items_data.index_range()) { - items_data[item_index].curr_strength = FACE_STRENGTH_WEAK; - } - } + WeightedNormalDataAggregateItem start_item{}; + start_item.curr_strength = FACE_STRENGTH_WEAK; + items_data = Array(verts_num, start_item); } wn_data->items_data = items_data; -- 2.30.2 From 0e1f63140d0d14b3598c181c6a09509b67aef488 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Wed, 3 May 2023 16:46:37 -0400 Subject: [PATCH 11/22] WIP --- source/blender/blenkernel/BKE_mesh.hh | 15 +--- .../blender/blenkernel/intern/mesh_normals.cc | 89 +++++++++++-------- 2 files changed, 57 insertions(+), 47 deletions(-) diff --git a/source/blender/blenkernel/BKE_mesh.hh b/source/blender/blenkernel/BKE_mesh.hh index 7ccdedc08d4..79b411b767d 100644 --- a/source/blender/blenkernel/BKE_mesh.hh +++ b/source/blender/blenkernel/BKE_mesh.hh @@ -68,7 +68,6 @@ struct NormalFanSpace { float ref_alpha; /** Reference angle, around vec_lnor, in [0, 2pi] range (0.0 marks that space as invalid). */ float ref_beta; - Vector corners; }; /** @@ -77,20 +76,14 @@ struct NormalFanSpace { struct MeshNormalFanSpaces { /** * The normal coordinate spaces, potentially shared between multiple face corners in a smooth fan - * connected to a vertex. Depending on the geometry (the amount of sharing / size of each fan), - * there may be many fewer spaces than face corners, so they are stored in a separate array. + * connected to a vertex. Depending on the mesh (the amount of sharing / number of sharp edges / + * size of each fan), there may be many fewer spaces than face corners, so they are stored in a + * separate array. */ Array spaces; - /** The index in #spaces for each face corner. */ + /** The index of the data in the #spaces array for each face corner. */ Array corner_space_indices; - - /** - * An index-based linked list of the face corners in each smooth fan, starting at each corner. - * Each index stores the index of the next corner in the fan, or -1 if it is the last. "Single" - * fans with only a single corner store -1 at that corner index directly. - */ - Array corner_group_lists; }; void fan_space_custom_normal_to_data(const NormalFanSpace *lnor_space, diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc index bd928712821..9655cfc4496 100644 --- a/source/blender/blenkernel/intern/mesh_normals.cc +++ b/source/blender/blenkernel/intern/mesh_normals.cc @@ -879,17 +879,6 @@ static void loop_manifold_fan_around_vert_next(const Span corner_verts, } } -static void fan_space_add_corners(MeshNormalFanSpaces &fan_spaces, - const Span corners, - const int space_index) -{ - for (const int i : corners.index_range().drop_back(1)) { - fan_spaces.corner_group_lists[corners[i]] = corners[i + 1]; - } - fan_spaces.corner_group_lists[corners.last()] = -1; - fan_spaces.corner_space_indices.as_mutable_span().fill_indices(corners, space_index); -} - static void lnor_space_for_single_fan(LoopSplitTaskDataCommon *common_data, const int ml_curr_index, const int space_index) @@ -925,8 +914,7 @@ static void lnor_space_for_single_fan(LoopSplitTaskDataCommon *common_data, NormalFanSpace *lnor_space = &lnors_spacearr->spaces[space_index]; normal_fan_space_define(lnor_space, loop_normals[ml_curr_index], vec_curr, vec_prev, {}); - /* We know there is only one loop in this space, no need to create a link-list in this case. */ - fan_space_add_corners(*lnors_spacearr, {ml_curr_index}, space_index); + lnors_spacearr->corner_space_indices[ml_curr_index] = space_index; if (!clnors_data.is_empty()) { fan_space_custom_data_to_normal(lnor_space, @@ -1078,16 +1066,16 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, * and optionally compute final lnor from custom data too! */ if (lnors_spacearr) { - fan_space_add_corners(*lnors_spacearr, processed_corners, space_index); if (UNLIKELY(length == 0.0f)) { /* Use vertex normal as fallback! */ - copy_v3_v3(lnor, loop_normals[mlfan_vert_index]); + lnor = loop_normals[mlfan_vert_index]; length = 1.0f; } NormalFanSpace *lnor_space = &lnors_spacearr->spaces[space_index]; normal_fan_space_define(lnor_space, lnor, vec_org, vec_curr, *edge_vectors); - lnor_space->corners = std::move(processed_corners); + lnors_spacearr->corner_space_indices.as_mutable_span().fill_indices( + processed_corners.as_span(), space_index); edge_vectors->clear(); if (!clnors_data.is_empty()) { @@ -1098,11 +1086,14 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, if (G.debug & G_DEBUG) { printf("Invalid clnors in this fan!\n"); } - /* Extra bonus: since small-stack is local to this function, - * no more need to empty it at all cost! */ - - fan_space_custom_data_to_normal(lnor_space, lnor, *clnor_ref, lnor); + clnors_data.fill_indices(processed_corners.as_span(), + short2(clnors_avg[0], clnors_avg[1])); + // print_v2("new clnors", clnors_avg); } + /* Extra bonus: since small-stack is local to this function, + * no more need to empty it at all cost! */ + + fan_space_custom_data_to_normal(lnor_space, lnor, *clnor_ref, lnor); } } @@ -1387,7 +1378,6 @@ void normals_calc_loop(const Span vert_positions, if (r_lnors_spacearr) { r_lnors_spacearr->spaces.reinitialize(single_corners.size() + fan_corners.size()); - r_lnors_spacearr->corner_group_lists.reinitialize(corner_verts.size()); r_lnors_spacearr->corner_space_indices = Array(corner_verts.size(), -1); } @@ -1418,13 +1408,13 @@ void normals_calc_loop(const Span vert_positions, std::cout << " vec_ortho: " << space.vec_ortho << '\n'; std::cout << " ref_alpha: " << space.ref_alpha << '\n'; std::cout << " ref_beta: " << space.ref_beta << '\n'; - std::cout << " fan indices: ("; - int iter = r_lnors_spacearr->corner_group_lists[corner]; - while (iter != -1) { - std::cout << iter << ", "; - iter = r_lnors_spacearr->corner_group_lists[iter]; - } - std::cout << ")\n"; + // std::cout << " fan indices: ("; + // int iter = r_lnors_spacearr->corner_group_lists[corner]; + // while (iter != -1) { + // std::cout << iter << ", "; + // iter = r_lnors_spacearr->corner_group_lists[iter]; + // } + // std::cout << ")\n"; } } } @@ -1433,6 +1423,24 @@ void normals_calc_loop(const Span vert_positions, #undef INDEX_INVALID #undef IS_EDGE_SHARP +static void reverse_space_index_array(const MeshNormalFanSpaces &spaces, + Array &corner_offset_indices, + Array &space_corner_indices) +{ + corner_offset_indices = Array(spaces.spaces.size() + 1, 0); + for (const int index : spaces.corner_space_indices) { + corner_offset_indices[index]++; + } + offset_indices::accumulate_counts_to_offsets(corner_offset_indices); + + space_corner_indices.reinitialize(corner_offset_indices.last()); + Array count(spaces.spaces.size(), 0); + for (const int corner : spaces.corner_space_indices.index_range()) { + const int space = spaces.corner_space_indices[corner]; + space_corner_indices[corner_offset_indices[space] + count[space]] = corner; + } +} + /** * 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 @@ -1513,6 +1521,11 @@ static void mesh_normals_loop_custom_set(Span positions, done_loops.fill(true); } else { + Array space_corner_offset_indices; + Array space_corner_indices; + reverse_space_index_array(lnors_spacearr, space_corner_offset_indices, space_corner_indices); + const OffsetIndices space_corner_offsets(space_corner_offset_indices); + for (const int i : corner_verts.index_range()) { if (lnors_spacearr.corner_space_indices[i] == -1) { /* This should not happen in theory, but in some rare case (probably ugly geometry) @@ -1528,6 +1541,10 @@ static void mesh_normals_loop_custom_set(Span positions, continue; } + const int space_index = lnors_spacearr.corner_space_indices[i]; + const Span space_corners = space_corner_indices.as_span().slice( + space_corner_offsets[space_index]); + /* Notes: * - In case of mono-loop smooth fan, we have nothing to do. * - Loops in this linklist are ordered (in reversed order compared to how they were @@ -1537,8 +1554,7 @@ static void mesh_normals_loop_custom_set(Span positions, * - In smooth fan case, we compare each clnor against a ref one, * to avoid small differences adding up into a real big one in the end! */ - int loop_link = lnors_spacearr.corner_group_lists[i]; - if (loop_link == -1) { + if (space_corners.is_empty()) { done_loops[i].set(); continue; } @@ -1546,8 +1562,7 @@ static void mesh_normals_loop_custom_set(Span positions, int prev_corner = -1; const float *org_nor = nullptr; - while (loop_link != -1) { - const int lidx = loop_link; + for (const int lidx : space_corners) { float *nor = r_custom_loop_normals[lidx]; if (!org_nor) { @@ -1569,7 +1584,6 @@ static void mesh_normals_loop_custom_set(Span positions, } prev_corner = lidx; - loop_link = lnors_spacearr.corner_group_lists[loop_link]; done_loops[lidx].set(); } @@ -1612,7 +1626,10 @@ static void mesh_normals_loop_custom_set(Span positions, loop_normals); } - Vector processed_corners; + Array space_corner_offset_indices; + Array space_corner_indices; + reverse_space_index_array(lnors_spacearr, space_corner_offset_indices, space_corner_indices); + const OffsetIndices space_corner_offsets(space_corner_offset_indices); /* And we just have to convert plain object-space custom normals to our * lnor space-encoded ones. */ @@ -1626,6 +1643,8 @@ static void mesh_normals_loop_custom_set(Span positions, continue; } + const int space_index = lnors_spacearr.corner_space_indices[i]; + if (done_loops[i]) { /* Note we accumulate and average all custom normals in current smooth fan, * to avoid getting different clnors data (tiny differences in plain custom normals can @@ -1650,7 +1669,6 @@ static void mesh_normals_loop_custom_set(Span positions, avg_nor_count++; add_v3_v3(avg_nor, nor); - processed_corners.append(lidx); loop_link = lnors_spacearr.corner_group_lists[loop_link]; done_loops[lidx].reset(); @@ -1658,7 +1676,6 @@ static void mesh_normals_loop_custom_set(Span positions, mul_v3_fl(avg_nor, 1.0f / float(avg_nor_count)); short2 clnor_data_tmp; - const int space_index = lnors_spacearr.corner_space_indices[i]; fan_space_custom_normal_to_data( &lnors_spacearr.spaces[space_index], loop_normals[i], avg_nor, clnor_data_tmp); -- 2.30.2 From 789f932582743e4fd5751fa997801a6189427475 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Wed, 3 May 2023 17:07:29 -0400 Subject: [PATCH 12/22] Fix --- .../blender/blenkernel/intern/mesh_normals.cc | 55 ++++++++----------- 1 file changed, 22 insertions(+), 33 deletions(-) diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc index abccd592ab5..2314546ea3b 100644 --- a/source/blender/blenkernel/intern/mesh_normals.cc +++ b/source/blender/blenkernel/intern/mesh_normals.cc @@ -1397,26 +1397,19 @@ void normals_calc_loop(const Span vert_positions, } }); - for (const int corner : corner_verts.index_range()) { - std::cout << "Corner " << corner << '\n'; - std::cout << " Vert: " << corner_verts[corner] << '\n'; - std::cout << " Normal: " << r_loop_normals[corner] << '\n'; - if (r_lnors_spacearr) { - const NormalFanSpace &space = - r_lnors_spacearr->spaces[r_lnors_spacearr->corner_space_indices[corner]]; - std::cout << " vec_ref: " << space.vec_ref << '\n'; - std::cout << " vec_ortho: " << space.vec_ortho << '\n'; - std::cout << " ref_alpha: " << space.ref_alpha << '\n'; - std::cout << " ref_beta: " << space.ref_beta << '\n'; - // std::cout << " fan indices: ("; - // int iter = r_lnors_spacearr->corner_group_lists[corner]; - // while (iter != -1) { - // std::cout << iter << ", "; - // iter = r_lnors_spacearr->corner_group_lists[iter]; - // } - // std::cout << ")\n"; - } - } + // for (const int corner : corner_verts.index_range()) { + // std::cout << "Corner " << corner << '\n'; + // std::cout << " Vert: " << corner_verts[corner] << '\n'; + // std::cout << " Normal: " << r_loop_normals[corner] << '\n'; + // if (r_lnors_spacearr) { + // const NormalFanSpace &space = + // r_lnors_spacearr->spaces[r_lnors_spacearr->corner_space_indices[corner]]; + // std::cout << " vec_ref: " << space.vec_ref << '\n'; + // std::cout << " vec_ortho: " << space.vec_ortho << '\n'; + // std::cout << " ref_alpha: " << space.ref_alpha << '\n'; + // std::cout << " ref_beta: " << space.ref_beta << '\n'; + // } + // } } #undef INDEX_UNSET @@ -1438,6 +1431,7 @@ static void reverse_space_index_array(const MeshNormalFanSpaces &spaces, for (const int corner : spaces.corner_space_indices.index_range()) { const int space = spaces.corner_space_indices[corner]; space_corner_indices[corner_offset_indices[space] + count[space]] = corner; + count[space]++; } } @@ -1591,9 +1585,8 @@ static void mesh_normals_loop_custom_set(Span positions, * otherwise we may miss some sharp edges here! * This is just a simplified version of above while loop. * See #45984. */ - loop_link = lnors_spacearr.corner_group_lists[i]; - if (loop_link != -1 && org_nor) { - const int lidx = loop_link; + if (space_corners.size() > 1 && org_nor) { + const int lidx = space_corners.last(); float *nor = r_custom_loop_normals[lidx]; if (dot_v3v3(org_nor, nor) < LNOR_SPACE_TRIGO_THRESHOLD) { @@ -1647,12 +1640,13 @@ static void mesh_normals_loop_custom_set(Span positions, } const int space_index = lnors_spacearr.corner_space_indices[i]; + const Span space_corners = space_corner_indices.as_span().slice( + space_corner_offsets[space_index]); /* Note we accumulate and average all custom normals in current smooth fan, * to avoid getting different clnors data (tiny differences in plain custom normals can * give rather huge differences in computed 2D factors). */ - int loop_link = lnors_spacearr.corner_group_lists[i]; - if (loop_link == -1) { + if (space_corners.size() < 2) { const int nidx = use_vertices ? corner_verts[i] : i; float *nor = r_custom_loop_normals[nidx]; @@ -1662,27 +1656,22 @@ static void mesh_normals_loop_custom_set(Span positions, done_loops[i].reset(); } else { - int avg_nor_count = 0; float3 avg_nor(0.0f); - while (loop_link != -1) { - const int lidx = loop_link; + for (const int lidx : space_corners) { const int nidx = use_vertices ? corner_verts[lidx] : lidx; float *nor = r_custom_loop_normals[nidx]; - avg_nor_count++; add_v3_v3(avg_nor, nor); - loop_link = lnors_spacearr.corner_group_lists[loop_link]; done_loops[lidx].reset(); } - mul_v3_fl(avg_nor, 1.0f / float(avg_nor_count)); + mul_v3_fl(avg_nor, 1.0f / float(space_corners.size())); short2 clnor_data_tmp; fan_space_custom_normal_to_data( &lnors_spacearr.spaces[space_index], loop_normals[i], avg_nor, clnor_data_tmp); - r_clnors_data.fill_indices(processed_corners.as_span(), clnor_data_tmp); - processed_corners.clear(); + r_clnors_data.fill_indices(space_corners, clnor_data_tmp); } } } -- 2.30.2 From 8c58a35723613e93c5954b2a0b5264106a8efdbe Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Wed, 3 May 2023 17:18:28 -0400 Subject: [PATCH 13/22] Cleanup --- .../blender/blenkernel/intern/mesh_normals.cc | 96 +++++++++---------- .../modifiers/intern/MOD_weighted_normal.cc | 1 - 2 files changed, 48 insertions(+), 49 deletions(-) diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc index 2314546ea3b..6f029447e64 100644 --- a/source/blender/blenkernel/intern/mesh_normals.cc +++ b/source/blender/blenkernel/intern/mesh_normals.cc @@ -36,7 +36,7 @@ #include "atomic_ops.h" -#define DEBUG_TIME +// #define DEBUG_TIME #ifdef DEBUG_TIME # include "BLI_timeit.hh" @@ -1396,42 +1396,36 @@ void normals_calc_loop(const Span vert_positions, split_loop_nor_fan_do(&common_data, corner, space_index, &edge_vectors); } }); - - // for (const int corner : corner_verts.index_range()) { - // std::cout << "Corner " << corner << '\n'; - // std::cout << " Vert: " << corner_verts[corner] << '\n'; - // std::cout << " Normal: " << r_loop_normals[corner] << '\n'; - // if (r_lnors_spacearr) { - // const NormalFanSpace &space = - // r_lnors_spacearr->spaces[r_lnors_spacearr->corner_space_indices[corner]]; - // std::cout << " vec_ref: " << space.vec_ref << '\n'; - // std::cout << " vec_ortho: " << space.vec_ortho << '\n'; - // std::cout << " ref_alpha: " << space.ref_alpha << '\n'; - // std::cout << " ref_beta: " << space.ref_beta << '\n'; - // } - // } } #undef INDEX_UNSET #undef INDEX_INVALID #undef IS_EDGE_SHARP -static void reverse_space_index_array(const MeshNormalFanSpaces &spaces, - Array &corner_offset_indices, - Array &space_corner_indices) +/** + * Take an array of N indices that points to \a items_num items, where multiple indices map to the + * same item, and reverse the indices to create an array of all the indices that reference each + * item. Group each item's indices together consecutively, encoding the grouping in #r_offsets, + * which is meant to be used by #OffsetIndices. + */ +static void reverse_index_array(const Span item_indices, + const int items_num, + Array &r_offsets, + Array &r_reverse_indices) { - corner_offset_indices = Array(spaces.spaces.size() + 1, 0); - for (const int index : spaces.corner_space_indices) { - corner_offset_indices[index]++; + r_offsets = Array(items_num + 1, 0); + for (const int index : item_indices) { + r_offsets[index]++; } - offset_indices::accumulate_counts_to_offsets(corner_offset_indices); - space_corner_indices.reinitialize(corner_offset_indices.last()); - Array count(spaces.spaces.size(), 0); - for (const int corner : spaces.corner_space_indices.index_range()) { - const int space = spaces.corner_space_indices[corner]; - space_corner_indices[corner_offset_indices[space] + count[space]] = corner; - count[space]++; + offset_indices::accumulate_counts_to_offsets(r_offsets); + r_reverse_indices.reinitialize(r_offsets.last()); + + Array count_per_item(items_num, 0); + for (const int corner : item_indices.index_range()) { + const int space = item_indices[corner]; + r_reverse_indices[r_offsets[space] + count_per_item[space]] = corner; + count_per_item[space]++; } } @@ -1515,10 +1509,13 @@ static void mesh_normals_loop_custom_set(Span positions, done_loops.fill(true); } else { - Array space_corner_offset_indices; - Array space_corner_indices; - reverse_space_index_array(lnors_spacearr, space_corner_offset_indices, space_corner_indices); - const OffsetIndices space_corner_offsets(space_corner_offset_indices); + Array fan_corner_offset_indices; + Array fan_corners_data; + reverse_index_array(lnors_spacearr.corner_space_indices, + lnors_spacearr.spaces.size(), + fan_corner_offset_indices, + fan_corners_data); + const OffsetIndices fan_corner_offsets(fan_corner_offset_indices); for (const int i : corner_verts.index_range()) { if (lnors_spacearr.corner_space_indices[i] == -1) { @@ -1536,8 +1533,8 @@ static void mesh_normals_loop_custom_set(Span positions, } const int space_index = lnors_spacearr.corner_space_indices[i]; - const Span space_corners = space_corner_indices.as_span().slice( - space_corner_offsets[space_index]); + const Span fan_corners = fan_corners_data.as_span().slice( + fan_corner_offsets[space_index]); /* Notes: * - In case of mono-loop smooth fan, we have nothing to do. @@ -1548,7 +1545,7 @@ static void mesh_normals_loop_custom_set(Span positions, * - In smooth fan case, we compare each clnor against a ref one, * to avoid small differences adding up into a real big one in the end! */ - if (space_corners.is_empty()) { + if (fan_corners.is_empty()) { done_loops[i].set(); continue; } @@ -1556,7 +1553,7 @@ static void mesh_normals_loop_custom_set(Span positions, int prev_corner = -1; const float *org_nor = nullptr; - for (const int lidx : space_corners) { + for (const int lidx : fan_corners) { float *nor = r_custom_loop_normals[lidx]; if (!org_nor) { @@ -1585,8 +1582,8 @@ static void mesh_normals_loop_custom_set(Span positions, * otherwise we may miss some sharp edges here! * This is just a simplified version of above while loop. * See #45984. */ - if (space_corners.size() > 1 && org_nor) { - const int lidx = space_corners.last(); + if (fan_corners.size() > 1 && org_nor) { + const int lidx = fan_corners.last(); float *nor = r_custom_loop_normals[lidx]; if (dot_v3v3(org_nor, nor) < LNOR_SPACE_TRIGO_THRESHOLD) { @@ -1619,10 +1616,13 @@ static void mesh_normals_loop_custom_set(Span positions, loop_normals); } - Array space_corner_offset_indices; - Array space_corner_indices; - reverse_space_index_array(lnors_spacearr, space_corner_offset_indices, space_corner_indices); - const OffsetIndices space_corner_offsets(space_corner_offset_indices); + Array fan_corner_offset_indices; + Array fan_corners_data; + reverse_index_array(lnors_spacearr.corner_space_indices, + lnors_spacearr.spaces.size(), + fan_corner_offset_indices, + fan_corners_data); + const OffsetIndices fan_corner_offsets(fan_corner_offset_indices); /* And we just have to convert plain object-space custom normals to our * lnor space-encoded ones. */ @@ -1640,13 +1640,13 @@ static void mesh_normals_loop_custom_set(Span positions, } const int space_index = lnors_spacearr.corner_space_indices[i]; - const Span space_corners = space_corner_indices.as_span().slice( - space_corner_offsets[space_index]); + const Span fan_corners = fan_corners_data.as_span().slice( + fan_corner_offsets[space_index]); /* Note we accumulate and average all custom normals in current smooth fan, * to avoid getting different clnors data (tiny differences in plain custom normals can * give rather huge differences in computed 2D factors). */ - if (space_corners.size() < 2) { + if (fan_corners.size() < 2) { const int nidx = use_vertices ? corner_verts[i] : i; float *nor = r_custom_loop_normals[nidx]; @@ -1657,7 +1657,7 @@ static void mesh_normals_loop_custom_set(Span positions, } else { float3 avg_nor(0.0f); - for (const int lidx : space_corners) { + for (const int lidx : fan_corners) { const int nidx = use_vertices ? corner_verts[lidx] : lidx; float *nor = r_custom_loop_normals[nidx]; @@ -1666,12 +1666,12 @@ static void mesh_normals_loop_custom_set(Span positions, done_loops[lidx].reset(); } - mul_v3_fl(avg_nor, 1.0f / float(space_corners.size())); + mul_v3_fl(avg_nor, 1.0f / float(fan_corners.size())); short2 clnor_data_tmp; fan_space_custom_normal_to_data( &lnors_spacearr.spaces[space_index], loop_normals[i], avg_nor, clnor_data_tmp); - r_clnors_data.fill_indices(space_corners, clnor_data_tmp); + r_clnors_data.fill_indices(fan_corners, clnor_data_tmp); } } } diff --git a/source/blender/modifiers/intern/MOD_weighted_normal.cc b/source/blender/modifiers/intern/MOD_weighted_normal.cc index 947e5214acb..0f4cea550c4 100644 --- a/source/blender/modifiers/intern/MOD_weighted_normal.cc +++ b/source/blender/modifiers/intern/MOD_weighted_normal.cc @@ -237,7 +237,6 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd, WeightedNormalDataAggregateItem start_item{}; start_item.curr_strength = FACE_STRENGTH_WEAK; - items_data = Array(lnors_spacearr.spaces.size(), start_item); } else { -- 2.30.2 From 7a4448b0f2f571946dee5ac7af6690e2ccf64f17 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Wed, 3 May 2023 18:16:37 -0400 Subject: [PATCH 14/22] Cleanup: Rearrange header additions, rename type to remove part redundant with namespace --- source/blender/blenkernel/BKE_mesh.hh | 70 +++++++++---------- .../blender/blenkernel/intern/mesh_mirror.cc | 2 +- .../blender/blenkernel/intern/mesh_normals.cc | 12 ++-- .../modifiers/intern/MOD_weighted_normal.cc | 2 +- 4 files changed, 43 insertions(+), 43 deletions(-) diff --git a/source/blender/blenkernel/BKE_mesh.hh b/source/blender/blenkernel/BKE_mesh.hh index 79b411b767d..1b6de45de8e 100644 --- a/source/blender/blenkernel/BKE_mesh.hh +++ b/source/blender/blenkernel/BKE_mesh.hh @@ -50,6 +50,35 @@ void poly_angles_calc(Span vert_positions, /** \} */ +/* -------------------------------------------------------------------- */ +/** \name Medium-Level Normals Calculation + * \{ */ + +/** + * Calculate face normals directly into a result array. + * + * \note Usually #Mesh::poly_normals() is the preferred way to access face normals, + * since they may already be calculated and cached on the mesh. + */ +void normals_calc_polys(Span vert_positions, + OffsetIndices polys, + Span corner_verts, + MutableSpan poly_normals); + +/** + * Calculate face and vertex normals directly into result arrays. + * + * \note Usually #Mesh::vert_normals() is the preferred way to access vertex normals, + * since they may already be calculated and cached on the mesh. + */ +void normals_calc_poly_vert(Span vert_positions, + OffsetIndices polys, + Span corner_verts, + MutableSpan poly_normals, + MutableSpan vert_normals); + +/** \} */ + /* -------------------------------------------------------------------- */ /** \name Face Corner Normal Calculation * \{ */ @@ -60,20 +89,20 @@ void poly_angles_calc(Span vert_positions, * a regular #float3 format. */ struct NormalFanSpace { - /** Reference vector, orthogonal to vec_lnor. */ + /** Reference vector, orthogonal to corner normal. */ float3 vec_ref; - /** Third vector, orthogonal to vec_lnor and vec_ref. */ + /** Third vector, orthogonal to corner normal and #vec_ref. */ float3 vec_ortho; - /** Reference angle, around vec_ortho, in [0, pi] range (0.0 marks that space as invalid). */ + /** Reference angle around #vec_ortho, in [0, pi] range (0.0 marks space as invalid). */ float ref_alpha; - /** Reference angle, around vec_lnor, in [0, 2pi] range (0.0 marks that space as invalid). */ + /** Reference angle around corner normal, in [0, 2pi] range (0.0 marks space as invalid). */ float ref_beta; }; /** * Storage for coordinate spaces and connection information during normal calculation. */ -struct MeshNormalFanSpaces { +struct NormalFanSpaces { /** * The normal coordinate spaces, potentially shared between multiple face corners in a smooth fan * connected to a vertex. Depending on the mesh (the amount of sharing / number of sharp edges / @@ -115,38 +144,9 @@ void normals_calc_loop(Span vert_positions, bool use_split_normals, float split_angle, short2 *clnors_data, - MeshNormalFanSpaces *r_lnors_spacearr, + NormalFanSpaces *r_lnors_spacearr, MutableSpan r_loop_normals); -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Medium-Level Normals Calculation - * \{ */ - -/** - * Calculate face normals directly into a result array. - * - * \note Usually #Mesh::poly_normals() is the preferred way to access face normals, - * since they may already be calculated and cached on the mesh. - */ -void normals_calc_polys(Span vert_positions, - OffsetIndices polys, - Span corner_verts, - MutableSpan poly_normals); - -/** - * Calculate face and vertex normals directly into result arrays. - * - * \note Usually #Mesh::vert_normals() is the preferred way to access vertex normals, - * since they may already be calculated and cached on the mesh. - */ -void normals_calc_poly_vert(Span vert_positions, - OffsetIndices polys, - Span corner_verts, - MutableSpan poly_normals, - MutableSpan vert_normals); - void normals_loop_custom_set(Span vert_positions, Span edges, OffsetIndices polys, diff --git a/source/blender/blenkernel/intern/mesh_mirror.cc b/source/blender/blenkernel/intern/mesh_mirror.cc index 68f60ca574e..204acd35d8f 100644 --- a/source/blender/blenkernel/intern/mesh_mirror.cc +++ b/source/blender/blenkernel/intern/mesh_mirror.cc @@ -390,7 +390,7 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd, CustomData *ldata = &result->ldata; blender::short2 *clnors = static_cast( CustomData_get_layer_for_write(ldata, CD_CUSTOMLOOPNORMAL, result->totloop)); - blender::bke::mesh::MeshNormalFanSpaces lnors_spacearr; + blender::bke::mesh::NormalFanSpaces lnors_spacearr; /* The transform matrix of a normal must be * the transpose of inverse of transform matrix of the geometry... */ diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc index 6f029447e64..1077b5c2f81 100644 --- a/source/blender/blenkernel/intern/mesh_normals.cc +++ b/source/blender/blenkernel/intern/mesh_normals.cc @@ -709,7 +709,7 @@ struct LoopSplitTaskDataCommon { /* Read/write. * Note we do not need to protect it, though, since two different tasks will *always* affect * different elements in the arrays. */ - MeshNormalFanSpaces *lnors_spacearr; + NormalFanSpaces *lnors_spacearr; MutableSpan loop_normals; MutableSpan clnors_data; @@ -889,7 +889,7 @@ static void lnor_space_for_single_fan(LoopSplitTaskDataCommon *common_data, loop_normals[ml_curr_index] = poly_normals[loop_to_poly[ml_curr_index]]; - if (MeshNormalFanSpaces *lnors_spacearr = common_data->lnors_spacearr) { + if (NormalFanSpaces *lnors_spacearr = common_data->lnors_spacearr) { const Span positions = common_data->positions; const Span edges = common_data->edges; const OffsetIndices polys = common_data->polys; @@ -930,7 +930,7 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, const int space_index, Vector *edge_vectors) { - MeshNormalFanSpaces *lnors_spacearr = common_data->lnors_spacearr; + NormalFanSpaces *lnors_spacearr = common_data->lnors_spacearr; MutableSpan loop_normals = common_data->loop_normals; MutableSpan clnors_data = common_data->clnors_data; @@ -1270,7 +1270,7 @@ void normals_calc_loop(const Span vert_positions, bool use_split_normals, float split_angle, short2 *clnors_data, - MeshNormalFanSpaces *r_lnors_spacearr, + NormalFanSpaces *r_lnors_spacearr, MutableSpan r_loop_normals) { /* For now this is not supported. @@ -1328,7 +1328,7 @@ void normals_calc_loop(const Span vert_positions, /* When using custom loop normals, disable the angle feature! */ const bool check_angle = (split_angle < float(M_PI)) && (clnors_data == nullptr); - MeshNormalFanSpaces _lnors_spacearr; + NormalFanSpaces _lnors_spacearr; #ifdef DEBUG_TIME SCOPED_TIMER_AVERAGED(__func__); @@ -1457,7 +1457,7 @@ static void mesh_normals_loop_custom_set(Span positions, * function *is not* performance-critical, since it is mostly expected to be called by io add-ons * when importing custom normals, and modifier (and perhaps from some editing tools later?). So * better to keep some simplicity here, and just call #bke::mesh::normals_calc_loop() twice! */ - MeshNormalFanSpaces lnors_spacearr; + NormalFanSpaces lnors_spacearr; BitVector<> done_loops(corner_verts.size(), false); Array loop_normals(corner_verts.size()); const Array loop_to_poly = mesh_topology::build_loop_to_poly_map(polys); diff --git a/source/blender/modifiers/intern/MOD_weighted_normal.cc b/source/blender/modifiers/intern/MOD_weighted_normal.cc index 0f4cea550c4..8c9735ebfc8 100644 --- a/source/blender/modifiers/intern/MOD_weighted_normal.cc +++ b/source/blender/modifiers/intern/MOD_weighted_normal.cc @@ -205,7 +205,7 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd, const bool has_clnors = wn_data->has_clnors; const float split_angle = wn_data->split_angle; - bke::mesh::MeshNormalFanSpaces lnors_spacearr; + bke::mesh::NormalFanSpaces lnors_spacearr; const bool keep_sharp = (wnmd->flag & MOD_WEIGHTEDNORMAL_KEEP_SHARP) != 0; const bool use_face_influence = (wnmd->flag & MOD_WEIGHTEDNORMAL_FACE_INFLUENCE) != 0 && -- 2.30.2 From e4c4520eacd1597bc766e73ff0367c358f447397 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Sat, 6 May 2023 23:40:34 -0400 Subject: [PATCH 15/22] Add detail to comments, rename structs --- source/blender/blenkernel/BKE_mesh.hh | 18 ++++++------ .../blender/blenkernel/intern/mesh_mirror.cc | 2 +- .../blender/blenkernel/intern/mesh_normals.cc | 28 +++++++++---------- .../modifiers/intern/MOD_weighted_normal.cc | 2 +- 4 files changed, 25 insertions(+), 25 deletions(-) diff --git a/source/blender/blenkernel/BKE_mesh.hh b/source/blender/blenkernel/BKE_mesh.hh index a9e2d3b2a38..190af7400fa 100644 --- a/source/blender/blenkernel/BKE_mesh.hh +++ b/source/blender/blenkernel/BKE_mesh.hh @@ -90,7 +90,7 @@ void normals_calc_poly_vert(Span vert_positions, * coordinate space used to convert normals between the "custom normal" #short2 representation and * a regular #float3 format. */ -struct NormalFanSpace { +struct CornerNormalSpace { /** Reference vector, orthogonal to corner normal. */ float3 vec_ref; /** Third vector, orthogonal to corner normal and #vec_ref. */ @@ -102,22 +102,22 @@ struct NormalFanSpace { }; /** - * Storage for coordinate spaces and connection information during normal calculation. + * Storage for corner fan coordinate spaces for an entire mesh. */ -struct NormalFanSpaces { +struct CornerNormalSpaceArray { /** * The normal coordinate spaces, potentially shared between multiple face corners in a smooth fan - * connected to a vertex. Depending on the mesh (the amount of sharing / number of sharp edges / - * size of each fan), there may be many fewer spaces than face corners, so they are stored in a - * separate array. + * connected to a vertex (and not per face corner). Depending on the mesh (the amount of sharing + * / number of sharp edges / size of each fan), there may be many fewer spaces than face corners, + * so they are stored in a separate array. */ - Array spaces; + Array spaces; /** The index of the data in the #spaces array for each face corner. */ Array corner_space_indices; }; -void fan_space_custom_normal_to_data(const NormalFanSpace *lnor_space, +void fan_space_custom_normal_to_data(const CornerNormalSpace *lnor_space, const float3 lnor_no_custom, const float custom_lnor[3], short r_clnor_data[2]); @@ -146,7 +146,7 @@ void normals_calc_loop(Span vert_positions, bool use_split_normals, float split_angle, short2 *clnors_data, - NormalFanSpaces *r_lnors_spacearr, + CornerNormalSpaceArray *r_lnors_spacearr, MutableSpan r_loop_normals); void normals_loop_custom_set(Span vert_positions, diff --git a/source/blender/blenkernel/intern/mesh_mirror.cc b/source/blender/blenkernel/intern/mesh_mirror.cc index 4d4891d63dd..4880e83dbba 100644 --- a/source/blender/blenkernel/intern/mesh_mirror.cc +++ b/source/blender/blenkernel/intern/mesh_mirror.cc @@ -390,7 +390,7 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd, CustomData *ldata = &result->ldata; blender::short2 *clnors = static_cast( CustomData_get_layer_for_write(ldata, CD_CUSTOMLOOPNORMAL, result->totloop)); - blender::bke::mesh::NormalFanSpaces lnors_spacearr; + blender::bke::mesh::CornerNormalSpaceArray lnors_spacearr; /* The transform matrix of a normal must be * the transpose of inverse of transform matrix of the geometry... */ diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc index 1077b5c2f81..dc3b6bb6805 100644 --- a/source/blender/blenkernel/intern/mesh_normals.cc +++ b/source/blender/blenkernel/intern/mesh_normals.cc @@ -468,7 +468,7 @@ MLoopNorSpace *BKE_lnor_space_create(MLoopNorSpaceArray *lnors_spacearr) #define LNOR_SPACE_TRIGO_THRESHOLD (1.0f - 1e-4f) namespace blender::bke::mesh { -static void normal_fan_space_define(NormalFanSpace *lnor_space, +static void normal_fan_space_define(CornerNormalSpace *lnor_space, const float lnor[3], float vec_ref[3], float vec_other[3], @@ -540,7 +540,7 @@ void BKE_lnor_space_define(MLoopNorSpace *lnor_space, const blender::Span edge_vectors) { using namespace blender::bke::mesh; - NormalFanSpace space{}; + CornerNormalSpace space{}; normal_fan_space_define(&space, lnor, vec_ref, vec_other, edge_vectors); copy_v3_v3(lnor_space->vec_lnor, lnor); copy_v3_v3(lnor_space->vec_ref, space.vec_ref); @@ -585,7 +585,7 @@ MINLINE short unit_float_to_short(const float val) } namespace blender::bke::mesh { -static void fan_space_custom_data_to_normal(const NormalFanSpace *lnor_space, +static void fan_space_custom_data_to_normal(const CornerNormalSpace *lnor_space, const float3 lnor_no_custom, const short clnor_data[2], float r_custom_lnor[3]) @@ -626,7 +626,7 @@ void BKE_lnor_space_custom_data_to_normal(const MLoopNorSpace *lnor_space, float r_custom_lnor[3]) { using namespace blender::bke::mesh; - NormalFanSpace space; + CornerNormalSpace space; space.vec_ref = lnor_space->vec_ref; space.vec_ortho = lnor_space->vec_ortho; space.ref_alpha = lnor_space->ref_alpha; @@ -635,7 +635,7 @@ void BKE_lnor_space_custom_data_to_normal(const MLoopNorSpace *lnor_space, } namespace blender::bke::mesh { -void fan_space_custom_normal_to_data(const NormalFanSpace *lnor_space, +void fan_space_custom_normal_to_data(const CornerNormalSpace *lnor_space, const float3 lnor_no_custom, const float custom_lnor[3], short r_clnor_data[2]) @@ -695,7 +695,7 @@ void BKE_lnor_space_custom_normal_to_data(const MLoopNorSpace *lnor_space, short r_clnor_data[2]) { using namespace blender::bke::mesh; - NormalFanSpace space; + CornerNormalSpace space; space.vec_ref = lnor_space->vec_ref; space.vec_ortho = lnor_space->vec_ortho; space.ref_alpha = lnor_space->ref_alpha; @@ -709,7 +709,7 @@ struct LoopSplitTaskDataCommon { /* Read/write. * Note we do not need to protect it, though, since two different tasks will *always* affect * different elements in the arrays. */ - NormalFanSpaces *lnors_spacearr; + CornerNormalSpaceArray *lnors_spacearr; MutableSpan loop_normals; MutableSpan clnors_data; @@ -889,7 +889,7 @@ static void lnor_space_for_single_fan(LoopSplitTaskDataCommon *common_data, loop_normals[ml_curr_index] = poly_normals[loop_to_poly[ml_curr_index]]; - if (NormalFanSpaces *lnors_spacearr = common_data->lnors_spacearr) { + if (CornerNormalSpaceArray *lnors_spacearr = common_data->lnors_spacearr) { const Span positions = common_data->positions; const Span edges = common_data->edges; const OffsetIndices polys = common_data->polys; @@ -912,7 +912,7 @@ static void lnor_space_for_single_fan(LoopSplitTaskDataCommon *common_data, sub_v3_v3v3(vec_prev, positions[vert_3], positions[vert_pivot]); normalize_v3(vec_prev); - NormalFanSpace *lnor_space = &lnors_spacearr->spaces[space_index]; + CornerNormalSpace *lnor_space = &lnors_spacearr->spaces[space_index]; normal_fan_space_define(lnor_space, loop_normals[ml_curr_index], vec_curr, vec_prev, {}); lnors_spacearr->corner_space_indices[ml_curr_index] = space_index; @@ -930,7 +930,7 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, const int space_index, Vector *edge_vectors) { - NormalFanSpaces *lnors_spacearr = common_data->lnors_spacearr; + CornerNormalSpaceArray *lnors_spacearr = common_data->lnors_spacearr; MutableSpan loop_normals = common_data->loop_normals; MutableSpan clnors_data = common_data->clnors_data; @@ -1072,7 +1072,7 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, length = 1.0f; } - NormalFanSpace *lnor_space = &lnors_spacearr->spaces[space_index]; + CornerNormalSpace *lnor_space = &lnors_spacearr->spaces[space_index]; normal_fan_space_define(lnor_space, lnor, vec_org, vec_curr, *edge_vectors); lnors_spacearr->corner_space_indices.as_mutable_span().fill_indices( processed_corners.as_span(), space_index); @@ -1270,7 +1270,7 @@ void normals_calc_loop(const Span vert_positions, bool use_split_normals, float split_angle, short2 *clnors_data, - NormalFanSpaces *r_lnors_spacearr, + CornerNormalSpaceArray *r_lnors_spacearr, MutableSpan r_loop_normals) { /* For now this is not supported. @@ -1328,7 +1328,7 @@ void normals_calc_loop(const Span vert_positions, /* When using custom loop normals, disable the angle feature! */ const bool check_angle = (split_angle < float(M_PI)) && (clnors_data == nullptr); - NormalFanSpaces _lnors_spacearr; + CornerNormalSpaceArray _lnors_spacearr; #ifdef DEBUG_TIME SCOPED_TIMER_AVERAGED(__func__); @@ -1457,7 +1457,7 @@ static void mesh_normals_loop_custom_set(Span positions, * function *is not* performance-critical, since it is mostly expected to be called by io add-ons * when importing custom normals, and modifier (and perhaps from some editing tools later?). So * better to keep some simplicity here, and just call #bke::mesh::normals_calc_loop() twice! */ - NormalFanSpaces lnors_spacearr; + CornerNormalSpaceArray lnors_spacearr; BitVector<> done_loops(corner_verts.size(), false); Array loop_normals(corner_verts.size()); const Array loop_to_poly = mesh_topology::build_loop_to_poly_map(polys); diff --git a/source/blender/modifiers/intern/MOD_weighted_normal.cc b/source/blender/modifiers/intern/MOD_weighted_normal.cc index ff3068cec5b..ac09aa22568 100644 --- a/source/blender/modifiers/intern/MOD_weighted_normal.cc +++ b/source/blender/modifiers/intern/MOD_weighted_normal.cc @@ -205,7 +205,7 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd, const bool has_clnors = wn_data->has_clnors; const float split_angle = wn_data->split_angle; - bke::mesh::NormalFanSpaces lnors_spacearr; + bke::mesh::CornerNormalSpaceArray lnors_spacearr; const bool keep_sharp = (wnmd->flag & MOD_WEIGHTEDNORMAL_KEEP_SHARP) != 0; const bool use_face_influence = (wnmd->flag & MOD_WEIGHTEDNORMAL_FACE_INFLUENCE) != 0 && -- 2.30.2 From a7c06198ef9de01d662da0bfc08166729628fc99 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Sat, 6 May 2023 23:47:03 -0400 Subject: [PATCH 16/22] Add note about -1 indices --- source/blender/blenkernel/BKE_mesh.hh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/source/blender/blenkernel/BKE_mesh.hh b/source/blender/blenkernel/BKE_mesh.hh index 190af7400fa..c7f8ab83035 100644 --- a/source/blender/blenkernel/BKE_mesh.hh +++ b/source/blender/blenkernel/BKE_mesh.hh @@ -113,7 +113,10 @@ struct CornerNormalSpaceArray { */ Array spaces; - /** The index of the data in the #spaces array for each face corner. */ + /** + * The index of the data in the #spaces array for each face corner. + * Rare -1 values define face corners without a coordinate space. + */ Array corner_space_indices; }; -- 2.30.2 From 6fcb79f1765d95f58a4dc0508d112ea5828a857c Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Sat, 6 May 2023 23:47:17 -0400 Subject: [PATCH 17/22] Use function names more similar to old names --- .../blender/blenkernel/intern/mesh_normals.cc | 50 +++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc index dc3b6bb6805..faa0c77dcfd 100644 --- a/source/blender/blenkernel/intern/mesh_normals.cc +++ b/source/blender/blenkernel/intern/mesh_normals.cc @@ -468,11 +468,11 @@ MLoopNorSpace *BKE_lnor_space_create(MLoopNorSpaceArray *lnors_spacearr) #define LNOR_SPACE_TRIGO_THRESHOLD (1.0f - 1e-4f) namespace blender::bke::mesh { -static void normal_fan_space_define(CornerNormalSpace *lnor_space, - const float lnor[3], - float vec_ref[3], - float vec_other[3], - const blender::Span edge_vectors) +static void lnor_space_define(CornerNormalSpace *lnor_space, + const float lnor[3], + float vec_ref[3], + float vec_other[3], + const blender::Span edge_vectors) { const float pi2 = float(M_PI) * 2.0f; float tvec[3], dtp; @@ -541,7 +541,7 @@ void BKE_lnor_space_define(MLoopNorSpace *lnor_space, { using namespace blender::bke::mesh; CornerNormalSpace space{}; - normal_fan_space_define(&space, lnor, vec_ref, vec_other, edge_vectors); + lnor_space_define(&space, lnor, vec_ref, vec_other, edge_vectors); copy_v3_v3(lnor_space->vec_lnor, lnor); copy_v3_v3(lnor_space->vec_ref, space.vec_ref); copy_v3_v3(lnor_space->vec_ortho, space.vec_ortho); @@ -585,10 +585,10 @@ MINLINE short unit_float_to_short(const float val) } namespace blender::bke::mesh { -static void fan_space_custom_data_to_normal(const CornerNormalSpace *lnor_space, - const float3 lnor_no_custom, - const short clnor_data[2], - float r_custom_lnor[3]) +static void lnor_space_custom_data_to_normal(const CornerNormalSpace *lnor_space, + const float3 lnor_no_custom, + const short clnor_data[2], + float r_custom_lnor[3]) { /* NOP custom normal data or invalid lnor space, return. */ if (clnor_data[0] == 0 || lnor_space->ref_alpha == 0.0f || lnor_space->ref_beta == 0.0f) { @@ -631,14 +631,14 @@ void BKE_lnor_space_custom_data_to_normal(const MLoopNorSpace *lnor_space, space.vec_ortho = lnor_space->vec_ortho; space.ref_alpha = lnor_space->ref_alpha; space.ref_beta = lnor_space->ref_beta; - fan_space_custom_data_to_normal(&space, lnor_space->vec_lnor, clnor_data, r_custom_lnor); + lnor_space_custom_data_to_normal(&space, lnor_space->vec_lnor, clnor_data, r_custom_lnor); } namespace blender::bke::mesh { -void fan_space_custom_normal_to_data(const CornerNormalSpace *lnor_space, - const float3 lnor_no_custom, - const float custom_lnor[3], - short r_clnor_data[2]) +void lnor_space_custom_normal_to_data(const CornerNormalSpace *lnor_space, + const float3 lnor_no_custom, + const float custom_lnor[3], + short r_clnor_data[2]) { /* We use nullptr vector as NOP custom normal (can be simpler than giving auto-computed `lnor`). */ @@ -700,7 +700,7 @@ void BKE_lnor_space_custom_normal_to_data(const MLoopNorSpace *lnor_space, space.vec_ortho = lnor_space->vec_ortho; space.ref_alpha = lnor_space->ref_alpha; space.ref_beta = lnor_space->ref_beta; - fan_space_custom_normal_to_data(&space, lnor_space->vec_lnor, custom_lnor, r_clnor_data); + lnor_space_custom_normal_to_data(&space, lnor_space->vec_lnor, custom_lnor, r_clnor_data); } namespace blender::bke::mesh { @@ -913,14 +913,14 @@ static void lnor_space_for_single_fan(LoopSplitTaskDataCommon *common_data, normalize_v3(vec_prev); CornerNormalSpace *lnor_space = &lnors_spacearr->spaces[space_index]; - normal_fan_space_define(lnor_space, loop_normals[ml_curr_index], vec_curr, vec_prev, {}); + lnor_space_define(lnor_space, loop_normals[ml_curr_index], vec_curr, vec_prev, {}); lnors_spacearr->corner_space_indices[ml_curr_index] = space_index; if (!clnors_data.is_empty()) { - fan_space_custom_data_to_normal(lnor_space, - loop_normals[ml_curr_index], - clnors_data[ml_curr_index], - loop_normals[ml_curr_index]); + lnor_space_custom_data_to_normal(lnor_space, + loop_normals[ml_curr_index], + clnors_data[ml_curr_index], + loop_normals[ml_curr_index]); } } } @@ -1073,7 +1073,7 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, } CornerNormalSpace *lnor_space = &lnors_spacearr->spaces[space_index]; - normal_fan_space_define(lnor_space, lnor, vec_org, vec_curr, *edge_vectors); + lnor_space_define(lnor_space, lnor, vec_org, vec_curr, *edge_vectors); lnors_spacearr->corner_space_indices.as_mutable_span().fill_indices( processed_corners.as_span(), space_index); edge_vectors->clear(); @@ -1093,7 +1093,7 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data, /* Extra bonus: since small-stack is local to this function, * no more need to empty it at all cost! */ - fan_space_custom_data_to_normal(lnor_space, lnor, *clnor_ref, lnor); + lnor_space_custom_data_to_normal(lnor_space, lnor, *clnor_ref, lnor); } } @@ -1651,7 +1651,7 @@ static void mesh_normals_loop_custom_set(Span positions, float *nor = r_custom_loop_normals[nidx]; const int space_index = lnors_spacearr.corner_space_indices[i]; - fan_space_custom_normal_to_data( + lnor_space_custom_normal_to_data( &lnors_spacearr.spaces[space_index], loop_normals[i], nor, r_clnors_data[i]); done_loops[i].reset(); } @@ -1668,7 +1668,7 @@ static void mesh_normals_loop_custom_set(Span positions, mul_v3_fl(avg_nor, 1.0f / float(fan_corners.size())); short2 clnor_data_tmp; - fan_space_custom_normal_to_data( + lnor_space_custom_normal_to_data( &lnors_spacearr.spaces[space_index], loop_normals[i], avg_nor, clnor_data_tmp); r_clnors_data.fill_indices(fan_corners, clnor_data_tmp); -- 2.30.2 From f1f92faa775349ee5586f4d332be17c5be6dfd7a Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Sun, 7 May 2023 21:24:31 -0400 Subject: [PATCH 18/22] Add more detail to comment --- source/blender/blenkernel/BKE_mesh.hh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/blenkernel/BKE_mesh.hh b/source/blender/blenkernel/BKE_mesh.hh index c7f8ab83035..385fa40e832 100644 --- a/source/blender/blenkernel/BKE_mesh.hh +++ b/source/blender/blenkernel/BKE_mesh.hh @@ -114,8 +114,8 @@ struct CornerNormalSpaceArray { Array spaces; /** - * The index of the data in the #spaces array for each face corner. - * Rare -1 values define face corners without a coordinate space. + * The index of the data in the #spaces array for each face corner (the array size is the + * same as #Mesh::totloop). Rare -1 values define face corners without a coordinate space. */ Array corner_space_indices; }; -- 2.30.2 From 11cd3d3118b80e8c338e7c6dbe201c055be95b5b Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Sun, 7 May 2023 21:25:13 -0400 Subject: [PATCH 19/22] Complete renaming of function from last time --- source/blender/blenkernel/BKE_mesh.hh | 8 ++++---- source/blender/blenkernel/intern/mesh_mirror.cc | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/source/blender/blenkernel/BKE_mesh.hh b/source/blender/blenkernel/BKE_mesh.hh index 385fa40e832..4302c787252 100644 --- a/source/blender/blenkernel/BKE_mesh.hh +++ b/source/blender/blenkernel/BKE_mesh.hh @@ -120,10 +120,10 @@ struct CornerNormalSpaceArray { Array corner_space_indices; }; -void fan_space_custom_normal_to_data(const CornerNormalSpace *lnor_space, - const float3 lnor_no_custom, - const float custom_lnor[3], - short r_clnor_data[2]); +void lnor_space_custom_data_to_normal(const CornerNormalSpace *lnor_space, + const float3 lnor_no_custom, + const float custom_lnor[3], + short r_clnor_data[2]); /** * Compute split normals, i.e. vertex normals associated with each poly (hence 'loop normals'). diff --git a/source/blender/blenkernel/intern/mesh_mirror.cc b/source/blender/blenkernel/intern/mesh_mirror.cc index 4880e83dbba..88d3056f671 100644 --- a/source/blender/blenkernel/intern/mesh_mirror.cc +++ b/source/blender/blenkernel/intern/mesh_mirror.cc @@ -434,10 +434,10 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd, mul_m4_v3(mtx_nor, loop_normals[mirrorj]); const int space_index = lnors_spacearr.corner_space_indices[mirrorj]; - blender::bke::mesh::fan_space_custom_normal_to_data(&lnors_spacearr.spaces[space_index], - loop_normals[mirrorj], - loop_normals[mirrorj], - clnors[mirrorj]); + blender::bke::mesh::lnor_space_custom_data_to_normal(&lnors_spacearr.spaces[space_index], + loop_normals[mirrorj], + loop_normals[mirrorj], + clnors[mirrorj]); } } } -- 2.30.2 From a87d0eeebafe6b5b672b6d662602f66ef8992db8 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Sun, 7 May 2023 21:26:07 -0400 Subject: [PATCH 20/22] Use suggested variable names for reverse_index_array names --- .../blender/blenkernel/intern/mesh_normals.cc | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc index faa0c77dcfd..1c3881c60c1 100644 --- a/source/blender/blenkernel/intern/mesh_normals.cc +++ b/source/blender/blenkernel/intern/mesh_normals.cc @@ -1509,13 +1509,13 @@ static void mesh_normals_loop_custom_set(Span positions, done_loops.fill(true); } else { - Array fan_corner_offset_indices; - Array fan_corners_data; + Array fan_corners_from_space_offset_indices; + Array fan_corners_from_space_data; reverse_index_array(lnors_spacearr.corner_space_indices, lnors_spacearr.spaces.size(), - fan_corner_offset_indices, - fan_corners_data); - const OffsetIndices fan_corner_offsets(fan_corner_offset_indices); + fan_corners_from_space_offset_indices, + fan_corners_from_space_data); + const OffsetIndices fan_corner_offsets(fan_corners_from_space_offset_indices); for (const int i : corner_verts.index_range()) { if (lnors_spacearr.corner_space_indices[i] == -1) { @@ -1533,7 +1533,7 @@ static void mesh_normals_loop_custom_set(Span positions, } const int space_index = lnors_spacearr.corner_space_indices[i]; - const Span fan_corners = fan_corners_data.as_span().slice( + const Span fan_corners = fan_corners_from_space_data.as_span().slice( fan_corner_offsets[space_index]); /* Notes: @@ -1616,13 +1616,13 @@ static void mesh_normals_loop_custom_set(Span positions, loop_normals); } - Array fan_corner_offset_indices; - Array fan_corners_data; + Array fan_corners_from_space_offset_indices; + Array fan_corners_from_space_data; reverse_index_array(lnors_spacearr.corner_space_indices, lnors_spacearr.spaces.size(), - fan_corner_offset_indices, - fan_corners_data); - const OffsetIndices fan_corner_offsets(fan_corner_offset_indices); + fan_corners_from_space_offset_indices, + fan_corners_from_space_data); + const OffsetIndices fan_corner_offsets(fan_corners_from_space_offset_indices); /* And we just have to convert plain object-space custom normals to our * lnor space-encoded ones. */ @@ -1640,7 +1640,7 @@ static void mesh_normals_loop_custom_set(Span positions, } const int space_index = lnors_spacearr.corner_space_indices[i]; - const Span fan_corners = fan_corners_data.as_span().slice( + const Span fan_corners = fan_corners_from_space_data.as_span().slice( fan_corner_offsets[space_index]); /* Note we accumulate and average all custom normals in current smooth fan, -- 2.30.2 From ffc8d2aefdbdedcda340b7a588afcb38faa25e95 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Sun, 7 May 2023 21:29:12 -0400 Subject: [PATCH 21/22] Improve reverse_index_array doc-string --- source/blender/blenkernel/intern/mesh_normals.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc index 1c3881c60c1..78efd3e2256 100644 --- a/source/blender/blenkernel/intern/mesh_normals.cc +++ b/source/blender/blenkernel/intern/mesh_normals.cc @@ -1407,6 +1407,11 @@ void normals_calc_loop(const Span vert_positions, * same item, and reverse the indices to create an array of all the indices that reference each * item. Group each item's indices together consecutively, encoding the grouping in #r_offsets, * which is meant to be used by #OffsetIndices. + * + * \param r_offsets: An array to be filled with the first index of each item in + * \a r_reverse_indices, used to split the indices into chunks by item. (See #OffsetIndices). + * \param r_reverse_indices: The indices into \a item_indices that point to each item, split by \a + * r_offsets. */ static void reverse_index_array(const Span item_indices, const int items_num, -- 2.30.2 From 59bdd13e13944f949366ade0fc75cf0ad1fad3b4 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Sun, 7 May 2023 21:42:35 -0400 Subject: [PATCH 22/22] Fix function name --- source/blender/blenkernel/BKE_mesh.hh | 4 ++-- source/blender/blenkernel/intern/mesh_mirror.cc | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/source/blender/blenkernel/BKE_mesh.hh b/source/blender/blenkernel/BKE_mesh.hh index 4302c787252..d2e03ee3755 100644 --- a/source/blender/blenkernel/BKE_mesh.hh +++ b/source/blender/blenkernel/BKE_mesh.hh @@ -120,8 +120,8 @@ struct CornerNormalSpaceArray { Array corner_space_indices; }; -void lnor_space_custom_data_to_normal(const CornerNormalSpace *lnor_space, - const float3 lnor_no_custom, +void lnor_space_custom_normal_to_data(const CornerNormalSpace *lnor_space, + float3 lnor_no_custom, const float custom_lnor[3], short r_clnor_data[2]); diff --git a/source/blender/blenkernel/intern/mesh_mirror.cc b/source/blender/blenkernel/intern/mesh_mirror.cc index 88d3056f671..103947f91c2 100644 --- a/source/blender/blenkernel/intern/mesh_mirror.cc +++ b/source/blender/blenkernel/intern/mesh_mirror.cc @@ -434,7 +434,7 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd, mul_m4_v3(mtx_nor, loop_normals[mirrorj]); const int space_index = lnors_spacearr.corner_space_indices[mirrorj]; - blender::bke::mesh::lnor_space_custom_data_to_normal(&lnors_spacearr.spaces[space_index], + blender::bke::mesh::lnor_space_custom_normal_to_data(&lnors_spacearr.spaces[space_index], loop_normals[mirrorj], loop_normals[mirrorj], clnors[mirrorj]); -- 2.30.2