Animation: Weight Paint select more/less for vertices #105633

Merged
Christoph Lendenfeld merged 14 commits from ChrisLend/blender:weight_paint_grow_sel_vert into main 2023-03-31 14:48:09 +02:00
7 changed files with 198 additions and 0 deletions

View File

@ -4437,6 +4437,8 @@ def km_weight_paint_vertex_selection(params):
{"properties": [("select", True)]}),
("paint.vert_select_linked_pick", {"type": 'L', "value": 'PRESS', "shift": True},
{"properties": [("select", False)]}),
("paint.vert_select_more", {"type": 'NUMPAD_PLUS', "value": 'PRESS', "ctrl": True}, None),
("paint.vert_select_less", {"type": 'NUMPAD_MINUS', "value": 'PRESS', "ctrl": True}, None),
])
return keymap

View File

@ -2032,6 +2032,9 @@ class VIEW3D_MT_select_paint_mask_vertex(Menu):
layout.operator("paint.vert_select_all", text="None").action = 'DESELECT'
layout.operator("paint.vert_select_all", text="Invert").action = 'INVERT'
layout.operator("paint.vert_select_more"),
layout.operator("paint.vert_select_less"),
layout.separator()
layout.operator("view3d.select_box")

View File

@ -444,6 +444,8 @@ void paintvert_select_linked_pick(struct bContext *C,
struct Object *ob,
const int region_coordinates[2],
bool select);
void paintvert_select_more(struct Mesh *mesh, bool face_step);
void paintvert_select_less(struct Mesh *mesh, bool face_step);
void paintvert_hide(struct bContext *C, struct Object *ob, bool unselected);
void paintvert_reveal(struct bContext *C, struct Object *ob, bool select);

View File

@ -24,6 +24,7 @@
#include "BKE_customdata.h"
#include "BKE_global.h"
#include "BKE_mesh.hh"
#include "BKE_mesh_mapping.h"
#include "BKE_object.h"
#include "ED_mesh.h"
@ -660,6 +661,126 @@ void paintvert_select_linked(bContext *C, Object *ob)
paintvert_select_linked_vertices(C, ob, indices, true);
}
void paintvert_select_more(Mesh *mesh, const bool face_step)
{
using namespace blender;
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);
const VArray<bool> hide_edge = attributes.lookup_or_default<bool>(
".hide_edge", ATTR_DOMAIN_EDGE, false);
const VArray<bool> hide_poly = attributes.lookup_or_default<bool>(
".hide_poly", ATTR_DOMAIN_FACE, false);
const Span<MPoly> polys = mesh->polys();
const Span<int> corner_edges = mesh->corner_edges();
const Span<int> corner_verts = mesh->corner_verts();
const Span<MEdge> edges = mesh->edges();
Array<Vector<int, 2>> edge_to_face_map;
if (face_step) {
edge_to_face_map = bke::mesh_topology::build_edge_to_poly_map(
polys, corner_edges, mesh->totedge);
}

You set every value of the bit vector, so there's no need to explicitly initialize it to false here.

You set every value of the bit vector, so there's no need to explicitly initialize it to false here.

The functionality is the same, but mesh_topology::build_edge_to_poly_map(..) has an interface that's a bit more friendly in C++. Performance might be slightly worse currently, but there are plans to improve those functions in the near future.

