Cleanup: Use C++ types, references for custom normals

Also remove unnecessary namespace specification.
This commit is contained in:
Hans Goudey 2023-07-10 11:59:18 -04:00
parent 41335edf22
commit 3fc45d6151
3 changed files with 121 additions and 135 deletions

View File

@ -132,9 +132,8 @@ struct CornerNormalSpaceArray {
bool create_corners_by_space = false;
};
void lnor_space_custom_normal_to_data(const CornerNormalSpace *lnor_space,
const float custom_lnor[3],
short r_clnor_data[2]);
short2 lnor_space_custom_normal_to_data(const CornerNormalSpace &lnor_space,
const float3 &custom_lnor);
/**
* Compute split normals, i.e. vertex normals associated with each poly (hence 'loop normals').

View File

@ -436,8 +436,8 @@ 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_normal_to_data(
&lnors_spacearr.spaces[space_index], loop_normals[mirrorj], clnors[mirrorj]);
clnors[mirrorj] = blender::bke::mesh::lnor_space_custom_normal_to_data(
lnors_spacearr.spaces[space_index], loop_normals[mirrorj]);
}
}
}

View File

@ -168,12 +168,8 @@ float3 poly_normal_calc(const Span<float3> vert_positions, const Span<int> poly_
return float3(0);
}
} // namespace blender::bke::mesh
/** \} */
namespace blender::bke::mesh {
/* -------------------------------------------------------------------- */
/** \name Mesh Normal Calculation (Polygons & Vertices)
*
@ -453,11 +449,12 @@ MLoopNorSpace *BKE_lnor_space_create(MLoopNorSpaceArray *lnors_spacearr)
#define LNOR_SPACE_TRIGO_THRESHOLD (1.0f - 1e-4f)
namespace blender::bke::mesh {
static void lnor_space_define(CornerNormalSpace *lnor_space,
static void lnor_space_define(CornerNormalSpace &lnor_space,
const float lnor[3],
float vec_ref[3],
float vec_other[3],
const blender::Span<blender::float3> edge_vectors)
const Span<float3> edge_vectors)
{
const float pi2 = float(M_PI) * 2.0f;
float tvec[3], dtp;
@ -469,16 +466,16 @@ static void lnor_space_define(CornerNormalSpace *lnor_space,
{
/* 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;
lnor_space.ref_alpha = lnor_space.ref_beta = 0.0f;
return;
}
lnor_space->vec_lnor = lnor;
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. */
@ -487,21 +484,21 @@ static void lnor_space_define(CornerNormalSpace *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);
@ -509,15 +506,16 @@ static void lnor_space_define(CornerNormalSpace *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;
}
}
} // namespace blender::bke::mesh
void BKE_lnor_space_define(MLoopNorSpace *lnor_space,
@ -528,7 +526,7 @@ void BKE_lnor_space_define(MLoopNorSpace *lnor_space,
{
using namespace blender::bke::mesh;
CornerNormalSpace space{};
lnor_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, space.vec_lnor);
copy_v3_v3(lnor_space->vec_ref, space.vec_ref);
copy_v3_v3(lnor_space->vec_ortho, space.vec_ortho);
@ -572,39 +570,41 @@ MINLINE short unit_float_to_short(const float val)
}
namespace blender::bke::mesh {
static void lnor_space_custom_data_to_normal(const CornerNormalSpace *lnor_space,
const short clnor_data[2],
float r_custom_lnor[3])
static float3 lnor_space_custom_data_to_normal(const CornerNormalSpace &lnor_space,
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) {
copy_v3_v3(r_custom_lnor, lnor_space->vec_lnor);
return;
if (clnor_data[0] == 0 || lnor_space.ref_alpha == 0.0f || lnor_space.ref_beta == 0.0f) {
return lnor_space.vec_lnor;
}
{
/* 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]);
float3 r_custom_lnor;
mul_v3_v3fl(r_custom_lnor, lnor_space->vec_lnor, cosf(alpha));
/* 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]);
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));
}
mul_v3_v3fl(r_custom_lnor, lnor_space.vec_lnor, 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,
@ -618,62 +618,63 @@ 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;
lnor_space_custom_data_to_normal(&space, clnor_data, r_custom_lnor);
copy_v3_v3(r_custom_lnor, lnor_space_custom_data_to_normal(space, clnor_data));
}
namespace blender::bke::mesh {
void lnor_space_custom_normal_to_data(const CornerNormalSpace *lnor_space,
const float custom_lnor[3],
short r_clnor_data[2])
short2 lnor_space_custom_normal_to_data(const CornerNormalSpace &lnor_space,
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_space->vec_lnor, custom_lnor, 1e-4f)) {
r_clnor_data[0] = r_clnor_data[1] = 0;
return;
/* We use zero 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)) {
return short2(0);
}
{
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;
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));
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[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;
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,
@ -687,7 +688,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;
lnor_space_custom_normal_to_data(&space, custom_lnor, r_clnor_data);
copy_v2_v2_short(r_clnor_data, lnor_space_custom_normal_to_data(space, custom_lnor));
}
namespace blender::bke::mesh {
@ -899,13 +900,13 @@ 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);
CornerNormalSpace *lnor_space = &lnors_spacearr->spaces[space_index];
CornerNormalSpace &lnor_space = lnors_spacearr->spaces[space_index];
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()) {
lnor_space_custom_data_to_normal(
lnor_space, clnors_data[ml_curr_index], loop_normals[ml_curr_index]);
loop_normals[ml_curr_index] = lnor_space_custom_data_to_normal(lnor_space,
clnors_data[ml_curr_index]);
}
if (!lnors_spacearr->corners_by_space.is_empty()) {
@ -953,7 +954,7 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data,
/* We validate clnors data on the fly - cheapest way to do! */
int2 clnors_avg(0);
short2 *clnor_ref = nullptr;
const short2 *clnor_ref = nullptr;
int clnors_count = 0;
bool clnors_invalid = false;
@ -998,26 +999,21 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data,
// printf("\thandling edge %d / loop %d\n", corner_edges[mlfan_curr_index], mlfan_curr_index);
{
/* Code similar to accumulate_vertex_normals_poly_v3. */
/* Calculate angle between the two poly edges incident on this vertex. */
const float fac = saacos(dot_v3v3(vec_curr, vec_prev));
/* Accumulate */
lnor += poly_normals[mpfan_curr_index] * fac;
/* Code similar to accumulate_vertex_normals_poly_v3. */
/* Calculate angle between the two poly edges incident on this vertex. */
lnor += poly_normals[mpfan_curr_index] * saacos(math::dot(vec_curr, vec_prev));
if (!clnors_data.is_empty()) {
/* Accumulate all clnors, if they are not all equal we have to fix that! */
short2 *clnor = &clnors_data[mlfan_vert_index];
if (clnors_count) {
clnors_invalid |= ((*clnor_ref)[0] != (*clnor)[0] || (*clnor_ref)[1] != (*clnor)[1]);
}
else {
clnor_ref = clnor;
}
clnors_avg[0] += (*clnor)[0];
clnors_avg[1] += (*clnor)[1];
clnors_count++;
if (!clnors_data.is_empty()) {
/* Accumulate all clnors, if they are not all equal we have to fix that! */
const short2 &clnor = clnors_data[mlfan_vert_index];
if (clnors_count) {
clnors_invalid |= *clnor_ref != clnor;
}
else {
clnor_ref = &clnor;
}
clnors_avg += int2(clnor);
clnors_count++;
}
processed_corners.append(mlfan_vert_index);
@ -1064,7 +1060,7 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data,
length = 1.0f;
}
CornerNormalSpace *lnor_space = &lnors_spacearr->spaces[space_index];
CornerNormalSpace &lnor_space = lnors_spacearr->spaces[space_index];
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);
@ -1072,20 +1068,17 @@ static void split_loop_nor_fan_do(LoopSplitTaskDataCommon *common_data,
if (!clnors_data.is_empty()) {
if (clnors_invalid) {
clnors_avg[0] /= clnors_count;
clnors_avg[1] /= clnors_count;
clnors_avg /= clnors_count;
/* Fix/update all clnors of this fan with computed average value. */
if (G.debug & G_DEBUG) {
printf("Invalid clnors in this fan!\n");
}
clnors_data.fill_indices(processed_corners.as_span(),
short2(clnors_avg[0], clnors_avg[1]));
// print_v2("new clnors", clnors_avg);
clnors_data.fill_indices(processed_corners.as_span(), short2(clnors_avg));
}
/* Extra bonus: since small-stack is local to this function,
* no more need to empty it at all cost! */
lnor_space_custom_data_to_normal(lnor_space, *clnor_ref, lnor);
lnor = lnor_space_custom_data_to_normal(lnor_space, *clnor_ref);
}
}
@ -1598,27 +1591,21 @@ static void mesh_normals_loop_custom_set(Span<float3> positions,
* give rather huge differences in computed 2D factors). */
if (fan_corners.size() < 2) {
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];
lnor_space_custom_normal_to_data(&lnors_spacearr.spaces[space_index], nor, r_clnors_data[i]);
r_clnors_data[i] = lnor_space_custom_normal_to_data(lnors_spacearr.spaces[space_index],
r_custom_loop_normals[nidx]);
done_loops[i].reset();
}
else {
float3 avg_nor(0.0f);
for (const int lidx : fan_corners) {
const int nidx = use_vertices ? corner_verts[lidx] : lidx;
float *nor = r_custom_loop_normals[nidx];
add_v3_v3(avg_nor, nor);
avg_nor += r_custom_loop_normals[nidx];
done_loops[lidx].reset();
}
mul_v3_fl(avg_nor, 1.0f / float(fan_corners.size()));
short2 clnor_data_tmp;
lnor_space_custom_normal_to_data(
&lnors_spacearr.spaces[space_index], avg_nor, clnor_data_tmp);
short2 clnor_data_tmp = lnor_space_custom_normal_to_data(lnors_spacearr.spaces[space_index],
avg_nor);
r_clnors_data.fill_indices(fan_corners, clnor_data_tmp);
}