diff options
-rw-r--r-- | release/scripts/startup/bl_ui/space_toolsystem_toolbar.py | 10 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/paint_mask.c | 57 |
2 files changed, 65 insertions, 2 deletions
diff --git a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py index 00ae884eeb9..d07241203fb 100644 --- a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py +++ b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py @@ -1226,22 +1226,32 @@ class _defs_sculpt: @ToolDef.from_fn def mask_border(): + def draw_settings(_context, layout, tool): + props = tool.operator_properties("paint.mask_box_gesture") + layout.prop(props, "use_front_faces_only", expand=False) + return dict( idname="builtin.box_mask", label="Box Mask", icon="ops.sculpt.border_mask", widget=None, keymap=(), + draw_settings=draw_settings, ) @ToolDef.from_fn def mask_lasso(): + def draw_settings(_context, layout, tool): + props = tool.operator_properties("paint.mask_lasso_gesture") + layout.prop(props, "use_front_faces_only", expand=False) + return dict( idname="builtin.lasso_mask", label="Lasso Mask", icon="ops.sculpt.lasso_mask", widget=None, keymap=(), + draw_settings=draw_settings, ) @ToolDef.from_fn diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c index 7e5825835fb..05ffb80d8a1 100644 --- a/source/blender/editors/sculpt_paint/paint_mask.c +++ b/source/blender/editors/sculpt_paint/paint_mask.c @@ -100,6 +100,9 @@ typedef struct MaskTaskData { PaintMaskFloodMode mode; float value; float (*clip_planes_final)[4]; + + bool front_faces_only; + float view_normal[3]; } MaskTaskData; static void mask_flood_fill_task_cb(void *__restrict userdata, @@ -265,9 +268,15 @@ static void mask_box_select_task_cb(void *__restrict userdata, bool any_masked = false; bool redraw = false; + float vertex_normal[3]; + BKE_pbvh_vertex_iter_begin(data->pbvh, node, vi, PBVH_ITER_UNIQUE) { - if (is_effected(clip_planes_final, vi.co)) { + SCULPT_vertex_normal_get(data->ob->sculpt, vi.index, vertex_normal); + float dot = dot_v3v3(data->view_normal, vertex_normal); + const bool is_effected_front_face = !(data->front_faces_only && dot < 0.0f); + + if (is_effected_front_face && is_effected(clip_planes_final, vi.co)) { float prevmask = *vi.mask; if (!any_masked) { any_masked = true; @@ -311,6 +320,7 @@ static int paint_mask_gesture_box_exec(bContext *C, wmOperator *op) const PaintMaskFloodMode mode = RNA_enum_get(op->ptr, "mode"); const float value = RNA_float_get(op->ptr, "value"); + const bool front_faces_only = RNA_boolean_get(op->ptr, "use_front_faces_only"); rcti rect; WM_operator_properties_border_to_rcti(op, &rect); @@ -324,6 +334,16 @@ static int paint_mask_gesture_box_exec(bContext *C, wmOperator *op) SCULPT_undo_push_begin("Mask box fill"); + /* Calculate the view normal in object space. */ + float mat[3][3]; + float view_dir[3] = {0.0f, 0.0f, 1.0f}; + float true_view_normal[3]; + copy_m3_m4(mat, vc.rv3d->viewinv); + mul_m3_v3(mat, view_dir); + copy_m3_m4(mat, ob->imat); + mul_m3_v3(mat, view_dir); + normalize_v3_v3(true_view_normal, view_dir); + for (int symmpass = 0; symmpass <= symm; symmpass++) { if (symmpass == 0 || (symm & symmpass && (symm != 5 || symmpass != 3) && (symm != 6 || (symmpass != 3 && symmpass != 5)))) { @@ -346,8 +366,11 @@ static int paint_mask_gesture_box_exec(bContext *C, wmOperator *op) .mode = mode, .value = value, .clip_planes_final = clip_planes_final, + .front_faces_only = front_faces_only, }; + flip_v3_v3(data.view_normal, true_view_normal, symmpass); + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, true, totnode); BLI_task_parallel_range(0, totnode, &data, mask_box_select_task_cb, &settings); @@ -439,9 +462,15 @@ static void mask_gesture_lasso_task_cb(void *__restrict userdata, PBVHVertexIter vi; bool any_masked = false; + float vertex_normal[3]; + BKE_pbvh_vertex_iter_begin(data->pbvh, node, vi, PBVH_ITER_UNIQUE) { - if (is_effected_lasso(lasso_data, vi.co)) { + SCULPT_vertex_normal_get(data->ob->sculpt, vi.index, vertex_normal); + float dot = dot_v3v3(lasso_data->task_data.view_normal, vertex_normal); + const bool is_effected_front_face = !(data->front_faces_only && dot < 0.0f); + + if (is_effected_front_face && is_effected_lasso(lasso_data, vi.co)) { if (!any_masked) { any_masked = true; @@ -479,6 +508,7 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op) bool multires; PaintMaskFloodMode mode = RNA_enum_get(op->ptr, "mode"); float value = RNA_float_get(op->ptr, "value"); + const bool front_faces_only = RNA_boolean_get(op->ptr, "use_front_faces_only"); /* Calculations of individual vertices are done in 2D screen space to diminish the amount of * calculations done. Bounding box PBVH collision is not computed against enclosing rectangle @@ -511,6 +541,16 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op) SCULPT_undo_push_begin("Mask lasso fill"); + /* Calculate the view normal in object space. */ + float mat[3][3]; + float view_dir[3] = {0.0f, 0.0f, 1.0f}; + float true_view_normal[3]; + copy_m3_m4(mat, vc.rv3d->viewinv); + mul_m3_v3(mat, view_dir); + copy_m3_m4(mat, ob->imat); + mul_m3_v3(mat, view_dir); + normalize_v3_v3(true_view_normal, view_dir); + for (int symmpass = 0; symmpass <= symm; symmpass++) { if ((symmpass == 0) || (symm & symmpass && (symm != 5 || symmpass != 3) && (symm != 6 || (symmpass != 3 && symmpass != 5)))) { @@ -520,6 +560,8 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op) flip_plane(clip_planes_final[j], clip_planes[j], symmpass); } + flip_v3_v3(data.task_data.view_normal, true_view_normal, symmpass); + data.symmpass = symmpass; /* Gather nodes inside lasso's enclosing rectangle @@ -536,6 +578,7 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op) data.task_data.multires = multires; data.task_data.mode = mode; data.task_data.value = value; + data.task_data.front_faces_only = front_faces_only; TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, true, totnode); @@ -594,6 +637,11 @@ void PAINT_OT_mask_lasso_gesture(wmOperatorType *ot) "Mask level to use when mode is 'Value'; zero means no masking and one is fully masked", 0.0f, 1.0f); + RNA_def_boolean(ot->srna, + "use_front_faces_only", + false, + "Front Faces Only", + "Affect only faces facing towards the view"); } void PAINT_OT_mask_box_gesture(wmOperatorType *ot) @@ -624,4 +672,9 @@ void PAINT_OT_mask_box_gesture(wmOperatorType *ot) "Mask level to use when mode is 'Value'; zero means no masking and one is fully masked", 0.0f, 1.0f); + RNA_def_boolean(ot->srna, + "use_front_faces_only", + false, + "Front Faces Only", + "Affect only faces facing towards the view"); } |