The functionality is the same, but `mesh_topology::build_edge_to_poly_map(..)` has an interface that's a bit more friendly in C++. Performance might be slightly worse currently, but there are plans to improve those functions in the near future.
/* Need a copy of the selected verts that we can read from and is not modified. */
BitVector<> select_vert_original(mesh->totvert, false);
for (int i = 0; i < mesh->totvert; i++) {
select_vert_original[i].set(select_vert.span[i]);
}
/* If we iterated over polys we wouldn't extend the selection through edges that have no face
* attached to them. */
for (const int i : edges.index_range()) {
const MEdge &edge = edges[i];
if ((!select_vert_original[edge.v1] && !select_vert_original[edge.v2]) || hide_edge[i]) {
continue;
}
select_vert.span[edge.v1] = true;
select_vert.span[edge.v2] = true;
if (!face_step) {
continue;
}
const Span<int> neighbor_polys = edge_to_face_map[i];
for (const int poly_i : neighbor_polys) {
if (hide_poly[poly_i]) {
continue;
}
const MPoly &poly = polys[poly_i];
for (const int vert : corner_verts.slice(poly.loopstart, poly.totloop)) {
select_vert.span[vert] = true;
}
}
}
select_vert.finish();
}
void paintvert_select_less(Mesh *mesh, const bool face_step)
{
using namespace blender;
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);
const VArray<bool> hide_edge = attributes.lookup_or_default<bool>(
".hide_edge", ATTR_DOMAIN_EDGE, false);
const VArray<bool> hide_poly = attributes.lookup_or_default<bool>(
".hide_poly", ATTR_DOMAIN_FACE, false);
const Span<MPoly> polys = mesh->polys();
const Span<int> corner_edges = mesh->corner_edges();
const Span<int> corner_verts = mesh->corner_verts();
const Span<MEdge> edges = mesh->edges();
MeshElemMap *edge_poly_map;
int *edge_poly_mem = nullptr;
if (face_step) {
BKE_mesh_edge_poly_map_create(&edge_poly_map,
&edge_poly_mem,
edges.size(),
polys.data(),
polys.size(),
corner_edges.data(),
corner_edges.size());
}
/* Need a copy of the selected verts that we can read from and is not modified. */
BitVector<> select_vert_original(mesh->totvert);
for (int i = 0; i < mesh->totvert; i++) {
select_vert_original[i].set(select_vert.span[i]);
}
for (const int i : edges.index_range()) {
const MEdge &edge = edges[i];
if ((select_vert_original[edge.v1] && select_vert_original[edge.v2]) && !hide_edge[i]) {
continue;
}
select_vert.span[edge.v1] = false;
select_vert.span[edge.v2] = false;
if (!face_step) {
continue;
}
const Span<int> neighbor_polys(edge_poly_map[i].indices, edge_poly_map[i].count);
for (const int poly_i : neighbor_polys) {
if (hide_poly[poly_i]) {
continue;
}
const MPoly &poly = polys[poly_i];
for (const int vert : corner_verts.slice(poly.loopstart, poly.totloop)) {
select_vert.span[vert] = false;
}
}
}
if (edge_poly_mem) {
MEM_freeN(edge_poly_map);
MEM_freeN(edge_poly_mem);
}
select_vert.finish();
}
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

@ -387,6 +387,8 @@ 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);
void PAINT_OT_vert_select_more(struct wmOperatorType *ot);
void PAINT_OT_vert_select_less(struct wmOperatorType *ot);
bool vert_paint_poll(struct bContext *C);
bool mask_paint_poll(struct bContext *C);

View File

@ -1501,6 +1501,8 @@ void ED_operatortypes_paint(void)
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);
WM_operatortype_append(PAINT_OT_vert_select_more);
WM_operatortype_append(PAINT_OT_vert_select_less);
/* vertex */
WM_operatortype_append(PAINT_OT_vertex_paint_toggle);

View File

@ -796,6 +796,72 @@ void PAINT_OT_vert_select_linked_pick(wmOperatorType *ot)
"Whether to select or deselect linked vertices under the cursor");
}
static int paintvert_select_more_exec(bContext *C, wmOperator *op)
{
Object *ob = CTX_data_active_object(C);
Mesh *mesh = BKE_mesh_from_object(ob);
if (mesh == NULL || mesh->totpoly == 0) {
return OPERATOR_CANCELLED;
}
const bool face_step = RNA_boolean_get(op->ptr, "face_step");
paintvert_select_more(mesh, face_step);
paintvert_flush_flags(ob);
paintvert_tag_select_update(C, ob);
ED_region_tag_redraw(CTX_wm_region(C));
return OPERATOR_FINISHED;
}
void PAINT_OT_vert_select_more(wmOperatorType *ot)
{
ot->name = "Select More";
ot->description = "Select Vertices connected to existing selection";
ot->idname = "PAINT_OT_vert_select_more";
ot->exec = paintvert_select_more_exec;
ot->poll = vert_paint_poll;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_boolean(
ot->srna, "face_step", true, "Face Step", "Also select faces that only touch on a corner");
}
static int paintvert_select_less_exec(bContext *C, wmOperator *op)
{
Object *ob = CTX_data_active_object(C);
Mesh *mesh = BKE_mesh_from_object(ob);
if (mesh == NULL || mesh->totpoly == 0) {
return OPERATOR_CANCELLED;
}
const bool face_step = RNA_boolean_get(op->ptr, "face_step");
paintvert_select_less(mesh, face_step);
paintvert_flush_flags(ob);
paintvert_tag_select_update(C, ob);
ED_region_tag_redraw(CTX_wm_region(C));
return OPERATOR_FINISHED;
}
void PAINT_OT_vert_select_less(wmOperatorType *ot)
{
ot->name = "Select Less";
ot->description = "Deselect Vertices connected to existing selection";
ot->idname = "PAINT_OT_vert_select_less";
ot->exec = paintvert_select_less_exec;
ot->poll = vert_paint_poll;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
RNA_def_boolean(
ot->srna, "face_step", true, "Face Step", "Also deselect faces that only touch on a corner");
}
static int face_select_hide_exec(bContext *C, wmOperator *op)
{
const bool unselected = RNA_boolean_get(op->ptr, "unselected");