52 mesh.runtime->vert_normals_cache.ensure([&](
Vector<float3> &r_data) { r_data = vert_normals; });
57 mesh.runtime->vert_normals_cache.ensure(
58 [&](
Vector<float3> &r_data) { r_data = std::move(vert_normals); });
65 return mesh->runtime->vert_normals_cache.is_dirty();
70 return mesh->runtime->face_normals_cache.is_dirty();
93 const float *v_prev = vert_positions[face_verts.
last()];
95 const float *v_curr = vert_positions[face_verts[i]];
111 if (face_verts.
size() == 4) {
113 vert_positions[face_verts[0]],
114 vert_positions[face_verts[1]],
115 vert_positions[face_verts[2]],
116 vert_positions[face_verts[3]]);
118 else if (face_verts.
size() == 3) {
120 vert_positions[face_verts[1]],
121 vert_positions[face_verts[2]]);
152 for (const int i : range) {
153 face_normals[i] = normal_calc_ngon(positions, corner_verts.slice(faces[i]));
166 threading::parallel_for(positions.index_range(), 1024, [&](
const IndexRange range) {
167 for (const int vert : range) {
168 const Span<int> vert_faces = vert_to_face_map[vert];
169 if (vert_faces.is_empty()) {
170 vert_normals[vert] = math::normalize(positions[vert]);
174 float3 vert_normal(0);
175 for (const int face : vert_faces) {
176 const int2 adjacent_verts = face_find_adjacent_verts(faces[face], corner_verts, vert);
177 const float3 dir_prev = math::normalize(positions[adjacent_verts[0]] - positions[vert]);
178 const float3 dir_next = math::normalize(positions[adjacent_verts[1]] - positions[vert]);
179 const float factor = math::safe_acos_approx(math::dot(dir_prev, dir_next));
181 vert_normal += face_normals[face] * factor;
184 vert_normals[vert] = math::normalize(vert_normal);
202 return MeshNormalDomain::Point;
206 return MeshNormalDomain::Corner;
210 const VArray<bool> sharp_faces = *attributes.lookup_or_default<
bool>(
211 "sharp_face", AttrDomain::Face,
false);
214 if (face_mix == array_utils::BooleanMix::AllTrue) {
215 return MeshNormalDomain::Face;
218 const VArray<bool> sharp_edges = *attributes.lookup_or_default<
bool>(
219 "sharp_edge", AttrDomain::Edge,
false);
221 if (edge_mix == array_utils::BooleanMix::AllTrue) {
222 return MeshNormalDomain::Face;
225 if (edge_mix == array_utils::BooleanMix::AllFalse &&
226 (face_mix == array_utils::BooleanMix::AllFalse || support_sharp_face))
228 return MeshNormalDomain::Point;
231 return MeshNormalDomain::Corner;
238 if (this->
runtime->vert_normals_cache.is_cached()) {
239 return this->
runtime->vert_normals_cache.data();
242 const OffsetIndices faces = this->
faces();
243 const Span<int> corner_verts = this->corner_verts();
246 this->
runtime->vert_normals_cache.ensure([&](Vector<float3> &r_data) {
247 r_data.reinitialize(positions.size());
248 mesh::normals_calc_verts(positions, faces, corner_verts, vert_to_face, face_normals, r_data);
250 return this->
runtime->vert_normals_cache.data();
256 this->
runtime->face_normals_cache.ensure([&](Vector<float3> &r_data) {
258 const OffsetIndices faces = this->
faces();
259 const Span<int> corner_verts = this->corner_verts();
260 r_data.reinitialize(faces.size());
261 bke::mesh::normals_calc_faces(positions, faces, corner_verts, r_data);
263 return this->
runtime->face_normals_cache.data();
270 this->
runtime->corner_normals_cache.ensure([&](Vector<float3> &r_data) {
272 const OffsetIndices<int> faces = this->
faces();
273 switch (this->normals_domain()) {
274 case MeshNormalDomain::Point: {
275 array_utils::gather(this->vert_normals(), this->corner_verts(), r_data.as_mutable_span());
278 case MeshNormalDomain::Face: {
280 threading::parallel_for(faces.index_range(), 1024, [&](
const IndexRange range) {
281 for (const int i : range) {
282 r_data.as_mutable_span().slice(faces[i]).fill(face_normals[i]);
287 case MeshNormalDomain::Corner: {
289 const VArraySpan sharp_edges = *attributes.lookup<
bool>(
"sharp_edge", AttrDomain::Edge);
290 const VArraySpan sharp_faces = *attributes.lookup<
bool>(
"sharp_face", AttrDomain::Face);
291 const short2 *custom_normals =
static_cast<const short2 *
>(
293 mesh::normals_calc_corners(this->vert_positions(),
296 this->corner_verts(),
297 this->corner_edges(),
298 this->corner_to_face_map(),
299 this->vert_normals(),
300 this->face_normals(),
310 return this->runtime->corner_normals_cache.data();
315 const char data_type)
320 if (!lnors_spacearr->
mem) {
323 mem = lnors_spacearr->
mem;
328 mem,
sizeof(
LinkNode) * size_t(numLoops));
344 *lnors_spacearr_tls = *lnors_spacearr;
356 lnors_spacearr_tls->
mem =
nullptr;
365 if (lnors_spacearr->
mem !=
nullptr) {
376 lnors_spacearr->
mem =
nullptr;
386#define LNOR_SPACE_TRIGO_THRESHOLD (1.0f - 1e-4f)
397 const float dtp_ref =
math::dot(vec_ref, lnor);
398 const float dtp_other =
math::dot(vec_other, lnor);
405 lnor_space.ref_alpha = lnor_space.ref_beta = 0.0f;
409 lnor_space.vec_lnor = lnor;
414 for (
const float3 &vec : edge_vectors) {
423 lnor_space.ref_alpha = alpha /
float(edge_vectors.
size());
439 const float dtp =
math::dot(lnor_space.vec_ref, vec_other_proj);
442 lnor_space.ref_beta = (
math::dot(lnor_space.vec_ortho, vec_other_proj) < 0.0f) ? pi2 -
beta :
446 lnor_space.ref_beta = pi2;
456 const float vec_ref[3],
457 const float vec_other[3],
461 const CornerNormalSpace space = corner_fan_space_define(lnor, vec_ref, vec_other, edge_vectors);
466 lnor_space->
ref_beta = space.ref_beta;
473 const bool is_single)
478 lnors_spacearr->
lspacearr[corner] = lnor_space;
479 if (bm_loop ==
nullptr) {
501 return short(
floorf(val *
float(SHRT_MAX) + 0.5f));
510 if (clnor_data[0] == 0 || lnor_space.
ref_alpha == 0.0f || lnor_space.
ref_beta == 0.0f) {
520 const float alpha = (alphafac > 0.0f ? lnor_space.
ref_alpha : pi2 - lnor_space.
ref_alpha) *
526 if (betafac == 0.0f) {
530 const float sinalpha =
sinf(alpha);
537 return r_custom_lnor;
543 const short clnor_data[2],
544 float r_custom_lnor[3])
549 space.vec_ref = lnor_space->
vec_ref;
552 space.ref_beta = lnor_space->
ref_beta;
553 copy_v3_v3(r_custom_lnor, corner_space_custom_data_to_normal(space, clnor_data));
559 const float3 &custom_lnor)
609 const float custom_lnor[3],
610 short r_clnor_data[2])
615 space.vec_ref = lnor_space->
vec_ref;
618 space.ref_beta = lnor_space->
ref_beta;
619 copy_v2_v2_short(r_clnor_data, corner_space_custom_normal_to_data(space, custom_lnor));
644#define INDEX_UNSET INT_MIN
645#define INDEX_INVALID -1
647#define IS_EDGE_SHARP(_e2l) ELEM((_e2l)[1], INDEX_UNSET, INDEX_INVALID)
656 const float split_angle,
660 const float split_angle_cos =
cosf(split_angle);
661 auto face_is_smooth = [&](
const int face_i) {
662 return sharp_faces.
is_empty() || !sharp_faces[face_i];
665 for (
const int face_i : faces.index_range()) {
666 for (
const int corner : faces[face_i]) {
667 const int vert = corner_verts[corner];
668 const int edge = corner_edges[corner];
670 int2 &e2l = edge_to_corners[edge];
673 if ((e2l[0] | e2l[1]) == 0) {
680 const bool is_angle_sharp =
math::dot(face_normals[corner_to_face_map[e2l[0]]],
681 face_normals[face_i]) < split_angle_cos;
687 if (!face_is_smooth(face_i) || (!sharp_edges.
is_empty() && sharp_edges[edge]) ||
688 vert == corner_verts[e2l[0]] || is_angle_sharp)
695 if (is_angle_sharp) {
696 r_sharp_edges[edge] =
true;
709 r_sharp_edges[edge] =
false;
727 auto face_is_smooth = [&](
const int face_i) {
728 return sharp_faces.
is_empty() || !sharp_faces[face_i];
731 for (
const int face_i : faces.index_range()) {
732 for (
const int corner : faces[face_i]) {
733 const int vert = corner_verts[corner];
734 const int edge = corner_edges[corner];
736 int2 &e2l = edge_to_corners[edge];
739 if ((e2l[0] | e2l[1]) == 0) {
750 if (!face_is_smooth(face_i) || (!sharp_edges.
is_empty() && sharp_edges[edge]) ||
751 vert == corner_verts[e2l[0]])
775 const float split_angle,
778 if (split_angle >=
float(
M_PI)) {
801 const int2 e2lfan_curr,
802 const int vert_pivot,
806 const int fan_corner_orig = *r_fan_corner;
807 const int vert_fan_orig = corner_verts[fan_corner_orig];
816 *r_fan_corner = (e2lfan_curr[0] == *r_fan_corner) ? e2lfan_curr[1] : e2lfan_curr[0];
820 const int vert_fan_next = corner_verts[*r_fan_corner];
821 const IndexRange face_fan_next = faces[corner_to_face[*r_fan_corner]];
822 if ((vert_fan_orig == vert_fan_next && vert_fan_orig == vert_pivot) ||
823 !
ELEM(vert_fan_orig, vert_fan_next, vert_pivot))
826 *r_vert_corner = *r_fan_corner;
832 *r_vert_corner = *r_fan_corner;
838 const int space_index)
844 corner_normals[corner] = face_normals[corner_to_face[corner]];
854 const int face_index = corner_to_face[corner];
858 const int vert_pivot = corner_verts[corner];
859 const int vert_2 =
edge_other_vert(edges[corner_edges[corner]], vert_pivot);
860 const int vert_3 =
edge_other_vert(edges[corner_edges[corner_prev]], vert_pivot);
867 lnors_spacearr->corner_space_indices[corner] = space_index;
873 if (!lnors_spacearr->corners_by_space.is_empty()) {
874 lnors_spacearr->corners_by_space[space_index] = {corner};
881 const int space_index,
897 const int face_index = corner_to_face[corner];
906 const int vert_pivot = corner_verts[corner];
909 const int2 &edge_orig = edges[corner_edges[corner]];
923 int fan_corner = corner_prev;
924 int vert_corner = corner;
935 if (lnors_spacearr) {
936 edge_vectors->
append(vec_org);
941 const int2 &edge = edges[corner_edges[fan_corner]];
954 lnor += face_normals[corner_to_face[fan_corner]] *
957 processed_corners.
append(vert_corner);
959 if (lnors_spacearr) {
960 if (edge != edge_orig) {
962 edge_vectors->
append(vec_curr);
968 clnors_avg +=
int2(clnors_data[vert_corner]);
972 if (
IS_EDGE_SHARP(edge_to_corners[corner_edges[fan_corner]]) || (edge == edge_orig)) {
984 edge_to_corners[corner_edges[fan_corner]],
996 if (lnors_spacearr) {
999 lnor = corner_normals[vert_corner];
1006 processed_corners.
as_span(), space_index);
1007 edge_vectors->
clear();
1010 clnors_avg /= processed_corners.
size();
1016 if (
LIKELY(length != 0.0f)) {
1032 const int2 e2l_prev,
1035 const int corner_prev)
1038 const int vert_pivot = corner_verts[corner];
1040 int2 e2lfan_curr = e2l_prev;
1049 int fan_corner = corner_prev;
1050 int vert_corner = corner;
1056 skip_corners[vert_corner].set();
1061 corner_verts, faces, corner_to_face, e2lfan_curr, vert_pivot, &fan_corner, &vert_corner);
1063 e2lfan_curr = edge_to_corners[corner_edges[fan_corner]];
1070 if (skip_corners[vert_corner]) {
1071 if (vert_corner == corner) {
1081 skip_corners[vert_corner].set();
1104 for (
const int face_index : faces.index_range()) {
1107 for (
const int corner : face) {
1111 printf(
"Checking corner %d / edge %u / vert %u (sharp edge: %d, skiploop: %d)",
1113 corner_edges[corner],
1114 corner_verts[corner],
1116 skip_corners[corner]);
1129 if (!
IS_EDGE_SHARP(edge_to_corners[corner_edges[corner]]) &&
1136 edge_to_corners[corner_edges[corner_prev]],
1149 r_single_corners.
append(corner);
1159 r_fan_corners.
append(corner);
1176 const short2 *clnors_data,
1202 if (!r_lnors_spacearr && clnors_data) {
1204 r_lnors_spacearr = &_lnors_spacearr;
1211 common_data.
clnors_data = {clnors_data, clnors_data ? corner_verts.
size() : 0};
1213 common_data.
edges = edges;
1228 faces, corner_verts, corner_edges, sharp_faces, sharp_edges, edge_to_corners);
1234 if (r_lnors_spacearr) {
1235 r_lnors_spacearr->
spaces.reinitialize(single_corners.
size() + fan_corners.
size());
1243 for (const int i : range) {
1244 const int corner = single_corners[i];
1245 lnor_space_for_single_fan(&common_data, corner, i);
1250 Vector<float3, 16> edge_vectors;
1251 for (const int i : range) {
1252 const int corner = fan_corners[i];
1253 const int space_index = single_corners.size() + i;
1254 split_corner_normal_fan_do(&common_data, corner, space_index, &edge_vectors);
1281 const bool use_vertices,
1309 r_clnors_data.
data(),
1315 for (
const int i : positions.index_range()) {
1316 if (
is_zero_v3(r_custom_corner_normals[i])) {
1317 copy_v3_v3(r_custom_corner_normals[i], vert_normals[i]);
1323 if (
is_zero_v3(r_custom_corner_normals[i])) {
1324 copy_v3_v3(r_custom_corner_normals[i], corner_normals[i]);
1336 done_corners.
fill(
true);
1344 done_corners[i].set();
1346 printf(
"WARNING! Getting invalid nullptr corner space for corner %d!\n", i);
1350 if (done_corners[i]) {
1367 done_corners[i].set();
1371 int prev_corner = -1;
1372 const float *org_nor =
nullptr;
1375 const int corner = fan_corners[i];
1376 float *
nor = r_custom_corner_normals[corner];
1386 const IndexRange face = faces[corner_to_face[corner]];
1388 const int edge = corner_edges[corner];
1389 const int edge_prev = corner_edges[corner_prev];
1390 const int prev_edge = corner_edges[prev_corner];
1391 sharp_edges[prev_edge == edge_prev ? prev_edge : edge] =
true;
1396 prev_corner = corner;
1397 done_corners[corner].set();
1404 if (fan_corners.
size() > 1 && org_nor) {
1405 const int corner = fan_corners.
last();
1406 float *
nor = r_custom_corner_normals[corner];
1409 const IndexRange face = faces[corner_to_face[corner]];
1411 const int edge = corner_edges[corner];
1412 const int edge_prev = corner_edges[corner_prev];
1413 const int prev_edge = corner_edges[prev_corner];
1414 sharp_edges[prev_edge == edge_prev ? prev_edge : edge] =
true;
1430 r_clnors_data.
data(),
1439 done_corners[i].reset();
1441 printf(
"WARNING! Still getting invalid nullptr corner space in second for loop %d!\n", i);
1445 if (!done_corners[i]) {
1455 if (fan_corners.
size() < 2) {
1456 const int nidx = use_vertices ? corner_verts[i] : i;
1458 r_custom_corner_normals[nidx]);
1459 done_corners[i].reset();
1463 for (
const int corner : fan_corners) {
1464 const int nidx = use_vertices ? corner_verts[corner] : corner;
1465 avg_nor += r_custom_corner_normals[nidx];
1466 done_corners[corner].reset();
1471 lnors_spacearr.
spaces[space_index], avg_nor);
1473 r_clnors_data.
fill_indices(fan_corners, clnor_data_tmp);
1499 r_custom_corner_normals,
1525 r_custom_vert_normals,
1534 if (clnors !=
nullptr) {
1535 memset(clnors, 0,
sizeof(*clnors) * mesh->corners_num);
1543 "sharp_edge", AttrDomain::Edge);
1544 const VArraySpan sharp_faces = *attributes.lookup<
bool>(
"sharp_face", AttrDomain::Face);
1549 mesh->corner_verts(),
1550 mesh->corner_edges(),
1551 mesh->vert_normals(),
1552 mesh->face_normals(),
1555 {reinterpret_cast<float3 *>(r_custom_nors),
1556 use_vertices ? mesh->verts_num : mesh->corners_num},
1558 {clnors, mesh->corners_num});
1569 threading::parallel_for(normals.index_range(), 4096, [&](
const IndexRange range) {
1570 for (const int i : range) {
1571 normals[i] = math::normalize(normals[i]);
1579 {
reinterpret_cast<blender::float3 *
>(r_custom_corner_normals), mesh->corners_num});
1597 float (*r_custom_vert_normals)[3])
1603 const int *corner_verts,
1605 const float (*clnors)[3],
1606 float (*r_vert_clnors)[3])
1609 size_t(numVerts),
sizeof(*vert_loops_count), __func__);
1611 copy_vn_fl((
float *)r_vert_clnors, 3 * numVerts, 0.0f);
1614 for (i = 0; i < numLoops; i++) {
1615 const int vert = corner_verts[i];
1616 add_v3_v3(r_vert_clnors[vert], clnors[i]);
1617 vert_loops_count[vert]++;
1620 for (i = 0; i < numVerts; i++) {
1621 mul_v3_fl(r_vert_clnors[i], 1.0f /
float(vert_loops_count[i]));
1627#undef LNOR_SPACE_TRIGO_THRESHOLD
CustomData interface, see also DNA_customdata_types.h.
const void * CustomData_get_layer(const CustomData *data, eCustomDataType type)
void * CustomData_get_layer_for_write(CustomData *data, eCustomDataType type, int totelem)
bool CustomData_has_layer(const CustomData *data, eCustomDataType type)
void * CustomData_add_layer(CustomData *data, eCustomDataType type, eCDAllocType alloctype, int totelem)
@ MLNOR_SPACEARR_LOOP_INDEX
@ MLNOR_SPACEARR_BMLOOP_PTR
void BLI_linklist_prepend_nlink(LinkNode **listp, void *ptr, LinkNode *nlink) ATTR_NONNULL(1
#define BLI_ASSERT_UNIT_V3(v)
float normal_quad_v3(float n[3], const float v1[3], const float v2[3], const float v3[3], const float v4[3])
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void add_newell_cross_v3_v3v3(float n[3], const float v_prev[3], const float v_curr[3])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
void copy_vn_fl(float *array_tar, int size, float val)
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void copy_v2_v2_short(short r[2], const short a[2])
MINLINE bool compare_v3v3(const float v1[3], const float v2[3], float limit) ATTR_WARN_UNUSED_RESULT
MINLINE bool is_zero_v3(const float v[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void mul_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void add_v3_v3(float r[3], const float a[3])
MINLINE float normalize_v3(float n[3])
void * BLI_memarena_alloc(struct MemArena *ma, size_t size) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_ALLOC_SIZE(2)
void * BLI_memarena_calloc(struct MemArena *ma, size_t size) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_ALLOC_SIZE(2)
void BLI_memarena_free(struct MemArena *ma) ATTR_NONNULL(1)
struct MemArena * BLI_memarena_new(size_t bufsize, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(2) ATTR_MALLOC
void BLI_memarena_merge(MemArena *ma_dst, MemArena *ma_src) ATTR_NONNULL(1
#define BLI_MEMARENA_STD_BUFSIZE
void void BLI_memarena_clear(MemArena *ma) ATTR_NONNULL(1)
#define SCOPED_TIMER_AVERAGED(name)
#define POINTER_FROM_INT(i)
Read Guarded memory(de)allocation.
SIMD_FORCE_INLINE btScalar length() const
Return the length of the vector.
MutableSpan< T > as_mutable_span()
constexpr int64_t last(const int64_t n=0) const
constexpr int64_t size() const
constexpr T * data() const
constexpr void fill_indices(Span< IndexT > indices, const T &value) const
constexpr int64_t size() const
constexpr const T & last(const int64_t n=0) const
constexpr IndexRange index_range() const
constexpr bool is_empty() const
void append(const T &value)
IndexRange index_range() const
Span< T > as_span() const
void fill(const bool value)
draw_view in_light_buf[] float
void *(* MEM_calloc_arrayN)(size_t len, size_t size, const char *str)
void MEM_freeN(void *vmemh)
void BKE_lnor_space_custom_data_to_normal(const MLoopNorSpace *lnor_space, const short clnor_data[2], float r_custom_lnor[3])
MLoopNorSpace * BKE_lnor_space_create(MLoopNorSpaceArray *lnors_spacearr)
void BKE_lnor_space_custom_normal_to_data(const MLoopNorSpace *lnor_space, const float custom_lnor[3], short r_clnor_data[2])
bool BKE_mesh_vert_normals_are_dirty(const Mesh *mesh)
MINLINE short unit_float_to_short(const float val)
void BKE_lnor_spacearr_init(MLoopNorSpaceArray *lnors_spacearr, const int numLoops, const char data_type)
static void normalize_vecs(blender::MutableSpan< blender::float3 > normals)
void BKE_lnor_spacearr_clear(MLoopNorSpaceArray *lnors_spacearr)
void BKE_mesh_normals_loop_to_vertex(const int numVerts, const int *corner_verts, const int numLoops, const float(*clnors)[3], float(*r_vert_clnors)[3])
bool BKE_mesh_face_normals_are_dirty(const Mesh *mesh)
#define LNOR_SPACE_TRIGO_THRESHOLD
void BKE_lnor_space_define(MLoopNorSpace *lnor_space, const float lnor[3], const float vec_ref[3], const float vec_other[3], const blender::Span< blender::float3 > edge_vectors)
void BKE_mesh_set_custom_normals(Mesh *mesh, float(*r_custom_corner_normals)[3])
void BKE_mesh_set_custom_normals_from_verts_normalized(Mesh *mesh, float(*r_custom_vert_normals)[3])
void BKE_lnor_space_add_loop(MLoopNorSpaceArray *lnors_spacearr, MLoopNorSpace *lnor_space, const int corner, void *bm_loop, const bool is_single)
void BKE_mesh_set_custom_normals_from_verts(Mesh *mesh, float(*r_custom_vert_normals)[3])
void BKE_lnor_spacearr_free(MLoopNorSpaceArray *lnors_spacearr)
void BKE_lnor_spacearr_tls_join(MLoopNorSpaceArray *lnors_spacearr, MLoopNorSpaceArray *lnors_spacearr_tls)
void BKE_mesh_set_custom_normals_normalized(Mesh *mesh, float(*r_custom_corner_normals)[3])
MINLINE float unit_short_to_float(const short val)
void BKE_lnor_spacearr_tls_init(MLoopNorSpaceArray *lnors_spacearr, MLoopNorSpaceArray *lnors_spacearr_tls)
#define IS_EDGE_SHARP(_e2l)
void gather(const GVArray &src, const IndexMask &indices, GMutableSpan dst, int64_t grain_size=4096)
void normals_corner_custom_set_from_verts(Span< float3 > vert_positions, Span< int2 > edges, OffsetIndices< int > faces, Span< int > corner_verts, Span< int > corner_edges, Span< float3 > vert_normals, Span< float3 > face_normals, Span< bool > sharp_faces, MutableSpan< bool > sharp_edges, MutableSpan< float3 > r_custom_vert_normals, MutableSpan< short2 > r_clnors_data)
int edge_other_vert(const int2 edge, const int vert)
static void split_corner_normal_fan_do(CornerSplitTaskDataCommon *common_data, const int corner, const int space_index, Vector< float3, 16 > *edge_vectors)
static void mesh_normals_corner_custom_set(const Span< float3 > positions, const Span< int2 > edges, const OffsetIndices< int > faces, const Span< int > corner_verts, const Span< int > corner_edges, const Span< float3 > vert_normals, const Span< float3 > face_normals, const Span< bool > sharp_faces, const bool use_vertices, MutableSpan< float3 > r_custom_corner_normals, MutableSpan< bool > sharp_edges, MutableSpan< short2 > r_clnors_data)
static CornerNormalSpace corner_fan_space_define(const float3 &lnor, const float3 &vec_ref, const float3 &vec_other, const Span< float3 > edge_vectors)
static float3 normal_calc_ngon(const Span< float3 > vert_positions, const Span< int > face_verts)
static void corner_manifold_fan_around_vert_next(const Span< int > corner_verts, const OffsetIndices< int > faces, const Span< int > corner_to_face, const int2 e2lfan_curr, const int vert_pivot, int *r_fan_corner, int *r_vert_corner)
static void lnor_space_for_single_fan(CornerSplitTaskDataCommon *common_data, const int corner, const int space_index)
static float3 corner_space_custom_data_to_normal(const CornerNormalSpace &lnor_space, const short2 clnor_data)
float3 face_normal_calc(Span< float3 > vert_positions, Span< int > face_verts)
int face_corner_prev(const IndexRange face, const int corner)
Array< int > build_corner_to_face_map(OffsetIndices< int > faces)
void normals_calc_corners(Span< float3 > vert_positions, Span< int2 > edges, OffsetIndices< int > faces, Span< int > corner_verts, Span< int > corner_edges, Span< int > corner_to_face_map, Span< float3 > vert_normals, Span< float3 > face_normals, Span< bool > sharp_edges, Span< bool > sharp_faces, const short2 *clnors_data, CornerNormalSpaceArray *r_lnors_spacearr, MutableSpan< float3 > r_corner_normals)
void normals_corner_custom_set(Span< float3 > vert_positions, Span< int2 > edges, OffsetIndices< int > faces, Span< int > corner_verts, Span< int > corner_edges, Span< float3 > vert_normals, Span< float3 > face_normals, Span< bool > sharp_faces, MutableSpan< bool > sharp_edges, MutableSpan< float3 > r_custom_corner_normals, MutableSpan< short2 > r_clnors_data)
static void mesh_set_custom_normals(Mesh *mesh, float(*r_custom_nors)[3], const bool use_vertices)
short2 corner_space_custom_normal_to_data(const CornerNormalSpace &lnor_space, const float3 &custom_lnor)
void edges_sharp_from_angle_set(OffsetIndices< int > faces, Span< int > corner_verts, Span< int > corner_edges, Span< float3 > face_normals, Span< int > corner_to_face, Span< bool > sharp_faces, const float split_angle, MutableSpan< bool > sharp_edges)
int face_corner_next(const IndexRange face, const int corner)
static void corner_split_generator(CornerSplitTaskDataCommon *common_data, Vector< int, 32 > &r_single_corners, Vector< int, 32 > &r_fan_corners)
void normals_calc_verts(Span< float3 > vert_positions, OffsetIndices< int > faces, Span< int > corner_verts, GroupedSpan< int > vert_to_face_map, Span< float3 > face_normals, MutableSpan< float3 > vert_normals)
static void mesh_edges_sharp_tag(const OffsetIndices< int > faces, const Span< int > corner_verts, const Span< int > corner_edges, const Span< int > corner_to_face_map, const Span< float3 > face_normals, const Span< bool > sharp_faces, const Span< bool > sharp_edges, const float split_angle, MutableSpan< int2 > edge_to_corners, MutableSpan< bool > r_sharp_edges)
void normals_calc_faces(Span< float3 > vert_positions, OffsetIndices< int > faces, Span< int > corner_verts, MutableSpan< float3 > face_normals)
static void build_edge_to_corner_map_with_flip_and_sharp(const OffsetIndices< int > faces, const Span< int > corner_verts, const Span< int > corner_edges, const Span< bool > sharp_faces, const Span< bool > sharp_edges, MutableSpan< int2 > edge_to_corners)
static bool corner_split_generator_check_cyclic_smooth_fan(const Span< int > corner_verts, const Span< int > corner_edges, const OffsetIndices< int > faces, const Span< int2 > edge_to_corners, const Span< int > corner_to_face, const int2 e2l_prev, MutableBitSpan skip_corners, const int corner, const int corner_prev)
void mesh_vert_normals_assign(Mesh &mesh, Span< float3 > vert_normals)
VecBase< T, 3 > normal_tri(const VecBase< T, 3 > &v1, const VecBase< T, 3 > &v2, const VecBase< T, 3 > &v3)
float safe_acos_approx(float x)
QuaternionBase< T > normalize_and_get_length(const QuaternionBase< T > &q, T &out_length)
T dot(const QuaternionBase< T > &a, const QuaternionBase< T > &b)
AxisSigned cross(const AxisSigned a, const AxisSigned b)
MatBase< T, NumCol, NumRow > normalize(const MatBase< T, NumCol, NumRow > &a)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
VecBase< int32_t, 2 > int2
blender::VecBase< int16_t, 2 > short2
Frequency::GEOMETRY nor[]
struct LinkNode * loops_pool
MLoopNorSpace ** lspacearr
MeshRuntimeHandle * runtime
MutableVArraySpan< T > span
bool create_corners_by_space
Array< Array< int > > corners_by_space
Array< int > corner_space_indices
Array< CornerNormalSpace > spaces
Span< int > corner_to_face
Span< int2 > edge_to_corners
Span< short2 > clnors_data
CornerNormalSpaceArray * lnors_spacearr
MutableSpan< float3 > corner_normals
Span< float3 > vert_normals
OffsetIndices< int > faces
Span< float3 > face_normals
ccl_device_inline float beta(float x, float y)