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
This commit is contained in:
Falk David
2024-05-14 15:20:31 +02:00
committed by Falk David
parent 890105b5ef
commit 5d7e785fdd
8 changed files with 192 additions and 22 deletions

View File

@@ -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':

View File

@@ -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,
)

View File

@@ -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,

View File

@@ -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

View File

@@ -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;

View File

@@ -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.

View File

@@ -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;

View File

@@ -1515,6 +1515,7 @@ static void grease_pencil_brush_cursor_draw(PaintCursorContext *pcontext)
return;
}
GreasePencil *grease_pencil = static_cast<GreasePencil *>(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. */