Animation: Add "Select Linked Vertices" to Weight Paint Mode

Adds two operators to select linked  vertices in weight paint mode.
Similar to how it works in edit mode.
Press "L" to select vertices under the cursor,
or CTRL + "L" to select anything linked to the current selection.

Reviewed by: Sybren A. Stüvel, Hans Goudey, Marion Stalke
Differential Revision: https://developer.blender.org/D16848
Ref: D16848
This commit is contained in:
Christoph Lendenfeld 2023-02-02 16:16:14 +01:00
parent fe5d54d3d0
commit 04aab7d516
Notes: blender-bot 2023-02-14 11:21:43 +01:00
Referenced by issue #99113, Add Selection functionality to weight painting mode
8 changed files with 157 additions and 1 deletions

View File

@ -4421,6 +4421,11 @@ def km_weight_paint_vertex_selection(params):
("view3d.select_lasso", {"type": params.action_mouse, "value": 'CLICK_DRAG', "shift": True, "ctrl": True},
{"properties": [("mode", 'SUB')]}),
("view3d.select_circle", {"type": 'C', "value": 'PRESS'}, None),
("paint.vert_select_linked", {"type": 'L', "value": 'PRESS', "ctrl": True}, None),
("paint.vert_select_linked_pick", {"type": 'L', "value": 'PRESS'},
{"properties": [("select", True)]}),
("paint.vert_select_linked_pick", {"type": 'L', "value": 'PRESS', "shift": True},
{"properties": [("select", False)]}),
])
return keymap

View File

@ -2972,6 +2972,11 @@ def km_weight_paint_vertex_selection(params):
("paint.vert_select_hide", {"type": 'H', "value": 'PRESS', "shift": True},
{"properties": [("unselected", True)]}),
("paint.face_vert_reveal", {"type": 'H', "value": 'PRESS', "alt": True}, None),
("paint.vert_select_linked", {"type": 'L', "value": 'PRESS', "ctrl": True}, None),
("paint.vert_select_linked_pick", {"type": 'L', "value": 'PRESS'},
{"properties": [("select", True)]}),
("paint.vert_select_linked_pick", {"type": 'L', "value": 'PRESS', "shift": True},
{"properties": [("select", False)]}),
])
return keymap

View File

@ -2038,6 +2038,7 @@ class VIEW3D_MT_select_paint_mask_vertex(Menu):
layout.separator()
layout.operator("paint.vert_select_ungrouped", text="Ungrouped Vertices")
layout.operator("paint.vert_select_linked", text="Select Linked")
class VIEW3D_MT_select_edit_curves(Menu):

View File

