Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--release/scripts/startup/bl_ui/space_toolsystem_toolbar.py10
-rw-r--r--source/blender/editors/sculpt_paint/paint_mask.c57
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");
}