From 5d7e785fdd59c174c754ddc61441e3671052ec5c Mon Sep 17 00:00:00 2001 From: Falk David Date: Tue, 14 May 2024 15:20:31 +0200 Subject: [PATCH] GPv3: Brush radius unit option This implements and exposes the `View`/`Scene` brush radius option. * `View`: Brush units are in pixels. Zooming in and out in the viewport will make the brush stay the same size relative to the view, but grow/shrink relative to the scene. * `Scene`: Brush units are in meters. Zooming in and out in the viewport will make the brush grow/shrink relative to the view, but stay the same size relative to the scene. The default radius unit is `Scene`, which is what GPv2 did. The "2D Animation Template" was updated to disable using the radius in the unified paint settings. This means that using the template by default will use the brush radius, which also mimics the behavior of GPv2. The user can change the radius brush unit from the `Advanced` panel. Pull Request: https://projects.blender.org/blender/blender/pulls/120257 --- .../startup/bl_ui/properties_paint_common.py | 18 ++-- scripts/startup/bl_ui/space_view3d.py | 13 ++- scripts/startup/bl_ui/space_view3d_toolbar.py | 92 +++++++++++++++++++ .../blender/blenkernel/BKE_blender_version.h | 2 +- source/blender/blenkernel/intern/brush.cc | 40 +++++++- .../blenloader/intern/versioning_400.cc | 13 +++ .../blenloader/intern/versioning_defaults.cc | 7 ++ .../editors/sculpt_paint/paint_cursor.cc | 29 +++--- 8 files changed, 192 insertions(+), 22 deletions(-) diff --git a/scripts/startup/bl_ui/properties_paint_common.py b/scripts/startup/bl_ui/properties_paint_common.py index 6a686d479ca..f25b5c23691 100644 --- a/scripts/startup/bl_ui/properties_paint_common.py +++ b/scripts/startup/bl_ui/properties_paint_common.py @@ -915,6 +915,7 @@ def brush_shared_settings(layout, context, brush, popover=False): # Grease Pencil # if mode == 'PAINT_GREASE_PENCIL': + size_mode = True size = True strength = True @@ -1446,13 +1447,21 @@ def brush_basic_grease_pencil_paint_settings(layout, context, brush, *, compact= if gp_settings is None: return + tool_settings = context.tool_settings + ups = tool_settings.unified_paint_settings + grease_pencil_tool = brush.gpencil_tool + size = "size" + size_owner = ups if ups.use_unified_size else brush + if size_owner.use_locked_size == 'SCENE': + size = "unprojected_radius" + UnifiedPaintPanel.prop_unified( layout, context, brush, - "size", + size, unified_name="use_unified_size", pressure_name="use_pressure_size", text="Radius", @@ -1511,13 +1520,6 @@ def brush_basic_grease_pencil_paint_settings(layout, context, brush, *, compact= if settings.use_thickness_curve: # Pressure curve. layout.template_curve_mapping(settings, "thickness_primitive_curve", brush=True) - elif grease_pencil_tool == 'DRAW': - layout.prop(gp_settings, "active_smooth_factor") - row = layout.row(align=True) - if compact: - row.prop(gp_settings, "caps_type", text="", expand=True) - else: - row.prop(gp_settings, "caps_type", text="Caps Type") elif grease_pencil_tool == 'ERASE': layout.prop(gp_settings, "eraser_mode", expand=True) if gp_settings.eraser_mode == 'HARD': diff --git a/scripts/startup/bl_ui/space_view3d.py b/scripts/startup/bl_ui/space_view3d.py index 6fe5423d296..eeb0a8db9af 100644 --- a/scripts/startup/bl_ui/space_view3d.py +++ b/scripts/startup/bl_ui/space_view3d.py @@ -114,6 +114,18 @@ class VIEW3D_HT_tool_header(Header): layout.popover("VIEW3D_PT_tools_grease_pencil_brush_stroke") layout.popover("VIEW3D_PT_tools_grease_pencil_paint_appearance") + elif tool_mode == 'PAINT_GREASE_PENCIL': + if is_valid_context: + brush = context.tool_settings.gpencil_paint.brush + if brush: + if brush.gpencil_tool != 'ERASE': + if brush.gpencil_tool != 'TINT': + layout.popover("VIEW3D_PT_tools_grease_pencil_v3_brush_advanced") + + if brush.gpencil_tool not in {'FILL', 'TINT'}: + layout.popover("VIEW3D_PT_tools_grease_pencil_brush_stroke") + + # layout.popover("VIEW3D_PT_tools_grease_pencil_paint_appearance") elif tool_mode == 'SCULPT_GPENCIL': if is_valid_context: brush = context.tool_settings.gpencil_sculpt_paint.brush @@ -701,7 +713,6 @@ class _draw_tool_settings_context_mode: row.prop_with_popover(brush, "color", text="", panel="TOPBAR_PT_gpencil_vertexcolor") from bl_ui.properties_paint_common import ( - brush_basic__draw_color_selector, brush_basic_grease_pencil_paint_settings, ) diff --git a/scripts/startup/bl_ui/space_view3d_toolbar.py b/scripts/startup/bl_ui/space_view3d_toolbar.py index e919341d385..ec22f3d122a 100644 --- a/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -2583,6 +2583,97 @@ class VIEW3D_PT_tools_grease_pencil_v3_brush_settings(Panel, View3DPanel, Grease brush_basic_grease_pencil_paint_settings(layout, context, brush, compact=False) +class VIEW3D_PT_tools_grease_pencil_v3_brush_advanced(View3DPanel, Panel): + bl_context = ".greasepencil_paint" + bl_label = "Advanced" + bl_parent_id = "VIEW3D_PT_tools_grease_pencil_brush_settings" + bl_category = "Tool" + bl_options = {'DEFAULT_CLOSED'} + bl_ui_units_x = 13 + + @classmethod + def poll(cls, context): + ob = context.active_object + if ob.type != 'GREASEPENCIL': + return False + brush = context.tool_settings.gpencil_paint.brush + return brush is not None and brush.gpencil_tool not in {'ERASE', 'TINT'} + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False + + tool_settings = context.scene.tool_settings + ups = tool_settings.unified_paint_settings + gpencil_paint = tool_settings.gpencil_paint + brush = gpencil_paint.brush + gp_settings = brush.gpencil_settings + + col = layout.column(align=True) + if brush is None: + return + if brush.gpencil_tool != 'FILL': + size_owner = ups if ups.use_unified_size else brush + + row = col.row(align=True) + row.prop(size_owner, "use_locked_size", expand=True) + col.separator() + + col.prop(gp_settings, "input_samples") + col.separator() + + col.prop(gp_settings, "active_smooth_factor") + col.separator() + + col.prop(gp_settings, "angle", slider=True) + col.prop(gp_settings, "angle_factor", text="Factor", slider=True) + + ob = context.object + ma = None + if ob and brush.gpencil_settings.use_material_pin is False: + ma = ob.active_material + elif brush.gpencil_settings.material: + ma = brush.gpencil_settings.material + + col.separator() + col.prop(gp_settings, "hardness", slider=True) + subcol = col.column(align=True) + if ma and ma.grease_pencil.mode == 'LINE': + subcol.enabled = False + subcol.prop(gp_settings, "aspect") + + elif brush.gpencil_tool == 'FILL': + row = col.row(align=True) + row.prop(gp_settings, "fill_draw_mode", text="Boundary", text_ctxt=i18n_contexts.id_gpencil) + row.prop( + gp_settings, + "show_fill_boundary", + icon='HIDE_OFF' if gp_settings.show_fill_boundary else 'HIDE_ON', + text="", + ) + + col.separator() + row = col.row(align=True) + row.prop(gp_settings, "fill_layer_mode", text="Layers") + + col.separator() + col.prop(gp_settings, "fill_simplify_level", text="Simplify") + if gp_settings.fill_draw_mode != 'STROKE': + col = layout.column(align=False, heading="Ignore Transparent") + col.use_property_decorate = False + row = col.row(align=True) + sub = row.row(align=True) + sub.prop(gp_settings, "show_fill", text="") + sub = sub.row(align=True) + sub.active = gp_settings.show_fill + sub.prop(gp_settings, "fill_threshold", text="") + + col.separator() + row = col.row(align=True) + row.prop(gp_settings, "use_fill_limit") + + class VIEW3D_PT_tools_grease_pencil_v3_brush_mixcolor(View3DPanel, Panel): bl_context = ".grease_pencil_paint" bl_label = "Color" @@ -2780,6 +2871,7 @@ classes = ( VIEW3D_PT_tools_grease_pencil_v3_brush_select, VIEW3D_PT_tools_grease_pencil_v3_brush_settings, + VIEW3D_PT_tools_grease_pencil_v3_brush_advanced, VIEW3D_PT_tools_grease_pencil_v3_brush_mixcolor, VIEW3D_PT_tools_grease_pencil_v3_brush_mix_palette, diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 3164c83eef3..b7e5982a91e 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -29,7 +29,7 @@ extern "C" { /* Blender file format version. */ #define BLENDER_FILE_VERSION BLENDER_VERSION -#define BLENDER_FILE_SUBVERSION 35 +#define BLENDER_FILE_SUBVERSION 36 /* Minimum Blender version that supports reading file written with the current * version. Older Blender versions will test this and cancel loading the file, showing a warning to diff --git a/source/blender/blenkernel/intern/brush.cc b/source/blender/blenkernel/intern/brush.cc index 896af0690d9..ddc94c435b1 100644 --- a/source/blender/blenkernel/intern/brush.cc +++ b/source/blender/blenkernel/intern/brush.cc @@ -24,6 +24,7 @@ #include "BKE_brush.hh" #include "BKE_colortools.hh" #include "BKE_gpencil_legacy.h" +#include "BKE_grease_pencil.hh" #include "BKE_idtype.hh" #include "BKE_lib_id.hh" #include "BKE_lib_query.hh" @@ -692,6 +693,7 @@ static void brush_gpencil_curvemap_reset(CurveMap *cuma, int tot, eGPCurveMappin void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type) { + using namespace blender; #define SMOOTH_STROKE_RADIUS 40 #define SMOOTH_STROKE_FACTOR 0.9f #define ACTIVE_SMOOTH 0.35f @@ -708,6 +710,11 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type) brush->smooth_stroke_radius = SMOOTH_STROKE_RADIUS; brush->smooth_stroke_factor = SMOOTH_STROKE_FACTOR; + /* GPv3 uses the `Scene` size aka BRUSH_LOCK_SIZE by default. */ + if (U.experimental.use_grease_pencil_version3) { + brush->flag |= BRUSH_LOCK_SIZE; + } + brush->rgb[0] = 0.498f; brush->rgb[1] = 1.0f; brush->rgb[2] = 0.498f; @@ -733,6 +740,10 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type) switch (type) { case GP_BRUSH_PRESET_AIRBRUSH: { brush->size = 300.0f; + if (U.experimental.use_grease_pencil_version3) { + brush->unprojected_radius = brush->size * + bke::greasepencil::LEGACY_RADIUS_CONVERSION_FACTOR; + } brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; brush->gpencil_settings->draw_strength = 0.4f; @@ -755,8 +766,11 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type) break; } case GP_BRUSH_PRESET_INK_PEN: { - brush->size = 60.0f; + if (U.experimental.use_grease_pencil_version3) { + brush->unprojected_radius = brush->size * + bke::greasepencil::LEGACY_RADIUS_CONVERSION_FACTOR; + } brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; brush->gpencil_settings->draw_strength = 1.0f; @@ -792,6 +806,10 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type) } case GP_BRUSH_PRESET_INK_PEN_ROUGH: { brush->size = 60.0f; + if (U.experimental.use_grease_pencil_version3) { + brush->unprojected_radius = brush->size * + bke::greasepencil::LEGACY_RADIUS_CONVERSION_FACTOR; + } brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; brush->gpencil_settings->draw_strength = 1.0f; @@ -829,6 +847,10 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type) } case GP_BRUSH_PRESET_MARKER_BOLD: { brush->size = 150.0f; + if (U.experimental.use_grease_pencil_version3) { + brush->unprojected_radius = brush->size * + bke::greasepencil::LEGACY_RADIUS_CONVERSION_FACTOR; + } brush->gpencil_settings->flag &= ~GP_BRUSH_USE_PRESSURE; brush->gpencil_settings->draw_strength = 0.3f; @@ -866,6 +888,10 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type) } case GP_BRUSH_PRESET_MARKER_CHISEL: { brush->size = 150.0f; + if (U.experimental.use_grease_pencil_version3) { + brush->unprojected_radius = brush->size * + bke::greasepencil::LEGACY_RADIUS_CONVERSION_FACTOR; + } brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; brush->gpencil_settings->draw_strength = 1.0f; @@ -907,6 +933,10 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type) } case GP_BRUSH_PRESET_PEN: { brush->size = 25.0f; + if (U.experimental.use_grease_pencil_version3) { + brush->unprojected_radius = brush->size * + bke::greasepencil::LEGACY_RADIUS_CONVERSION_FACTOR; + } brush->gpencil_settings->flag &= ~GP_BRUSH_USE_PRESSURE; brush->gpencil_settings->draw_strength = 1.0f; @@ -938,6 +968,10 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type) } case GP_BRUSH_PRESET_PENCIL_SOFT: { brush->size = 80.0f; + if (U.experimental.use_grease_pencil_version3) { + brush->unprojected_radius = brush->size * + bke::greasepencil::LEGACY_RADIUS_CONVERSION_FACTOR; + } brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; brush->gpencil_settings->draw_strength = 0.4f; @@ -972,6 +1006,10 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type) } case GP_BRUSH_PRESET_PENCIL: { brush->size = 20.0f; + if (U.experimental.use_grease_pencil_version3) { + brush->unprojected_radius = brush->size * + bke::greasepencil::LEGACY_RADIUS_CONVERSION_FACTOR; + } brush->gpencil_settings->flag |= GP_BRUSH_USE_PRESSURE; brush->gpencil_settings->draw_strength = 0.6f; diff --git a/source/blender/blenloader/intern/versioning_400.cc b/source/blender/blenloader/intern/versioning_400.cc index d8b2382353e..3202dd3eeea 100644 --- a/source/blender/blenloader/intern/versioning_400.cc +++ b/source/blender/blenloader/intern/versioning_400.cc @@ -3535,6 +3535,19 @@ void blo_do_versions_400(FileData *fd, Library * /*lib*/, Main *bmain) } } + if (!MAIN_VERSION_FILE_ATLEAST(bmain, 402, 36)) { + LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) { + /* Only for grease pencil brushes. */ + if (brush->gpencil_settings) { + /* Use the `Scene` radius unit by default (confusingly named `BRUSH_LOCK_SIZE`). + * Convert the radius to be the same visual size as in GPv2. */ + brush->flag |= BRUSH_LOCK_SIZE; + brush->unprojected_radius = brush->size * + blender::bke::greasepencil::LEGACY_RADIUS_CONVERSION_FACTOR; + } + } + } + /** * Always bump subversion in BKE_blender_version.h when adding versioning * code here, and wrap it inside a MAIN_VERSION_FILE_ATLEAST check. diff --git a/source/blender/blenloader/intern/versioning_defaults.cc b/source/blender/blenloader/intern/versioning_defaults.cc index e5a0c5360d6..edab453e68d 100644 --- a/source/blender/blenloader/intern/versioning_defaults.cc +++ b/source/blender/blenloader/intern/versioning_defaults.cc @@ -911,6 +911,13 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) } } + if (app_template && STREQ(app_template, "2D_Animation")) { + /* Disable the unified paint setting for the brush radius. */ + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + scene->toolsettings->unified_paint_settings.flag &= ~UNIFIED_PAINT_SIZE; + } + } + { LISTBASE_FOREACH (Light *, light, &bmain->lights) { light->shadow_maximum_resolution = 0.001f; diff --git a/source/blender/editors/sculpt_paint/paint_cursor.cc b/source/blender/editors/sculpt_paint/paint_cursor.cc index faea7cd62f4..b4ca7d19509 100644 --- a/source/blender/editors/sculpt_paint/paint_cursor.cc +++ b/source/blender/editors/sculpt_paint/paint_cursor.cc @@ -1515,6 +1515,7 @@ static void grease_pencil_brush_cursor_draw(PaintCursorContext *pcontext) return; } + GreasePencil *grease_pencil = static_cast(object->data); Paint *paint = pcontext->paint; Brush *brush = pcontext->brush; if ((brush == nullptr) || (brush->gpencil_settings == nullptr)) { @@ -1526,9 +1527,9 @@ static void grease_pencil_brush_cursor_draw(PaintCursorContext *pcontext) } /* default radius and color */ - float color[3] = {1.0f, 1.0f, 1.0f}; - float radius = BKE_brush_size_get(pcontext->scene, brush); + pcontext->pixel_radius = BKE_brush_size_get(pcontext->scene, brush); + float3 color(1.0f); const int x = pcontext->x; const int y = pcontext->y; @@ -1540,9 +1541,17 @@ static void grease_pencil_brush_cursor_draw(PaintCursorContext *pcontext) return; } + if (BKE_brush_use_locked_size(pcontext->scene, brush)) { + const bke::greasepencil::Layer &layer = *grease_pencil->get_active_layer(); + const ed::greasepencil::DrawingPlacement placement( + *pcontext->scene, *pcontext->region, *pcontext->vc.v3d, *object, layer); + const float radius = BKE_brush_unprojected_radius_get(pcontext->scene, brush); + const float3 location = placement.project(float2(pcontext->x, pcontext->y)); + pcontext->pixel_radius = project_brush_radius(&pcontext->vc, radius, location); + } + /* Get current drawing material. */ - Material *ma = BKE_grease_pencil_object_material_from_brush_get(object, brush); - if (ma) { + if (Material *ma = BKE_grease_pencil_object_material_from_brush_get(object, brush)) { MaterialGPencilStyle *gp_style = ma->gp_style; /* Follow user settings for the size of the draw cursor: @@ -1560,8 +1569,7 @@ static void grease_pencil_brush_cursor_draw(PaintCursorContext *pcontext) ELEM(brush->gpencil_settings->vertex_mode, GPPAINT_MODE_STROKE, GPPAINT_MODE_BOTH); - - copy_v3_v3(color, use_vertex_color_stroke ? brush->rgb : gp_style->stroke_rgba); + color = use_vertex_color_stroke ? float3(brush->rgb) : float4(gp_style->stroke_rgba).xyz(); } } } @@ -1571,14 +1579,13 @@ static void grease_pencil_brush_cursor_draw(PaintCursorContext *pcontext) GPU_line_width(1.0f); /* Inner Ring: Color from UI panel */ - immUniformColor4f(color[0], color[1], color[2], 0.8f); - imm_draw_circle_wire_2d(pcontext->pos, x, y, radius, 32); + immUniformColor4f(color.x, color.y, color.z, 0.8f); + imm_draw_circle_wire_2d(pcontext->pos, x, y, pcontext->pixel_radius, 32); /* Outer Ring: Dark color for contrast on light backgrounds (e.g. gray on white) */ - float darkcolor[3]; - mul_v3_v3fl(darkcolor, color, 0.40f); + const float3 darkcolor = color * 0.40f; immUniformColor4f(darkcolor[0], darkcolor[1], darkcolor[2], 0.8f); - imm_draw_circle_wire_2d(pcontext->pos, x, y, radius + 1, 32); + imm_draw_circle_wire_2d(pcontext->pos, x, y, pcontext->pixel_radius + 1, 32); /* Draw line for lazy mouse */ /* TODO: No stabilize mode yet. */