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:
Diffstat (limited to 'source/blender/editors/sculpt_paint/paint_mask.c')
-rw-r--r--source/blender/editors/sculpt_paint/paint_mask.c252
1 files changed, 199 insertions, 53 deletions
diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c
index cc0d20089b4..26abd19d5e8 100644
--- a/source/blender/editors/sculpt_paint/paint_mask.c
+++ b/source/blender/editors/sculpt_paint/paint_mask.c
@@ -246,8 +246,16 @@ typedef struct LassoGestureData {
} LassoGestureData;
typedef struct LineGestureData {
+ /* Plane aligned to the gesture line. */
float true_plane[4];
float plane[4];
+
+ /* Planes to limit the action to the length of the gesture segment at both sides of the affected
+ * area. */
+ float side_plane[2][4];
+ float true_side_plane[2][4];
+ bool use_side_planes;
+
bool flip;
} LineGestureData;
@@ -320,6 +328,13 @@ static void sculpt_gesture_operator_properties(wmOperatorType *ot)
false,
"Front Faces Only",
"Affect only faces facing towards the view");
+
+ RNA_def_boolean(ot->srna,
+ "use_limit_to_segment",
+ false,
+ "Limit to Segment",
+ "Apply the gesture action only to the area that is contained within the "
+ "segement without extending its effect to the entire line");
}
static void sculpt_gesture_context_init_common(bContext *C,
@@ -332,6 +347,7 @@ static void sculpt_gesture_context_init_common(bContext *C,
/* Operator properties. */
sgcontext->front_faces_only = RNA_boolean_get(op->ptr, "use_front_faces_only");
+ sgcontext->line.use_side_planes = RNA_boolean_get(op->ptr, "use_limit_to_segment");
/* SculptSession */
sgcontext->ss = ob->sculpt;
@@ -448,6 +464,50 @@ static SculptGestureContext *sculpt_gesture_init_from_box(bContext *C, wmOperato
return sgcontext;
}
+static void sculpt_gesture_line_plane_from_tri(float *r_plane,
+ SculptGestureContext *sgcontext,
+ const bool flip,
+ const float p1[3],
+ const float p2[3],
+ const float p3[3])
+{
+ float normal[3];
+ normal_tri_v3(normal, p1, p2, p3);
+ mul_v3_mat3_m4v3(normal, sgcontext->vc.obact->imat, normal);
+ if (flip) {
+ mul_v3_fl(normal, -1.0f);
+ }
+ float plane_point_object_space[3];
+ mul_v3_m4v3(plane_point_object_space, sgcontext->vc.obact->imat, p1);
+ plane_from_point_normal_v3(r_plane, plane_point_object_space, normal);
+}
+
+/* Creates 4 points in the plane defined by the line and 2 extra points with an offset relative to
+ * this plane. */
+static void sculpt_gesture_line_calculate_plane_points(SculptGestureContext *sgcontext,
+ float line_points[2][2],
+ float r_plane_points[4][3],
+ float r_offset_plane_points[2][3])
+{
+ float depth_point[3];
+ add_v3_v3v3(depth_point, sgcontext->true_view_origin, sgcontext->true_view_normal);
+ ED_view3d_win_to_3d(
+ sgcontext->vc.v3d, sgcontext->vc.region, depth_point, line_points[0], r_plane_points[0]);
+ ED_view3d_win_to_3d(
+ sgcontext->vc.v3d, sgcontext->vc.region, depth_point, line_points[1], r_plane_points[3]);
+
+ madd_v3_v3v3fl(depth_point, sgcontext->true_view_origin, sgcontext->true_view_normal, 10.0f);
+ ED_view3d_win_to_3d(
+ sgcontext->vc.v3d, sgcontext->vc.region, depth_point, line_points[0], r_plane_points[1]);
+ ED_view3d_win_to_3d(
+ sgcontext->vc.v3d, sgcontext->vc.region, depth_point, line_points[1], r_plane_points[2]);
+
+ float normal[3];
+ normal_tri_v3(normal, r_plane_points[0], r_plane_points[1], r_plane_points[2]);
+ add_v3_v3v3(r_offset_plane_points[0], r_plane_points[0], normal);
+ add_v3_v3v3(r_offset_plane_points[1], r_plane_points[3], normal);
+}
+
static SculptGestureContext *sculpt_gesture_init_from_line(bContext *C, wmOperator *op)
{
SculptGestureContext *sgcontext = MEM_callocN(sizeof(SculptGestureContext),
@@ -464,36 +524,33 @@ static SculptGestureContext *sculpt_gesture_init_from_line(bContext *C, wmOperat
sgcontext->line.flip = RNA_boolean_get(op->ptr, "flip");
- float depth_point[3];
- float plane_points[3][3];
-
- /* Calculate a triangle in the line's plane. */
- add_v3_v3v3(depth_point, sgcontext->true_view_origin, sgcontext->true_view_normal);
- ED_view3d_win_to_3d(
- sgcontext->vc.v3d, sgcontext->vc.region, depth_point, line_points[0], plane_points[0]);
-
- madd_v3_v3v3fl(depth_point, sgcontext->true_view_origin, sgcontext->true_view_normal, 10.0f);
- ED_view3d_win_to_3d(
- sgcontext->vc.v3d, sgcontext->vc.region, depth_point, line_points[0], plane_points[1]);
- ED_view3d_win_to_3d(
- sgcontext->vc.v3d, sgcontext->vc.region, depth_point, line_points[1], plane_points[2]);
-
- /* Calculate final line plane and normal using the triangle. */
- float normal[3];
- normal_tri_v3(normal, plane_points[0], plane_points[1], plane_points[2]);
- if (!sgcontext->vc.rv3d->is_persp) {
- mul_v3_fl(normal, -1.0f);
- }
-
- /* Apply flip. */
- if (sgcontext->line.flip) {
- mul_v3_fl(normal, -1.0f);
- }
-
- mul_v3_mat3_m4v3(normal, sgcontext->vc.obact->imat, normal);
- float plane_point_object_space[3];
- mul_v3_m4v3(plane_point_object_space, sgcontext->vc.obact->imat, plane_points[0]);
- plane_from_point_normal_v3(sgcontext->line.true_plane, plane_point_object_space, normal);
+ float plane_points[4][3];
+ float offset_plane_points[2][3];
+ sculpt_gesture_line_calculate_plane_points(
+ sgcontext, line_points, plane_points, offset_plane_points);
+
+ /* Calculate line plane and normal. */
+ const bool flip = sgcontext->line.flip ^ !sgcontext->vc.rv3d->is_persp;
+ sculpt_gesture_line_plane_from_tri(sgcontext->line.true_plane,
+ sgcontext,
+ flip,
+ plane_points[0],
+ plane_points[1],
+ plane_points[2]);
+
+ /* Calculate the side planes. */
+ sculpt_gesture_line_plane_from_tri(sgcontext->line.true_side_plane[0],
+ sgcontext,
+ false,
+ plane_points[1],
+ plane_points[0],
+ offset_plane_points[0]);
+ sculpt_gesture_line_plane_from_tri(sgcontext->line.true_side_plane[1],
+ sgcontext,
+ false,
+ plane_points[3],
+ plane_points[2],
+ offset_plane_points[1]);
return sgcontext;
}
@@ -544,14 +601,20 @@ static void sculpt_gesture_flip_for_symmetry_pass(SculptGestureContext *sgcontex
flip_v3_v3(sgcontext->view_normal, sgcontext->true_view_normal, symmpass);
flip_v3_v3(sgcontext->view_origin, sgcontext->true_view_origin, symmpass);
flip_plane(sgcontext->line.plane, sgcontext->line.true_plane, symmpass);
+ flip_plane(sgcontext->line.side_plane[0], sgcontext->line.true_side_plane[0], symmpass);
+ flip_plane(sgcontext->line.side_plane[1], sgcontext->line.true_side_plane[1], symmpass);
}
static void sculpt_gesture_update_effected_nodes_by_line_plane(SculptGestureContext *sgcontext)
{
SculptSession *ss = sgcontext->ss;
- float clip_planes[1][4];
+ float clip_planes[3][4];
copy_v4_v4(clip_planes[0], sgcontext->line.plane);
- PBVHFrustumPlanes frustum = {.planes = clip_planes, .num_planes = 1};
+ copy_v4_v4(clip_planes[1], sgcontext->line.side_plane[0]);
+ copy_v4_v4(clip_planes[2], sgcontext->line.side_plane[1]);
+
+ const int num_planes = sgcontext->line.use_side_planes ? 3 : 1;
+ PBVHFrustumPlanes frustum = {.planes = clip_planes, .num_planes = num_planes};
BKE_pbvh_search_gather(ss->pbvh,
BKE_pbvh_node_frustum_contain_AABB,
&frustum,
@@ -630,6 +693,11 @@ static bool sculpt_gesture_is_vertex_effected(SculptGestureContext *sgcontext, P
case SCULPT_GESTURE_SHAPE_LASSO:
return sculpt_gesture_is_effected_lasso(sgcontext, vd->co);
case SCULPT_GESTURE_SHAPE_LINE:
+ if (sgcontext->line.use_side_planes) {
+ return plane_point_side_v3(sgcontext->line.plane, vd->co) > 0.0f &&
+ plane_point_side_v3(sgcontext->line.side_plane[0], vd->co) > 0.0f &&
+ plane_point_side_v3(sgcontext->line.side_plane[1], vd->co) > 0.0f;
+ }
return plane_point_side_v3(sgcontext->line.plane, vd->co) > 0.0f;
}
return false;
@@ -862,6 +930,24 @@ static EnumPropertyItem prop_trim_operation_types[] = {
{0, NULL, 0, NULL, NULL},
};
+typedef enum eSculptTrimOrientationType {
+ SCULPT_GESTURE_TRIM_ORIENTATION_VIEW,
+ SCULPT_GESTURE_TRIM_ORIENTATION_SURFACE,
+} eSculptTrimOrientationType;
+static EnumPropertyItem prop_trim_orientation_types[] = {
+ {SCULPT_GESTURE_TRIM_ORIENTATION_VIEW,
+ "VIEW",
+ 0,
+ "View",
+ "Use the view to orientate the trimming shape"},
+ {SCULPT_GESTURE_TRIM_ORIENTATION_SURFACE,
+ "SURFACE",
+ 0,
+ "Surface",
+ "Use the surface normal to orientate the trimming shape"},
+ {0, NULL, 0, NULL, NULL},
+};
+
typedef struct SculptGestureTrimOperation {
SculptGestureOperation op;
@@ -874,6 +960,7 @@ typedef struct SculptGestureTrimOperation {
bool use_cursor_depth;
eSculptTrimOperationType mode;
+ eSculptTrimOrientationType orientation;
} SculptGestureTrimOperation;
static void sculpt_gesture_trim_normals_update(SculptGestureContext *sgcontext)
@@ -910,6 +997,29 @@ static void sculpt_gesture_trim_normals_update(SculptGestureContext *sgcontext)
trim_operation->mesh = result;
}
+/* Get the origin and normal that are going to be used for calculating the depth and position the
+ * trimming geometry. */
+static void sculpt_gesture_trim_shape_origin_normal_get(SculptGestureContext *sgcontext,
+ float *r_origin,
+ float *r_normal)
+{
+ SculptGestureTrimOperation *trim_operation = (SculptGestureTrimOperation *)sgcontext->operation;
+ /* Use the view origin and normal in world space. The trimming mesh coordinates are
+ * calculated in world space, aligned to the view, and then converted to object space to
+ * store them in the final trimming mesh which is going to be used in the boolean operation.
+ */
+ switch (trim_operation->orientation) {
+ case SCULPT_GESTURE_TRIM_ORIENTATION_VIEW:
+ copy_v3_v3(r_origin, sgcontext->world_space_view_origin);
+ copy_v3_v3(r_normal, sgcontext->world_space_view_normal);
+ break;
+ case SCULPT_GESTURE_TRIM_ORIENTATION_SURFACE:
+ mul_v3_m4v3(r_origin, sgcontext->vc.obact->obmat, sgcontext->ss->gesture_initial_location);
+ mul_v3_m4v3(r_normal, sgcontext->vc.obact->obmat, sgcontext->ss->gesture_initial_normal);
+ break;
+ }
+}
+
static void sculpt_gesture_trim_calculate_depth(bContext *C, SculptGestureContext *sgcontext)
{
SculptGestureTrimOperation *trim_operation = (SculptGestureTrimOperation *)sgcontext->operation;
@@ -919,11 +1029,11 @@ static void sculpt_gesture_trim_calculate_depth(bContext *C, SculptGestureContex
const int totvert = SCULPT_vertex_count_get(ss);
- float view_plane[4];
- const float *view_origin = sgcontext->world_space_view_origin;
- const float *view_normal = sgcontext->world_space_view_normal;
-
- plane_from_point_normal_v3(view_plane, view_origin, view_normal);
+ float shape_plane[4];
+ float shape_origin[3];
+ float shape_normal[3];
+ sculpt_gesture_trim_shape_origin_normal_get(sgcontext, shape_origin, shape_normal);
+ plane_from_point_normal_v3(shape_plane, shape_origin, shape_normal);
trim_operation->depth_front = FLT_MAX;
trim_operation->depth_back = -FLT_MAX;
@@ -935,7 +1045,7 @@ static void sculpt_gesture_trim_calculate_depth(bContext *C, SculptGestureContex
* store them. */
float world_space_vco[3];
mul_v3_m4v3(world_space_vco, vc->obact->obmat, vco);
- const float dist = dist_signed_to_plane_v3(world_space_vco, view_plane);
+ const float dist = dist_signed_to_plane_v3(world_space_vco, shape_plane);
trim_operation->depth_front = min_ff(dist, trim_operation->depth_front);
trim_operation->depth_back = max_ff(dist, trim_operation->depth_back);
}
@@ -944,11 +1054,22 @@ static void sculpt_gesture_trim_calculate_depth(bContext *C, SculptGestureContex
float world_space_gesture_initial_location[3];
mul_v3_m4v3(
world_space_gesture_initial_location, vc->obact->obmat, ss->gesture_initial_location);
- const float mid_point_depth = ss->gesture_initial_hit ?
- dist_signed_to_plane_v3(world_space_gesture_initial_location,
- view_plane) :
- (trim_operation->depth_back + trim_operation->depth_front) *
- 0.5f;
+
+ float mid_point_depth;
+ if (trim_operation->orientation == SCULPT_GESTURE_TRIM_ORIENTATION_VIEW) {
+ mid_point_depth = ss->gesture_initial_hit ?
+ dist_signed_to_plane_v3(world_space_gesture_initial_location,
+ shape_plane) :
+ (trim_operation->depth_back + trim_operation->depth_front) * 0.5f;
+ }
+ else {
+ /* When using normal orientation, if the stroke started over the mesh, position the mid point
+ * at 0 distance from the shape plane. This positions the trimming shape half inside of the
+ * surface. */
+ mid_point_depth = ss->gesture_initial_hit ?
+ 0.0f :
+ (trim_operation->depth_back + trim_operation->depth_front) * 0.5f;
+ }
Sculpt *sd = CTX_data_tool_settings(C)->sculpt;
Brush *brush = BKE_paint_brush(&sd->paint);
@@ -986,30 +1107,41 @@ static void sculpt_gesture_trim_geometry_generate(SculptGestureContext *sgcontex
depth_back += 0.1f;
}
- /* Use the view origin and normal in world space. The trimming mesh coordinates are calculated in
- * world space, aligned to the view, and then converted to object space to store them in the
- * final trimming mesh which is going to be used in the boolean operation.
- */
- const float *view_origin = sgcontext->world_space_view_origin;
- const float *view_normal = sgcontext->world_space_view_normal;
+ float shape_origin[3];
+ float shape_normal[3];
+ float shape_plane[4];
+ sculpt_gesture_trim_shape_origin_normal_get(sgcontext, shape_origin, shape_normal);
+ plane_from_point_normal_v3(shape_plane, shape_origin, shape_normal);
const float(*ob_imat)[4] = vc->obact->imat;
/* Write vertices coordinates for the front face. */
float depth_point[3];
- madd_v3_v3v3fl(depth_point, view_origin, view_normal, depth_front);
+ madd_v3_v3v3fl(depth_point, shape_origin, shape_normal, depth_front);
for (int i = 0; i < tot_screen_points; i++) {
float new_point[3];
- ED_view3d_win_to_3d(vc->v3d, region, depth_point, screen_points[i], new_point);
+ if (trim_operation->orientation == SCULPT_GESTURE_TRIM_ORIENTATION_VIEW) {
+ ED_view3d_win_to_3d(vc->v3d, region, depth_point, screen_points[i], new_point);
+ }
+ else {
+ ED_view3d_win_to_3d_on_plane(region, shape_plane, screen_points[i], false, new_point);
+ madd_v3_v3fl(new_point, shape_normal, depth_front);
+ }
mul_v3_m4v3(trim_operation->mesh->mvert[i].co, ob_imat, new_point);
mul_v3_m4v3(trim_operation->true_mesh_co[i], ob_imat, new_point);
}
/* Write vertices coordinates for the back face. */
- madd_v3_v3v3fl(depth_point, view_origin, view_normal, depth_back);
+ madd_v3_v3v3fl(depth_point, shape_origin, shape_normal, depth_back);
for (int i = 0; i < tot_screen_points; i++) {
float new_point[3];
- ED_view3d_win_to_3d(vc->v3d, region, depth_point, screen_points[i], new_point);
+ if (trim_operation->orientation == SCULPT_GESTURE_TRIM_ORIENTATION_VIEW) {
+ ED_view3d_win_to_3d(vc->v3d, region, depth_point, screen_points[i], new_point);
+ }
+ else {
+ ED_view3d_win_to_3d_on_plane(region, shape_plane, screen_points[i], false, new_point);
+ madd_v3_v3fl(new_point, shape_normal, depth_back);
+ }
mul_v3_m4v3(trim_operation->mesh->mvert[i + tot_screen_points].co, ob_imat, new_point);
mul_v3_m4v3(trim_operation->true_mesh_co[i + tot_screen_points], ob_imat, new_point);
}
@@ -1224,6 +1356,12 @@ static void sculpt_gesture_init_trim_properties(SculptGestureContext *sgcontext,
trim_operation->mode = RNA_enum_get(op->ptr, "trim_mode");
trim_operation->use_cursor_depth = RNA_boolean_get(op->ptr, "use_cursor_depth");
+ trim_operation->orientation = RNA_enum_get(op->ptr, "trim_orientation");
+
+ /* If the cursor was not over the mesh, force the orientation to view. */
+ if (!sgcontext->ss->gesture_initial_hit) {
+ trim_operation->orientation = SCULPT_GESTURE_TRIM_ORIENTATION_VIEW;
+ }
}
static void sculpt_trim_gesture_operator_properties(wmOperatorType *ot)
@@ -1240,6 +1378,12 @@ static void sculpt_trim_gesture_operator_properties(wmOperatorType *ot)
false,
"Use Cursor for Depth",
"Use cursor location and radius for the dimensions and position of the trimming shape");
+ RNA_def_enum(ot->srna,
+ "trim_orientation",
+ prop_trim_orientation_types,
+ SCULPT_GESTURE_TRIM_ORIENTATION_VIEW,
+ "Shape Orientation",
+ NULL);
}
/* Project Gesture Operation. */
@@ -1425,6 +1569,7 @@ static int sculpt_trim_gesture_box_invoke(bContext *C, wmOperator *op, const wmE
ss->gesture_initial_hit = SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
if (ss->gesture_initial_hit) {
copy_v3_v3(ss->gesture_initial_location, sgi.location);
+ copy_v3_v3(ss->gesture_initial_normal, sgi.normal);
}
return WM_gesture_box_invoke(C, op, event);
@@ -1460,6 +1605,7 @@ static int sculpt_trim_gesture_lasso_invoke(bContext *C, wmOperator *op, const w
ss->gesture_initial_hit = SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false);
if (ss->gesture_initial_hit) {
copy_v3_v3(ss->gesture_initial_location, sgi.location);
+ copy_v3_v3(ss->gesture_initial_normal, sgi.normal);
}
return WM_gesture_lasso_invoke(C, op, event);