Mesh: Reduce custom normal calculation memory usage #107592

Merged
Hans Goudey merged 32 commits from HooglyBoogly/blender:corner-normals-refactor-storage into main 2023-05-10 14:41:16 +02:00
4 changed files with 43 additions and 43 deletions
Showing only changes of commit 7a4448b0f2 - Show all commits

View File

@ -50,6 +50,35 @@ void poly_angles_calc(Span<float3> 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<float3> vert_positions,
OffsetIndices<int> polys,
Span<int> corner_verts,
MutableSpan<float3> 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<float3> vert_positions,
OffsetIndices<int> polys,
Span<int> corner_verts,
MutableSpan<float3> poly_normals,
MutableSpan<float3> vert_normals);
/** \} */
/* -------------------------------------------------------------------- */
/** \name Face Corner Normal Calculation
* \{ */
@ -60,20 +89,20 @@ void poly_angles_calc(Span<float3> 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;
};
/**

Worth mentioning some things that might seem obvious, that this stores normal data for an entire mesh.

Worth mentioning some things that might seem obvious, that this stores normal data for an entire mesh.
* Storage for coordinate spaces and connection information during normal calculation.
*/
struct MeshNormalFanSpaces {
struct NormalFanSpaces {

The names NormalFanSpaces & NormalFanSpace are too similar, the old suffix "Array" wasn't exactly accurate either (as it's not just an array) but at least it was easily distinguishable.

The names `NormalFanSpaces` & `NormalFanSpace` are too similar, the old suffix "Array" wasn't exactly accurate either (as it's not just an array) but at least it was easily distinguishable.
/**
* 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<float3> vert_positions,
bool use_split_normals,
float split_angle,
short2 *clnors_data,
MeshNormalFanSpaces *r_lnors_spacearr,
NormalFanSpaces *r_lnors_spacearr,
MutableSpan<float3> 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<float3> vert_positions,
OffsetIndices<int> polys,
Span<int> corner_verts,
MutableSpan<float3> 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<float3> vert_positions,
OffsetIndices<int> polys,
Span<int> corner_verts,
MutableSpan<float3> poly_normals,
MutableSpan<float3> vert_normals);
void normals_loop_custom_set(Span<float3> vert_positions,
Span<int2> edges,
OffsetIndices<int> polys,

View File

@ -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<blender::short2 *>(
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... */

View File

@ -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<float3> loop_normals;
MutableSpan<short2> 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<float3> positions = common_data->positions;
const Span<int2> 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<float3> *edge_vectors)
{
MeshNormalFanSpaces *lnors_spacearr = common_data->lnors_spacearr;
NormalFanSpaces *lnors_spacearr = common_data->lnors_spacearr;
MutableSpan<float3> loop_normals = common_data->loop_normals;
MutableSpan<short2> clnors_data = common_data->clnors_data;
@ -1270,7 +1270,7 @@ void normals_calc_loop(const Span<float3> vert_positions,
bool use_split_normals,
float split_angle,
short2 *clnors_data,
MeshNormalFanSpaces *r_lnors_spacearr,
NormalFanSpaces *r_lnors_spacearr,
MutableSpan<float3> r_loop_normals)
{
/* For now this is not supported.
@ -1328,7 +1328,7 @@ void normals_calc_loop(const Span<float3> 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<float3> 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<float3> loop_normals(corner_verts.size());
const Array<int> loop_to_poly = mesh_topology::build_loop_to_poly_map(polys);

View File

@ -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 &&