Sculpt: Face Set Edit Operator
This operator performs an edit operation in the active face set defined by the cursor position and updates the visibility. For now, it has a Grow and Shrink operations, similar to Select More/Less in edit mode or to the mask filter Grow/Shrink modes. More operations can be added in the future. In multires, this updates the visibility of an entire face from the base mesh at once, which makes it very convenient to edit the visible area without manipulating the face set directly. Reviewed By: sergey Differential Revision: https://developer.blender.org/D7367
This commit is contained in:
parent
77789a1904
commit
cb9de95d61
Notes:
blender-bot
2023-02-14 03:29:37 +01:00
Referenced by commit eb2c26bd38
, Fix use of operator flag as boolean
|
@ -4318,6 +4318,10 @@ def km_sculpt(params):
|
|||
{"properties": [("mode", 'SHOW_ALL')]}),
|
||||
("sculpt.mask_expand", {"type": 'W', "value": 'PRESS', "shift": True},
|
||||
{"properties": [("use_normals", False), ("keep_previous_mask", False), ("invert", False), ("smooth_iterations", 0), ("create_face_set", True)]}),
|
||||
("sculpt.face_set_edit", {"type": 'W', "value": 'PRESS', "ctrl": True},
|
||||
{"properties": [("mode", "GROW")]}),
|
||||
("sculpt.face_set_edit", {"type": 'W', "value": 'PRESS', "ctrl": True, "alt": True},
|
||||
{"properties": [("mode", "SHRINK")]}),
|
||||
# Subdivision levels
|
||||
*_template_items_object_subdivision_set(),
|
||||
("object.subdivision_set", {"type": 'PAGE_UP', "value": 'PRESS'},
|
||||
|
|
|
@ -3126,6 +3126,14 @@ class VIEW3D_MT_face_sets(Menu):
|
|||
|
||||
layout.separator()
|
||||
|
||||
op = layout.operator("sculpt.face_set_edit", text='Grow Face Set')
|
||||
op.mode = 'GROW'
|
||||
|
||||
op = layout.operator("sculpt.face_set_edit", text='Shrink Face Set')
|
||||
op.mode = 'SHRINK'
|
||||
|
||||
layout.separator()
|
||||
|
||||
op = layout.operator("sculpt.face_set_change_visibility", text='Invert Visible Face Sets')
|
||||
op.mode = 'INVERT'
|
||||
|
||||
|
|
|
@ -315,6 +315,8 @@ typedef struct SculptSession {
|
|||
/* Mesh Face Sets */
|
||||
/* Total number of polys of the base mesh. */
|
||||
int totfaces;
|
||||
/* Face sets store its visibility in the sign of the integer, using the absolute value as the
|
||||
* Face Set ID. Positive IDs are visible, negative IDs are hidden. */
|
||||
int *face_sets;
|
||||
|
||||
/* BMesh for dynamic topology sculpting */
|
||||
|
|
|
@ -7907,4 +7907,5 @@ void ED_operatortypes_sculpt(void)
|
|||
WM_operatortype_append(SCULPT_OT_face_sets_randomize_colors);
|
||||
WM_operatortype_append(SCULPT_OT_face_sets_init);
|
||||
WM_operatortype_append(SCULPT_OT_cloth_filter);
|
||||
WM_operatortype_append(SCULPT_OT_face_sets_edit);
|
||||
}
|
||||
|
|
|
@ -978,3 +978,170 @@ void SCULPT_OT_face_sets_randomize_colors(wmOperatorType *ot)
|
|||
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
}
|
||||
|
||||
typedef enum eSculptFaceSetEditMode {
|
||||
SCULPT_FACE_SET_EDIT_GROW = 0,
|
||||
SCULPT_FACE_SET_EDIT_SHRINK = 1,
|
||||
} eSculptFaceSetEditMode;
|
||||
|
||||
static EnumPropertyItem prop_sculpt_face_sets_edit_types[] = {
|
||||
{
|
||||
SCULPT_FACE_SET_EDIT_GROW,
|
||||
"GROW",
|
||||
0,
|
||||
"Grow Face Set",
|
||||
"Grows the Face Sets boundary by one face based on mesh topology",
|
||||
},
|
||||
{
|
||||
SCULPT_FACE_SET_EDIT_SHRINK,
|
||||
"SHRINK",
|
||||
0,
|
||||
"Shrink Face Set",
|
||||
"Shrinks the Face Sets boundary by one face based on mesh topology",
|
||||
},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
static void sculpt_face_set_grow(Object *ob,
|
||||
SculptSession *ss,
|
||||
int *prev_face_sets,
|
||||
const int active_face_set_id)
|
||||
{
|
||||
Mesh *mesh = BKE_mesh_from_object(ob);
|
||||
for (int p = 0; p < mesh->totpoly; p++) {
|
||||
const MPoly *c_poly = &mesh->mpoly[p];
|
||||
for (int l = 0; l < c_poly->totloop; l++) {
|
||||
const MLoop *c_loop = &mesh->mloop[c_poly->loopstart + l];
|
||||
const MeshElemMap *vert_map = &ss->pmap[c_loop->v];
|
||||
for (int i = 0; i < vert_map->count; i++) {
|
||||
const int neighbor_face_index = vert_map->indices[i];
|
||||
if (neighbor_face_index != p) {
|
||||
|
||||
if (abs(prev_face_sets[neighbor_face_index]) == active_face_set_id) {
|
||||
ss->face_sets[p] = active_face_set_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void sculpt_face_set_shrink(Object *ob,
|
||||
SculptSession *ss,
|
||||
int *prev_face_sets,
|
||||
const int active_face_set_id)
|
||||
{
|
||||
Mesh *mesh = BKE_mesh_from_object(ob);
|
||||
for (int p = 0; p < mesh->totpoly; p++) {
|
||||
if (abs(prev_face_sets[p]) == active_face_set_id) {
|
||||
const MPoly *c_poly = &mesh->mpoly[p];
|
||||
for (int l = 0; l < c_poly->totloop; l++) {
|
||||
const MLoop *c_loop = &mesh->mloop[c_poly->loopstart + l];
|
||||
const MeshElemMap *vert_map = &ss->pmap[c_loop->v];
|
||||
for (int i = 0; i < vert_map->count; i++) {
|
||||
const int neighbor_face_index = vert_map->indices[i];
|
||||
if (neighbor_face_index != p) {
|
||||
if (abs(prev_face_sets[neighbor_face_index]) != active_face_set_id) {
|
||||
ss->face_sets[p] = prev_face_sets[neighbor_face_index];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void sculpt_face_set_apply_edit(Object *ob, const int active_face_set_id, const int mode)
|
||||
{
|
||||
SculptSession *ss = ob->sculpt;
|
||||
|
||||
int *prev_face_sets = MEM_dupallocN(ss->face_sets);
|
||||
|
||||
switch (mode) {
|
||||
case SCULPT_FACE_SET_EDIT_GROW:
|
||||
sculpt_face_set_grow(ob, ss, prev_face_sets, active_face_set_id);
|
||||
break;
|
||||
case SCULPT_FACE_SET_EDIT_SHRINK:
|
||||
sculpt_face_set_shrink(ob, ss, prev_face_sets, active_face_set_id);
|
||||
break;
|
||||
}
|
||||
|
||||
MEM_SAFE_FREE(prev_face_sets);
|
||||
}
|
||||
|
||||
static int sculpt_face_set_edit_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
|
||||
{
|
||||
Object *ob = CTX_data_active_object(C);
|
||||
SculptSession *ss = ob->sculpt;
|
||||
ARegion *region = CTX_wm_region(C);
|
||||
Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C);
|
||||
|
||||
const int mode = RNA_enum_get(op->ptr, "mode");
|
||||
|
||||
/* Dyntopo not supported. */
|
||||
if (BKE_pbvh_type(ss->pbvh) == PBVH_BMESH) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false);
|
||||
|
||||
PBVH *pbvh = ob->sculpt->pbvh;
|
||||
PBVHNode **nodes;
|
||||
int totnode;
|
||||
BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode);
|
||||
|
||||
if (!nodes) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
SCULPT_undo_push_begin("face set edit");
|
||||
SCULPT_undo_push_node(ob, nodes[0], SCULPT_UNDO_FACE_SETS);
|
||||
|
||||
const int active_face_set = SCULPT_active_face_set_get(ss);
|
||||
|
||||
sculpt_face_set_apply_edit(ob, abs(active_face_set), mode);
|
||||
|
||||
SCULPT_undo_push_end();
|
||||
|
||||
/* Sync face sets visibility and vertex visibility as now all Face Sets are visible. */
|
||||
SCULPT_visibility_sync_all_face_sets_to_vertices(ss);
|
||||
|
||||
for (int i = 0; i < totnode; i++) {
|
||||
BKE_pbvh_node_mark_update_visibility(nodes[i]);
|
||||
}
|
||||
|
||||
BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateVisibility);
|
||||
|
||||
MEM_SAFE_FREE(nodes);
|
||||
|
||||
if (BKE_pbvh_type(pbvh) == PBVH_FACES) {
|
||||
BKE_mesh_flush_hidden_from_verts(ob->data);
|
||||
}
|
||||
|
||||
ED_region_tag_redraw(region);
|
||||
DEG_id_tag_update(&ob->id, ID_RECALC_SHADING);
|
||||
|
||||
View3D *v3d = CTX_wm_view3d(C);
|
||||
if (!BKE_sculptsession_use_pbvh_draw(ob, v3d)) {
|
||||
DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY);
|
||||
}
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
void SCULPT_OT_face_sets_edit(struct wmOperatorType *ot)
|
||||
{
|
||||
/* Identifiers. */
|
||||
ot->name = "Edit Face Set";
|
||||
ot->idname = "SCULPT_OT_face_set_edit";
|
||||
ot->description = "Edits the current active Face Set";
|
||||
|
||||
/* Api callbacks. */
|
||||
ot->invoke = sculpt_face_set_edit_invoke;
|
||||
ot->poll = SCULPT_mode_poll;
|
||||
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
RNA_def_enum(
|
||||
ot->srna, "mode", prop_sculpt_face_sets_edit_types, SCULPT_FACE_SET_EDIT_GROW, "Mode", "");
|
||||
}
|
||||
|
|
|
@ -890,6 +890,7 @@ void SCULPT_OT_face_sets_randomize_colors(struct wmOperatorType *ot);
|
|||
void SCULPT_OT_face_sets_change_visibility(struct wmOperatorType *ot);
|
||||
void SCULPT_OT_face_sets_init(struct wmOperatorType *ot);
|
||||
void SCULPT_OT_face_sets_create(struct wmOperatorType *ot);
|
||||
void SCULPT_OT_face_sets_edit(struct wmOperatorType *ot);
|
||||
|
||||
/* Transform. */
|
||||
void SCULPT_OT_set_pivot_position(struct wmOperatorType *ot);
|
||||
|
|
Loading…
Reference in New Issue