diff options
author | Pablo Dobarro <pablodp606@gmail.com> | 2019-08-19 18:03:55 +0300 |
---|---|---|
committer | Pablo Dobarro <pablodp606@gmail.com> | 2019-08-27 15:58:24 +0300 |
commit | 87cafe92ce2f99d8da620b80e1c26f8078554f93 (patch) | |
tree | 72c961fa8410da4e5c28287ab1c9a9452e0ce3bf | |
parent | cd890c4c256ebe396a42a3b20476d81faa10d3b1 (diff) |
Sculpt/Paint: Brush world spacing option for sculpt mode
New brush option to calculate the distance to generate a new brush step using the cursor position over the mesh instead of the screen coordinates. This avoids artifacts when sculpting across curved surfaces.
Reviewed By: brecht
Differential Revision: https://developer.blender.org/D5432
-rw-r--r-- | release/scripts/startup/bl_ui/space_view3d_toolbar.py | 2 | ||||
-rw-r--r-- | source/blender/blenloader/intern/versioning_270.c | 2 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/paint_stroke.c | 118 | ||||
-rw-r--r-- | source/blender/makesdna/DNA_brush_types.h | 2 | ||||
-rw-r--r-- | source/blender/makesrna/intern/rna_brush.c | 17 |
5 files changed, 119 insertions, 22 deletions
diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py index 9fd35808b4b..a3c8f759f06 100644 --- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -913,6 +913,8 @@ class VIEW3D_PT_tools_brush_stroke(Panel, View3DPaintPanel): if brush.sculpt_capabilities.has_space_attenuation: col.prop(brush, "use_space_attenuation") + col.prop(brush, "use_scene_spacing") + if brush.sculpt_capabilities.has_jitter: row = col.row(align=True) diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c index b61692799ed..5010cc8071d 100644 --- a/source/blender/blenloader/intern/versioning_270.c +++ b/source/blender/blenloader/intern/versioning_270.c @@ -1748,7 +1748,7 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *bmain) for (Brush *br = bmain->brushes.first; br; br = br->id.next) { br->falloff_angle = DEG2RADF(80); br->flag &= ~(BRUSH_FLAG_UNUSED_1 | BRUSH_FLAG_UNUSED_6 | BRUSH_FLAG_UNUSED_7 | - BRUSH_FLAG_UNUSED_17 | BRUSH_FRONTFACE_FALLOFF); + BRUSH_SCENE_SPACING | BRUSH_FRONTFACE_FALLOFF); } for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c index 694dae49d30..b4b1ae3b0af 100644 --- a/source/blender/editors/sculpt_paint/paint_stroke.c +++ b/source/blender/editors/sculpt_paint/paint_stroke.c @@ -57,6 +57,7 @@ #include "IMB_imbuf_types.h" #include "paint_intern.h" +#include "sculpt_intern.h" #include <float.h> #include <math.h> @@ -93,6 +94,8 @@ typedef struct PaintStroke { int cur_sample; float last_mouse_position[2]; + float last_scene_space_position[3]; + bool stroke_over_mesh; /* space distance covered so far */ float stroke_distance; @@ -233,6 +236,17 @@ static bool paint_tool_require_location(Brush *brush, ePaintMode mode) return true; } +static bool paint_stroke_use_scene_spacing(Brush *brush, ePaintMode mode) +{ + switch (mode) { + case PAINT_MODE_SCULPT: + return brush->flag & BRUSH_SCENE_SPACING; + default: + break; + } + return false; +} + static bool paint_tool_require_inbetween_mouse_events(Brush *brush, ePaintMode mode) { switch (mode) { @@ -523,6 +537,10 @@ static void paint_brush_stroke_add_step(bContext *C, copy_v2_v2(stroke->last_mouse_position, mouse_in); stroke->last_pressure = pressure; + if (paint_stroke_use_scene_spacing(brush, mode)) { + sculpt_stroke_get_location(C, stroke->last_scene_space_position, stroke->last_mouse_position); + } + if (paint_stroke_use_jitter(mode, brush, stroke->stroke_mode == BRUSH_STROKE_INVERT)) { float delta[2]; float factor = stroke->zoom_2d; @@ -600,14 +618,32 @@ static bool paint_smooth_stroke(PaintStroke *stroke, return true; } -static float paint_space_stroke_spacing(const Scene *scene, +static float paint_space_stroke_spacing(bContext *C, + const Scene *scene, PaintStroke *stroke, float size_pressure, float spacing_pressure) { - /* brushes can have a minimum size of 1.0 but with pressure it can be smaller then a pixel - * causing very high step sizes, hanging blender [#32381] */ - const float size_clamp = max_ff(1.0f, BKE_brush_size_get(scene, stroke->brush) * size_pressure); + Paint *paint = BKE_paint_get_active_from_context(C); + ePaintMode mode = BKE_paintmode_get_active_from_context(C); + Brush *brush = BKE_paint_brush(paint); + float size_clamp = 0.0f; + float size = BKE_brush_size_get(scene, stroke->brush) * size_pressure; + if (paint_stroke_use_scene_spacing(brush, mode)) { + if (!BKE_brush_use_locked_size(scene, brush)) { + size_clamp = paint_calc_object_space_radius( + &stroke->vc, stroke->last_scene_space_position, size); + } + else { + size_clamp = BKE_brush_unprojected_radius_get(scene, brush) * size_pressure; + } + } + else { + /* brushes can have a minimum size of 1.0 but with pressure it can be smaller then a pixel + * causing very high step sizes, hanging blender [#32381] */ + size_clamp = max_ff(1.0f, size); + } + float spacing = stroke->brush->spacing; /* apply spacing pressure */ @@ -619,7 +655,12 @@ static float paint_space_stroke_spacing(const Scene *scene, * the fact that brush can be scaled there. */ spacing *= stroke->zoom_2d; - return max_ff(1.0, size_clamp * spacing / 50.0f); + if (paint_stroke_use_scene_spacing(brush, mode)) { + return size_clamp * spacing / 50.0f; + } + else { + return max_ff(1.0, size_clamp * spacing / 50.0f); + } } static float paint_stroke_overlapped_curve(Brush *br, float x, float spacing) @@ -677,14 +718,18 @@ static float paint_stroke_integrate_overlap(Brush *br, float factor) } } -static float paint_space_stroke_spacing_variable( - const Scene *scene, PaintStroke *stroke, float pressure, float dpressure, float length) +static float paint_space_stroke_spacing_variable(bContext *C, + const Scene *scene, + PaintStroke *stroke, + float pressure, + float dpressure, + float length) { if (BKE_brush_use_size_pressure(scene, stroke->brush)) { /* use pressure to modify size. set spacing so that at 100%, the circles * are aligned nicely with no overlap. for this the spacing needs to be * the average of the previous and next size. */ - float s = paint_space_stroke_spacing(scene, stroke, 1.0f, pressure); + float s = paint_space_stroke_spacing(C, scene, stroke, 1.0f, pressure); float q = s * dpressure / (2.0f * length); float pressure_fac = (1.0f + q) / (1.0f - q); @@ -692,14 +737,15 @@ static float paint_space_stroke_spacing_variable( float new_size_pressure = stroke->last_pressure * pressure_fac; /* average spacing */ - float last_spacing = paint_space_stroke_spacing(scene, stroke, last_size_pressure, pressure); - float new_spacing = paint_space_stroke_spacing(scene, stroke, new_size_pressure, pressure); + float last_spacing = paint_space_stroke_spacing( + C, scene, stroke, last_size_pressure, pressure); + float new_spacing = paint_space_stroke_spacing(C, scene, stroke, new_size_pressure, pressure); return 0.5f * (last_spacing + new_spacing); } else { /* no size pressure */ - return paint_space_stroke_spacing(scene, stroke, 1.0f, pressure); + return paint_space_stroke_spacing(C, scene, stroke, 1.0f, pressure); } } @@ -711,29 +757,57 @@ static int paint_space_stroke(bContext *C, float final_pressure) { const Scene *scene = CTX_data_scene(C); + ARegion *ar = CTX_wm_region(C); PaintStroke *stroke = op->customdata; UnifiedPaintSettings *ups = stroke->ups; + Paint *paint = BKE_paint_get_active_from_context(C); + ePaintMode mode = BKE_paintmode_get_active_from_context(C); + Brush *brush = BKE_paint_brush(paint); int cnt = 0; float pressure, dpressure; float mouse[2], dmouse[2]; + float scene_space_position[3], d_scene_space_position[3], final_scene_space_position[3]; float length; - float no_pressure_spacing = paint_space_stroke_spacing(scene, stroke, 1.0f, 1.0f); - - sub_v2_v2v2(dmouse, final_mouse, stroke->last_mouse_position); - + float no_pressure_spacing = paint_space_stroke_spacing(C, scene, stroke, 1.0f, 1.0f); pressure = stroke->last_pressure; dpressure = final_pressure - stroke->last_pressure; - + sub_v2_v2v2(dmouse, final_mouse, stroke->last_mouse_position); length = normalize_v2(dmouse); + if (paint_stroke_use_scene_spacing(brush, mode)) { + bool hit = sculpt_stroke_get_location(C, scene_space_position, final_mouse); + if (hit && stroke->stroke_over_mesh) { + sub_v3_v3v3(d_scene_space_position, scene_space_position, stroke->last_scene_space_position); + length = len_v3(d_scene_space_position); + stroke->stroke_over_mesh = true; + } + else { + length = 0.0f; + stroke->stroke_over_mesh = hit; + if (stroke->stroke_over_mesh) { + copy_v3_v3(stroke->last_scene_space_position, scene_space_position); + } + } + } + while (length > 0.0f) { float spacing = paint_space_stroke_spacing_variable( - scene, stroke, pressure, dpressure, length); + C, scene, stroke, pressure, dpressure, length); if (length >= spacing) { - mouse[0] = stroke->last_mouse_position[0] + dmouse[0] * spacing; - mouse[1] = stroke->last_mouse_position[1] + dmouse[1] * spacing; + if (paint_stroke_use_scene_spacing(brush, mode)) { + normalize_v3(d_scene_space_position); + mul_v3_v3fl(final_scene_space_position, d_scene_space_position, spacing); + add_v3_v3v3(final_scene_space_position, + stroke->last_scene_space_position, + final_scene_space_position); + ED_view3d_project(ar, final_scene_space_position, mouse); + } + else { + mouse[0] = stroke->last_mouse_position[0] + dmouse[0] * spacing; + mouse[1] = stroke->last_mouse_position[1] + dmouse[1] * spacing; + } pressure = stroke->last_pressure + (spacing / length) * dpressure; ups->overlap_factor = paint_stroke_integrate_overlap(stroke->brush, @@ -1079,7 +1153,7 @@ static bool paint_stroke_curve_end(bContext *C, wmOperator *op, PaintStroke *str if (br->flag & BRUSH_CURVE) { UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings; const Scene *scene = CTX_data_scene(C); - const float spacing = paint_space_stroke_spacing(scene, stroke, 1.0f, 1.0f); + const float spacing = paint_space_stroke_spacing(C, scene, stroke, 1.0f, 1.0f); PaintCurve *pc = br->paint_curve; PaintCurvePoint *pcp; float length_residue = 0.0f; @@ -1250,6 +1324,10 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event) if (!stroke->stroke_started) { stroke->last_pressure = sample_average.pressure; copy_v2_v2(stroke->last_mouse_position, sample_average.mouse); + if (paint_stroke_use_scene_spacing(br, mode)) { + stroke->stroke_over_mesh = sculpt_stroke_get_location( + C, stroke->last_scene_space_position, sample_average.mouse); + } stroke->stroke_started = stroke->test_start(C, op, sample_average.mouse); BLI_assert((stroke->stroke_started & ~1) == 0); /* 0/1 */ diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h index 93ce3d9769b..78aa68556cb 100644 --- a/source/blender/makesdna/DNA_brush_types.h +++ b/source/blender/makesdna/DNA_brush_types.h @@ -395,7 +395,7 @@ typedef enum eBrushFlags { BRUSH_LOCK_ALPHA = (1 << 14), BRUSH_ORIGINAL_NORMAL = (1 << 15), BRUSH_OFFSET_PRESSURE = (1 << 16), - BRUSH_FLAG_UNUSED_17 = (1 << 17), /* cleared */ + BRUSH_SCENE_SPACING = (1 << 17), BRUSH_SPACE_ATTEN = (1 << 18), BRUSH_ADAPTIVE_SPACE = (1 << 19), BRUSH_LOCK_SIZE = (1 << 20), diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index 15602599e4e..a51897bc340 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -1571,6 +1571,16 @@ static void rna_def_brush(BlenderRNA *brna) {0, NULL, 0, NULL, NULL}, }; + static const EnumPropertyItem brush_spacing_unit_items[] = { + {0, "VIEW", 0, "View", "Calculate brush spacing relative to the view"}, + {BRUSH_SCENE_SPACING, + "SCENE", + 0, + "Scene", + "Calculate brush spacing relative to the scene using the stroke location"}, + {0, NULL, 0, NULL, NULL}, + }; + static const EnumPropertyItem brush_curve_preset_items[] = { {BRUSH_CURVE_CUSTOM, "CUSTOM", ICON_RNDCURVE, "Custom", ""}, {BRUSH_CURVE_SMOOTH, "SMOOTH", ICON_SMOOTHCURVE, "Smooth", ""}, @@ -1920,6 +1930,13 @@ static void rna_def_brush(BlenderRNA *brna) "When locked keep using normal of surface where stroke was initiated"); RNA_def_property_update(prop, 0, "rna_Brush_update"); + prop = RNA_def_property(srna, "use_scene_spacing", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag"); + RNA_def_property_enum_items(prop, brush_spacing_unit_items); + RNA_def_property_ui_text( + prop, "Spacing distance", "Calculate the brush spacing using view or scene distance"); + RNA_def_property_update(prop, 0, "rna_Brush_update"); + prop = RNA_def_property(srna, "use_pressure_strength", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_ALPHA_PRESSURE); RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0); |