@ -437,7 +437,13 @@ void paintvert_select_ungrouped(struct Object *ob, bool extend, bool flush_flags
*/
void paintvert_flush_flags(struct Object *ob);
void paintvert_tag_select_update(struct bContext *C, struct Object *ob);
/* Select vertices that are connected to already selected vertices. */
void paintvert_select_linked(struct bContext *C, struct Object *ob);
/* Select vertices that are linked to the vertex under the given region space coordinates. */
void paintvert_select_linked_pick(struct bContext *C,
struct Object *ob,
const int region_coordinates[2],
bool select);
void paintvert_hide(struct bContext *C, struct Object *ob, bool unselected);
void paintvert_reveal(struct bContext *C, struct Object *ob, bool select);

View File

@ -6,9 +6,11 @@
#include "MEM_guardedalloc.h"
#include "BLI_atomic_disjoint_set.hh"
#include "BLI_bitmap.h"
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_task.hh"
#include "IMB_imbuf.h"
#include "IMB_imbuf_types.h"
@ -536,6 +538,92 @@ void paintvert_flush_flags(Object *ob)
BKE_mesh_batch_cache_dirty_tag(me, BKE_MESH_BATCH_DIRTY_ALL);
}
static void paintvert_select_linked_vertices(bContext *C,
Object *ob,
const blender::Span<int> vertex_indices,
const bool select)
{
using namespace blender;
Mesh *mesh = BKE_mesh_from_object(ob);
if (mesh == nullptr || mesh->totpoly == 0) {
return;
}
/* AtomicDisjointSet is used to store connection information in vertex indices. */
AtomicDisjointSet islands(mesh->totvert);
const Span<MEdge> edges = mesh->edges();
/* By calling join() on the vertices of all edges, the AtomicDisjointSet contains information on
* which parts of the mesh are connected. */
threading::parallel_for(edges.index_range(), 1024, [&](const IndexRange range) {
for (const MEdge &edge : edges.slice(range)) {
islands.join(edge.v1, edge.v2);
}
});
bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
bke::SpanAttributeWriter<bool> select_vert = attributes.lookup_or_add_for_write_span<bool>(
".select_vert", ATTR_DOMAIN_POINT);
Set<int> selected_roots;
for (const int i : vertex_indices) {
const int root = islands.find_root(i);
selected_roots.add(root);
}
threading::parallel_for(select_vert.span.index_range(), 1024, [&](const IndexRange range) {
for (const int i : range) {
const int root = islands.find_root(i);
if (selected_roots.contains(root)) {
select_vert.span[i] = select;
}
}
});
select_vert.finish();
paintvert_flush_flags(ob);
paintvert_tag_select_update(C, ob);
}
void paintvert_select_linked_pick(bContext *C,
Object *ob,
const int region_coordinates[2],
const bool select)
{
uint index = uint(-1);
if (!ED_mesh_pick_vert(
C, ob, region_coordinates, ED_MESH_PICK_DEFAULT_VERT_DIST, true, &index)) {
return;
}
paintvert_select_linked_vertices(C, ob, {int(index)}, select);
}
void paintvert_select_linked(bContext *C, Object *ob)
{
Mesh *mesh = BKE_mesh_from_object(ob);
if (mesh == nullptr || mesh->totpoly == 0) {
return;
}
blender::bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
blender::bke::SpanAttributeWriter<bool> select_vert =
attributes.lookup_or_add_for_write_span<bool>(".select_vert", ATTR_DOMAIN_POINT);
blender::Vector<int> indices;
for (const int i : select_vert.span.index_range()) {
if (!select_vert.span[i]) {
continue;
}
indices.append(i);
}
select_vert.finish();
paintvert_select_linked_vertices(C, ob, indices, true);
}
void paintvert_tag_select_update(bContext *C, Object *ob)
{
DEG_id_tag_update(static_cast<ID *>(ob->data), ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT);

View File

@ -383,6 +383,8 @@ void PAINT_OT_face_vert_reveal(struct wmOperatorType *ot);
void PAINT_OT_vert_select_all(struct wmOperatorType *ot);
void PAINT_OT_vert_select_ungrouped(struct wmOperatorType *ot);
void PAINT_OT_vert_select_hide(struct wmOperatorType *ot);
void PAINT_OT_vert_select_linked(struct wmOperatorType *ot);
void PAINT_OT_vert_select_linked_pick(struct wmOperatorType *ot);
bool vert_paint_poll(struct bContext *C);
bool mask_paint_poll(struct bContext *C);

View File

@ -1457,6 +1457,8 @@ void ED_operatortypes_paint(void)
WM_operatortype_append(PAINT_OT_vert_select_all);
WM_operatortype_append(PAINT_OT_vert_select_ungrouped);
WM_operatortype_append(PAINT_OT_vert_select_hide);
WM_operatortype_append(PAINT_OT_vert_select_linked);
WM_operatortype_append(PAINT_OT_vert_select_linked_pick);
/* vertex */
WM_operatortype_append(PAINT_OT_vertex_paint_toggle);

View File

@ -733,6 +733,53 @@ void PAINT_OT_vert_select_ungrouped(wmOperatorType *ot)
RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
}
static int paintvert_select_linked_exec(bContext *C, wmOperator *UNUSED(op))
{
paintvert_select_linked(C, CTX_data_active_object(C));
ED_region_tag_redraw(CTX_wm_region(C));
return OPERATOR_FINISHED;
}
void PAINT_OT_vert_select_linked(wmOperatorType *ot)
{
ot->name = "Select Linked Vertices";
ot->description = "Select linked vertices";
ot->idname = "PAINT_OT_vert_select_linked";
ot->exec = paintvert_select_linked_exec;
ot->poll = vert_paint_poll;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
static int paintvert_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
const bool select = RNA_boolean_get(op->ptr, "select");
view3d_operator_needs_opengl(C);
paintvert_select_linked_pick(C, CTX_data_active_object(C), event->mval, select);
ED_region_tag_redraw(CTX_wm_region(C));
return OPERATOR_FINISHED;
}
void PAINT_OT_vert_select_linked_pick(wmOperatorType *ot)
{
ot->name = "Select Linked Vertices Pick";
ot->description = "Select linked vertices under the cursor";
ot->idname = "PAINT_OT_vert_select_linked_pick";
ot->invoke = paintvert_select_linked_pick_invoke;
ot->poll = vert_paint_poll;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_boolean(ot->srna,
"select",
true,
"Select",
"Whether to select or deselect linked vertices under the cursor");
}
static int face_select_hide_exec(bContext *C, wmOperator *op)
{
const bool unselected = RNA_boolean_get(op->ptr, "unselected");