Blender V4.3
MOD_mask.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2005 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include "MEM_guardedalloc.h"
10
11#include "BLI_utildefines.h"
12
13#include "BLI_array_utils.hh"
14#include "BLI_listbase.h"
15
16#include "BLT_translation.hh"
17
18#include "DNA_armature_types.h"
19#include "DNA_defaults.h"
20#include "DNA_mesh_types.h"
21#include "DNA_meshdata_types.h"
22#include "DNA_modifier_types.h"
23#include "DNA_object_types.h"
24#include "DNA_screen_types.h"
25
26#include "BKE_action.hh" /* BKE_pose_channel_find_name */
27#include "BKE_customdata.hh"
28#include "BKE_deform.hh"
29#include "BKE_lib_query.hh"
30#include "BKE_mesh.hh"
31#include "BKE_modifier.hh"
32
33#include "UI_interface.hh"
34#include "UI_resources.hh"
35
36#include "RNA_access.hh"
37#include "RNA_prototypes.hh"
38
40
41#include "MOD_ui_common.hh"
42
43#include "BLI_array.hh"
45#include "BLI_vector.hh"
46
47using blender::Array;
48using blender::float3;
50using blender::int2;
53using blender::Span;
54using blender::Vector;
55
64
65static void required_data_mask(ModifierData * /*md*/, CustomData_MeshMasks *r_cddata_masks)
66{
67 r_cddata_masks->vmask |= CD_MASK_MDEFORMVERT;
68}
69
70static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
71{
72 MaskModifierData *mmd = reinterpret_cast<MaskModifierData *>(md);
73 walk(user_data, ob, (ID **)&mmd->ob_arm, IDWALK_CB_NOP);
74}
75
77{
78 MaskModifierData *mmd = reinterpret_cast<MaskModifierData *>(md);
79 if (mmd->ob_arm) {
80 bArmature *arm = (bArmature *)mmd->ob_arm->data;
81 /* Tag relationship in depsgraph, but also on the armature. */
82 /* TODO(sergey): Is it a proper relation here? */
83 DEG_add_object_relation(ctx->node, mmd->ob_arm, DEG_OB_COMP_TRANSFORM, "Mask Modifier");
84 arm->flag |= ARM_HAS_VIZ_DEPS;
85 DEG_add_depends_on_transform_relation(ctx->node, "Mask Modifier");
86 }
87}
88
89/* A vertex will be in the mask if a selected bone influences it more than a certain threshold. */
91 Mesh *mesh,
92 Object *armature_ob,
93 float threshold,
94 MutableSpan<bool> r_vertex_mask)
95{
96 /* Element i is true if there is a selected bone that uses vertex group i. */
97 Vector<bool> selected_bone_uses_group;
98
99 LISTBASE_FOREACH (bDeformGroup *, def, &mesh->vertex_group_names) {
100 bPoseChannel *pchan = BKE_pose_channel_find_name(armature_ob->pose, def->name);
101 bool bone_for_group_exists = pchan && pchan->bone && (pchan->bone->flag & BONE_SELECTED);
102 selected_bone_uses_group.append(bone_for_group_exists);
103 }
104 const int64_t total_size = selected_bone_uses_group.size();
105
106 for (int i : r_vertex_mask.index_range()) {
107 Span<MDeformWeight> weights(dvert[i].dw, dvert[i].totweight);
108 r_vertex_mask[i] = false;
109
110 /* check the groups that vertex is assigned to, and see if it was any use */
111 for (const MDeformWeight &dw : weights) {
112 if (dw.def_nr >= total_size) {
113 continue;
114 }
115 if (selected_bone_uses_group[dw.def_nr]) {
116 if (dw.weight > threshold) {
117 r_vertex_mask[i] = true;
118 break;
119 }
120 }
121 }
122 }
123}
124
125/* A vertex will be in the mask if the vertex group influences it more than a certain threshold. */
127 int defgrp_index,
128 float threshold,
129 MutableSpan<bool> r_vertex_mask)
130{
131 for (int i : r_vertex_mask.index_range()) {
132 const bool found = BKE_defvert_find_weight(&dvert[i], defgrp_index) > threshold;
133 r_vertex_mask[i] = found;
134 }
135}
136
137static void compute_masked_verts(Span<bool> vertex_mask,
138 MutableSpan<int> r_vertex_map,
139 uint *r_verts_masked_num)
140{
141 BLI_assert(vertex_mask.size() == r_vertex_map.size());
142
143 uint verts_masked_num = 0;
144 for (uint i_src : r_vertex_map.index_range()) {
145 if (vertex_mask[i_src]) {
146 r_vertex_map[i_src] = verts_masked_num;
147 verts_masked_num++;
148 }
149 else {
150 r_vertex_map[i_src] = -1;
151 }
152 }
153
154 *r_verts_masked_num = verts_masked_num;
155}
156
157static void computed_masked_edges(const Mesh *mesh,
158 Span<bool> vertex_mask,
159 MutableSpan<int> r_edge_map,
160 uint *r_edges_masked_num)
161{
162 BLI_assert(mesh->edges_num == r_edge_map.size());
163 const Span<int2> edges = mesh->edges();
164
165 uint edges_masked_num = 0;
166 for (int i : IndexRange(mesh->edges_num)) {
167 const int2 &edge = edges[i];
168
169 /* only add if both verts will be in new mesh */
170 if (vertex_mask[edge[0]] && vertex_mask[edge[1]]) {
171 r_edge_map[i] = edges_masked_num;
172 edges_masked_num++;
173 }
174 else {
175 r_edge_map[i] = -1;
176 }
177 }
178
179 *r_edges_masked_num = edges_masked_num;
180}
181
182static void computed_masked_edges_smooth(const Mesh *mesh,
183 Span<bool> vertex_mask,
184 MutableSpan<int> r_edge_map,
185 uint *r_edges_masked_num,
186 uint *r_verts_add_num)
187{
188 BLI_assert(mesh->edges_num == r_edge_map.size());
189 const Span<int2> edges = mesh->edges();
190
191 uint edges_masked_num = 0;
192 uint verts_add_num = 0;
193 for (int i : IndexRange(mesh->edges_num)) {
194 const int2 &edge = edges[i];
195
196 /* only add if both verts will be in new mesh */
197 bool v1 = vertex_mask[edge[0]];
198 bool v2 = vertex_mask[edge[1]];
199 if (v1 && v2) {
200 r_edge_map[i] = edges_masked_num;
201 edges_masked_num++;
202 }
203 else if (v1 != v2) {
204 r_edge_map[i] = -2;
205 verts_add_num++;
206 }
207 else {
208 r_edge_map[i] = -1;
209 }
210 }
211
212 edges_masked_num += verts_add_num;
213 *r_edges_masked_num = edges_masked_num;
214 *r_verts_add_num = verts_add_num;
215}
216
217static void computed_masked_faces(const Mesh *mesh,
218 Span<bool> vertex_mask,
219 Vector<int> &r_masked_face_indices,
220 Vector<int> &r_loop_starts,
221 uint *r_faces_masked_num,
222 uint *r_loops_masked_num)
223{
224 BLI_assert(mesh->verts_num == vertex_mask.size());
225 const blender::OffsetIndices faces = mesh->faces();
226 const Span<int> corner_verts = mesh->corner_verts();
227
228 r_masked_face_indices.reserve(mesh->faces_num);
229 r_loop_starts.reserve(mesh->faces_num);
230
231 uint loops_masked_num = 0;
232 for (int i : IndexRange(mesh->faces_num)) {
233 const blender::IndexRange face = faces[i];
234
235 bool all_verts_in_mask = true;
236 for (const int vert_i : corner_verts.slice(face)) {
237 if (!vertex_mask[vert_i]) {
238 all_verts_in_mask = false;
239 break;
240 }
241 }
242
243 if (all_verts_in_mask) {
244 r_masked_face_indices.append_unchecked(i);
245 r_loop_starts.append_unchecked(loops_masked_num);
246 loops_masked_num += face.size();
247 }
248 }
249
250 *r_faces_masked_num = r_masked_face_indices.size();
251 *r_loops_masked_num = loops_masked_num;
252}
253
254static void compute_interpolated_faces(const Mesh *mesh,
255 Span<bool> vertex_mask,
256 uint verts_add_num,
257 uint loops_masked_num,
258 Vector<int> &r_masked_face_indices,
259 Vector<int> &r_loop_starts,
260 uint *r_edges_add_num,
261 uint *r_faces_add_num,
262 uint *r_loops_add_num)
263{
264 BLI_assert(mesh->verts_num == vertex_mask.size());
265
266 /* Can't really know ahead of time how much space to use exactly. Estimate limit instead. */
267 /* NOTE: this reserve can only lift the capacity if there are ngons, which get split. */
268 r_masked_face_indices.reserve(r_masked_face_indices.size() + verts_add_num);
269 r_loop_starts.reserve(r_loop_starts.size() + verts_add_num);
270 const blender::OffsetIndices faces = mesh->faces();
271 const Span<int> corner_verts = mesh->corner_verts();
272
273 uint edges_add_num = 0;
274 uint faces_add_num = 0;
275 uint loops_add_num = 0;
276 for (int i : IndexRange(mesh->faces_num)) {
277 const blender::IndexRange face_src = faces[i];
278
279 int in_count = 0;
280 int start = -1;
281 int dst_totloop = -1;
282 const Span<int> face_verts_src = corner_verts.slice(face_src);
283 for (const int j : face_verts_src.index_range()) {
284 const int vert_i = face_verts_src[j];
285 if (vertex_mask[vert_i]) {
286 in_count++;
287 }
288 else if (start == -1) {
289 start = j;
290 }
291 }
292 if (0 < in_count && in_count < face_src.size()) {
293 /* Ring search starting at a vertex which is not included in the mask. */
294 int last_corner_vert = face_verts_src[start];
295 bool v_loop_in_mask_last = vertex_mask[last_corner_vert];
296 for (const int j : face_verts_src.index_range()) {
297 const int corner_vert = face_verts_src[(start + 1 + j) % face_src.size()];
298 const bool v_loop_in_mask = vertex_mask[corner_vert];
299 if (v_loop_in_mask && !v_loop_in_mask_last) {
300 dst_totloop = 3;
301 }
302 else if (!v_loop_in_mask && v_loop_in_mask_last) {
303 BLI_assert(dst_totloop > 2);
304 r_masked_face_indices.append(i);
305 r_loop_starts.append(loops_masked_num + loops_add_num);
306 loops_add_num += dst_totloop;
307 faces_add_num++;
308 edges_add_num++;
309 dst_totloop = -1;
310 }
311 else if (v_loop_in_mask && v_loop_in_mask_last) {
312 BLI_assert(dst_totloop > 2);
313 dst_totloop++;
314 }
315 last_corner_vert = corner_vert;
316 v_loop_in_mask_last = v_loop_in_mask;
317 }
318 }
319 }
320
321 *r_edges_add_num = edges_add_num;
322 *r_faces_add_num = faces_add_num;
323 *r_loops_add_num = loops_add_num;
324}
325
326static void copy_masked_verts_to_new_mesh(const Mesh &src_mesh,
327 Mesh &dst_mesh,
328 Span<int> vertex_map)
329{
330 BLI_assert(src_mesh.verts_num == vertex_map.size());
331 for (const int i_src : vertex_map.index_range()) {
332 const int i_dst = vertex_map[i_src];
333 if (i_dst == -1) {
334 continue;
335 }
336
337 CustomData_copy_data(&src_mesh.vert_data, &dst_mesh.vert_data, i_src, i_dst, 1);
338 }
339}
340
342 const MDeformVert *dvert, int defgrp_index, float threshold, uint v1, uint v2)
343{
344 /* NOTE: this calculation is done twice for every vertex,
345 * instead of storing it the first time and then reusing it. */
346 float value1 = BKE_defvert_find_weight(&dvert[v1], defgrp_index);
347 float value2 = BKE_defvert_find_weight(&dvert[v2], defgrp_index);
348 return (threshold - value1) / (value2 - value1);
349}
350
352 Mesh &dst_mesh,
353 Span<bool> vertex_mask,
354 Span<int> vertex_map,
355 const MDeformVert *dvert,
356 int defgrp_index,
357 float threshold,
358 uint edges_masked_num,
359 uint verts_add_num,
360 MutableSpan<int> r_edge_map)
361{
362 BLI_assert(src_mesh.verts_num == vertex_mask.size());
363 BLI_assert(src_mesh.edges_num == r_edge_map.size());
364 const Span<int2> src_edges = src_mesh.edges();
365 MutableSpan<int2> dst_edges = dst_mesh.edges_for_write();
366
367 uint vert_index = dst_mesh.verts_num - verts_add_num;
368 uint edge_index = edges_masked_num - verts_add_num;
369 for (int i_src : IndexRange(src_mesh.edges_num)) {
370 if (r_edge_map[i_src] != -1) {
371 int i_dst = r_edge_map[i_src];
372 if (i_dst == -2) {
373 i_dst = edge_index;
374 }
375 const int2 &e_src = src_edges[i_src];
376 int2 &e_dst = dst_edges[i_dst];
377
378 CustomData_copy_data(&src_mesh.edge_data, &dst_mesh.edge_data, i_src, i_dst, 1);
379 e_dst = e_src;
380 e_dst[0] = vertex_map[e_src[0]];
381 e_dst[1] = vertex_map[e_src[1]];
382 }
383 if (r_edge_map[i_src] == -2) {
384 const int i_dst = edge_index++;
385 r_edge_map[i_src] = i_dst;
386 const int2 &e_src = src_edges[i_src];
387 /* Cut destination edge and make v1 the new vertex. */
388 int2 &e_dst = dst_edges[i_dst];
389 if (!vertex_mask[e_src[0]]) {
390 e_dst[0] = vert_index;
391 }
392 else {
393 BLI_assert(!vertex_mask[e_src[1]]);
394 e_dst[1] = e_dst[0];
395 e_dst[0] = vert_index;
396 }
397 /* Create the new vertex. */
399 dvert, defgrp_index, threshold, e_src[0], e_src[1]);
400
401 float weights[2] = {1.0f - fac, fac};
403 &dst_mesh.vert_data,
404 (int *)&e_src[0],
405 weights,
406 nullptr,
407 2,
408 vert_index);
409 vert_index++;
410 }
411 }
412 BLI_assert(vert_index == dst_mesh.verts_num);
413 BLI_assert(edge_index == edges_masked_num);
414}
415
416static void copy_masked_edges_to_new_mesh(const Mesh &src_mesh,
417 Mesh &dst_mesh,
418 Span<int> vertex_map,
419 Span<int> edge_map)
420{
421 const Span<int2> src_edges = src_mesh.edges();
422 MutableSpan<int2> dst_edges = dst_mesh.edges_for_write();
423
424 BLI_assert(src_mesh.verts_num == vertex_map.size());
425 BLI_assert(src_mesh.edges_num == edge_map.size());
426 for (const int i_src : IndexRange(src_mesh.edges_num)) {
427 const int i_dst = edge_map[i_src];
428 if (ELEM(i_dst, -1, -2)) {
429 continue;
430 }
431
432 CustomData_copy_data(&src_mesh.edge_data, &dst_mesh.edge_data, i_src, i_dst, 1);
433 dst_edges[i_dst][0] = vertex_map[src_edges[i_src][0]];
434 dst_edges[i_dst][1] = vertex_map[src_edges[i_src][1]];
435 }
436}
437
438static void copy_masked_faces_to_new_mesh(const Mesh &src_mesh,
439 Mesh &dst_mesh,
440 Span<int> vertex_map,
441 Span<int> edge_map,
442 Span<int> masked_face_indices,
443 Span<int> new_loop_starts,
444 int faces_masked_num)
445{
446 const blender::OffsetIndices src_faces = src_mesh.faces();
447 MutableSpan<int> dst_face_offsets = dst_mesh.face_offsets_for_write();
448 const Span<int> src_corner_verts = src_mesh.corner_verts();
449 const Span<int> src_corner_edges = src_mesh.corner_edges();
450 MutableSpan<int> dst_corner_verts = dst_mesh.corner_verts_for_write();
451 MutableSpan<int> dst_corner_edges = dst_mesh.corner_edges_for_write();
452
453 for (const int i_dst : IndexRange(faces_masked_num)) {
454 const int i_src = masked_face_indices[i_dst];
455 const blender::IndexRange src_face = src_faces[i_src];
456
457 dst_face_offsets[i_dst] = new_loop_starts[i_dst];
458
459 CustomData_copy_data(&src_mesh.face_data, &dst_mesh.face_data, i_src, i_dst, 1);
461 &dst_mesh.corner_data,
462 src_face.start(),
463 dst_face_offsets[i_dst],
464 src_face.size());
465
466 for (int i : IndexRange(src_face.size())) {
467 dst_corner_verts[new_loop_starts[i_dst] + i] = vertex_map[src_corner_verts[src_face[i]]];
468 dst_corner_edges[new_loop_starts[i_dst] + i] = edge_map[src_corner_edges[src_face[i]]];
469 }
470 }
471}
472
473static void add_interpolated_faces_to_new_mesh(const Mesh &src_mesh,
474 Mesh &dst_mesh,
475 Span<bool> vertex_mask,
476 Span<int> vertex_map,
477 Span<int> edge_map,
478 const MDeformVert *dvert,
479 int defgrp_index,
480 float threshold,
481 Span<int> masked_face_indices,
482 Span<int> new_loop_starts,
483 int faces_masked_num,
484 int edges_add_num)
485{
486 const blender::OffsetIndices src_faces = src_mesh.faces();
487 MutableSpan<int> dst_face_offsets = dst_mesh.face_offsets_for_write();
488 MutableSpan<int2> dst_edges = dst_mesh.edges_for_write();
489 const Span<int> src_corner_verts = src_mesh.corner_verts();
490 const Span<int> src_corner_edges = src_mesh.corner_edges();
491 MutableSpan<int> dst_corner_verts = dst_mesh.corner_verts_for_write();
492 MutableSpan<int> dst_corner_edges = dst_mesh.corner_edges_for_write();
493
494 int edge_index = dst_mesh.edges_num - edges_add_num;
495 int sub_face_index = 0;
496 int last_i_src = -1;
497 for (const int i_dst :
498 IndexRange(faces_masked_num, masked_face_indices.size() - faces_masked_num))
499 {
500 const int i_src = masked_face_indices[i_dst];
501 if (i_src == last_i_src) {
502 sub_face_index++;
503 }
504 else {
505 sub_face_index = 0;
506 last_i_src = i_src;
507 }
508
509 const blender::IndexRange src_face = src_faces[i_src];
510 const int i_ml_src = src_face.start();
511 int i_ml_dst = new_loop_starts[i_dst];
512 CustomData_copy_data(&src_mesh.face_data, &dst_mesh.face_data, i_src, i_dst, 1);
513
514 dst_face_offsets[i_dst] = i_ml_dst;
515
516 /* Ring search starting at a vertex which is not included in the mask. */
517 int start = -sub_face_index - 1;
518 bool skip = false;
519 const Span<int> face_verts_src = src_corner_verts.slice(src_face);
520 const Span<int> face_edges_src = src_corner_edges.slice(src_face);
521 for (const int j : face_verts_src.index_range()) {
522 if (!vertex_mask[face_verts_src[j]]) {
523 if (start == -1) {
524 start = j;
525 break;
526 }
527 if (!skip) {
528 skip = true;
529 }
530 }
531 else if (skip) {
532 skip = false;
533 start++;
534 }
535 }
536
537 BLI_assert(start >= 0);
538 BLI_assert(edge_index < dst_mesh.edges_num);
539
540 int last_index = start;
541 bool v_loop_in_mask_last = vertex_mask[face_verts_src[last_index]];
542 for (const int j : face_verts_src.index_range()) {
543 const int index = (start + 1 + j) % src_face.size();
544 const bool v_loop_in_mask = vertex_mask[face_verts_src[index]];
545 if (v_loop_in_mask && !v_loop_in_mask_last) {
546 /* Start new cut. */
548 dvert, defgrp_index, threshold, face_verts_src[last_index], face_verts_src[index]);
549 float weights[2] = {1.0f - fac, fac};
550 int indices[2] = {i_ml_src + last_index, i_ml_src + index};
552 &src_mesh.corner_data, &dst_mesh.corner_data, indices, weights, nullptr, 2, i_ml_dst);
553 dst_corner_edges[i_ml_dst] = edge_map[face_edges_src[last_index]];
554 dst_corner_verts[i_ml_dst] = dst_edges[dst_corner_edges[i_ml_dst]][0];
555 i_ml_dst++;
556
558 &src_mesh.corner_data, &dst_mesh.corner_data, i_ml_src + index, i_ml_dst, 1);
559 dst_corner_verts[i_ml_dst] = vertex_map[face_verts_src[index]];
560 dst_corner_edges[i_ml_dst] = edge_map[face_edges_src[index]];
561 i_ml_dst++;
562 }
563 else if (!v_loop_in_mask && v_loop_in_mask_last) {
564 BLI_assert(i_ml_dst != dst_face_offsets[i_dst]);
565 /* End active cut. */
567 dvert, defgrp_index, threshold, face_verts_src[last_index], face_verts_src[index]);
568 float weights[2] = {1.0f - fac, fac};
569 int indices[2] = {i_ml_src + last_index, i_ml_src + index};
571 &src_mesh.corner_data, &dst_mesh.corner_data, indices, weights, nullptr, 2, i_ml_dst);
572 dst_corner_edges[i_ml_dst] = edge_index;
573 dst_corner_verts[i_ml_dst] = dst_edges[edge_map[face_edges_src[last_index]]][0];
574
575 /* Create closing edge. */
576 int2 &cut_edge = dst_edges[edge_index];
577 cut_edge[0] = dst_corner_verts[dst_face_offsets[i_dst]];
578 cut_edge[1] = dst_corner_verts[i_ml_dst];
579 BLI_assert(cut_edge[0] != cut_edge[1]);
580 edge_index++;
581 i_ml_dst++;
582
583 /* Only handle one of the cuts per iteration. */
584 break;
585 }
586 else if (v_loop_in_mask && v_loop_in_mask_last) {
587 BLI_assert(i_ml_dst != dst_face_offsets[i_dst]);
588 /* Extend active face. */
590 &src_mesh.corner_data, &dst_mesh.corner_data, i_ml_src + index, i_ml_dst, 1);
591 dst_corner_verts[i_ml_dst] = vertex_map[face_verts_src[index]];
592 dst_corner_edges[i_ml_dst] = edge_map[face_edges_src[index]];
593 i_ml_dst++;
594 }
595 last_index = index;
596 v_loop_in_mask_last = v_loop_in_mask;
597 }
598 }
599 BLI_assert(edge_index == dst_mesh.edges_num);
600}
601
602/* Components of the algorithm:
603 * 1. Figure out which vertices should be present in the output mesh.
604 * 2. Find edges and faces only using those vertices.
605 * 3. Create a new mesh that only uses the found vertices, edges and faces.
606 */
607static Mesh *modify_mesh(ModifierData *md, const ModifierEvalContext * /*ctx*/, Mesh *mesh)
608{
609 MaskModifierData *mmd = reinterpret_cast<MaskModifierData *>(md);
610 const bool invert_mask = mmd->flag & MOD_MASK_INV;
611 const bool use_interpolation = mmd->mode == MOD_MASK_MODE_VGROUP &&
612 (mmd->flag & MOD_MASK_SMOOTH);
613
614 /* Return empty or input mesh when there are no vertex groups. */
615 const Span<MDeformVert> dverts = mesh->deform_verts();
616 if (dverts.is_empty()) {
617 return invert_mask ? mesh : BKE_mesh_new_nomain_from_template(mesh, 0, 0, 0, 0);
618 }
619
620 /* Quick test to see if we can return early. */
621 if (!ELEM(mmd->mode, MOD_MASK_MODE_ARM, MOD_MASK_MODE_VGROUP) || (mesh->verts_num == 0) ||
622 BLI_listbase_is_empty(&mesh->vertex_group_names))
623 {
624 return mesh;
625 }
626
627 int defgrp_index = -1;
628
629 Array<bool> vertex_mask;
630 if (mmd->mode == MOD_MASK_MODE_ARM) {
631 Object *armature_ob = mmd->ob_arm;
632
633 /* Return input mesh if there is no armature with bones. */
634 if (ELEM(nullptr, armature_ob, armature_ob->pose)) {
635 return mesh;
636 }
637
638 vertex_mask = Array<bool>(mesh->verts_num);
640 dverts.data(), mesh, armature_ob, mmd->threshold, vertex_mask);
641 }
642 else {
644 defgrp_index = BKE_id_defgroup_name_index(&mesh->id, mmd->vgroup);
645
646 /* Return input mesh if the vertex group does not exist. */
647 if (defgrp_index == -1) {
648 return mesh;
649 }
650
651 vertex_mask = Array<bool>(mesh->verts_num);
653 dverts.data(), defgrp_index, mmd->threshold, vertex_mask);
654 }
655
656 if (invert_mask) {
658 }
659
660 Array<int> vertex_map(mesh->verts_num);
661 uint verts_masked_num;
662 compute_masked_verts(vertex_mask, vertex_map, &verts_masked_num);
663
664 Array<int> edge_map(mesh->edges_num);
665 uint edges_masked_num;
666 uint verts_add_num;
667 if (use_interpolation) {
668 computed_masked_edges_smooth(mesh, vertex_mask, edge_map, &edges_masked_num, &verts_add_num);
669 }
670 else {
671 computed_masked_edges(mesh, vertex_mask, edge_map, &edges_masked_num);
672 verts_add_num = 0;
673 }
674
675 Vector<int> masked_face_indices;
676 Vector<int> new_loop_starts;
677 uint faces_masked_num;
678 uint loops_masked_num;
680 vertex_mask,
681 masked_face_indices,
682 new_loop_starts,
683 &faces_masked_num,
684 &loops_masked_num);
685
686 uint edges_add_num = 0;
687 uint faces_add_num = 0;
688 uint loops_add_num = 0;
689 if (use_interpolation) {
691 vertex_mask,
692 verts_add_num,
693 loops_masked_num,
694 masked_face_indices,
695 new_loop_starts,
696 &edges_add_num,
697 &faces_add_num,
698 &loops_add_num);
699 }
700
702 verts_masked_num + verts_add_num,
703 edges_masked_num + edges_add_num,
704 faces_masked_num + faces_add_num,
705 loops_masked_num + loops_add_num);
706
707 copy_masked_verts_to_new_mesh(*mesh, *result, vertex_map);
708 if (use_interpolation) {
710 *result,
711 vertex_mask,
712 vertex_map,
713 dverts.data(),
714 defgrp_index,
715 mmd->threshold,
716 edges_masked_num,
717 verts_add_num,
718 edge_map);
719 }
720 else {
721 copy_masked_edges_to_new_mesh(*mesh, *result, vertex_map, edge_map);
722 }
724 *result,
725 vertex_map,
726 edge_map,
727 masked_face_indices,
728 new_loop_starts,
729 faces_masked_num);
730 if (use_interpolation) {
732 *result,
733 vertex_mask,
734 vertex_map,
735 edge_map,
736 dverts.data(),
737 defgrp_index,
738 mmd->threshold,
739 masked_face_indices,
740 new_loop_starts,
741 faces_masked_num,
742 edges_add_num);
743 }
744
745 return result;
746}
747
748static bool is_disabled(const Scene * /*scene*/, ModifierData *md, bool /*use_render_params*/)
749{
750 MaskModifierData *mmd = reinterpret_cast<MaskModifierData *>(md);
751
752 /* The object type check is only needed here in case we have a placeholder
753 * object assigned (because the library containing the armature is missing).
754 *
755 * In other cases it should be impossible to have a type mismatch.
756 */
757 return mmd->ob_arm && mmd->ob_arm->type != OB_ARMATURE;
758}
759
760static void panel_draw(const bContext * /*C*/, Panel *panel)
761{
762 uiLayout *sub, *row;
763 uiLayout *layout = panel->layout;
764
765 PointerRNA ob_ptr;
767
768 int mode = RNA_enum_get(ptr, "mode");
769
770 uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
771
772 uiLayoutSetPropSep(layout, true);
773
774 if (mode == MOD_MASK_MODE_ARM) {
775 row = uiLayoutRow(layout, true);
776 uiItemR(row, ptr, "armature", UI_ITEM_NONE, nullptr, ICON_NONE);
777 sub = uiLayoutRow(row, true);
778 uiLayoutSetPropDecorate(sub, false);
779 uiItemR(sub, ptr, "invert_vertex_group", UI_ITEM_NONE, "", ICON_ARROW_LEFTRIGHT);
780 }
781 else if (mode == MOD_MASK_MODE_VGROUP) {
782 modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", nullptr);
783 uiItemR(layout, ptr, "use_smooth", UI_ITEM_NONE, nullptr, ICON_NONE);
784 }
785
786 uiItemR(layout, ptr, "threshold", UI_ITEM_NONE, nullptr, ICON_NONE);
787
788 modifier_panel_end(layout, ptr);
789}
790
791static void panel_register(ARegionType *region_type)
792{
794}
795
797 /*idname*/ "Mask",
798 /*name*/ N_("Mask"),
799 /*struct_name*/ "MaskModifierData",
800 /*struct_size*/ sizeof(MaskModifierData),
801 /*srna*/ &RNA_MaskModifier,
803 /*flags*/
806 /*icon*/ ICON_MOD_MASK,
807
808 /*copy_data*/ BKE_modifier_copydata_generic,
809
810 /*deform_verts*/ nullptr,
811 /*deform_matrices*/ nullptr,
812 /*deform_verts_EM*/ nullptr,
813 /*deform_matrices_EM*/ nullptr,
814 /*modify_mesh*/ modify_mesh,
815 /*modify_geometry_set*/ nullptr,
816
817 /*init_data*/ init_data,
818 /*required_data_mask*/ required_data_mask,
819 /*free_data*/ nullptr,
820 /*is_disabled*/ is_disabled,
821 /*update_depsgraph*/ update_depsgraph,
822 /*depends_on_time*/ nullptr,
823 /*depends_on_normals*/ nullptr,
824 /*foreach_ID_link*/ foreach_ID_link,
825 /*foreach_tex_link*/ nullptr,
826 /*free_runtime_data*/ nullptr,
827 /*panel_register*/ panel_register,
828 /*blend_write*/ nullptr,
829 /*blend_read*/ nullptr,
830 /*foreach_cache*/ nullptr,
831};
Blender kernel action and pose functionality.
bPoseChannel * BKE_pose_channel_find_name(const bPose *pose, const char *name)
CustomData interface, see also DNA_customdata_types.h.
void CustomData_interp(const CustomData *source, CustomData *dest, const int *src_indices, const float *weights, const float *sub_weights, int count, int dest_index)
void CustomData_copy_data(const CustomData *source, CustomData *dest, int source_index, int dest_index, int count)
support for deformation groups and hooks.
int BKE_id_defgroup_name_index(const ID *id, blender::StringRef name)
Definition deform.cc:543
float BKE_defvert_find_weight(const MDeformVert *dvert, int defgroup)
Definition deform.cc:770
@ IDWALK_CB_NOP
Mesh * BKE_mesh_new_nomain_from_template(const Mesh *me_src, int verts_num, int edges_num, int faces_num, int corners_num)
void BKE_modifier_copydata_generic(const ModifierData *md, ModifierData *md_dst, int flag)
ModifierTypeFlag
@ eModifierTypeFlag_SupportsMapping
@ eModifierTypeFlag_SupportsEditmode
@ eModifierTypeFlag_AcceptsMesh
void(*)(void *user_data, Object *ob, ID **idpoin, int cb_flag) IDWalkFunc
#define BLI_assert(a)
Definition BLI_assert.h:50
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
#define LISTBASE_FOREACH(type, var, list)
unsigned int uint
#define ELEM(...)
#define MEMCMP_STRUCT_AFTER_IS_ZERO(struct_var, member)
#define MEMCPY_STRUCT_AFTER(struct_dst, struct_src, member)
void DEG_add_depends_on_transform_relation(DepsNodeHandle *node_handle, const char *description)
void DEG_add_object_relation(DepsNodeHandle *node_handle, Object *object, eDepsObjectComponentType component, const char *description)
@ DEG_OB_COMP_TRANSFORM
@ BONE_SELECTED
@ ARM_HAS_VIZ_DEPS
#define CD_MASK_MDEFORMVERT
#define DNA_struct_default_get(struct_name)
struct MaskModifierData MaskModifierData
@ eModifierType_Mask
@ MOD_MASK_MODE_ARM
@ MOD_MASK_MODE_VGROUP
@ MOD_MASK_SMOOTH
@ MOD_MASK_INV
Object is a sort of wrapper for general info.
@ OB_ARMATURE
static bool is_disabled
Read Guarded memory(de)allocation.
static void init_data(ModifierData *md)
Definition MOD_mask.cc:56
static void panel_register(ARegionType *region_type)
Definition MOD_mask.cc:791
static float get_interp_factor_from_vgroup(const MDeformVert *dvert, int defgrp_index, float threshold, uint v1, uint v2)
Definition MOD_mask.cc:341
static void add_interp_verts_copy_edges_to_new_mesh(const Mesh &src_mesh, Mesh &dst_mesh, Span< bool > vertex_mask, Span< int > vertex_map, const MDeformVert *dvert, int defgrp_index, float threshold, uint edges_masked_num, uint verts_add_num, MutableSpan< int > r_edge_map)
Definition MOD_mask.cc:351
static void required_data_mask(ModifierData *, CustomData_MeshMasks *r_cddata_masks)
Definition MOD_mask.cc:65
static void copy_masked_faces_to_new_mesh(const Mesh &src_mesh, Mesh &dst_mesh, Span< int > vertex_map, Span< int > edge_map, Span< int > masked_face_indices, Span< int > new_loop_starts, int faces_masked_num)
Definition MOD_mask.cc:438
static void computed_masked_faces(const Mesh *mesh, Span< bool > vertex_mask, Vector< int > &r_masked_face_indices, Vector< int > &r_loop_starts, uint *r_faces_masked_num, uint *r_loops_masked_num)
Definition MOD_mask.cc:217
static void add_interpolated_faces_to_new_mesh(const Mesh &src_mesh, Mesh &dst_mesh, Span< bool > vertex_mask, Span< int > vertex_map, Span< int > edge_map, const MDeformVert *dvert, int defgrp_index, float threshold, Span< int > masked_face_indices, Span< int > new_loop_starts, int faces_masked_num, int edges_add_num)
Definition MOD_mask.cc:473
static void computed_masked_edges(const Mesh *mesh, Span< bool > vertex_mask, MutableSpan< int > r_edge_map, uint *r_edges_masked_num)
Definition MOD_mask.cc:157
static Mesh * modify_mesh(ModifierData *md, const ModifierEvalContext *, Mesh *mesh)
Definition MOD_mask.cc:607
static void copy_masked_edges_to_new_mesh(const Mesh &src_mesh, Mesh &dst_mesh, Span< int > vertex_map, Span< int > edge_map)
Definition MOD_mask.cc:416
static void compute_masked_verts(Span< bool > vertex_mask, MutableSpan< int > r_vertex_map, uint *r_verts_masked_num)
Definition MOD_mask.cc:137
static void panel_draw(const bContext *, Panel *panel)
Definition MOD_mask.cc:760
static void copy_masked_verts_to_new_mesh(const Mesh &src_mesh, Mesh &dst_mesh, Span< int > vertex_map)
Definition MOD_mask.cc:326
static void compute_interpolated_faces(const Mesh *mesh, Span< bool > vertex_mask, uint verts_add_num, uint loops_masked_num, Vector< int > &r_masked_face_indices, Vector< int > &r_loop_starts, uint *r_edges_add_num, uint *r_faces_add_num, uint *r_loops_add_num)
Definition MOD_mask.cc:254
static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
Definition MOD_mask.cc:70
static void compute_vertex_mask__armature_mode(const MDeformVert *dvert, Mesh *mesh, Object *armature_ob, float threshold, MutableSpan< bool > r_vertex_mask)
Definition MOD_mask.cc:90
static void compute_vertex_mask__vertex_group_mode(const MDeformVert *dvert, int defgrp_index, float threshold, MutableSpan< bool > r_vertex_mask)
Definition MOD_mask.cc:126
static void update_depsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
Definition MOD_mask.cc:76
ModifierTypeInfo modifierType_Mask
Definition MOD_mask.cc:796
static void computed_masked_edges_smooth(const Mesh *mesh, Span< bool > vertex_mask, MutableSpan< int > r_edge_map, uint *r_edges_masked_num, uint *r_verts_add_num)
Definition MOD_mask.cc:182
void modifier_panel_end(uiLayout *layout, PointerRNA *ptr)
PanelType * modifier_panel_register(ARegionType *region_type, ModifierType type, PanelDrawFn draw)
PointerRNA * modifier_panel_get_property_pointers(Panel *panel, PointerRNA *r_ob_ptr)
void modifier_vgroup_ui(uiLayout *layout, PointerRNA *ptr, PointerRNA *ob_ptr, const char *vgroup_prop, const char *invert_vgroup_prop, const char *text)
uiLayout * uiLayoutRow(uiLayout *layout, bool align)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
#define UI_ITEM_NONE
void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep)
void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, eUI_Item_Flag flag, const char *name, int icon)
@ UI_ITEM_R_EXPAND
ATTR_WARN_UNUSED_RESULT const BMVert * v2
const T * data() const
Definition BLI_array.hh:301
constexpr int64_t size() const
constexpr int64_t start() const
constexpr int64_t size() const
Definition BLI_span.hh:494
constexpr IndexRange index_range() const
Definition BLI_span.hh:671
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:138
constexpr int64_t size() const
Definition BLI_span.hh:253
constexpr IndexRange index_range() const
Definition BLI_span.hh:402
int64_t size() const
void append(const T &value)
void append_unchecked(const T &value)
void reserve(const int64_t min_capacity)
void invert_booleans(MutableSpan< bool > span)
int RNA_enum_get(PointerRNA *ptr, const char *name)
__int64 int64_t
Definition stdint.h:89
Definition DNA_ID.h:413
struct Object * ob_arm
CustomData edge_data
int edges_num
CustomData corner_data
CustomData face_data
CustomData vert_data
int verts_num
struct bPose * pose
struct uiLayout * layout
struct Bone * bone
#define N_(msgid)
PointerRNA * ptr
Definition wm_files.cc:4126