GPencil: show brush size in Draw tool cursor

When drawing strokes in Grease Pencil, it was always a bit hard
to predict how thick the strokes would be, because there was
no visual reference of the thickness in the cursor.
This patch adds that visual reference. It shows the brush size
as a circle in the draw cursor.
Showing the brush size can be toggled in the Cursor menu
of the Grease Pencil draw tool.

Request in RCS with 26 upvotes for this option:
https://blender.community/c/rightclickselect/0zfbbc

On the technical side: the brush size is calculated
in 3D space and takes zoom level into account, as well as
object/layer transfrom, layer thickness change (gpl->line_change)
and thickness scale (gpd->pixfactor).

Reviewed By: mendio, antoniov

Differential Revision: https://developer.blender.org/D16851
This commit is contained in:
Sietse Brouwer 2022-12-23 16:02:01 +01:00 committed by Antonio Vazquez
parent b024577452
commit a44c128482
4 changed files with 66 additions and 10 deletions

View File

@ -117,11 +117,13 @@ class GreasePencilDisplayPanel:
row = layout.row(align=True)
row.prop(settings, "show_brush", text="Display Cursor")
col = layout.column(align=True)
col.active = settings.show_brush
if brush.gpencil_tool == 'DRAW':
col.prop(gp_settings, "show_lasso", text="Show Fill Color While Drawing")
row = layout.row(align=True)
row.active = settings.show_brush
row.prop(gp_settings, "show_brush_size", text="Show Brush Size")
row = layout.row(align=True)
row.active = settings.show_brush
row.prop(gp_settings, "show_lasso", text="Show Fill Color While Drawing")
elif ob.mode == 'SCULPT_GPENCIL':
col = layout.column(align=True)

View File

@ -1750,6 +1750,7 @@ static void gpencil_brush_cursor_draw(bContext *C, int x, int y, void *customdat
float color[3] = {1.0f, 1.0f, 1.0f};
float darkcolor[3];
float radius = 3.0f;
bool fixed_radius = true;
const int mval_i[2] = {x, y};
/* Check if cursor is in drawing region and has valid data-block. */
@ -1787,16 +1788,61 @@ static void gpencil_brush_cursor_draw(bContext *C, int x, int y, void *customdat
if (ma) {
gp_style = ma->gp_style;
/* after some testing, display the size of the brush is not practical because
* is too disruptive and the size of cursor does not change with zoom factor.
* The decision was to use a fix size, instead of brush->thickness value.
/* Follow user settings for the size of the draw cursor:
* - Fixed size, or
* - Brush size (i.e. stroke thickness)
*/
if ((gp_style) && GPENCIL_PAINT_MODE(gpd) &&
((brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE) == 0) &&
((brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE_TEMP) == 0) &&
(brush->gpencil_tool == GPAINT_TOOL_DRAW)) {
radius = 2.0f;
copy_v3_v3(color, gp_style->stroke_rgba);
/* Check user setting for cursor size. */
fixed_radius = ((brush->gpencil_settings->flag & GP_BRUSH_SHOW_DRAW_SIZE) == 0);
if (fixed_radius) {
/* Show fixed radius. */
radius = 2.0f;
copy_v3_v3(color, gp_style->stroke_rgba);
}
else {
/* Show brush size. */
tGPspoint point2D;
float p1[3];
float p2[3];
float distance;
/* Strokes in screen space or world space? */
if ((gpd->flag & GP_DATA_STROKE_KEEPTHICKNESS) != 0) {
/* In screen space the cursor radius matches the brush size. */
radius = (float)brush->size * 0.5f;
}
else {
/* To calculate the brush size in world space, we have to establish the zoom level.
* For this we take two 2D screen coordinates with a fixed offset,
* convert them to 3D coordinates and measure the offset distance in 3D.
* A small distance means a high zoom level. */
point2D.m_xy[0] = (float)x;
point2D.m_xy[1] = (float)y;
gpencil_stroke_convertcoords_tpoint(scene, region, ob, &point2D, NULL, p1);
point2D.m_xy[0] = (float)(x + 64);
gpencil_stroke_convertcoords_tpoint(scene, region, ob, &point2D, NULL, p2);
/* Clip extreme zoom level (and avoid division by zero). */
distance = MAX2(len_v3v3(p1, p2), 0.001f);
/* Handle layer thickness change. */
float brush_size = (float)brush->size;
bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd);
if (gpl != NULL) {
brush_size = MAX2(1.0f, brush_size + gpl->line_change);
}
/* Convert the 3D offset distance to a brush radius. */
radius = (1 / distance) * 2.0f * gpd->pixfactor * (brush_size / 64);
}
copy_v3_v3(color, brush->rgb);
}
}
else {
/* Only Tint tool must show big cursor. */
@ -1876,7 +1922,7 @@ static void gpencil_brush_cursor_draw(bContext *C, int x, int y, void *customdat
/* Inner Ring: Color from UI panel */
immUniformColor4f(color[0], color[1], color[2], 0.8f);
if ((gp_style) && GPENCIL_PAINT_MODE(gpd) &&
if ((gp_style) && GPENCIL_PAINT_MODE(gpd) && (fixed_radius) &&
((brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE) == 0) &&
((brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE_TEMP) == 0) &&
(brush->gpencil_tool == GPAINT_TOOL_DRAW)) {

View File

@ -91,6 +91,8 @@ typedef enum eGPDbrush_Flag {
GP_BRUSH_OUTLINE_STROKE = (1 << 17),
/* Collide with stroke. */
GP_BRUSH_FILL_STROKE_COLLIDE = (1 << 18),
/* Show brush size */
GP_BRUSH_SHOW_DRAW_SIZE = (1 << 19),
} eGPDbrush_Flag;
typedef enum eGPDbrush_Flag2 {

View File

@ -2005,6 +2005,12 @@ static void rna_def_gpencil_options(BlenderRNA *brna)
prop, "Show Lasso", "Do not display fill color while drawing the stroke");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
prop = RNA_def_property(srna, "show_brush_size", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_SHOW_DRAW_SIZE);
RNA_def_property_boolean_default(prop, true);
RNA_def_property_ui_text(prop, "Show Brush Size", "Show the real size of the draw brush");
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
prop = RNA_def_property(srna, "use_occlude_eraser", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_BRUSH_OCCLUDE_ERASER);
RNA_def_property_ui_text(prop, "Occlude Eraser", "Erase only strokes visible and not occluded");