49 mesh.runtime->vert_normals_true_cache.ensure(
55 mesh.runtime->vert_normals_true_cache.ensure(
56 [&](
Vector<float3> &r_data) { r_data = std::move(vert_normals); });
67 return std::get<Vector<float3>>(this->
data).as_mutable_span();
75 return std::get<Span<float3>>(this->
data);
81 this->data =
data.get_internal_span();
97 return mesh->
runtime->vert_normals_cache.is_dirty();
102 return mesh->
runtime->face_normals_cache.is_dirty();
107namespace blender::bke::mesh {
125 const float *v_prev = vert_positions[face_verts.
last()];
127 const float *v_curr = vert_positions[face_verts[
i]];
143 if (face_verts.
size() == 4) {
145 vert_positions[face_verts[0]],
146 vert_positions[face_verts[1]],
147 vert_positions[face_verts[2]],
148 vert_positions[face_verts[3]]);
150 else if (face_verts.
size() == 3) {
152 vert_positions[face_verts[1]],
153 vert_positions[face_verts[2]]);
184 for (const int i : range) {
185 face_normals[i] = normal_calc_ngon(positions, corner_verts.slice(faces[i]));
199 for (const int vert : range) {
200 const Span<int> vert_faces = vert_to_face_map[vert];
201 if (vert_faces.is_empty()) {
202 vert_normals[vert] = math::normalize(positions[vert]);
206 float3 vert_normal(0);
207 for (const int face : vert_faces) {
208 const int2 adjacent_verts = face_find_adjacent_verts(faces[face], corner_verts, vert);
209 const float3 dir_prev = math::normalize(positions[adjacent_verts[0]] - positions[vert]);
210 const float3 dir_next = math::normalize(positions[adjacent_verts[1]] - positions[vert]);
211 const float factor = math::safe_acos_approx(math::dot(dir_prev, dir_next));
213 vert_normal += face_normals[face] * factor;
216 vert_normals[vert] = math::normalize(vert_normal);
232 for (const int vert : range) {
233 const Span<int> vert_faces = vert_to_face_map[vert];
234 if (vert_faces.is_empty()) {
235 vert_normals[vert] = math::normalize(positions[vert]);
239 float3 vert_normal(0);
240 for (const int face : vert_faces) {
241 const int corner = mesh::face_find_corner_from_vert(faces[face], corner_verts, vert);
242 const int2 adjacent_verts{corner_verts[mesh::face_corner_prev(faces[face], corner)],
243 corner_verts[mesh::face_corner_next(faces[face], corner)]};
245 const float3 dir_prev = math::normalize(positions[adjacent_verts[0]] - positions[vert]);
246 const float3 dir_next = math::normalize(positions[adjacent_verts[1]] - positions[vert]);
247 const float factor = math::safe_acos_approx(math::dot(dir_prev, dir_next));
249 vert_normal += corner_normals[corner] * factor;
252 vert_normals[vert] = math::normalize(vert_normal);
263 for (const int face : range) {
265 for (const int vert : corner_verts.slice(faces[face])) {
266 sum += vert_normals[vert];
268 face_normals[face] = math::normalize(sum);
278 for (const int face : range) {
279 const Span<float3> face_corner_normals = corner_normals.slice(faces[face]);
280 const float3 sum = std::accumulate(
281 face_corner_normals.begin(), face_corner_normals.end(), float3(0));
282 face_normals[face] = math::normalize(sum);
298 if (
const std::optional<AttributeMetaData> custom = attributes.
lookup_meta_data(
"custom_normal"))
300 switch (custom->domain) {
315 "sharp_face", AttrDomain::Face,
false);
319 return MeshNormalDomain::Face;
323 "sharp_edge", AttrDomain::Edge,
false);
326 return MeshNormalDomain::Face;
332 return MeshNormalDomain::Point;
335 return MeshNormalDomain::Corner;
338blender::Span<blender::float3> Mesh::vert_normals()
const
340 using namespace blender;
341 using namespace blender::bke;
342 this->runtime->vert_normals_cache.ensure([&](NormalsCache &r_data) {
343 if (
const GAttributeReader custom = this->attributes().
lookup(
"custom_normal")) {
344 if (custom.varray.type().is<
float3>()) {
345 if (custom.domain == AttrDomain::Point) {
349 if (custom.domain == AttrDomain::Face) {
350 mesh::normals_calc_verts(this->vert_positions(),
352 this->corner_verts(),
353 this->vert_to_face_map(),
359 if (custom.domain == AttrDomain::Corner) {
360 mesh::mix_normals_corner_to_vert(this->vert_positions(),
362 this->corner_verts(),
363 this->vert_to_face_map(),
369 else if (custom.varray.type().is<
short2>() && custom.domain == AttrDomain::Corner) {
370 mesh::mix_normals_corner_to_vert(this->vert_positions(),
372 this->corner_verts(),
373 this->vert_to_face_map(),
374 this->corner_normals(),
379 r_data.
data = NormalsCache::UseTrueCache();
381 if (std::holds_alternative<NormalsCache::UseTrueCache>(
382 this->runtime->vert_normals_cache.data().data))
384 return this->vert_normals_true();
387 return this->runtime->vert_normals_cache.data().get_span();
390blender::Span<blender::float3> Mesh::vert_normals_true()
const
392 using namespace blender;
393 using namespace blender::bke;
394 this->runtime->vert_normals_true_cache.ensure([&](
Vector<float3> &r_data) {
396 mesh::normals_calc_verts(this->vert_positions(),
398 this->corner_verts(),
399 this->vert_to_face_map(),
400 this->face_normals_true(),
403 return this->runtime->vert_normals_true_cache.data();
406blender::Span<blender::float3> Mesh::face_normals()
const
408 using namespace blender;
409 using namespace blender::bke;
410 this->runtime->face_normals_cache.ensure([&](NormalsCache &r_data) {
411 if (
const GAttributeReader custom = this->attributes().
lookup(
"custom_normal")) {
412 if (custom.varray.type().is<
float3>()) {
413 if (custom.domain == AttrDomain::Face) {
417 if (custom.domain == AttrDomain::Point) {
418 mesh::mix_normals_vert_to_face(this->
faces(),
419 this->corner_verts(),
424 if (custom.domain == AttrDomain::Corner) {
425 mesh::mix_normals_corner_to_face(this->
faces(),
431 else if (custom.varray.type().is<
short2>() && custom.domain == AttrDomain::Corner) {
432 mesh::mix_normals_corner_to_face(
437 r_data.
data = NormalsCache::UseTrueCache();
439 if (std::holds_alternative<NormalsCache::UseTrueCache>(
440 this->runtime->face_normals_cache.data().data))
442 return this->face_normals_true();
444 return this->runtime->face_normals_cache.data().get_span();
447blender::Span<blender::float3> Mesh::face_normals_true()
const
449 using namespace blender;
450 using namespace blender::bke;
451 this->runtime->face_normals_true_cache.ensure([&](
Vector<float3> &r_data) {
453 mesh::normals_calc_faces(this->vert_positions(), this->
faces(), this->corner_verts(), r_data);
455 return this->runtime->face_normals_true_cache.data();
458blender::Span<blender::float3> Mesh::corner_normals()
const
460 using namespace blender;
461 using namespace blender::bke;
462 this->runtime->corner_normals_cache.ensure([&](NormalsCache &r_data) {
464 switch (this->normals_domain()) {
465 case MeshNormalDomain::Point: {
470 case MeshNormalDomain::Face: {
476 case MeshNormalDomain::Corner: {
477 const AttributeAccessor attributes = this->attributes();
478 const GAttributeReader custom = attributes.
lookup(
"custom_normal");
486 const VArraySpan sharp_edges = *attributes.
lookup<
bool>(
"sharp_edge", AttrDomain::Edge);
487 const VArraySpan sharp_faces = *attributes.
lookup<
bool>(
"sharp_face", AttrDomain::Face);
488 mesh::normals_calc_corners(this->vert_positions(),
490 this->corner_verts(),
491 this->corner_edges(),
492 this->vert_to_face_map(),
493 this->face_normals_true(),
502 return this->runtime->corner_normals_cache.data().get_span();
507 const char data_type)
512 if (!lnors_spacearr->
mem) {
515 mem = lnors_spacearr->
mem;
520 mem,
sizeof(
LinkNode) *
size_t(numLoops));
536 *lnors_spacearr_tls = *lnors_spacearr;
548 lnors_spacearr_tls->
mem =
nullptr;
557 if (lnors_spacearr->
mem !=
nullptr) {
568 lnors_spacearr->
mem =
nullptr;
578#define LNOR_SPACE_TRIGO_THRESHOLD (1.0f - 1e-4f)
588 const float pi2 = float(
M_PI) * 2.0f;
589 const float dtp_ref =
math::dot(vec_ref, lnor);
590 const float dtp_other =
math::dot(vec_other, lnor);
606 for (
const float3 &vec : edge_vectors) {
615 lnor_space.
ref_alpha = alpha / float(edge_vectors.size());
648 const float vec_ref[3],
649 const float vec_other[3],
665 const bool is_single)
670 lnors_spacearr->
lspacearr[corner] = lnor_space;
671 if (bm_loop ==
nullptr) {
687 return float(val) / float(SHRT_MAX);
693 return short(
floorf(val *
float(SHRT_MAX) + 0.5f));
696namespace blender::bke::mesh {
702 if (clnor_data[0] == 0 || lnor_space.
ref_alpha == 0.0f || lnor_space.
ref_beta == 0.0f) {
710 const float pi2 = float(
M_PI * 2.0);
712 const float alpha = (alphafac > 0.0f ? lnor_space.
ref_alpha : pi2 - lnor_space.
ref_alpha) *
718 if (betafac == 0.0f) {
722 const float sinalpha =
sinf(alpha);
729 return r_custom_lnor;
735 const short clnor_data[2],
736 float r_custom_lnor[3])
748namespace blender::bke::mesh {
751 const float3 &custom_lnor)
760 const float pi2 = float(
M_PI * 2.0);
801 const float custom_lnor[3],
802 short r_clnor_data[2])
814namespace blender::bke {
818#define INDEX_UNSET INT_MIN
819#define INDEX_INVALID -1
821#define IS_EDGE_SHARP(_e2l) ELEM((_e2l)[1], INDEX_UNSET, INDEX_INVALID)
830 const float split_angle,
834 const float split_angle_cos =
cosf(split_angle);
835 auto face_is_smooth = [&](
const int face_i) {
836 return sharp_faces.
is_empty() || !sharp_faces[face_i];
839 for (
const int face_i :
faces.index_range()) {
840 for (
const int corner :
faces[face_i]) {
841 const int vert = corner_verts[corner];
842 const int edge = corner_edges[corner];
844 int2 &e2l = edge_to_corners[edge];
847 if ((e2l[0] | e2l[1]) == 0) {
854 const bool is_angle_sharp =
math::dot(face_normals[corner_to_face_map[e2l[0]]],
855 face_normals[face_i]) < split_angle_cos;
861 if (!face_is_smooth(face_i) || (!sharp_edges.
is_empty() && sharp_edges[edge]) ||
862 vert == corner_verts[e2l[0]] || is_angle_sharp)
869 if (is_angle_sharp) {
870 r_sharp_edges[edge] =
true;
883 r_sharp_edges[edge] =
false;
896 const float split_angle,
899 if (split_angle >=
float(
M_PI)) {
944 const int face = vert_faces[
i];
945 r_corner_infos[
i].face = face;
949 r_corner_infos[
i].vert_prev = corner_verts[r_corner_infos[
i].corner_prev];
950 r_corner_infos[
i].vert_next = corner_verts[r_corner_infos[
i].corner_next];
983using VertEdgeInfo = std::variant<EdgeUninitialized, EdgeOneCorner, EdgeTwoCorners, EdgeSharp>;
987 const int local_corner,
989 const int other_corner,
990 const bool winding_torwards_vert,
993 if (std::holds_alternative<EdgeUninitialized>(info)) {
998 if (sharp_edges[corner_edges[winding_torwards_vert ? other_corner : corner]]) {
1005 else if (
const EdgeOneCorner *info_one_edge = std::get_if<EdgeOneCorner>(&info)) {
1011 if (info_one_edge->winding_torwards_vert == winding_torwards_vert) {
1015 info =
EdgeTwoCorners{info_one_edge->local_corner_1, local_corner};
1040 r_other_vert_to_edge.
reserve(corner_infos.
size());
1042 info.local_edge_prev = r_other_vert_to_edge.
index_of_or_add(info.vert_prev);
1043 info.local_edge_next = r_other_vert_to_edge.
index_of_or_add(info.vert_next);
1053 for (
const int local_corner : corner_infos.
index_range()) {
1055 if (!sharp_faces.
is_empty() && sharp_faces[info.
face]) {
1086 const int start_local_corner,
1089 result_fan.
append(start_local_corner);
1095 int current = start_local_corner;
1096 int local_edge = corner_infos[current].local_edge_next;
1097 bool found_cyclic_fan =
false;
1098 while (
const EdgeTwoCorners *edge = std::get_if<EdgeTwoCorners>(&edge_infos[local_edge])) {
1099 current = current == edge->local_corner_1 ? edge->local_corner_2 : edge->local_corner_1;
1100 if (current == start_local_corner) {
1101 found_cyclic_fan =
true;
1104 result_fan.
append(current);
1105 local_edge = corner_infos[current].local_edge_next;
1110 if (found_cyclic_fan) {
1113 int *fan_first_corner = std::min_element(
1114 result_fan.
begin(), result_fan.
end(), [&](
const int a,
const int b) {
1115 return corner_infos[a].corner < corner_infos[b].corner;
1117 std::rotate(result_fan.
begin(), fan_first_corner, result_fan.
end());
1123 int current = start_local_corner;
1124 int local_edge = corner_infos[current].local_edge_prev;
1125 while (
const EdgeTwoCorners *edge = std::get_if<EdgeTwoCorners>(&edge_infos[local_edge])) {
1126 current = current == edge->local_corner_1 ? edge->local_corner_2 : edge->local_corner_1;
1128 result_fan.
append(current);
1129 local_edge = corner_infos[current].local_edge_prev;
1140 const float3 &vert_position,
1144 edge_dirs[
i] =
math::normalize(vert_positions[local_edge_by_vert[
i]] - vert_position);
1154 if (local_corners_in_fan.
size() == 1) {
1157 return face_normals[corner_infos[local_corners_in_fan.
first()].face];
1160 for (
const int local_corner : local_corners_in_fan) {
1165 fan_normal += face_normals[info.
face] * factor;
1179 const int local_edge_first = corner_infos[local_corners_in_fan.
first()].local_edge_next;
1180 const int local_edge_last = corner_infos[local_corners_in_fan.
last()].local_edge_prev;
1183 if (local_corners_in_fan.
size() > 1) {
1184 fan_edge_dirs.
reserve(local_corners_in_fan.
size() + 1);
1185 for (
const int local_corner : local_corners_in_fan) {
1189 if (local_edge_last != local_edge_first) {
1195 fan_normal, edge_dirs[local_edge_first], edge_dirs[local_edge_last], fan_edge_dirs);
1198 int2 average_custom_normal(0);
1199 for (
const int local_corner : local_corners_in_fan) {
1201 average_custom_normal +=
int2(custom_normals[info.
corner]);
1203 average_custom_normal /= local_corners_in_fan.size();
1209 r_fan_spaces->
spaces.append(fan_space);
1210 const int fan_space_index = r_fan_spaces->
spaces.size() - 1;
1211 for (
const int local_corner : local_corners_in_fan) {
1216 Array<int> corners_in_space(local_corners_in_fan.size());
1217 for (
const int i : local_corners_in_fan.index_range()) {
1219 corners_in_space[
i] = info.
corner;
1240 r_fan_spaces->
spaces.reserve(corner_verts.
size());
1249 if (!custom_normals.
is_empty() || r_fan_spaces) {
1250 grain_size = std::max(
int64_t(16384), vert_positions.
size() / 2);
1254 Vector<VertCornerInfo, 16> corner_infos;
1255 LocalEdgeVectorSet local_edge_by_vert;
1256 Vector<VertEdgeInfo, 16> edge_infos;
1257 Vector<float3, 16> edge_dirs;
1258 Vector<bool, 16> local_corner_visited;
1259 Vector<int, 16> corners_in_fan;
1260 for (const int vert : range) {
1261 const float3 vert_position = vert_positions[vert];
1262 const Span<int> vert_faces = vert_to_face_map[vert];
1266 if (vert_faces.is_empty()) {
1270 corner_infos.resize(vert_faces.size());
1271 collect_corner_info(faces, corner_verts, vert_faces, vert, corner_infos);
1273 local_edge_by_vert.clear_and_keep_capacity();
1274 calc_local_edge_indices(corner_infos, local_edge_by_vert);
1277 edge_infos.resize(local_edge_by_vert.size());
1278 calc_connecting_edge_info(corner_edges, sharp_edges, sharp_faces, corner_infos, edge_infos);
1280 edge_dirs.resize(edge_infos.size());
1281 calc_edge_directions(vert_positions, local_edge_by_vert, vert_position, edge_dirs);
1288 int visited_count = 0;
1289 local_corner_visited.resize(vert_faces.size());
1290 local_corner_visited.fill(false);
1292 int start_local_corner = 0;
1293 while (start_local_corner != -1) {
1294 corners_in_fan.clear();
1295 traverse_fan_local_corners(corner_infos, edge_infos, start_local_corner, corners_in_fan);
1297 float3 fan_normal = accumulate_fan_normal(
1298 corner_infos, edge_dirs, face_normals, corners_in_fan);
1300 if (!custom_normals.is_empty() || r_fan_spaces) {
1301 handle_fan_result_and_custom_normals(
1302 custom_normals, corner_infos, edge_dirs, corners_in_fan, fan_normal, r_fan_spaces);
1305 for (const int local_corner : corners_in_fan) {
1306 const VertCornerInfo &info = corner_infos[local_corner];
1307 r_corner_normals[info.corner] = fan_normal;
1310 visited_count += corners_in_fan.size();
1311 if (visited_count == corner_infos.size()) {
1314 local_corner_visited.as_mutable_span().fill_indices(corners_in_fan.as_span(), true);
1315 start_local_corner = local_corner_visited.first_index_of_try(false);
1317 BLI_assert(visited_count == corner_infos.size());
1344 const bool use_vertices,
1378 copy_v3_v3(r_custom_corner_normals[
i], vert_normals[
i]);
1385 copy_v3_v3(r_custom_corner_normals[
i], corner_normals[
i]);
1397 done_corners.
fill(
true);
1405 done_corners[
i].set();
1407 printf(
"WARNING! Getting invalid nullptr corner space for corner %d!\n",
i);
1411 if (done_corners[
i]) {
1428 done_corners[
i].set();
1432 int prev_corner = -1;
1433 const float *org_nor =
nullptr;
1436 const int corner = fan_corners[
i];
1437 float *
nor = r_custom_corner_normals[corner];
1449 const int edge = corner_edges[corner];
1450 const int edge_prev = corner_edges[corner_prev];
1451 const int prev_edge = corner_edges[prev_corner];
1452 sharp_edges[prev_edge == edge_prev ? prev_edge : edge] =
true;
1457 prev_corner = corner;
1458 done_corners[corner].set();
1465 if (fan_corners.
size() > 1 && org_nor) {
1466 const int corner = fan_corners.
last();
1467 float *
nor = r_custom_corner_normals[corner];
1472 const int edge = corner_edges[corner];
1473 const int edge_prev = corner_edges[corner_prev];
1474 const int prev_edge = corner_edges[prev_corner];
1475 sharp_edges[prev_edge == edge_prev ? prev_edge : edge] =
true;
1498 done_corners[
i].reset();
1500 printf(
"WARNING! Still getting invalid nullptr corner space in second for loop %d!\n",
i);
1504 if (!done_corners[
i]) {
1514 if (fan_corners.
size() < 2) {
1515 const int nidx = use_vertices ? corner_verts[
i] :
i;
1517 r_custom_corner_normals[nidx]);
1518 done_corners[
i].reset();
1522 for (
const int corner : fan_corners) {
1523 const int nidx = use_vertices ? corner_verts[corner] : corner;
1524 avg_nor += r_custom_corner_normals[nidx];
1525 done_corners[corner].reset();
1528 mul_v3_fl(avg_nor, 1.0f /
float(fan_corners.size()));
1530 lnors_spacearr.
spaces[space_index], avg_nor);
1532 r_clnors_data.
fill_indices(fan_corners, clnor_data_tmp);
1558 r_custom_corner_normals,
1584 r_custom_vert_normals,
1591 const bool use_vertices)
1596 if (!custom_normals) {
1605 mesh.corner_verts(),
1606 mesh.corner_edges(),
1607 mesh.vert_to_face_map(),
1608 mesh.vert_normals_true(),
1609 mesh.face_normals_true(),
1614 custom_normals.
span);
1625 for (const int i : range) {
1626 normals[i] = math::normalize(normals[i]);
1655#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)
@ MLNOR_SPACEARR_LOOP_INDEX
@ MLNOR_SPACEARR_BMLOOP_PTR
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)
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)
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)
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(const StringRef attribute_id) const
GAttributeReader lookup_or_default(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type, const void *default_value=nullptr) const
std::optional< AttributeMetaData > lookup_meta_data(StringRef attribute_id) const
GSpanAttributeWriter lookup_or_add_for_write_span(StringRef attribute_id, AttrDomain domain, eCustomDataType 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)
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
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)
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)
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)
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)
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)
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)
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)
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