50 mesh.runtime->vert_normals_true_cache.ensure(
56 mesh.runtime->vert_normals_true_cache.ensure(
57 [&](
Vector<float3> &r_data) { r_data = std::move(vert_normals); });
68 return std::get<Vector<float3>>(this->
data).as_mutable_span();
76 return std::get<Span<float3>>(this->
data);
82 this->data =
data.get_internal_span();
98 return mesh->
runtime->vert_normals_cache.is_dirty();
103 return mesh->
runtime->face_normals_cache.is_dirty();
108namespace blender::bke::mesh {
126 const float *v_prev = vert_positions[face_verts.
last()];
128 const float *v_curr = vert_positions[face_verts[
i]];
144 if (face_verts.
size() == 4) {
146 vert_positions[face_verts[0]],
147 vert_positions[face_verts[1]],
148 vert_positions[face_verts[2]],
149 vert_positions[face_verts[3]]);
151 else if (face_verts.
size() == 3) {
153 vert_positions[face_verts[1]],
154 vert_positions[face_verts[2]]);
185 for (const int i : range) {
186 face_normals[i] = normal_calc_ngon(positions, corner_verts.slice(faces[i]));
200 for (const int vert : range) {
201 const Span<int> vert_faces = vert_to_face_map[vert];
202 if (vert_faces.is_empty()) {
203 vert_normals[vert] = math::normalize(positions[vert]);
207 float3 vert_normal(0);
208 for (const int face : vert_faces) {
209 const int2 adjacent_verts = face_find_adjacent_verts(faces[face], corner_verts, vert);
210 const float3 dir_prev = math::normalize(positions[adjacent_verts[0]] - positions[vert]);
211 const float3 dir_next = math::normalize(positions[adjacent_verts[1]] - positions[vert]);
212 const float factor = math::safe_acos_approx(math::dot(dir_prev, dir_next));
214 vert_normal += face_normals[face] * factor;
217 vert_normals[vert] = math::normalize(vert_normal);
233 for (const int vert : range) {
234 const Span<int> vert_faces = vert_to_face_map[vert];
235 if (vert_faces.is_empty()) {
236 vert_normals[vert] = math::normalize(positions[vert]);
240 float3 vert_normal(0);
241 for (const int face : vert_faces) {
242 const int corner = mesh::face_find_corner_from_vert(faces[face], corner_verts, vert);
243 const int2 adjacent_verts{corner_verts[mesh::face_corner_prev(faces[face], corner)],
244 corner_verts[mesh::face_corner_next(faces[face], corner)]};
246 const float3 dir_prev = math::normalize(positions[adjacent_verts[0]] - positions[vert]);
247 const float3 dir_next = math::normalize(positions[adjacent_verts[1]] - positions[vert]);
248 const float factor = math::safe_acos_approx(math::dot(dir_prev, dir_next));
250 vert_normal += corner_normals[corner] * factor;
253 vert_normals[vert] = math::normalize(vert_normal);
264 for (const int face : range) {
266 for (const int vert : corner_verts.slice(faces[face])) {
267 sum += vert_normals[vert];
269 face_normals[face] = math::normalize(sum);
279 for (const int face : range) {
280 const Span<float3> face_corner_normals = corner_normals.slice(faces[face]);
281 const float3 sum = std::accumulate(
282 face_corner_normals.begin(), face_corner_normals.end(), float3(0));
283 face_normals[face] = math::normalize(sum);
298 if (this->faces_num == 0) {
303 if (
const std::optional<AttributeMetaData> custom = attributes.
lookup_meta_data(
"custom_normal"))
305 switch (custom->domain) {
306 case AttrDomain::Point:
307 return MeshNormalDomain::Point;
308 case AttrDomain::Edge:
310 case AttrDomain::Face:
311 return MeshNormalDomain::Face;
312 case AttrDomain::Corner:
313 return MeshNormalDomain::Corner;
320 "sharp_face", AttrDomain::Face,
false);
324 return MeshNormalDomain::Face;
328 "sharp_edge", AttrDomain::Edge,
false);
331 return MeshNormalDomain::Face;
337 return MeshNormalDomain::Point;
340 return MeshNormalDomain::Corner;
343blender::Span<blender::float3> Mesh::vert_normals()
const
345 using namespace blender;
346 using namespace blender::bke;
347 this->runtime->vert_normals_cache.ensure([&](NormalsCache &r_data) {
348 if (
const GAttributeReader custom = this->attributes().
lookup(
"custom_normal")) {
349 if (custom.varray.type().is<
float3>()) {
350 if (custom.domain == AttrDomain::Point) {
354 if (custom.domain == AttrDomain::Face) {
355 mesh::normals_calc_verts(this->vert_positions(),
357 this->corner_verts(),
358 this->vert_to_face_map(),
364 if (custom.domain == AttrDomain::Corner) {
365 mesh::mix_normals_corner_to_vert(this->vert_positions(),
367 this->corner_verts(),
368 this->vert_to_face_map(),
374 else if (custom.varray.type().is<
short2>() && custom.domain == AttrDomain::Corner) {
375 mesh::mix_normals_corner_to_vert(this->vert_positions(),
377 this->corner_verts(),
378 this->vert_to_face_map(),
379 this->corner_normals(),
384 r_data.
data = NormalsCache::UseTrueCache();
386 if (std::holds_alternative<NormalsCache::UseTrueCache>(
387 this->runtime->vert_normals_cache.data().data))
389 return this->vert_normals_true();
392 return this->runtime->vert_normals_cache.data().get_span();
395blender::Span<blender::float3> Mesh::vert_normals_true()
const
397 using namespace blender;
398 using namespace blender::bke;
399 this->runtime->vert_normals_true_cache.ensure([&](
Vector<float3> &r_data) {
401 mesh::normals_calc_verts(this->vert_positions(),
403 this->corner_verts(),
404 this->vert_to_face_map(),
405 this->face_normals_true(),
408 return this->runtime->vert_normals_true_cache.data();
411blender::Span<blender::float3> Mesh::face_normals()
const
413 using namespace blender;
414 using namespace blender::bke;
415 if (this->faces_num == 0) {
418 this->runtime->face_normals_cache.ensure([&](NormalsCache &r_data) {
419 if (
const GAttributeReader custom = this->attributes().
lookup(
"custom_normal")) {
420 if (custom.varray.type().is<
float3>()) {
421 if (custom.domain == AttrDomain::Face) {
425 if (custom.domain == AttrDomain::Point) {
426 mesh::mix_normals_vert_to_face(this->
faces(),
427 this->corner_verts(),
432 if (custom.domain == AttrDomain::Corner) {
433 mesh::mix_normals_corner_to_face(this->
faces(),
439 else if (custom.varray.type().is<
short2>() && custom.domain == AttrDomain::Corner) {
440 mesh::mix_normals_corner_to_face(
445 r_data.
data = NormalsCache::UseTrueCache();
447 if (std::holds_alternative<NormalsCache::UseTrueCache>(
448 this->runtime->face_normals_cache.data().data))
450 return this->face_normals_true();
452 return this->runtime->face_normals_cache.data().get_span();
455blender::Span<blender::float3> Mesh::face_normals_true()
const
457 using namespace blender;
458 using namespace blender::bke;
459 this->runtime->face_normals_true_cache.ensure([&](
Vector<float3> &r_data) {
461 mesh::normals_calc_faces(this->vert_positions(), this->
faces(), this->corner_verts(), r_data);
463 return this->runtime->face_normals_true_cache.data();
466blender::Span<blender::float3> Mesh::corner_normals()
const
468 using namespace blender;
469 using namespace blender::bke;
470 if (this->faces_num == 0) {
473 this->runtime->corner_normals_cache.ensure([&](NormalsCache &r_data) {
475 switch (this->normals_domain()) {
476 case MeshNormalDomain::Point: {
481 case MeshNormalDomain::Face: {
487 case MeshNormalDomain::Corner: {
488 const AttributeAccessor attributes = this->attributes();
489 const GAttributeReader custom = attributes.
lookup(
"custom_normal");
497 const VArraySpan sharp_edges = *attributes.
lookup<
bool>(
"sharp_edge", AttrDomain::Edge);
498 const VArraySpan sharp_faces = *attributes.
lookup<
bool>(
"sharp_face", AttrDomain::Face);
499 mesh::normals_calc_corners(this->vert_positions(),
501 this->corner_verts(),
502 this->corner_edges(),
503 this->vert_to_face_map(),
504 this->face_normals_true(),
513 return this->runtime->corner_normals_cache.data().get_span();
518 const char data_type)
523 if (!lnors_spacearr->
mem) {
526 mem = lnors_spacearr->
mem;
531 mem,
sizeof(
LinkNode) *
size_t(numLoops));
547 *lnors_spacearr_tls = *lnors_spacearr;
559 lnors_spacearr_tls->
mem =
nullptr;
568 if (lnors_spacearr->
mem !=
nullptr) {
579 lnors_spacearr->
mem =
nullptr;
589#define LNOR_SPACE_TRIGO_THRESHOLD (1.0f - 1e-4f)
600 const float dtp_ref =
math::dot(vec_ref, lnor);
601 const float dtp_other =
math::dot(vec_other, lnor);
617 for (
const float3 &vec : edge_vectors) {
659 const float vec_ref[3],
660 const float vec_other[3],
676 const bool is_single)
681 lnors_spacearr->
lspacearr[corner] = lnor_space;
682 if (bm_loop ==
nullptr) {
704 return short(
floorf(val *
float(SHRT_MAX) + 0.5f));
707namespace blender::bke::mesh {
713 if (clnor_data[0] == 0 || lnor_space.
ref_alpha == 0.0f || lnor_space.
ref_beta == 0.0f) {
723 const float alpha = (alphafac > 0.0f ? lnor_space.
ref_alpha : pi2 - lnor_space.
ref_alpha) *
729 if (betafac == 0.0f) {
733 const float sinalpha =
sinf(alpha);
746 const short clnor_data[2],
747 float r_custom_lnor[3])
759namespace blender::bke::mesh {
762 const float3 &custom_lnor)
812 const float custom_lnor[3],
813 short r_clnor_data[2])
825namespace blender::bke {
829#define INDEX_UNSET INT_MIN
830#define INDEX_INVALID -1
832#define IS_EDGE_SHARP(_e2l) ELEM((_e2l)[1], INDEX_UNSET, INDEX_INVALID)
841 const float split_angle,
845 const float split_angle_cos =
cosf(split_angle);
846 auto face_is_smooth = [&](
const int face_i) {
847 return sharp_faces.
is_empty() || !sharp_faces[face_i];
850 for (
const int face_i :
faces.index_range()) {
851 for (
const int corner :
faces[face_i]) {
852 const int vert = corner_verts[corner];
853 const int edge = corner_edges[corner];
855 int2 &e2l = edge_to_corners[edge];
858 if ((e2l[0] | e2l[1]) == 0) {
865 const bool is_angle_sharp =
math::dot(face_normals[corner_to_face_map[e2l[0]]],
866 face_normals[face_i]) < split_angle_cos;
872 if (!face_is_smooth(face_i) || (!sharp_edges.
is_empty() && sharp_edges[edge]) ||
873 vert == corner_verts[e2l[0]] || is_angle_sharp)
880 if (is_angle_sharp) {
881 r_sharp_edges[edge] =
true;
894 r_sharp_edges[edge] =
false;
907 const float split_angle,
910 if (split_angle >=
float(
M_PI)) {
955 const int face = vert_faces[
i];
956 r_corner_infos[
i].face = face;
960 r_corner_infos[
i].vert_prev = corner_verts[r_corner_infos[
i].corner_prev];
961 r_corner_infos[
i].vert_next = corner_verts[r_corner_infos[
i].corner_next];
994using VertEdgeInfo = std::variant<EdgeUninitialized, EdgeOneCorner, EdgeTwoCorners, EdgeSharp>;
998 const int local_corner,
1000 const int other_corner,
1001 const bool winding_torwards_vert,
1004 if (std::holds_alternative<EdgeUninitialized>(info)) {
1009 if (sharp_edges[corner_edges[winding_torwards_vert ? other_corner : corner]]) {
1016 else if (
const EdgeOneCorner *info_one_edge = std::get_if<EdgeOneCorner>(&info)) {
1022 if (info_one_edge->winding_torwards_vert == winding_torwards_vert) {
1026 info =
EdgeTwoCorners{info_one_edge->local_corner_1, local_corner};
1051 r_other_vert_to_edge.
reserve(corner_infos.
size());
1053 info.local_edge_prev = r_other_vert_to_edge.
index_of_or_add(info.vert_prev);
1054 info.local_edge_next = r_other_vert_to_edge.
index_of_or_add(info.vert_next);
1064 for (
const int local_corner : corner_infos.
index_range()) {
1066 if (!sharp_faces.
is_empty() && sharp_faces[info.
face]) {
1097 const int start_local_corner,
1100 result_fan.
append(start_local_corner);
1106 int current = start_local_corner;
1107 int local_edge = corner_infos[current].local_edge_next;
1108 bool found_cyclic_fan =
false;
1109 while (
const EdgeTwoCorners *edge = std::get_if<EdgeTwoCorners>(&edge_infos[local_edge])) {
1111 if (current == start_local_corner) {
1112 found_cyclic_fan =
true;
1115 result_fan.
append(current);
1116 local_edge = corner_infos[current].local_edge_next;
1121 if (found_cyclic_fan) {
1124 int *fan_first_corner = std::min_element(
1125 result_fan.
begin(), result_fan.
end(), [&](
const int a,
const int b) {
1126 return corner_infos[a].corner < corner_infos[b].corner;
1128 std::rotate(result_fan.
begin(), fan_first_corner, result_fan.
end());
1134 int current = start_local_corner;
1135 int local_edge = corner_infos[current].local_edge_prev;
1136 while (
const EdgeTwoCorners *edge = std::get_if<EdgeTwoCorners>(&edge_infos[local_edge])) {
1137 current = current == edge->local_corner_1 ? edge->local_corner_2 : edge->local_corner_1;
1139 result_fan.
append(current);
1140 local_edge = corner_infos[current].local_edge_prev;
1151 const float3 &vert_position,
1155 edge_dirs[
i] =
math::normalize(vert_positions[local_edge_by_vert[
i]] - vert_position);
1165 if (local_corners_in_fan.
size() == 1) {
1168 return face_normals[corner_infos[local_corners_in_fan.
first()].face];
1171 for (
const int local_corner : local_corners_in_fan) {
1176 fan_normal += face_normals[info.
face] * factor;
1197 const int local_edge_first = corner_infos[local_corners_in_fan.
first()].local_edge_next;
1198 const int local_edge_last = corner_infos[local_corners_in_fan.
last()].local_edge_prev;
1201 if (local_corners_in_fan.
size() > 1) {
1202 fan_edge_dirs.
reserve(local_corners_in_fan.
size() + 1);
1203 for (
const int local_corner : local_corners_in_fan) {
1207 if (local_edge_last != local_edge_first) {
1213 fan_normal, edge_dirs[local_edge_first], edge_dirs[local_edge_last], fan_edge_dirs);
1216 int2 average_custom_normal(0);
1217 for (
const int local_corner : local_corners_in_fan) {
1219 average_custom_normal +=
int2(custom_normals[info.
corner]);
1221 average_custom_normal /= local_corners_in_fan.size();
1225 if (!r_fan_spaces) {
1230 for (
const int i : local_corners_in_fan.
index_range()) {
1234 r_local_space_groups->
append({std::move(fan_corners), fan_space});
1262 Vector<VertCornerInfo, 16> corner_infos;
1263 LocalEdgeVectorSet local_edge_by_vert;
1264 Vector<VertEdgeInfo, 16> edge_infos;
1265 Vector<float3, 16> edge_dirs;
1266 Vector<bool, 16> local_corner_visited;
1267 Vector<int, 16> corners_in_fan;
1269 Vector<CornerSpaceGroup, 0> *local_space_groups = r_fan_spaces ? &space_groups.local() :
1272 for (const int vert : range) {
1273 const float3 vert_position = vert_positions[vert];
1274 const Span<int> vert_faces = vert_to_face_map[vert];
1278 if (vert_faces.is_empty()) {
1282 corner_infos.resize(vert_faces.size());
1283 collect_corner_info(faces, corner_verts, vert_faces, vert, corner_infos);
1285 local_edge_by_vert.clear_and_keep_capacity();
1286 calc_local_edge_indices(corner_infos, local_edge_by_vert);
1289 edge_infos.resize(local_edge_by_vert.size());
1290 calc_connecting_edge_info(corner_edges, sharp_edges, sharp_faces, corner_infos, edge_infos);
1292 edge_dirs.resize(edge_infos.size());
1293 calc_edge_directions(vert_positions, local_edge_by_vert, vert_position, edge_dirs);
1300 int visited_count = 0;
1301 local_corner_visited.resize(vert_faces.size());
1302 local_corner_visited.fill(false);
1304 int start_local_corner = 0;
1306 corners_in_fan.clear();
1307 traverse_fan_local_corners(corner_infos, edge_infos, start_local_corner, corners_in_fan);
1309 float3 fan_normal = accumulate_fan_normal(
1310 corner_infos, edge_dirs, face_normals, corners_in_fan);
1312 if (!custom_normals.is_empty() || r_fan_spaces) {
1313 handle_fan_result_and_custom_normals(custom_normals,
1319 local_space_groups);
1322 for (const int local_corner : corners_in_fan) {
1323 const VertCornerInfo &info = corner_infos[local_corner];
1324 r_corner_normals[info.corner] = fan_normal;
1327 visited_count += corners_in_fan.size();
1328 if (visited_count == corner_infos.size()) {
1332 local_corner_visited.as_mutable_span().fill_indices(corners_in_fan.as_span(), true);
1333 BLI_assert(!local_corner_visited.as_span().take_front(start_local_corner).contains(false));
1334 BLI_assert(local_corner_visited.as_span().drop_front(start_local_corner).contains(false));
1336 while (local_corner_visited[start_local_corner]) {
1337 start_local_corner++;
1340 BLI_assert(visited_count == corner_infos.size());
1344 if (!r_fan_spaces) {
1352 space_groups_count.
append(groups.size());
1353 all_space_groups.
append(std::move(groups));
1355 space_groups_count.
append(0);
1357 space_groups_count);
1359 r_fan_spaces->spaces.reinitialize(space_offsets.
total_size());
1360 r_fan_spaces->corner_space_indices.reinitialize(corner_verts.size());
1361 if (r_fan_spaces->create_corners_by_space) {
1362 r_fan_spaces->corners_by_space.reinitialize(space_offsets.
total_size());
1368 const int64_t mean_size = std::max<int64_t>(1,
1370 const int64_t grain_size = std::max<int64_t>(1, 1024 * 16 / mean_size);
1371 threading::parallel_for(all_space_groups.
index_range(), grain_size, [&](
const IndexRange range) {
1372 for (const int thread_i : range) {
1373 Vector<CornerSpaceGroup, 0> &local_space_groups = all_space_groups[thread_i];
1374 for (const int group_i : local_space_groups.index_range()) {
1375 const int space_index = space_offsets[thread_i][group_i];
1376 r_fan_spaces->spaces[space_index] = local_space_groups[group_i].space;
1377 r_fan_spaces->corner_space_indices.as_mutable_span().fill_indices(
1378 local_space_groups[group_i].fan_corners.as_span(), space_index);
1380 if (!r_fan_spaces->create_corners_by_space) {
1383 for (const int group_i : local_space_groups.index_range()) {
1384 const int space_index = space_offsets[thread_i][group_i];
1385 r_fan_spaces->corners_by_space[space_index] = std::move(
1386 local_space_groups[group_i].fan_corners);
1414 const bool use_vertices,
1448 copy_v3_v3(r_custom_corner_normals[
i], vert_normals[
i]);
1455 copy_v3_v3(r_custom_corner_normals[
i], corner_normals[
i]);
1467 done_corners.
fill(
true);
1471 if (done_corners[
i]) {
1488 done_corners[
i].set();
1492 int prev_corner = -1;
1493 const float *org_nor =
nullptr;
1496 const int corner = fan_corners[
i];
1497 float *
nor = r_custom_corner_normals[corner];
1509 const int edge = corner_edges[corner];
1510 const int edge_prev = corner_edges[corner_prev];
1511 const int prev_edge = corner_edges[prev_corner];
1512 sharp_edges[prev_edge == edge_prev ? prev_edge : edge] =
true;
1517 prev_corner = corner;
1518 done_corners[corner].set();
1525 if (fan_corners.
size() > 1 && org_nor) {
1526 const int corner = fan_corners.
last();
1527 float *
nor = r_custom_corner_normals[corner];
1532 const int edge = corner_edges[corner];
1533 const int edge_prev = corner_edges[corner_prev];
1534 const int prev_edge = corner_edges[prev_corner];
1535 sharp_edges[prev_edge == edge_prev ? prev_edge : edge] =
true;
1558 done_corners[
i].reset();
1560 printf(
"WARNING! Still getting invalid nullptr corner space in second for loop %d!\n",
i);
1564 if (!done_corners[
i]) {
1574 if (fan_corners.
size() < 2) {
1575 const int nidx = use_vertices ? corner_verts[
i] :
i;
1577 r_custom_corner_normals[nidx]);
1578 done_corners[
i].reset();
1582 for (
const int corner : fan_corners) {
1583 const int nidx = use_vertices ? corner_verts[corner] : corner;
1584 avg_nor += r_custom_corner_normals[nidx];
1585 done_corners[corner].reset();
1588 mul_v3_fl(avg_nor, 1.0f /
float(fan_corners.size()));
1590 lnors_spacearr.
spaces[space_index], avg_nor);
1592 r_clnors_data.
fill_indices(fan_corners, clnor_data_tmp);
1618 r_custom_corner_normals,
1644 r_custom_vert_normals,
1651 const bool use_vertices)
1656 if (!custom_normals) {
1665 mesh.corner_verts(),
1666 mesh.corner_edges(),
1667 mesh.vert_to_face_map(),
1668 mesh.vert_normals_true(),
1669 mesh.face_normals_true(),
1674 custom_normals.
span);
1685 for (const int i : range) {
1686 normals[i] = math::normalize(normals[i]);
1771 const std::optional<bke::AttributeMetaData> custom_normal = attributes.
lookup_meta_data(
1773 if (!custom_normal) {
1794#undef LNOR_SPACE_TRIGO_THRESHOLD
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])
@ MLNOR_SPACEARR_LOOP_INDEX
@ MLNOR_SPACEARR_BMLOOP_PTR
bool BKE_mesh_vert_normals_are_dirty(const Mesh *mesh)
void BKE_lnor_space_add_loop(MLoopNorSpaceArray *lnors_spacearr, MLoopNorSpace *lnor_space, int corner, void *bm_loop, bool is_single)
void BKE_lnor_spacearr_clear(MLoopNorSpaceArray *lnors_spacearr)
void BKE_lnor_spacearr_init(MLoopNorSpaceArray *lnors_spacearr, int numLoops, char data_type)
bool BKE_mesh_face_normals_are_dirty(const Mesh *mesh)
void BKE_lnor_space_define(MLoopNorSpace *lnor_space, const float lnor[3], const float vec_ref[3], const float vec_other[3], blender::Span< blender::float3 > edge_vectors)
void BKE_lnor_spacearr_free(MLoopNorSpaceArray *lnors_spacearr)
void BKE_lnor_spacearr_tls_join(MLoopNorSpaceArray *lnors_spacearr, MLoopNorSpaceArray *lnors_spacearr_tls)
void BKE_lnor_spacearr_tls_init(MLoopNorSpaceArray *lnors_spacearr, MLoopNorSpaceArray *lnors_spacearr_tls)
#define BLI_assert_unreachable()
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])
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 float normalize_v3(float n[3])
void BLI_memarena_merge(MemArena *ma_dst, MemArena *ma_src)
#define BLI_MEMARENA_STD_BUFSIZE
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_calloc(MemArena *ma, size_t size) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_ALLOC_SIZE(2)
void BLI_memarena_free(MemArena *ma) ATTR_NONNULL(1)
void * BLI_memarena_alloc(MemArena *ma, size_t size) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_ALLOC_SIZE(2)
void BLI_memarena_clear(MemArena *ma) ATTR_NONNULL(1)
#define POINTER_FROM_INT(i)
BMesh const char void * data
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
void reinitialize(const int64_t new_size)
const CPPType & type() const
VArray< T > typed() const
constexpr int64_t last(const int64_t n=0) const
constexpr int64_t size() const
constexpr void fill_indices(Span< IndexT > indices, const T &value) const
constexpr const T & first() 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
int64_t index_of_or_add(const Key &key)
void reserve(const int64_t n)
void append(const T &value)
IndexRange index_range() const
MutableSpan< T > as_mutable_span()
void append_unchecked(const T &value)
void reserve(const int64_t min_capacity)
void fill(const bool value)
GAttributeReader lookup_or_default(StringRef attribute_id, AttrDomain domain, AttrType data_type, const void *default_value=nullptr) const
GAttributeReader lookup(const StringRef attribute_id) const
std::optional< AttributeMetaData > lookup_meta_data(StringRef attribute_id) const
GSpanAttributeWriter lookup_or_add_for_write_span(StringRef attribute_id, AttrDomain domain, AttrType data_type, const AttributeInit &initializer=AttributeInitDefaultValue())
void store_varray(const VArray< float3 > &data)
std::variant< UseTrueCache, Vector< float3 >, Span< float3 > > data
MutableSpan< float3 > ensure_vector_size(const int size)
Span< float3 > get_span() const
void store_vector(Vector< float3 > &&data)
void add_corner_fan_normals()
std::optional< bke::AttrDomain > result_domain
void add_domain(bke::AttrDomain domain)
void add_free_normals(bke::AttrDomain domain)
void add_no_custom_normals(bke::MeshNormalDomain domain)
void add_mesh(const Mesh &mesh)
static float normals[][3]
VecBase< short, 2 > short2
ccl_device_inline float beta(const float x, const float y)
MINLINE short unit_float_to_short(const float val)
#define LNOR_SPACE_TRIGO_THRESHOLD
MINLINE float unit_short_to_float(const short val)
#define IS_EDGE_SHARP(_e2l)
void gather_to_groups(const OffsetIndices< int > dst_offsets, const IndexMask &src_selection, const Span< T > src, MutableSpan< T > dst)
BooleanMix booleans_mix_calc(const VArray< bool > &varray, IndexRange range_to_check)
void gather(const GVArray &src, const IndexMask &indices, GMutableSpan dst, int64_t grain_size=4096)
GAttributeReader lookup(const void *owner, const StringRef name)
std::monostate EdgeUninitialized
int edge_other_vert(const int2 edge, const int vert)
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 mesh_normals_corner_custom_set(const Span< float3 > positions, const OffsetIndices< int > faces, const Span< int > corner_verts, const Span< int > corner_edges, const GroupedSpan< int > vert_to_face_map, 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 float3 corner_space_custom_data_to_normal(const CornerNormalSpace &lnor_space, const short2 clnor_data)
constexpr AttributeMetaData CORNER_FAN_META_DATA
float3 face_normal_calc(Span< float3 > vert_positions, Span< int > face_verts)
static void calc_edge_directions(const Span< float3 > vert_positions, const Span< int > local_edge_by_vert, const float3 &vert_position, MutableSpan< float3 > edge_dirs)
static void mix_normals_vert_to_face(const OffsetIndices< int > faces, const Span< int > corner_verts, const Span< float3 > vert_normals, MutableSpan< float3 > face_normals)
int face_corner_prev(const IndexRange face, const int corner)
static void mix_normals_corner_to_vert(const Span< float3 > vert_positions, const OffsetIndices< int > faces, const Span< int > corner_verts, const GroupedSpan< int > vert_to_face_map, const Span< float3 > corner_normals, MutableSpan< float3 > vert_normals)
int face_find_corner_from_vert(const IndexRange face, const Span< int > corner_verts, const int vert)
static void calc_local_edge_indices(MutableSpan< VertCornerInfo > corner_infos, LocalEdgeVectorSet &r_other_vert_to_edge)
static void mesh_set_custom_normals(Mesh &mesh, MutableSpan< float3 > r_custom_nors, const bool use_vertices)
static void traverse_fan_local_corners(const Span< VertCornerInfo > corner_infos, const Span< VertEdgeInfo > edge_infos, const int start_local_corner, Vector< int, 16 > &result_fan)
static float3 accumulate_fan_normal(const Span< VertCornerInfo > corner_infos, const Span< float3 > edge_dirs, const Span< float3 > face_normals, const Span< int > local_corners_in_fan)
static void calc_connecting_edge_info(const Span< int > corner_edges, const Span< bool > sharp_edges, const Span< bool > sharp_faces, const Span< VertCornerInfo > corner_infos, MutableSpan< VertEdgeInfo > edge_infos)
Array< int > build_corner_to_face_map(OffsetIndices< int > faces)
static void add_corner_to_edge(const Span< int > corner_edges, const Span< bool > sharp_edges, const int local_corner, const int corner, const int other_corner, const bool winding_torwards_vert, VertEdgeInfo &info)
static void mix_normals_corner_to_face(const OffsetIndices< int > faces, const Span< float3 > corner_normals, MutableSpan< float3 > face_normals)
bool is_corner_fan_normals(const AttributeMetaData &meta_data)
void normals_calc_corners(Span< float3 > vert_positions, OffsetIndices< int > faces, Span< int > corner_verts, Span< int > corner_edges, GroupedSpan< int > vert_to_face_map, Span< float3 > face_normals, Span< bool > sharp_edges, Span< bool > sharp_faces, Span< short2 > custom_normals, CornerNormalSpaceArray *r_fan_spaces, MutableSpan< float3 > r_corner_normals)
void normals_corner_custom_set_from_verts(Span< float3 > vert_positions, OffsetIndices< int > faces, Span< int > corner_verts, Span< int > corner_edges, GroupedSpan< int > vert_to_face_map, 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)
static bke::AttrDomain normal_domain_to_domain(bke::MeshNormalDomain domain)
VectorSet< int, 16, DefaultProbingStrategy, DefaultHash< int >, DefaultEquality< int >, SimpleVectorSetSlot< int, int >, GuardedAllocator > LocalEdgeVectorSet
static void collect_corner_info(const OffsetIndices< int > faces, const Span< int > corner_verts, const Span< int > vert_faces, const int vert, MutableSpan< VertCornerInfo > r_corner_infos)
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)
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)
static BLI_NOINLINE void handle_fan_result_and_custom_normals(const Span< short2 > custom_normals, const Span< VertCornerInfo > corner_infos, const Span< float3 > edge_dirs, const Span< int > local_corners_in_fan, float3 &fan_normal, CornerNormalSpaceArray *r_fan_spaces, Vector< CornerSpaceGroup, 0 > *r_local_space_groups)
void normals_corner_custom_set(Span< float3 > vert_positions, OffsetIndices< int > faces, Span< int > corner_verts, Span< int > corner_edges, GroupedSpan< int > vert_to_face_map, 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)
std::variant< EdgeUninitialized, EdgeOneCorner, EdgeTwoCorners, EdgeSharp > VertEdgeInfo
void normals_calc_faces(Span< float3 > vert_positions, OffsetIndices< int > faces, Span< int > corner_verts, MutableSpan< float3 > face_normals)
static void normalize_vecs(MutableSpan< float3 > normals)
void mesh_set_custom_normals_normalized(Mesh &mesh, MutableSpan< float3 > corner_normals)
void mesh_set_custom_normals_from_verts(Mesh &mesh, MutableSpan< float3 > vert_normals)
void mesh_vert_normals_assign(Mesh &mesh, Span< float3 > vert_normals)
void mesh_set_custom_normals_from_verts_normalized(Mesh &mesh, MutableSpan< float3 > vert_normals)
void mesh_set_custom_normals(Mesh &mesh, MutableSpan< float3 > corner_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)
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)
OffsetIndices< int > accumulate_counts_to_offsets(MutableSpan< int > counts_to_offsets, int start_offset=0)
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
PythonProbingStrategy<> DefaultProbingStrategy
VecBase< float, 3 > float3
blender::VecBase< int16_t, 2 > short2
struct LinkNode * loops_pool
MLoopNorSpace ** lspacearr
MeshRuntimeHandle * runtime
MutableVArraySpan< T > span
bool create_corners_by_space
Array< int > corner_space_indices
Vector< Array< int > > corners_by_space
Vector< CornerNormalSpace > spaces
bool winding_torwards_vert
OffsetIndices< int > offsets