Sculpt/Paint: Brush curve presets
This patch introduces the same presets that are used for proportional editing in the brush falloff menu. The user can select any of these presets or use the regular custom falloff curve. The presets are hardcoded formulas, so the falloff curve is not used when they are active. This change improves the general feeling of the brushes and it is more convenient and simpler to use. The CUSTOM curve option should now be used in the case that an unusual deformation is needed, in other cases, the hardcoded curve presets should be the default. The smooth curve presets is a must in the grab brush, as it fixes the deformation issue with the current custom curve setting. The user may try to adjust the deformation by tweaking the curve, but it is nearly impossible to replicate this desired behavior. {F7636217} Other brushes that are included in the sculpt branch also rely on this as they need specific hardcoded falloffs to produce the desired effect. Reviewers: brecht, billreynish Reviewed By: brecht Subscribers: JulienKaspar Differential Revision: https://developer.blender.org/D5367
This commit is contained in:
parent
03f652b2c1
commit
4bb9fbd3a8
|
@ -1438,16 +1438,21 @@ class IMAGE_PT_paint_curve(BrushButtonsPanel, Panel):
|
|||
tool_settings = context.tool_settings.image_paint
|
||||
brush = tool_settings.brush
|
||||
|
||||
layout.template_curve_mapping(brush, "curve")
|
||||
|
||||
col = layout.column(align=True)
|
||||
row = col.row(align=True)
|
||||
row.operator("brush.curve_preset", icon='SMOOTHCURVE', text="").shape = 'SMOOTH'
|
||||
row.operator("brush.curve_preset", icon='SPHERECURVE', text="").shape = 'ROUND'
|
||||
row.operator("brush.curve_preset", icon='ROOTCURVE', text="").shape = 'ROOT'
|
||||
row.operator("brush.curve_preset", icon='SHARPCURVE', text="").shape = 'SHARP'
|
||||
row.operator("brush.curve_preset", icon='LINCURVE', text="").shape = 'LINE'
|
||||
row.operator("brush.curve_preset", icon='NOCURVE', text="").shape = 'MAX'
|
||||
row.prop(brush, "curve_preset", text="")
|
||||
|
||||
if brush.curve_preset == 'CUSTOM':
|
||||
layout.template_curve_mapping(brush, "curve")
|
||||
|
||||
col = layout.column(align=True)
|
||||
row = col.row(align=True)
|
||||
row.operator("brush.curve_preset", icon='SMOOTHCURVE', text="").shape = 'SMOOTH'
|
||||
row.operator("brush.curve_preset", icon='SPHERECURVE', text="").shape = 'ROUND'
|
||||
row.operator("brush.curve_preset", icon='ROOTCURVE', text="").shape = 'ROOT'
|
||||
row.operator("brush.curve_preset", icon='SHARPCURVE', text="").shape = 'SHARP'
|
||||
row.operator("brush.curve_preset", icon='LINCURVE', text="").shape = 'LINE'
|
||||
row.operator("brush.curve_preset", icon='NOCURVE', text="").shape = 'MAX'
|
||||
|
||||
|
||||
class IMAGE_PT_tools_imagepaint_symmetry(BrushButtonsPanel, Panel):
|
||||
|
@ -1538,15 +1543,20 @@ class IMAGE_PT_uv_sculpt_curve(Panel):
|
|||
brush = uvsculpt.brush
|
||||
|
||||
if brush is not None:
|
||||
layout.template_curve_mapping(brush, "curve")
|
||||
col = layout.column(align=True)
|
||||
row = col.row(align=True)
|
||||
row.prop(brush, "curve_preset", text="")
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.operator("brush.curve_preset", icon='SMOOTHCURVE', text="").shape = 'SMOOTH'
|
||||
row.operator("brush.curve_preset", icon='SPHERECURVE', text="").shape = 'ROUND'
|
||||
row.operator("brush.curve_preset", icon='ROOTCURVE', text="").shape = 'ROOT'
|
||||
row.operator("brush.curve_preset", icon='SHARPCURVE', text="").shape = 'SHARP'
|
||||
row.operator("brush.curve_preset", icon='LINCURVE', text="").shape = 'LINE'
|
||||
row.operator("brush.curve_preset", icon='NOCURVE', text="").shape = 'MAX'
|
||||
if brush.curve_preset == 'CUSTOM':
|
||||
layout.template_curve_mapping(brush, "curve")
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.operator("brush.curve_preset", icon='SMOOTHCURVE', text="").shape = 'SMOOTH'
|
||||
row.operator("brush.curve_preset", icon='SPHERECURVE', text="").shape = 'ROUND'
|
||||
row.operator("brush.curve_preset", icon='ROOTCURVE', text="").shape = 'ROOT'
|
||||
row.operator("brush.curve_preset", icon='SHARPCURVE', text="").shape = 'SHARP'
|
||||
row.operator("brush.curve_preset", icon='LINCURVE', text="").shape = 'LINE'
|
||||
row.operator("brush.curve_preset", icon='NOCURVE', text="").shape = 'MAX'
|
||||
|
||||
|
||||
class ImageScopesPanel:
|
||||
|
|
|
@ -2687,7 +2687,7 @@ class VIEW3D_MT_brush(Menu):
|
|||
sculpt_tool = brush.sculpt_tool
|
||||
|
||||
layout.separator()
|
||||
layout.operator_menu_enum("brush.curve_preset", "shape", text="Curve Preset")
|
||||
layout.prop_menu_enum(brush, "curve_preset")
|
||||
layout.separator()
|
||||
|
||||
if sculpt_tool != 'GRAB':
|
||||
|
|
|
@ -958,16 +958,21 @@ class VIEW3D_PT_tools_brush_falloff(Panel, View3DPaintPanel):
|
|||
settings = self.paint_settings(context)
|
||||
brush = settings.brush
|
||||
|
||||
layout.template_curve_mapping(brush, "curve", brush=True)
|
||||
|
||||
col = layout.column(align=True)
|
||||
row = col.row(align=True)
|
||||
row.operator("brush.curve_preset", icon='SMOOTHCURVE', text="").shape = 'SMOOTH'
|
||||
row.operator("brush.curve_preset", icon='SPHERECURVE', text="").shape = 'ROUND'
|
||||
row.operator("brush.curve_preset", icon='ROOTCURVE', text="").shape = 'ROOT'
|
||||
row.operator("brush.curve_preset", icon='SHARPCURVE', text="").shape = 'SHARP'
|
||||
row.operator("brush.curve_preset", icon='LINCURVE', text="").shape = 'LINE'
|
||||
row.operator("brush.curve_preset", icon='NOCURVE', text="").shape = 'MAX'
|
||||
row.prop(brush, "curve_preset", text="")
|
||||
|
||||
if brush.curve_preset == 'CUSTOM':
|
||||
layout.template_curve_mapping(brush, "curve", brush=True)
|
||||
|
||||
col = layout.column(align=True)
|
||||
row = col.row(align=True)
|
||||
row.operator("brush.curve_preset", icon='SMOOTHCURVE', text="").shape = 'SMOOTH'
|
||||
row.operator("brush.curve_preset", icon='SPHERECURVE', text="").shape = 'ROUND'
|
||||
row.operator("brush.curve_preset", icon='ROOTCURVE', text="").shape = 'ROOT'
|
||||
row.operator("brush.curve_preset", icon='SHARPCURVE', text="").shape = 'SHARP'
|
||||
row.operator("brush.curve_preset", icon='LINCURVE', text="").shape = 'LINE'
|
||||
row.operator("brush.curve_preset", icon='NOCURVE', text="").shape = 'MAX'
|
||||
|
||||
|
||||
class VIEW3D_PT_tools_brush_falloff_frontface(View3DPaintPanel, Panel):
|
||||
|
|
|
@ -1400,16 +1400,45 @@ void BKE_brush_randomize_texture_coords(UnifiedPaintSettings *ups, bool mask)
|
|||
/* Uses the brush curve control to find a strength value */
|
||||
float BKE_brush_curve_strength(const Brush *br, float p, const float len)
|
||||
{
|
||||
float strength;
|
||||
float strength = 1.0f;
|
||||
|
||||
if (p >= len) {
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
p = p / len;
|
||||
p = 1.0f - p;
|
||||
}
|
||||
|
||||
strength = curvemapping_evaluateF(br->curve, 0, p);
|
||||
switch (br->curve_preset) {
|
||||
case BRUSH_CURVE_CUSTOM:
|
||||
strength = curvemapping_evaluateF(br->curve, 0, 1.0f - p);
|
||||
break;
|
||||
case BRUSH_CURVE_SHARP:
|
||||
strength = p * p;
|
||||
break;
|
||||
case BRUSH_CURVE_SMOOTH:
|
||||
strength = 3.0f * p * p - 2.0f * p * p * p;
|
||||
break;
|
||||
case BRUSH_CURVE_ROOT:
|
||||
strength = sqrtf(p);
|
||||
break;
|
||||
case BRUSH_CURVE_LIN:
|
||||
strength = p;
|
||||
break;
|
||||
case BRUSH_CURVE_CONSTANT:
|
||||
strength = 1.0f;
|
||||
break;
|
||||
case BRUSH_CURVE_SPHERE:
|
||||
strength = sqrtf(2 * p - p * p);
|
||||
break;
|
||||
case BRUSH_CURVE_POW4:
|
||||
strength = p * p * p * p;
|
||||
break;
|
||||
case BRUSH_CURVE_INVSQUARE:
|
||||
strength = p * (2.0f - p);
|
||||
break;
|
||||
}
|
||||
|
||||
return strength;
|
||||
}
|
||||
|
|
|
@ -1262,7 +1262,6 @@ float tex_strength(SculptSession *ss,
|
|||
|
||||
/* Falloff curve */
|
||||
avg *= BKE_brush_curve_strength(br, len, cache->radius);
|
||||
|
||||
avg *= frontface(br, cache->view_normal, vno, fno);
|
||||
|
||||
/* Paint mask */
|
||||
|
|
|
@ -186,6 +186,18 @@ typedef enum eGP_BrushIcons {
|
|||
GP_BRUSH_ICON_ERASE_STROKE = 10,
|
||||
} eGP_BrushIcons;
|
||||
|
||||
typedef enum eBrushCurvePreset {
|
||||
BRUSH_CURVE_CUSTOM = 0,
|
||||
BRUSH_CURVE_SMOOTH = 1,
|
||||
BRUSH_CURVE_SPHERE = 2,
|
||||
BRUSH_CURVE_ROOT = 3,
|
||||
BRUSH_CURVE_SHARP = 4,
|
||||
BRUSH_CURVE_LIN = 5,
|
||||
BRUSH_CURVE_POW4 = 6,
|
||||
BRUSH_CURVE_INVSQUARE = 7,
|
||||
BRUSH_CURVE_CONSTANT = 8,
|
||||
} eBrushCurvePreset;
|
||||
|
||||
typedef struct Brush {
|
||||
ID id;
|
||||
|
||||
|
@ -289,6 +301,9 @@ typedef struct Brush {
|
|||
|
||||
float texture_sample_bias;
|
||||
|
||||
int curve_preset;
|
||||
char _pad1[4];
|
||||
|
||||
/* overlay */
|
||||
int texture_overlay_alpha;
|
||||
int mask_overlay_alpha;
|
||||
|
|
|
@ -1565,6 +1565,19 @@ static void rna_def_brush(BlenderRNA *brna)
|
|||
{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", ""},
|
||||
{BRUSH_CURVE_SPHERE, "SPHERE", ICON_SPHERECURVE, "Sphere", ""},
|
||||
{BRUSH_CURVE_ROOT, "ROOT", ICON_ROOTCURVE, "Root", ""},
|
||||
{BRUSH_CURVE_SHARP, "SHARP", ICON_SHARPCURVE, "Sharp", ""},
|
||||
{BRUSH_CURVE_LIN, "LIN", ICON_LINCURVE, "Linear", ""},
|
||||
{BRUSH_CURVE_POW4, "POW4", ICON_SHARPCURVE, "Sharper", ""},
|
||||
{BRUSH_CURVE_INVSQUARE, "INVSQUARE", ICON_INVERSESQUARECURVE, "Inverse square", ""},
|
||||
{BRUSH_CURVE_CONSTANT, "CONSTANT", ICON_NOCURVE, "Constant", ""},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
srna = RNA_def_struct(brna, "Brush", "ID");
|
||||
RNA_def_struct_ui_text(
|
||||
srna, "Brush", "Brush data-block for storing brush settings for painting and sculpting");
|
||||
|
@ -1640,6 +1653,11 @@ static void rna_def_brush(BlenderRNA *brna)
|
|||
RNA_def_property_ui_text(prop, "Mask Tool", "");
|
||||
RNA_def_property_update(prop, 0, "rna_Brush_update");
|
||||
|
||||
prop = RNA_def_property(srna, "curve_preset", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_items(prop, brush_curve_preset_items);
|
||||
RNA_def_property_ui_text(prop, "Curve Preset", "");
|
||||
RNA_def_property_update(prop, 0, "rna_Brush_update");
|
||||
|
||||
/* number values */
|
||||
prop = RNA_def_property(srna, "size", PROP_INT, PROP_PIXEL);
|
||||
RNA_def_property_int_funcs(prop, NULL, "rna_Brush_set_size", NULL);
|
||||
|
|
Loading…
Reference in New Issue