Cleanup: split BKE_mesh_calc_normals_poly function in two
Remove the 'only_face_normals' argument. - BKE_mesh_calc_normals_poly for polygon normals. - BKE_mesh_calc_normals_poly_and_vertex for poly and vertex normals. Order arguments logically: - Pair array and length arguments. - Position normal array arguments (to be filled) last.
This commit is contained in:
@@ -305,15 +305,21 @@ void BKE_mesh_calc_normals_mapping_ex(struct MVert *mverts,
|
|||||||
const int *origIndexFace,
|
const int *origIndexFace,
|
||||||
float (*r_faceNors)[3],
|
float (*r_faceNors)[3],
|
||||||
const bool only_face_normals);
|
const bool only_face_normals);
|
||||||
void BKE_mesh_calc_normals_poly(struct MVert *mverts,
|
void BKE_mesh_calc_normals_poly(const struct MVert *mvert,
|
||||||
float (*r_vertnors)[3],
|
int mvert_len,
|
||||||
int numVerts,
|
|
||||||
const struct MLoop *mloop,
|
const struct MLoop *mloop,
|
||||||
|
int mloop_len,
|
||||||
|
const struct MPoly *mpoly,
|
||||||
|
int mpoly_len,
|
||||||
|
float (*r_poly_normals)[3]);
|
||||||
|
void BKE_mesh_calc_normals_poly_and_vertex(struct MVert *mvert,
|
||||||
|
int mvert_len,
|
||||||
|
const struct MLoop *mloop,
|
||||||
|
int mloop_len,
|
||||||
const struct MPoly *mpolys,
|
const struct MPoly *mpolys,
|
||||||
int numLoops,
|
int mpoly_len,
|
||||||
int numPolys,
|
float (*r_poly_normals)[3],
|
||||||
float (*r_polyNors)[3],
|
float (*r_vert_normals)[3]);
|
||||||
const bool only_face_normals);
|
|
||||||
void BKE_mesh_calc_normals(struct Mesh *me);
|
void BKE_mesh_calc_normals(struct Mesh *me);
|
||||||
void BKE_mesh_ensure_normals(struct Mesh *me);
|
void BKE_mesh_ensure_normals(struct Mesh *me);
|
||||||
void BKE_mesh_ensure_normals_for_display(struct Mesh *mesh);
|
void BKE_mesh_ensure_normals_for_display(struct Mesh *mesh);
|
||||||
|
|||||||
@@ -816,15 +816,14 @@ static void mesh_calc_modifier_final_normals(const Mesh *mesh_input,
|
|||||||
if (!CustomData_has_layer(&mesh_final->pdata, CD_NORMAL)) {
|
if (!CustomData_has_layer(&mesh_final->pdata, CD_NORMAL)) {
|
||||||
float(*polynors)[3] = (float(*)[3])CustomData_add_layer(
|
float(*polynors)[3] = (float(*)[3])CustomData_add_layer(
|
||||||
&mesh_final->pdata, CD_NORMAL, CD_CALLOC, nullptr, mesh_final->totpoly);
|
&mesh_final->pdata, CD_NORMAL, CD_CALLOC, nullptr, mesh_final->totpoly);
|
||||||
BKE_mesh_calc_normals_poly(mesh_final->mvert,
|
BKE_mesh_calc_normals_poly_and_vertex(mesh_final->mvert,
|
||||||
nullptr,
|
|
||||||
mesh_final->totvert,
|
mesh_final->totvert,
|
||||||
mesh_final->mloop,
|
mesh_final->mloop,
|
||||||
mesh_final->mpoly,
|
|
||||||
mesh_final->totloop,
|
mesh_final->totloop,
|
||||||
|
mesh_final->mpoly,
|
||||||
mesh_final->totpoly,
|
mesh_final->totpoly,
|
||||||
polynors,
|
polynors,
|
||||||
false);
|
nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1536,15 +1535,14 @@ static void editbmesh_calc_modifier_final_normals(Mesh *mesh_final,
|
|||||||
if (!CustomData_has_layer(&mesh_final->pdata, CD_NORMAL)) {
|
if (!CustomData_has_layer(&mesh_final->pdata, CD_NORMAL)) {
|
||||||
float(*polynors)[3] = (float(*)[3])CustomData_add_layer(
|
float(*polynors)[3] = (float(*)[3])CustomData_add_layer(
|
||||||
&mesh_final->pdata, CD_NORMAL, CD_CALLOC, nullptr, mesh_final->totpoly);
|
&mesh_final->pdata, CD_NORMAL, CD_CALLOC, nullptr, mesh_final->totpoly);
|
||||||
BKE_mesh_calc_normals_poly(mesh_final->mvert,
|
BKE_mesh_calc_normals_poly_and_vertex(mesh_final->mvert,
|
||||||
nullptr,
|
|
||||||
mesh_final->totvert,
|
mesh_final->totvert,
|
||||||
mesh_final->mloop,
|
mesh_final->mloop,
|
||||||
mesh_final->mpoly,
|
|
||||||
mesh_final->totloop,
|
mesh_final->totloop,
|
||||||
|
mesh_final->mpoly,
|
||||||
mesh_final->totpoly,
|
mesh_final->totpoly,
|
||||||
polynors,
|
polynors,
|
||||||
false);
|
nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -301,14 +301,12 @@ static void data_transfer_dtdata_type_preprocess(Mesh *me_src,
|
|||||||
}
|
}
|
||||||
if (dirty_nors_dst || do_poly_nors_dst) {
|
if (dirty_nors_dst || do_poly_nors_dst) {
|
||||||
BKE_mesh_calc_normals_poly(verts_dst,
|
BKE_mesh_calc_normals_poly(verts_dst,
|
||||||
NULL,
|
|
||||||
num_verts_dst,
|
num_verts_dst,
|
||||||
loops_dst,
|
loops_dst,
|
||||||
polys_dst,
|
|
||||||
num_loops_dst,
|
num_loops_dst,
|
||||||
|
polys_dst,
|
||||||
num_polys_dst,
|
num_polys_dst,
|
||||||
poly_nors_dst,
|
poly_nors_dst);
|
||||||
true);
|
|
||||||
}
|
}
|
||||||
/* Cache loop nors into a temp CDLayer. */
|
/* Cache loop nors into a temp CDLayer. */
|
||||||
loop_nors_dst = CustomData_get_layer(ldata_dst, CD_NORMAL);
|
loop_nors_dst = CustomData_get_layer(ldata_dst, CD_NORMAL);
|
||||||
|
|||||||
@@ -2281,15 +2281,8 @@ void BKE_keyblock_mesh_calc_normals(struct KeyBlock *kb,
|
|||||||
r_polynors = MEM_mallocN(sizeof(float[3]) * me.totpoly, __func__);
|
r_polynors = MEM_mallocN(sizeof(float[3]) * me.totpoly, __func__);
|
||||||
free_polynors = true;
|
free_polynors = true;
|
||||||
}
|
}
|
||||||
BKE_mesh_calc_normals_poly(me.mvert,
|
BKE_mesh_calc_normals_poly_and_vertex(
|
||||||
r_vertnors,
|
me.mvert, me.totvert, me.mloop, me.totloop, me.mpoly, me.totpoly, r_polynors, r_vertnors);
|
||||||
me.totvert,
|
|
||||||
me.mloop,
|
|
||||||
me.mpoly,
|
|
||||||
me.totloop,
|
|
||||||
me.totpoly,
|
|
||||||
r_polynors,
|
|
||||||
false);
|
|
||||||
|
|
||||||
if (r_loopnors) {
|
if (r_loopnors) {
|
||||||
short(*clnors)[2] = CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL); /* May be NULL. */
|
short(*clnors)[2] = CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL); /* May be NULL. */
|
||||||
|
|||||||
@@ -1890,15 +1890,14 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spac
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
polynors = MEM_malloc_arrayN(mesh->totpoly, sizeof(float[3]), __func__);
|
polynors = MEM_malloc_arrayN(mesh->totpoly, sizeof(float[3]), __func__);
|
||||||
BKE_mesh_calc_normals_poly(mesh->mvert,
|
BKE_mesh_calc_normals_poly_and_vertex(mesh->mvert,
|
||||||
NULL,
|
|
||||||
mesh->totvert,
|
mesh->totvert,
|
||||||
mesh->mloop,
|
mesh->mloop,
|
||||||
mesh->mpoly,
|
|
||||||
mesh->totloop,
|
mesh->totloop,
|
||||||
|
mesh->mpoly,
|
||||||
mesh->totpoly,
|
mesh->totpoly,
|
||||||
polynors,
|
polynors,
|
||||||
false);
|
NULL);
|
||||||
free_polynors = true;
|
free_polynors = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -393,15 +393,14 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd,
|
|||||||
|
|
||||||
/* calculate custom normals into loop_normals, then mirror first half into second half */
|
/* calculate custom normals into loop_normals, then mirror first half into second half */
|
||||||
|
|
||||||
BKE_mesh_calc_normals_poly(result->mvert,
|
BKE_mesh_calc_normals_poly_and_vertex(result->mvert,
|
||||||
NULL,
|
|
||||||
result->totvert,
|
result->totvert,
|
||||||
result->mloop,
|
result->mloop,
|
||||||
result->mpoly,
|
|
||||||
totloop,
|
totloop,
|
||||||
|
result->mpoly,
|
||||||
totpoly,
|
totpoly,
|
||||||
poly_normals,
|
poly_normals,
|
||||||
false);
|
NULL);
|
||||||
|
|
||||||
BKE_mesh_normals_loop_split(result->mvert,
|
BKE_mesh_normals_loop_split(result->mvert,
|
||||||
result->totvert,
|
result->totvert,
|
||||||
|
|||||||
@@ -102,7 +102,9 @@ static void add_v3_v3_atomic(float r[3], const float a[3])
|
|||||||
/** \} */
|
/** \} */
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
/** \name Mesh Normal Calculation
|
/** \name Public Utility Functions
|
||||||
|
*
|
||||||
|
* Related to managing normals but not directly related to calculating normals.
|
||||||
* \{ */
|
* \{ */
|
||||||
|
|
||||||
void BKE_mesh_normals_tag_dirty(Mesh *mesh)
|
void BKE_mesh_normals_tag_dirty(Mesh *mesh)
|
||||||
@@ -111,6 +113,205 @@ void BKE_mesh_normals_tag_dirty(Mesh *mesh)
|
|||||||
mesh->runtime.cd_dirty_poly |= CD_MASK_NORMAL;
|
mesh->runtime.cd_dirty_poly |= CD_MASK_NORMAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** \} */
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
/** \name Mesh Normal Calculation (Polygons)
|
||||||
|
* \{ */
|
||||||
|
|
||||||
|
struct MeshCalcNormalsData_Poly {
|
||||||
|
const MVert *mvert;
|
||||||
|
const MLoop *mloop;
|
||||||
|
const MPoly *mpoly;
|
||||||
|
|
||||||
|
/** Polygon normal output. */
|
||||||
|
float (*pnors)[3];
|
||||||
|
};
|
||||||
|
|
||||||
|
static void mesh_calc_normals_poly_fn(void *__restrict userdata,
|
||||||
|
const int pidx,
|
||||||
|
const TaskParallelTLS *__restrict UNUSED(tls))
|
||||||
|
{
|
||||||
|
const MeshCalcNormalsData_Poly *data = (MeshCalcNormalsData_Poly *)userdata;
|
||||||
|
const MPoly *mp = &data->mpoly[pidx];
|
||||||
|
BKE_mesh_calc_poly_normal(mp, data->mloop + mp->loopstart, data->mvert, data->pnors[pidx]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BKE_mesh_calc_normals_poly(const MVert *mvert,
|
||||||
|
int UNUSED(mvert_len),
|
||||||
|
const MLoop *mloop,
|
||||||
|
int UNUSED(mloop_len),
|
||||||
|
const MPoly *mpoly,
|
||||||
|
int mpoly_len,
|
||||||
|
float (*r_poly_normals)[3])
|
||||||
|
{
|
||||||
|
TaskParallelSettings settings;
|
||||||
|
BLI_parallel_range_settings_defaults(&settings);
|
||||||
|
settings.min_iter_per_thread = 1024;
|
||||||
|
|
||||||
|
BLI_assert((r_poly_normals != nullptr) || (mpoly_len == 0));
|
||||||
|
|
||||||
|
MeshCalcNormalsData_Poly data = {};
|
||||||
|
data.mpoly = mpoly;
|
||||||
|
data.mloop = mloop;
|
||||||
|
data.mvert = mvert;
|
||||||
|
data.pnors = r_poly_normals;
|
||||||
|
|
||||||
|
BLI_task_parallel_range(0, mpoly_len, &data, mesh_calc_normals_poly_fn, &settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \} */
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
/** \name Mesh Normal Calculation (Polygons & Vertices)
|
||||||
|
*
|
||||||
|
* Implement #BKE_mesh_calc_normals_poly_and_vertex,
|
||||||
|
*
|
||||||
|
* Take care making optimizations to this function as improvements to low-poly
|
||||||
|
* meshes can slow down high-poly meshes. For details on performance, see D11993.
|
||||||
|
* \{ */
|
||||||
|
|
||||||
|
struct MeshCalcNormalsData_PolyAndVertex {
|
||||||
|
/** Write into vertex normals #MVert.no. */
|
||||||
|
MVert *mvert;
|
||||||
|
const MLoop *mloop;
|
||||||
|
const MPoly *mpoly;
|
||||||
|
|
||||||
|
/** Polygon normal output. */
|
||||||
|
float (*pnors)[3];
|
||||||
|
/** Vertex normal output (may be freed, copied into #MVert.no). */
|
||||||
|
float (*vnors)[3];
|
||||||
|
};
|
||||||
|
|
||||||
|
static void mesh_calc_normals_poly_and_vertex_accum_fn(
|
||||||
|
void *__restrict userdata, const int pidx, const TaskParallelTLS *__restrict UNUSED(tls))
|
||||||
|
{
|
||||||
|
const MeshCalcNormalsData_PolyAndVertex *data = (MeshCalcNormalsData_PolyAndVertex *)userdata;
|
||||||
|
const MPoly *mp = &data->mpoly[pidx];
|
||||||
|
const MLoop *ml = &data->mloop[mp->loopstart];
|
||||||
|
const MVert *mverts = data->mvert;
|
||||||
|
float(*vnors)[3] = data->vnors;
|
||||||
|
|
||||||
|
float pnor_temp[3];
|
||||||
|
float *pnor = data->pnors ? data->pnors[pidx] : pnor_temp;
|
||||||
|
|
||||||
|
const int i_end = mp->totloop - 1;
|
||||||
|
|
||||||
|
/* Polygon Normal and edge-vector */
|
||||||
|
/* inline version of #BKE_mesh_calc_poly_normal, also does edge-vectors */
|
||||||
|
{
|
||||||
|
zero_v3(pnor);
|
||||||
|
/* Newell's Method */
|
||||||
|
const float *v_curr = mverts[ml[i_end].v].co;
|
||||||
|
for (int i_next = 0; i_next <= i_end; i_next++) {
|
||||||
|
const float *v_next = mverts[ml[i_next].v].co;
|
||||||
|
add_newell_cross_v3_v3v3(pnor, v_curr, v_next);
|
||||||
|
v_curr = v_next;
|
||||||
|
}
|
||||||
|
if (UNLIKELY(normalize_v3(pnor) == 0.0f)) {
|
||||||
|
pnor[2] = 1.0f; /* other axes set to 0.0 */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Accumulate angle weighted face normal into the vertex normal. */
|
||||||
|
/* inline version of #accumulate_vertex_normals_poly_v3. */
|
||||||
|
{
|
||||||
|
float edvec_prev[3], edvec_next[3], edvec_end[3];
|
||||||
|
const float *v_curr = mverts[ml[i_end].v].co;
|
||||||
|
sub_v3_v3v3(edvec_prev, mverts[ml[i_end - 1].v].co, v_curr);
|
||||||
|
normalize_v3(edvec_prev);
|
||||||
|
copy_v3_v3(edvec_end, edvec_prev);
|
||||||
|
|
||||||
|
for (int i_next = 0, i_curr = i_end; i_next <= i_end; i_curr = i_next++) {
|
||||||
|
const float *v_next = mverts[ml[i_next].v].co;
|
||||||
|
|
||||||
|
/* Skip an extra normalization by reusing the first calculated edge. */
|
||||||
|
if (i_next != i_end) {
|
||||||
|
sub_v3_v3v3(edvec_next, v_curr, v_next);
|
||||||
|
normalize_v3(edvec_next);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
copy_v3_v3(edvec_next, edvec_end);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Calculate angle between the two poly edges incident on this vertex. */
|
||||||
|
const float fac = saacos(-dot_v3v3(edvec_prev, edvec_next));
|
||||||
|
const float vnor_add[3] = {pnor[0] * fac, pnor[1] * fac, pnor[2] * fac};
|
||||||
|
|
||||||
|
add_v3_v3_atomic(vnors[ml[i_curr].v], vnor_add);
|
||||||
|
v_curr = v_next;
|
||||||
|
copy_v3_v3(edvec_prev, edvec_next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mesh_calc_normals_poly_and_vertex_finalize_fn(
|
||||||
|
void *__restrict userdata, const int vidx, const TaskParallelTLS *__restrict UNUSED(tls))
|
||||||
|
{
|
||||||
|
MeshCalcNormalsData_PolyAndVertex *data = (MeshCalcNormalsData_PolyAndVertex *)userdata;
|
||||||
|
|
||||||
|
MVert *mv = &data->mvert[vidx];
|
||||||
|
float *no = data->vnors[vidx];
|
||||||
|
|
||||||
|
if (UNLIKELY(normalize_v3(no) == 0.0f)) {
|
||||||
|
/* following Mesh convention; we use vertex coordinate itself for normal in this case */
|
||||||
|
normalize_v3_v3(no, mv->co);
|
||||||
|
}
|
||||||
|
|
||||||
|
normal_float_to_short_v3(mv->no, no);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BKE_mesh_calc_normals_poly_and_vertex(MVert *mvert,
|
||||||
|
const int mvert_len,
|
||||||
|
const MLoop *mloop,
|
||||||
|
const int UNUSED(mloop_len),
|
||||||
|
const MPoly *mpoly,
|
||||||
|
const int mpoly_len,
|
||||||
|
float (*r_poly_normals)[3],
|
||||||
|
float (*r_vert_normals)[3])
|
||||||
|
{
|
||||||
|
TaskParallelSettings settings;
|
||||||
|
BLI_parallel_range_settings_defaults(&settings);
|
||||||
|
settings.min_iter_per_thread = 1024;
|
||||||
|
|
||||||
|
float(*vnors)[3] = r_vert_normals;
|
||||||
|
bool free_vnors = false;
|
||||||
|
|
||||||
|
/* first go through and calculate normals for all the polys */
|
||||||
|
if (vnors == nullptr) {
|
||||||
|
vnors = (float(*)[3])MEM_calloc_arrayN((size_t)mvert_len, sizeof(*vnors), __func__);
|
||||||
|
free_vnors = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
memset(vnors, 0, sizeof(*vnors) * (size_t)mvert_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
MeshCalcNormalsData_PolyAndVertex data = {};
|
||||||
|
data.mpoly = mpoly;
|
||||||
|
data.mloop = mloop;
|
||||||
|
data.mvert = mvert;
|
||||||
|
data.pnors = r_poly_normals;
|
||||||
|
data.vnors = vnors;
|
||||||
|
|
||||||
|
/* Compute poly normals (`pnors`), accumulating them into vertex normals (`vnors`). */
|
||||||
|
BLI_task_parallel_range(
|
||||||
|
0, mpoly_len, &data, mesh_calc_normals_poly_and_vertex_accum_fn, &settings);
|
||||||
|
|
||||||
|
/* Normalize and validate computed vertex normals (`vnors`). */
|
||||||
|
BLI_task_parallel_range(
|
||||||
|
0, mvert_len, &data, mesh_calc_normals_poly_and_vertex_finalize_fn, &settings);
|
||||||
|
|
||||||
|
if (free_vnors) {
|
||||||
|
MEM_freeN(vnors);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \} */
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
/** \name Mesh Normal Calculation
|
||||||
|
* \{ */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Call when there are no polygons.
|
* Call when there are no polygons.
|
||||||
*/
|
*/
|
||||||
@@ -212,8 +413,8 @@ void BKE_mesh_calc_normals_mapping_ex(MVert *mverts,
|
|||||||
if (only_face_normals == false) {
|
if (only_face_normals == false) {
|
||||||
/* vertex normals are optional, they require some extra calculations,
|
/* vertex normals are optional, they require some extra calculations,
|
||||||
* so make them optional */
|
* so make them optional */
|
||||||
BKE_mesh_calc_normals_poly(
|
BKE_mesh_calc_normals_poly_and_vertex(
|
||||||
mverts, nullptr, numVerts, mloop, mpolys, numLoops, numPolys, pnors, false);
|
mverts, numVerts, mloop, numLoops, mpolys, numPolys, pnors, nullptr);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* only calc poly normals */
|
/* only calc poly normals */
|
||||||
@@ -247,164 +448,6 @@ void BKE_mesh_calc_normals_mapping_ex(MVert *mverts,
|
|||||||
fnors = pnors = nullptr;
|
fnors = pnors = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MeshCalcNormalsData {
|
|
||||||
const MPoly *mpolys;
|
|
||||||
const MLoop *mloop;
|
|
||||||
MVert *mverts;
|
|
||||||
float (*pnors)[3];
|
|
||||||
float (*vnors)[3];
|
|
||||||
};
|
|
||||||
|
|
||||||
static void mesh_calc_normals_poly_cb(void *__restrict userdata,
|
|
||||||
const int pidx,
|
|
||||||
const TaskParallelTLS *__restrict UNUSED(tls))
|
|
||||||
{
|
|
||||||
MeshCalcNormalsData *data = (MeshCalcNormalsData *)userdata;
|
|
||||||
const MPoly *mp = &data->mpolys[pidx];
|
|
||||||
|
|
||||||
BKE_mesh_calc_poly_normal(mp, data->mloop + mp->loopstart, data->mverts, data->pnors[pidx]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void mesh_calc_normals_poly_and_accum_cb(void *__restrict userdata,
|
|
||||||
const int pidx,
|
|
||||||
const TaskParallelTLS *__restrict UNUSED(tls))
|
|
||||||
{
|
|
||||||
const MeshCalcNormalsData *data = (MeshCalcNormalsData *)userdata;
|
|
||||||
const MPoly *mp = &data->mpolys[pidx];
|
|
||||||
const MLoop *ml = &data->mloop[mp->loopstart];
|
|
||||||
const MVert *mverts = data->mverts;
|
|
||||||
float(*vnors)[3] = data->vnors;
|
|
||||||
|
|
||||||
float pnor_temp[3];
|
|
||||||
float *pnor = data->pnors ? data->pnors[pidx] : pnor_temp;
|
|
||||||
|
|
||||||
const int i_end = mp->totloop - 1;
|
|
||||||
|
|
||||||
/* Polygon Normal and edge-vector */
|
|
||||||
/* inline version of #BKE_mesh_calc_poly_normal, also does edge-vectors */
|
|
||||||
{
|
|
||||||
zero_v3(pnor);
|
|
||||||
/* Newell's Method */
|
|
||||||
const float *v_curr = mverts[ml[i_end].v].co;
|
|
||||||
for (int i_next = 0; i_next <= i_end; i_next++) {
|
|
||||||
const float *v_next = mverts[ml[i_next].v].co;
|
|
||||||
add_newell_cross_v3_v3v3(pnor, v_curr, v_next);
|
|
||||||
v_curr = v_next;
|
|
||||||
}
|
|
||||||
if (UNLIKELY(normalize_v3(pnor) == 0.0f)) {
|
|
||||||
pnor[2] = 1.0f; /* other axes set to 0.0 */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Accumulate angle weighted face normal into the vertex normal. */
|
|
||||||
/* inline version of #accumulate_vertex_normals_poly_v3. */
|
|
||||||
{
|
|
||||||
float edvec_prev[3], edvec_next[3], edvec_end[3];
|
|
||||||
const float *v_curr = mverts[ml[i_end].v].co;
|
|
||||||
sub_v3_v3v3(edvec_prev, mverts[ml[i_end - 1].v].co, v_curr);
|
|
||||||
normalize_v3(edvec_prev);
|
|
||||||
copy_v3_v3(edvec_end, edvec_prev);
|
|
||||||
|
|
||||||
for (int i_next = 0, i_curr = i_end; i_next <= i_end; i_curr = i_next++) {
|
|
||||||
const float *v_next = mverts[ml[i_next].v].co;
|
|
||||||
|
|
||||||
/* Skip an extra normalization by reusing the first calculated edge. */
|
|
||||||
if (i_next != i_end) {
|
|
||||||
sub_v3_v3v3(edvec_next, v_curr, v_next);
|
|
||||||
normalize_v3(edvec_next);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
copy_v3_v3(edvec_next, edvec_end);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Calculate angle between the two poly edges incident on this vertex. */
|
|
||||||
const float fac = saacos(-dot_v3v3(edvec_prev, edvec_next));
|
|
||||||
const float vnor_add[3] = {pnor[0] * fac, pnor[1] * fac, pnor[2] * fac};
|
|
||||||
|
|
||||||
add_v3_v3_atomic(vnors[ml[i_curr].v], vnor_add);
|
|
||||||
v_curr = v_next;
|
|
||||||
copy_v3_v3(edvec_prev, edvec_next);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void mesh_calc_normals_poly_finalize_cb(void *__restrict userdata,
|
|
||||||
const int vidx,
|
|
||||||
const TaskParallelTLS *__restrict UNUSED(tls))
|
|
||||||
{
|
|
||||||
MeshCalcNormalsData *data = (MeshCalcNormalsData *)userdata;
|
|
||||||
|
|
||||||
MVert *mv = &data->mverts[vidx];
|
|
||||||
float *no = data->vnors[vidx];
|
|
||||||
|
|
||||||
if (UNLIKELY(normalize_v3(no) == 0.0f)) {
|
|
||||||
/* following Mesh convention; we use vertex coordinate itself for normal in this case */
|
|
||||||
normalize_v3_v3(no, mv->co);
|
|
||||||
}
|
|
||||||
|
|
||||||
normal_float_to_short_v3(mv->no, no);
|
|
||||||
}
|
|
||||||
|
|
||||||
void BKE_mesh_calc_normals_poly(MVert *mverts,
|
|
||||||
float (*r_vertnors)[3],
|
|
||||||
int numVerts,
|
|
||||||
const MLoop *mloop,
|
|
||||||
const MPoly *mpolys,
|
|
||||||
int UNUSED(numLoops),
|
|
||||||
int numPolys,
|
|
||||||
float (*r_polynors)[3],
|
|
||||||
const bool only_face_normals)
|
|
||||||
{
|
|
||||||
float(*pnors)[3] = r_polynors;
|
|
||||||
|
|
||||||
TaskParallelSettings settings;
|
|
||||||
BLI_parallel_range_settings_defaults(&settings);
|
|
||||||
settings.min_iter_per_thread = 1024;
|
|
||||||
|
|
||||||
if (only_face_normals) {
|
|
||||||
BLI_assert((pnors != nullptr) || (numPolys == 0));
|
|
||||||
BLI_assert(r_vertnors == nullptr);
|
|
||||||
|
|
||||||
MeshCalcNormalsData data;
|
|
||||||
data.mpolys = mpolys;
|
|
||||||
data.mloop = mloop;
|
|
||||||
data.mverts = mverts;
|
|
||||||
data.pnors = pnors;
|
|
||||||
|
|
||||||
BLI_task_parallel_range(0, numPolys, &data, mesh_calc_normals_poly_cb, &settings);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
float(*vnors)[3] = r_vertnors;
|
|
||||||
bool free_vnors = false;
|
|
||||||
|
|
||||||
/* first go through and calculate normals for all the polys */
|
|
||||||
if (vnors == nullptr) {
|
|
||||||
vnors = (float(*)[3])MEM_calloc_arrayN((size_t)numVerts, sizeof(*vnors), __func__);
|
|
||||||
free_vnors = true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
memset(vnors, 0, sizeof(*vnors) * (size_t)numVerts);
|
|
||||||
}
|
|
||||||
|
|
||||||
MeshCalcNormalsData data;
|
|
||||||
data.mpolys = mpolys;
|
|
||||||
data.mloop = mloop;
|
|
||||||
data.mverts = mverts;
|
|
||||||
data.pnors = pnors;
|
|
||||||
data.vnors = vnors;
|
|
||||||
|
|
||||||
/* Compute poly normals (`pnors`), accumulating them into vertex normals (`vnors`). */
|
|
||||||
BLI_task_parallel_range(0, numPolys, &data, mesh_calc_normals_poly_and_accum_cb, &settings);
|
|
||||||
|
|
||||||
/* Normalize and validate computed vertex normals (`vnors`). */
|
|
||||||
BLI_task_parallel_range(0, numVerts, &data, mesh_calc_normals_poly_finalize_cb, &settings);
|
|
||||||
|
|
||||||
if (free_vnors) {
|
|
||||||
MEM_freeN(vnors);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void BKE_mesh_ensure_normals(Mesh *mesh)
|
void BKE_mesh_ensure_normals(Mesh *mesh)
|
||||||
{
|
{
|
||||||
if (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) {
|
if (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) {
|
||||||
@@ -446,15 +489,25 @@ void BKE_mesh_ensure_normals_for_display(Mesh *mesh)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* calculate poly/vert normals */
|
/* calculate poly/vert normals */
|
||||||
BKE_mesh_calc_normals_poly(mesh->mvert,
|
if (do_vert_normals) {
|
||||||
nullptr,
|
BKE_mesh_calc_normals_poly_and_vertex(mesh->mvert,
|
||||||
mesh->totvert,
|
mesh->totvert,
|
||||||
mesh->mloop,
|
mesh->mloop,
|
||||||
mesh->mpoly,
|
|
||||||
mesh->totloop,
|
mesh->totloop,
|
||||||
|
mesh->mpoly,
|
||||||
mesh->totpoly,
|
mesh->totpoly,
|
||||||
poly_nors,
|
poly_nors,
|
||||||
!do_vert_normals);
|
nullptr);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
BKE_mesh_calc_normals_poly(mesh->mvert,
|
||||||
|
mesh->totvert,
|
||||||
|
mesh->mloop,
|
||||||
|
mesh->totloop,
|
||||||
|
mesh->mpoly,
|
||||||
|
mesh->totpoly,
|
||||||
|
poly_nors);
|
||||||
|
}
|
||||||
|
|
||||||
if (do_add_poly_nors_cddata) {
|
if (do_add_poly_nors_cddata) {
|
||||||
CustomData_add_layer(&mesh->pdata, CD_NORMAL, CD_ASSIGN, poly_nors, mesh->totpoly);
|
CustomData_add_layer(&mesh->pdata, CD_NORMAL, CD_ASSIGN, poly_nors, mesh->totpoly);
|
||||||
@@ -472,15 +525,14 @@ void BKE_mesh_calc_normals(Mesh *mesh)
|
|||||||
#ifdef DEBUG_TIME
|
#ifdef DEBUG_TIME
|
||||||
TIMEIT_START_AVERAGED(BKE_mesh_calc_normals);
|
TIMEIT_START_AVERAGED(BKE_mesh_calc_normals);
|
||||||
#endif
|
#endif
|
||||||
BKE_mesh_calc_normals_poly(mesh->mvert,
|
BKE_mesh_calc_normals_poly_and_vertex(mesh->mvert,
|
||||||
nullptr,
|
|
||||||
mesh->totvert,
|
mesh->totvert,
|
||||||
mesh->mloop,
|
mesh->mloop,
|
||||||
mesh->mpoly,
|
|
||||||
mesh->totloop,
|
mesh->totloop,
|
||||||
|
mesh->mpoly,
|
||||||
mesh->totpoly,
|
mesh->totpoly,
|
||||||
nullptr,
|
nullptr,
|
||||||
false);
|
nullptr);
|
||||||
#ifdef DEBUG_TIME
|
#ifdef DEBUG_TIME
|
||||||
TIMEIT_END_AVERAGED(BKE_mesh_calc_normals);
|
TIMEIT_END_AVERAGED(BKE_mesh_calc_normals);
|
||||||
#endif
|
#endif
|
||||||
@@ -2121,15 +2173,14 @@ static void mesh_set_custom_normals(Mesh *mesh, float (*r_custom_nors)[3], const
|
|||||||
bool free_polynors = false;
|
bool free_polynors = false;
|
||||||
if (polynors == nullptr) {
|
if (polynors == nullptr) {
|
||||||
polynors = (float(*)[3])MEM_mallocN(sizeof(float[3]) * (size_t)mesh->totpoly, __func__);
|
polynors = (float(*)[3])MEM_mallocN(sizeof(float[3]) * (size_t)mesh->totpoly, __func__);
|
||||||
BKE_mesh_calc_normals_poly(mesh->mvert,
|
BKE_mesh_calc_normals_poly_and_vertex(mesh->mvert,
|
||||||
nullptr,
|
|
||||||
mesh->totvert,
|
mesh->totvert,
|
||||||
mesh->mloop,
|
mesh->mloop,
|
||||||
mesh->mpoly,
|
|
||||||
mesh->totloop,
|
mesh->totloop,
|
||||||
|
mesh->mpoly,
|
||||||
mesh->totpoly,
|
mesh->totpoly,
|
||||||
polynors,
|
polynors,
|
||||||
false);
|
nullptr);
|
||||||
free_polynors = true;
|
free_polynors = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1379,14 +1379,12 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
|
|||||||
}
|
}
|
||||||
if (dirty_nors_dst || do_poly_nors_dst) {
|
if (dirty_nors_dst || do_poly_nors_dst) {
|
||||||
BKE_mesh_calc_normals_poly(verts_dst,
|
BKE_mesh_calc_normals_poly(verts_dst,
|
||||||
NULL,
|
|
||||||
numverts_dst,
|
numverts_dst,
|
||||||
loops_dst,
|
loops_dst,
|
||||||
polys_dst,
|
|
||||||
numloops_dst,
|
numloops_dst,
|
||||||
|
polys_dst,
|
||||||
numpolys_dst,
|
numpolys_dst,
|
||||||
poly_nors_dst,
|
poly_nors_dst);
|
||||||
true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (need_lnors_dst) {
|
if (need_lnors_dst) {
|
||||||
@@ -2231,14 +2229,12 @@ void BKE_mesh_remap_calc_polys_from_mesh(const int mode,
|
|||||||
}
|
}
|
||||||
if (dirty_nors_dst) {
|
if (dirty_nors_dst) {
|
||||||
BKE_mesh_calc_normals_poly(verts_dst,
|
BKE_mesh_calc_normals_poly(verts_dst,
|
||||||
NULL,
|
|
||||||
numverts_dst,
|
numverts_dst,
|
||||||
loops_dst,
|
loops_dst,
|
||||||
polys_dst,
|
|
||||||
numloops_dst,
|
numloops_dst,
|
||||||
|
polys_dst,
|
||||||
numpolys_dst,
|
numpolys_dst,
|
||||||
poly_nors_dst,
|
poly_nors_dst);
|
||||||
true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1007,15 +1007,8 @@ static int mesh_customdata_custom_splitnormals_add_exec(bContext *C, wmOperator
|
|||||||
if (me->flag & ME_AUTOSMOOTH) {
|
if (me->flag & ME_AUTOSMOOTH) {
|
||||||
float(*polynors)[3] = MEM_mallocN(sizeof(*polynors) * (size_t)me->totpoly, __func__);
|
float(*polynors)[3] = MEM_mallocN(sizeof(*polynors) * (size_t)me->totpoly, __func__);
|
||||||
|
|
||||||
BKE_mesh_calc_normals_poly(me->mvert,
|
BKE_mesh_calc_normals_poly(
|
||||||
NULL,
|
me->mvert, me->totvert, me->mloop, me->totloop, me->mpoly, me->totpoly, polynors);
|
||||||
me->totvert,
|
|
||||||
me->mloop,
|
|
||||||
me->mpoly,
|
|
||||||
me->totloop,
|
|
||||||
me->totpoly,
|
|
||||||
polynors,
|
|
||||||
true);
|
|
||||||
|
|
||||||
BKE_edges_sharp_from_angle_set(me->mvert,
|
BKE_edges_sharp_from_angle_set(me->mvert,
|
||||||
me->totvert,
|
me->totvert,
|
||||||
|
|||||||
@@ -556,15 +556,13 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd,
|
|||||||
polynors = CustomData_add_layer(pdata, CD_NORMAL, CD_CALLOC, NULL, num_polys);
|
polynors = CustomData_add_layer(pdata, CD_NORMAL, CD_CALLOC, NULL, num_polys);
|
||||||
CustomData_set_layer_flag(pdata, CD_NORMAL, CD_FLAG_TEMPORARY);
|
CustomData_set_layer_flag(pdata, CD_NORMAL, CD_FLAG_TEMPORARY);
|
||||||
}
|
}
|
||||||
BKE_mesh_calc_normals_poly(mvert,
|
if (result->runtime.cd_dirty_vert & CD_MASK_NORMAL) {
|
||||||
NULL,
|
BKE_mesh_calc_normals_poly_and_vertex(
|
||||||
num_verts,
|
mvert, num_verts, mloop, num_loops, mpoly, num_polys, polynors, NULL);
|
||||||
mloop,
|
}
|
||||||
mpoly,
|
else {
|
||||||
num_loops,
|
BKE_mesh_calc_normals_poly(mvert, num_verts, mloop, num_loops, mpoly, num_polys, polynors);
|
||||||
num_polys,
|
}
|
||||||
polynors,
|
|
||||||
(result->runtime.cd_dirty_vert & CD_MASK_NORMAL) ? false : true);
|
|
||||||
|
|
||||||
result->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL;
|
result->runtime.cd_dirty_vert &= ~CD_MASK_NORMAL;
|
||||||
|
|
||||||
|
|||||||
@@ -259,14 +259,12 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex
|
|||||||
/* calculate only face normals */
|
/* calculate only face normals */
|
||||||
poly_nors = MEM_malloc_arrayN(numPolys, sizeof(*poly_nors), __func__);
|
poly_nors = MEM_malloc_arrayN(numPolys, sizeof(*poly_nors), __func__);
|
||||||
BKE_mesh_calc_normals_poly(orig_mvert,
|
BKE_mesh_calc_normals_poly(orig_mvert,
|
||||||
NULL,
|
|
||||||
(int)numVerts,
|
(int)numVerts,
|
||||||
orig_mloop,
|
orig_mloop,
|
||||||
orig_mpoly,
|
|
||||||
(int)numLoops,
|
(int)numLoops,
|
||||||
|
orig_mpoly,
|
||||||
(int)numPolys,
|
(int)numPolys,
|
||||||
poly_nors,
|
poly_nors);
|
||||||
true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
STACK_INIT(new_vert_arr, numVerts * 2);
|
STACK_INIT(new_vert_arr, numVerts * 2);
|
||||||
|
|||||||
@@ -211,15 +211,8 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
|
|||||||
|
|
||||||
/* Calculate only face normals. */
|
/* Calculate only face normals. */
|
||||||
poly_nors = MEM_malloc_arrayN(numPolys, sizeof(*poly_nors), __func__);
|
poly_nors = MEM_malloc_arrayN(numPolys, sizeof(*poly_nors), __func__);
|
||||||
BKE_mesh_calc_normals_poly(orig_mvert,
|
BKE_mesh_calc_normals_poly(
|
||||||
NULL,
|
orig_mvert, (int)numVerts, orig_mloop, (int)numLoops, orig_mpoly, (int)numPolys, poly_nors);
|
||||||
(int)numVerts,
|
|
||||||
orig_mloop,
|
|
||||||
orig_mpoly,
|
|
||||||
(int)numLoops,
|
|
||||||
(int)numPolys,
|
|
||||||
poly_nors,
|
|
||||||
true);
|
|
||||||
|
|
||||||
NewFaceRef *face_sides_arr = MEM_malloc_arrayN(
|
NewFaceRef *face_sides_arr = MEM_malloc_arrayN(
|
||||||
numPolys * 2, sizeof(*face_sides_arr), "face_sides_arr in solidify");
|
numPolys * 2, sizeof(*face_sides_arr), "face_sides_arr in solidify");
|
||||||
|
|||||||
@@ -615,8 +615,8 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
|
|||||||
polynors = CustomData_add_layer(pdata, CD_NORMAL, CD_CALLOC, NULL, numPolys);
|
polynors = CustomData_add_layer(pdata, CD_NORMAL, CD_CALLOC, NULL, numPolys);
|
||||||
CustomData_set_layer_flag(pdata, CD_NORMAL, CD_FLAG_TEMPORARY);
|
CustomData_set_layer_flag(pdata, CD_NORMAL, CD_FLAG_TEMPORARY);
|
||||||
}
|
}
|
||||||
BKE_mesh_calc_normals_poly(
|
BKE_mesh_calc_normals_poly_and_vertex(
|
||||||
mvert, NULL, numVerts, mloop, mpoly, numLoops, numPolys, polynors, false);
|
mvert, numVerts, mloop, numLoops, mpoly, numPolys, polynors, NULL);
|
||||||
|
|
||||||
const float split_angle = mesh->smoothresh;
|
const float split_angle = mesh->smoothresh;
|
||||||
short(*clnors)[2];
|
short(*clnors)[2];
|
||||||
|
|||||||
Reference in New Issue
Block a user