[Bf-blender-cvs] [0083c961259] master: Sculpt: Mask Expand operator
Pablo Dobarro
noreply at git.blender.org
Tue Sep 10 15:12:12 CEST 2019
Commit: 0083c96125926d4e76525ff1bbd08a3f1f20307b
Author: Pablo Dobarro
Date: Tue Sep 10 15:11:33 2019 +0200
Branches: master
https://developer.blender.org/rB0083c96125926d4e76525ff1bbd08a3f1f20307b
Sculpt: Mask Expand operator
This operator is a combined version of mask expand and mask by normal from the sculpt branch. It can be used to quickly isolate parts of a model based on topology or curvature.
- Shift + A starts the operator in topology mode from the active vertex
- Shift + Alt + A starts the operator in curvature mode from the active vertex
Reviewed By: brecht
Differential Revision: https://developer.blender.org/D5657
===================================================================
M release/scripts/presets/keyconfig/keymap_data/blender_default.py
M release/scripts/startup/bl_ui/space_view3d.py
M source/blender/blenkernel/BKE_paint.h
M source/blender/editors/sculpt_paint/sculpt.c
M source/blender/editors/sculpt_paint/sculpt_intern.h
===================================================================
diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
index 0bc1219fa4d..582757f2168 100644
--- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py
+++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py
@@ -3848,6 +3848,10 @@ def km_sculpt(params):
("paint.mask_lasso_gesture", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True, "ctrl": True}, None),
("wm.context_toggle", {"type": 'M', "value": 'PRESS', "ctrl": True},
{"properties": [("data_path", 'scene.tool_settings.sculpt.show_mask')]}),
+ ("sculpt.mask_expand", {"type": 'A', "value": 'PRESS', "shift": True},
+ {"properties": [("use_normals", False), ("keep_previous_mask", False), ("invert", True), ("smooth_iterations", 2)]}),
+ ("sculpt.mask_expand", {"type": 'A', "value": 'PRESS', "shift": True, 'alt': True},
+ {"properties": [("use_normals", True), ("keep_previous_mask", True), ("invert", False), ("smooth_iterations", 0)]}),
# Dynamic topology
("sculpt.dynamic_topology_toggle", {"type": 'D', "value": 'PRESS', "ctrl": True}, None),
("sculpt.set_detail_size", {"type": 'D', "value": 'PRESS', "shift": True}, None),
diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py
index 2333c8589c3..21c2631c904 100644
--- a/release/scripts/startup/bl_ui/space_view3d.py
+++ b/release/scripts/startup/bl_ui/space_view3d.py
@@ -2872,6 +2872,20 @@ class VIEW3D_MT_sculpt(Menu):
layout.separator()
+ props = layout.operator("sculpt.mask_expand", text="Expand Mask By Topology")
+ props.use_normals = False
+ props.keep_previous_mask = False
+ props.invert = True
+ props.smooth_iterations = 2
+
+ props = layout.operator("sculpt.mask_expand", text="Expand Mask By Curvature")
+ props.use_normals = True
+ props.keep_previous_mask = True
+ props.invert = False
+ props.smooth_iterations = 0
+
+ layout.separator()
+
props = layout.operator("sculpt.dirty_mask", text='Dirty Mask')
diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index ef798479b23..10c3f42bba7 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -267,6 +267,8 @@ typedef struct SculptSession {
float cursor_view_normal[3];
struct RegionView3D *rv3d;
+ float pivot_pos[3];
+
union {
struct {
struct SculptVertexPaintGeomMap gmap;
diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c
index e511a19b341..4702c64b8bc 100644
--- a/source/blender/editors/sculpt_paint/sculpt.c
+++ b/source/blender/editors/sculpt_paint/sculpt.c
@@ -30,7 +30,6 @@
#include "BLI_hash.h"
#include "BLI_gsqueue.h"
#include "BLI_stack.h"
-#include "BLI_gsqueue.h"
#include "BLI_task.h"
#include "BLI_utildefines.h"
#include "BLI_ghash.h"
@@ -7932,6 +7931,12 @@ static void sculpt_filter_cache_free(SculptSession *ss)
if (ss->filter_cache->mask_update_it) {
MEM_freeN(ss->filter_cache->mask_update_it);
}
+ if (ss->filter_cache->prev_mask) {
+ MEM_freeN(ss->filter_cache->prev_mask);
+ }
+ if (ss->filter_cache->normal_factor) {
+ MEM_freeN(ss->filter_cache->normal_factor);
+ }
MEM_freeN(ss->filter_cache);
ss->filter_cache = NULL;
}
@@ -8581,6 +8586,420 @@ static void SCULPT_OT_dirty_mask(struct wmOperatorType *ot)
ot->srna, "dirty_only", false, "Dirty Only", "Don't calculate cleans for convex areas");
}
+typedef struct vertex_topology_it {
+ int v;
+ int it;
+ float edge_factor;
+} vertex_topology_it;
+
+static int sculpt_mask_expand_cancel(bContext *C, wmOperator *op)
+{
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+
+ MEM_freeN(op->customdata);
+
+ int vert_count = sculpt_vertex_count_get(ss);
+ for (int i = 0; i < vert_count; i++) {
+ sculpt_vertex_mask_set(ss, i, ss->filter_cache->prev_mask[i]);
+ }
+
+ for (int i = 0; i < ss->filter_cache->totnode; i++) {
+ BKE_pbvh_node_mark_redraw(ss->filter_cache->nodes[i]);
+ }
+
+ sculpt_flush_update_step(C);
+ sculpt_filter_cache_free(ss);
+ sculpt_undo_push_end();
+ sculpt_flush_update_done(C, ob);
+ ED_workspace_status_text(C, NULL);
+ return OPERATOR_CANCELLED;
+}
+
+static void sculpt_expand_task_cb(void *__restrict userdata,
+ const int i,
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ SculptThreadedTaskData *data = userdata;
+ SculptSession *ss = data->ob->sculpt;
+ PBVHNode *node = data->nodes[i];
+ PBVHVertexIter vd;
+ int update_it = data->mask_expand_update_it;
+
+ BKE_pbvh_vertex_iter_begin(ss->pbvh, node, vd, PBVH_ITER_ALL)
+ {
+ int vi = vd.index;
+ float final_mask = *vd.mask;
+ if (data->mask_expand_use_normals) {
+ if (ss->filter_cache->normal_factor[sculpt_active_vertex_get(ss)] <
+ ss->filter_cache->normal_factor[vd.index]) {
+ final_mask = 1.0f;
+ }
+ else {
+ final_mask = 0.0f;
+ }
+ }
+ else {
+ if (ss->filter_cache->mask_update_it[vi] <= update_it &&
+ ss->filter_cache->mask_update_it[vi] != 0) {
+ final_mask = 1.0f;
+ }
+ else {
+ final_mask = 0.0f;
+ }
+ }
+
+ if (data->mask_expand_keep_prev_mask) {
+ final_mask = MAX2(ss->filter_cache->prev_mask[vd.index], final_mask);
+ }
+
+ if (data->mask_expand_invert_mask) {
+ final_mask = 1.0f - final_mask;
+ }
+
+ if (*vd.mask != final_mask) {
+ if (vd.mvert) {
+ vd.mvert->flag |= ME_VERT_PBVH_UPDATE;
+ }
+ *vd.mask = final_mask;
+ BKE_pbvh_node_mark_redraw(node);
+ }
+ }
+ BKE_pbvh_vertex_iter_end;
+}
+
+static int sculpt_mask_expand_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ Object *ob = CTX_data_active_object(C);
+ SculptSession *ss = ob->sculpt;
+ Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
+ float prevclick_f[2];
+ copy_v2_v2(prevclick_f, op->customdata);
+ int prevclick[2] = {(int)prevclick_f[0], (int)prevclick_f[1]};
+ int len = (int)len_v2v2_int(prevclick, event->mval);
+ len = ABS(len);
+ int mask_speed = RNA_int_get(op->ptr, "mask_speed");
+ int mask_expand_update_it = len / mask_speed;
+ mask_expand_update_it = mask_expand_update_it + 1;
+
+ if (RNA_boolean_get(op->ptr, "use_cursor")) {
+ SculptCursorGeometryInfo sgi;
+ float mouse[2];
+ mouse[0] = event->mval[0];
+ mouse[1] = event->mval[1];
+ sculpt_cursor_geometry_info_update(C, &sgi, mouse, false);
+ mask_expand_update_it = ss->filter_cache->mask_update_it[(int)sculpt_active_vertex_get(ss)];
+ }
+
+ if ((event->type == ESCKEY && event->val == KM_PRESS) ||
+ (event->type == RIGHTMOUSE && event->val == KM_PRESS)) {
+ return sculpt_mask_expand_cancel(C, op);
+ }
+
+ if ((event->type == LEFTMOUSE && event->val == KM_RELEASE) ||
+ (event->type == RETKEY && event->val == KM_PRESS) ||
+ (event->type == PADENTER && event->val == KM_PRESS)) {
+
+ /* Smooth iterations */
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .nodes = ss->filter_cache->nodes,
+ .filter_type = MASK_FILTER_SMOOTH,
+ };
+
+ int smooth_iterations = RNA_int_get(op->ptr, "smooth_iterations");
+ for (int i = 0; i < smooth_iterations; i++) {
+ TaskParallelSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) &&
+ ss->filter_cache->totnode > SCULPT_THREADED_LIMIT);
+ BLI_task_parallel_range(0, ss->filter_cache->totnode, &data, mask_filter_task_cb, &settings);
+ }
+
+ /* Pivot position */
+ if (RNA_boolean_get(op->ptr, "update_pivot")) {
+ const char symm = sd->paint.symmetry_flags & PAINT_SYMM_AXIS_ALL;
+ float avg[3];
+ int total = 0;
+ float threshold = 0.2f;
+ zero_v3(avg);
+ int vertex_count = sculpt_vertex_count_get(ss);
+ for (int i = 0; i < vertex_count; i++) {
+ if (sculpt_vertex_mask_get(ss, i) < (0.5f + threshold) &&
+ sculpt_vertex_mask_get(ss, i) > (0.5f - threshold) &&
+ check_vertex_pivot_symmetry(sculpt_vertex_co_get(ss, i), ss->pivot_pos, symm)) {
+ total++;
+ add_v3_v3(avg, sculpt_vertex_co_get(ss, i));
+ }
+ }
+ if (total > 0) {
+ mul_v3_fl(avg, 1.0f / total);
+ copy_v3_v3(ss->pivot_pos, avg);
+ }
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data);
+ }
+
+ MEM_freeN(op->customdata);
+
+ for (int i = 0; i < ss->filter_cache->totnode; i++) {
+ BKE_pbvh_node_mark_redraw(ss->filter_cache->nodes[i]);
+ }
+
+ sculpt_filter_cache_free(ss);
+
+ sculpt_undo_push_end();
+ sculpt_flush_update_done(C, ob);
+ ED_workspace_status_text(C, NULL);
+ return OPERATOR_FINISHED;
+ }
+
+ if (event->type != MOUSEMOVE) {
+ return OPERATOR_RUNNING_MODAL;
+ }
+
+ if (mask_expand_update_it == ss->filter_cache->mask_update_current_it) {
+ return OPERATOR_RUNNING_MODAL;
+ }
+
+ if (mask_expand_update_it < ss->filter_cache->mask_update_last_it) {
+ SculptThreadedTaskData data = {
+ .sd = sd,
+ .ob = ob,
+ .nodes = ss->filter_cache->nodes,
+ .mask_expand_update_it = mask_expand_update_it,
+ .mask_expand_use_normals = RNA_boolean_get(op->ptr, "use_normals"),
+ .mask_expand_invert_mask = RNA_boolean_get(op->ptr, "invert"),
+ .mask_expand_keep_prev_mask = RNA_boolean_get(op->ptr, "keep_previous_mask"),
+ };
+ TaskParallelSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ settings.use_threading = ((sd->flags & SCULPT_USE_OPENMP) &&
+ ss->filter_cache->totnode > SCULPT_THREADED_LIMIT);
+
+ BLI_task_parallel_range(0, ss->filter_cache->totnode, &data, sculpt_expand_task_cb, &settings);
+ ss->filter_cache->mask_update_current_it = mask_expand_update_it;
+ }
+
+ sculpt_flush_update_step(C);
+
@@ Diff output truncated at 10240 characters. @@
More information about the Bf-blender-cvs
mailing list