152 const uint verts_num =
uint(mesh->verts_num);
153 const uint edges_num =
uint(mesh->edges_num);
154 const uint faces_num =
uint(mesh->faces_num);
155 const uint loops_num =
uint(mesh->corners_num);
156 uint newLoops = 0, newPolys = 0, newEdges = 0, newVerts = 0, rimVerts = 0;
160 const short mat_ofs = mat_nr_max ? smd->
mat_ofs : 0;
161 const short mat_ofs_rim = mat_nr_max ? smd->
mat_ofs_rim : 0;
165 uint *new_vert_arr =
nullptr;
168 uint *new_edge_arr =
nullptr;
171 uint *old_vert_arr = MEM_cnew_array<uint>(verts_num,
"old_vert_arr in solidify");
173 uint *edge_users =
nullptr;
174 int *edge_order =
nullptr;
176 float(*vert_nors)[3] =
nullptr;
185 const float ofs_new = smd->
offset + ofs_orig;
192 const bool do_bevel_convex = bevel_convex != 0.0f;
204 const uint stride = do_shell ? 2 : 1;
216 if (need_face_normals) {
218 face_normals = mesh->face_normals();
229#define INVALID_UNUSED uint(-1)
230#define INVALID_PAIR uint(-2)
232 new_vert_arr =
static_cast<uint *
>(
234 new_edge_arr =
static_cast<uint *
>(
235 MEM_malloc_arrayN(((edges_num * 2) + verts_num),
sizeof(*new_edge_arr), __func__));
238 edge_order =
static_cast<int *
>(
MEM_malloc_arrayN(edges_num,
sizeof(*edge_order), __func__));
245 for (eidx = 0; eidx < edges_num; eidx++) {
253 int corner_i_prev = face.last();
255 for (j = 0; j < face.size(); j++) {
256 const int corner_i = face[j];
257 const int vert_i = orig_corner_verts[corner_i];
258 const int prev_vert_i = orig_corner_verts[corner_i_prev];
260 eidx =
int(orig_corner_edges[corner_i_prev]);
264 edge_users[eidx] = (prev_vert_i > vert_i) == (edge[0] < edge[1]) ?
uint(i) :
265 (
uint(i) + faces_num);
266 edge_order[eidx] = j;
271 corner_i_prev = corner_i;
275 for (eidx = 0; eidx < edges_num; eidx++) {
285 for (i = 0; i < verts_num; i++) {
299 if (do_shell ==
false) {
311#ifdef USE_NONMANIFOLD_WORKAROUND
316 vert_nors =
static_cast<float(*)[3]
>(
MEM_calloc_arrayN(verts_num,
sizeof(
float[3]), __func__));
328 int((verts_num * stride) + newVerts),
329 int((edges_num * stride) + newEdges + rimVerts),
330 int((faces_num * stride) + newPolys),
331 int((loops_num * stride) + newLoops));
357 face_offsets[faces_num + i] = orig_faces[i].start() + mesh->corners_num;
363 for (i = 0, j =
int(verts_num); i < verts_num; i++) {
372 for (i = 0, j =
int(edges_num); i < edges_num; i++) {
379 (*ed_dst)[0] = old_vert_arr[(*ed_src)[0]] + verts_num;
380 (*ed_dst)[1] = old_vert_arr[(*ed_src)[1]] + verts_num;
391 const float *orig_vert_bweight =
static_cast<const float *
>(
394 &result->edge_data,
CD_PROP_FLOAT,
"bevel_weight_edge", result->edges_num));
395 if (!result_edge_bweight && (do_bevel_convex || orig_vert_bweight)) {
400 "bevel_weight_edge"));
404#define INIT_VERT_ARRAY_OFFSETS(test) \
405 if (((ofs_new >= ofs_orig) == do_flip) == test) { \
407 do_shell_align = true; \
413 do_shell_align = true; \
417 do_shell_align = false; \
419 vert_index = verts_num; \
425 "material_index", bke::AttrDomain::Face);
432 const int loop_end = face.
size() - 1;
438 const int corner_2 = face.start() + mesh->corners_num;
440 for (j = 0; j < face.size(); j++) {
444 face.start() + (loop_end - j) + mesh->corners_num,
451 for (
int j_prev = loop_end; j < face.size(); j_prev = j++) {
453 &result->corner_data,
455 face.start() + (loop_end - j_prev) + mesh->corners_num,
461 dst_material_index.
span[faces_num + i] += mat_ofs;
462 CLAMP(dst_material_index.
span[faces_num + i], 0, mat_nr_max);
465 e = corner_edges[corner_2 + 0];
466 for (j = 0; j < loop_end; j++) {
467 corner_edges[corner_2 + j] = corner_edges[corner_2 + j + 1];
469 corner_edges[corner_2 + loop_end] =
e;
471 for (j = 0; j < face.size(); j++) {
472 corner_verts[corner_2 + j] += verts_num;
473 corner_edges[corner_2 + j] += edges_num;
477 for (
blender::int2 &edge : edges.slice(edges_num, edges_num)) {
485 float ofs_new_vgroup;
488 float *vert_lens =
nullptr;
489 float *vert_angs =
nullptr;
491 const float offset_sq = offset * offset;
494 float *edge_angs =
nullptr;
497 vert_lens =
static_cast<float *
>(
MEM_malloc_arrayN(verts_num,
sizeof(
float),
"vert_lens"));
499 for (
uint i = 0; i < edges_num; i++) {
501 vert_positions[edges[i][1]]);
502 vert_lens[edges[i][0]] =
min_ff(vert_lens[edges[i][0]], ed_len_sq);
503 vert_lens[edges[i][1]] =
min_ff(vert_lens[edges[i][1]], ed_len_sq);
507 if (do_angle_clamp || do_bevel_convex) {
509 if (do_angle_clamp) {
510 vert_angs =
static_cast<float *
>(
MEM_malloc_arrayN(verts_num,
sizeof(
float),
"vert_angs"));
513 if (do_bevel_convex) {
514 edge_angs =
static_cast<float *
>(
MEM_malloc_arrayN(edges_num,
sizeof(
float),
"edge_angs"));
516 edge_users =
static_cast<uint *
>(
520 uint(*edge_user_pairs)[2] =
static_cast<uint(*)[2]
>(
522 for (eidx = 0; eidx < edges_num; eidx++) {
528 int prev_corner_i = face.last();
529 for (
const int corner_i : face) {
530 const int vert_i = orig_corner_verts[corner_i];
531 const int prev_vert_i = orig_corner_verts[prev_corner_i];
533 eidx = orig_corner_edges[prev_corner_i];
536 char flip = char((prev_vert_i > vert_i) == (ed[0] < ed[1]));
538 edge_user_pairs[eidx][flip] =
uint(i);
544 prev_corner_i = corner_i;
548 for (
uint i = 0; i < edges_num; i++) {
553 const float *n0 = face_normals[edge_user_pairs[i][0]];
554 const float *n1 = face_normals[edge_user_pairs[i][1]];
555 sub_v3_v3v3(
e, orig_vert_positions[edge[0]], orig_vert_positions[edge[1]]);
558 if (do_angle_clamp) {
559 vert_angs[edge[0]] =
max_ff(vert_angs[edge[0]], angle);
560 vert_angs[edge[1]] =
max_ff(vert_angs[edge[1]], angle);
562 if (do_bevel_convex) {
563 edge_angs[i] =
angle;
573 if (ofs_new != 0.0f) {
577 ofs_new_vgroup = ofs_new;
582 for (i_orig = 0; i_orig < i_end; i_orig++, vert_index++) {
583 const uint i = do_shell_align ? i_orig : new_vert_arr[i_orig];
592 ofs_new_vgroup = (offset_fac_vg + (ofs_new_vgroup * offset_fac_vg_inv)) * ofs_new;
594 if (do_clamp && offset > FLT_EPSILON) {
596 if (dvert ==
nullptr) {
597 ofs_new_vgroup = ofs_new;
599 if (do_angle_clamp) {
600 float cos_ang =
cosf(((2 *
M_PI) - vert_angs[i]) * 0.5f);
602 float max_off =
sqrtf(vert_lens[i]) * 0.5f / cos_ang;
603 if (max_off < offset * 0.5f) {
604 ofs_new_vgroup *= max_off / offset * 2;
609 if (vert_lens[i] < offset_sq) {
610 float scalar =
sqrtf(vert_lens[i]) / offset;
611 ofs_new_vgroup *= scalar;
616 madd_v3_v3fl(vert_positions[vert_index], vert_nors[i], ofs_new_vgroup);
619 madd_v3_v3fl(vert_positions[vert_index], vert_normals[i], ofs_new_vgroup);
624 if (ofs_orig != 0.0f) {
628 ofs_new_vgroup = ofs_orig;
634 for (i_orig = 0; i_orig < i_end; i_orig++, vert_index++) {
635 const uint i = do_shell_align ? i_orig : new_vert_arr[i_orig];
644 ofs_new_vgroup = (offset_fac_vg + (ofs_new_vgroup * offset_fac_vg_inv)) * ofs_orig;
646 if (do_clamp && offset > FLT_EPSILON) {
648 if (dvert ==
nullptr) {
649 ofs_new_vgroup = ofs_orig;
651 if (do_angle_clamp) {
652 float cos_ang =
cosf(vert_angs[i_orig] * 0.5f);
654 float max_off =
sqrtf(vert_lens[i]) * 0.5f / cos_ang;
655 if (max_off < offset * 0.5f) {
656 ofs_new_vgroup *= max_off / offset * 2;
661 if (vert_lens[i] < offset_sq) {
662 float scalar =
sqrtf(vert_lens[i]) / offset;
663 ofs_new_vgroup *= scalar;
668 madd_v3_v3fl(vert_positions[vert_index], vert_nors[i], ofs_new_vgroup);
671 madd_v3_v3fl(vert_positions[vert_index], vert_normals[i], ofs_new_vgroup);
676 if (do_bevel_convex) {
677 for (
uint i = 0; i < edges_num; i++) {
679 float angle = edge_angs[i];
680 result_edge_bweight[i] =
clamp_f(result_edge_bweight[i] +
681 (angle <
M_PI ?
clamp_f(bevel_convex, 0.0f, 1.0f) :
682 clamp_f(bevel_convex, -1.0f, 0.0f)),
686 result_edge_bweight[i + edges_num] =
clamp_f(
687 result_edge_bweight[i + edges_num] + (angle >
M_PI ?
688 clamp_f(bevel_convex, 0.0f, 1.0f) :
689 clamp_f(bevel_convex, -1.0f, 0.0f)),
703 if (do_angle_clamp) {
709#ifdef USE_NONMANIFOLD_WORKAROUND
713 float *vert_angles =
static_cast<float *
>(
715 float *vert_accum = vert_angles + verts_num;
719 if (vert_nors ==
nullptr) {
720 vert_nors =
static_cast<float(*)[3]
>(
722 for (i = 0; i < verts_num; i++) {
733 int i_curr = face.
size() - 1;
736 const int *face_verts = &corner_verts[face.start()];
737 const int *face_edges = &corner_edges[face.start()];
740 nor_prev, vert_positions[face_verts[i_curr - 1]], vert_positions[face_verts[i_curr]]);
743 while (i_next < face.size()) {
746 nor_next, vert_positions[face_verts[i_curr]], vert_positions[face_verts[i_next]]);
751 if (angle < FLT_EPSILON) {
755 vidx = face_verts[i_curr];
756 vert_accum[vidx] +=
angle;
758#ifdef USE_NONMANIFOLD_WORKAROUND
760 if ((check_non_manifold ==
false) ||
768 vert_angles[vidx] +=
angle;
789 for (i = 0; i < verts_num; i++, dv++) {
791 scalar = offset_fac_vg + (scalar * offset_fac_vg_inv);
792 vert_angles[i] *= scalar;
796 for (i = 0; i < verts_num; i++, dv++) {
798 scalar = offset_fac_vg + (scalar * offset_fac_vg_inv);
799 vert_angles[i] *= scalar;
805 float *vert_angs =
nullptr;
807 float *edge_angs =
nullptr;
809 if (do_angle_clamp || do_bevel_convex) {
811 if (do_angle_clamp) {
812 vert_angs =
static_cast<float *
>(
816 if (do_bevel_convex) {
817 edge_angs =
static_cast<float *
>(
820 edge_users =
static_cast<uint *
>(
824 uint(*edge_user_pairs)[2] =
static_cast<uint(*)[2]
>(
826 for (eidx = 0; eidx < edges_num; eidx++) {
832 int prev_corner_i = face.start() + face.
size() - 1;
833 for (
int j = 0; j < face.size(); j++) {
834 const int corner_i = face.start() + j;
835 const int vert_i = orig_corner_verts[corner_i];
836 const int prev_vert_i = orig_corner_verts[prev_corner_i];
839 eidx = orig_corner_edges[prev_corner_i];
842 char flip = char((prev_vert_i > vert_i) == (edge[0] < edge[1]));
844 edge_user_pairs[eidx][flip] =
uint(i);
850 prev_corner_i = corner_i;
854 for (i = 0; i < edges_num; i++) {
859 const float *n0 = face_normals[edge_user_pairs[i][0]];
860 const float *n1 = face_normals[edge_user_pairs[i][1]];
861 if (do_angle_clamp) {
863 vert_angs[edge[0]] =
max_ff(vert_angs[edge[0]], angle);
864 vert_angs[edge[1]] =
max_ff(vert_angs[edge[1]], angle);
866 if (do_bevel_convex) {
867 sub_v3_v3v3(
e, orig_vert_positions[edge[0]], orig_vert_positions[edge[1]]);
880 const float clamp_fac = 1 + (do_angle_clamp ?
fabsf(smd->
offset_fac) : 0);
882 if (offset > FLT_EPSILON) {
883 float *vert_lens_sq =
static_cast<float *
>(
885 const float offset_sq = offset * offset;
887 for (i = 0; i < edges_num; i++) {
889 vert_positions[edges[i][1]]);
890 vert_lens_sq[edges[i][0]] =
min_ff(vert_lens_sq[edges[i][0]], ed_len);
891 vert_lens_sq[edges[i][1]] =
min_ff(vert_lens_sq[edges[i][1]], ed_len);
893 if (do_angle_clamp) {
894 for (i = 0; i < verts_num; i++) {
895 float cos_ang =
cosf(vert_angs[i] * 0.5f);
897 float max_off =
sqrtf(vert_lens_sq[i]) * 0.5f / cos_ang;
898 if (max_off < offset * 0.5f) {
899 vert_angles[i] *= max_off / offset * 2;
906 for (i = 0; i < verts_num; i++) {
907 if (vert_lens_sq[i] < offset_sq) {
908 float scalar =
sqrtf(vert_lens_sq[i]) / offset;
909 vert_angles[i] *= scalar;
917 if (do_bevel_convex) {
918 for (i = 0; i < edges_num; i++) {
920 float angle = edge_angs[i];
921 result_edge_bweight[i] =
clamp_f(result_edge_bweight[i] +
922 (angle <
M_PI ?
clamp_f(bevel_convex, 0.0f, 1.0f) :
923 clamp_f(bevel_convex, -1.0f, 0.0f)),
927 result_edge_bweight[i + edges_num] =
clamp_f(
928 result_edge_bweight[i + edges_num] +
944 if (ofs_new != 0.0f) {
951 for (i_orig = 0; i_orig < i_end; i_orig++, vert_index++) {
952 const uint i_other = do_shell_align ? i_orig : new_vert_arr[i_orig];
953 if (vert_accum[i_other]) {
956 ofs_new * (vert_angles[i_other] / vert_accum[i_other]));
961 if (ofs_orig != 0.0f) {
969 for (i_orig = 0; i_orig < i_end; i_orig++, vert_index++) {
970 const uint i_other = do_shell_align ? i_orig : new_vert_arr[i_orig];
971 if (vert_accum[i_other]) {
974 ofs_orig * (vert_angles[i_other] / vert_accum[i_other]));
982#ifdef USE_NONMANIFOLD_WORKAROUND
991 if (shell_defgrp_index != -1 || rim_defgrp_index != -1) {
992 MDeformVert *dst_dvert = result->deform_verts_for_write().data();
995 if (dst_dvert !=
nullptr) {
997 if (rim_defgrp_index != -1) {
998 for (
uint i = 0; i < rimVerts; i++) {
1006 if (shell_defgrp_index != -1) {
1007 for (
uint i = verts_num; i < result->verts_num; i++) {
1020 int *origindex_edge;
1024 float *result_edge_crease =
nullptr;
1025 if (crease_rim || crease_outer || crease_inner) {
1027 &result->edge_data,
CD_PROP_FLOAT,
"crease_edge", result->edges_num));
1028 if (!result_edge_crease) {
1035 origindex_edge =
static_cast<int *
>(
1037 orig_ed = (origindex_edge) ? &origindex_edge[(edges_num * stride) + newEdges] :
nullptr;
1039 int new_edge_index =
int(edges_num * stride + newEdges);
1040 for (i = 0; i < rimVerts; i++) {
1041 edges[new_edge_index][0] = new_vert_arr[i];
1042 edges[new_edge_index][1] = (do_shell ? new_vert_arr[i] : i) + verts_num;
1044 if (orig_vert_bweight) {
1045 result_edge_bweight[new_edge_index] = orig_vert_bweight[new_vert_arr[i]];
1054 result_edge_crease[new_edge_index] = crease_rim;
1060 int new_face_index =
int(faces_num * stride);
1064 for (i = 0; i < newPolys; i++) {
1065 uint eidx = new_edge_arr[i];
1066 uint pidx = edge_users[eidx];
1070 if (pidx >= faces_num) {
1082 &mesh->face_data, &result->face_data,
int(pidx),
int((faces_num * stride) + i), 1);
1084 const int old_face_size = orig_faces[pidx].
size();
1085 face_offsets[new_face_index] =
int(j + (loops_num * stride));
1088 k1 = face_offsets[pidx] + (((edge_order[eidx] - 1) + old_face_size) % old_face_size);
1090 k2 = face_offsets[pidx] + (edge_order[eidx]);
1093 &mesh->corner_data, &result->corner_data, k2,
int((loops_num * stride) + j + 0), 1);
1095 &mesh->corner_data, &result->corner_data, k1,
int((loops_num * stride) + j + 1), 1);
1097 &mesh->corner_data, &result->corner_data, k1,
int((loops_num * stride) + j + 2), 1);
1099 &mesh->corner_data, &result->corner_data, k2,
int((loops_num * stride) + j + 3), 1);
1101 if (flip ==
false) {
1102 new_corner_verts[j] = edge[0];
1103 new_corner_edges[j++] = eidx;
1105 new_corner_verts[j] = edge[1];
1106 new_corner_edges[j++] = (edges_num * stride) + old_vert_arr[edge[1]] + newEdges;
1108 new_corner_verts[j] = (do_shell ? edge[1] : old_vert_arr[edge[1]]) + verts_num;
1109 new_corner_edges[j++] = (do_shell ? eidx : i) + edges_num;
1111 new_corner_verts[j] = (do_shell ? edge[0] : old_vert_arr[edge[0]]) + verts_num;
1112 new_corner_edges[j++] = (edges_num * stride) + old_vert_arr[edge[0]] + newEdges;
1115 new_corner_verts[j] = edge[1];
1116 new_corner_edges[j++] = eidx;
1118 new_corner_verts[j] = edge[0];
1119 new_corner_edges[j++] = (edges_num * stride) + old_vert_arr[edge[0]] + newEdges;
1121 new_corner_verts[j] = (do_shell ? edge[0] : old_vert_arr[edge[0]]) + verts_num;
1122 new_corner_edges[j++] = (do_shell ? eidx : i) + edges_num;
1124 new_corner_verts[j] = (do_shell ? edge[1] : old_vert_arr[edge[1]]) + verts_num;
1125 new_corner_edges[j++] = (edges_num * stride) + old_vert_arr[edge[1]] + newEdges;
1128 if (origindex_edge) {
1135 dst_material_index.
span[new_face_index] += mat_ofs_rim;
1136 CLAMP(dst_material_index.
span[new_face_index], 0, mat_nr_max);
1140 float *cr = &(result_edge_crease[eidx]);
1141 float tcr = *cr + crease_outer;
1142 *cr = tcr > 1.0f ? 1.0f : tcr;
1147 float *cr = &(result_edge_crease[edges_num + (do_shell ? eidx : i)]);
1148 float tcr = *cr + crease_inner;
1149 *cr = tcr > 1.0f ? 1.0f : tcr;
1166 dst_material_index.
finish();