Sculpt-dev: New normal automasking modes
Two new automasking modes: "Brush Normal" and "View Normal." Brush Normal compares vertex normals to the initial sculpt normal, while View Normal of course compares with the view vector. Each of these modes have an angular limit and a falloff. There's also an "original normal" option, which needs a better name; "original normal" is actually already taken, but "automasking original normal" is a lot of characters. Not sure what to do here.
This commit is contained in:
parent
7e1c56d909
commit
c8aedd75d7
|
@ -2105,11 +2105,51 @@ def brush_settings_advanced(layout, context, brush, popover=False):
|
|||
context,
|
||||
brush,
|
||||
"automasking_boundary_edges_propagation_steps")
|
||||
UnifiedPaintPanel.channel_unified(layout.column(),
|
||||
|
||||
flags = UnifiedPaintPanel.get_channel_value(context, brush, "automasking")
|
||||
|
||||
if "CONCAVITY" in flags:
|
||||
UnifiedPaintPanel.channel_unified(layout.column(),
|
||||
context,
|
||||
brush,
|
||||
"concave_mask_factor",
|
||||
slider=True)
|
||||
|
||||
enable_orig_normal = False
|
||||
|
||||
if "BRUSH_NORMAL" in flags:
|
||||
UnifiedPaintPanel.channel_unified(layout.column(),
|
||||
context,
|
||||
brush,
|
||||
"normal_mask_limit",
|
||||
slider=True)
|
||||
UnifiedPaintPanel.channel_unified(layout.column(),
|
||||
context,
|
||||
brush,
|
||||
"normal_mask_falloff",
|
||||
slider=True)
|
||||
enable_orig_normal = True
|
||||
|
||||
if "VIEW_NORMAL" in flags:
|
||||
UnifiedPaintPanel.channel_unified(layout.column(),
|
||||
context,
|
||||
brush,
|
||||
"view_normal_mask_limit",
|
||||
slider=True)
|
||||
UnifiedPaintPanel.channel_unified(layout.column(),
|
||||
context,
|
||||
brush,
|
||||
"view_normal_mask_falloff",
|
||||
slider=True)
|
||||
enable_orig_normal = True
|
||||
|
||||
sub = layout.row()
|
||||
sub.enabled = enable_orig_normdal
|
||||
|
||||
UnifiedPaintPanel.channel_unified(sub,
|
||||
context,
|
||||
brush,
|
||||
"concave_mask_factor",
|
||||
slider=True)
|
||||
"automasking_use_original_normal")
|
||||
|
||||
"""
|
||||
col = layout.column(heading="Auto-Masking", align=True)
|
||||
|
|
|
@ -120,6 +120,8 @@ ToolDef = namedtuple(
|
|||
"draw_cursor",
|
||||
# Various options, see: `bpy.types.WorkSpaceTool.setup` options argument.
|
||||
"options",
|
||||
#get_enabled(ctx, idname) whether tool should be grayed out
|
||||
"get_enabled"
|
||||
)
|
||||
)
|
||||
del namedtuple
|
||||
|
@ -143,6 +145,7 @@ def from_dict(kw_args):
|
|||
"operator": None,
|
||||
"draw_settings": None,
|
||||
"draw_cursor": None,
|
||||
"get_enabled": None
|
||||
}
|
||||
kw.update(kw_args)
|
||||
|
||||
|
@ -725,9 +728,14 @@ class ToolSelectPanelHelper:
|
|||
icon_value = ToolSelectPanelHelper._icon_value_from_icon_handle(item.icon)
|
||||
|
||||
sub = ui_gen.send(False)
|
||||
sub2 = sub
|
||||
|
||||
if item.get_enabled is not None:
|
||||
sub2 = sub.row(align=False)
|
||||
sub2.enabled = item.get_enabled(context, item.idname)
|
||||
|
||||
if use_menu:
|
||||
sub.operator_menu_hold(
|
||||
sub2.operator_menu_hold(
|
||||
"wm.tool_set_by_id",
|
||||
text=item.label if show_text else "",
|
||||
depress=is_active,
|
||||
|
@ -735,7 +743,7 @@ class ToolSelectPanelHelper:
|
|||
icon_value=icon_value,
|
||||
).name = item.idname
|
||||
else:
|
||||
sub.operator(
|
||||
sub2.operator(
|
||||
"wm.tool_set_by_id",
|
||||
text=item.label if show_text else "",
|
||||
depress=is_active,
|
||||
|
|
|
@ -1211,6 +1211,83 @@ class _defs_particle:
|
|||
attr="tool",)
|
||||
|
||||
|
||||
def generate_from_enum_ex(_context, *,
|
||||
idname_prefix,
|
||||
icon_prefix,
|
||||
type,
|
||||
attr,
|
||||
cursor='DEFAULT',
|
||||
tooldef_keywords={},
|
||||
exclude_filter={},
|
||||
combine_map={}):
|
||||
"""
|
||||
combine_map combines items, takes the form of a dict:
|
||||
|
||||
combine_map = {
|
||||
"PARENT KEY" : (
|
||||
"CHILD KEY"
|
||||
)
|
||||
}
|
||||
|
||||
"""
|
||||
|
||||
combinekeys = {}
|
||||
parentmap = {}
|
||||
|
||||
for k, v in combine_map.items():
|
||||
combinekeys[k] = []
|
||||
|
||||
for child in v:
|
||||
parentmap[child] = k
|
||||
|
||||
tool_defs = []
|
||||
|
||||
#build combine key owners first
|
||||
for enum in type.bl_rna.properties[attr].enum_items_static:
|
||||
name = enum.name
|
||||
idname = enum.identifier
|
||||
if idname in exclude_filter:
|
||||
continue
|
||||
|
||||
if idname in combinekeys:
|
||||
combinekeys[idname].append(ToolDef.from_dict(dict(idname=idname_prefix + name,
|
||||
label=name,
|
||||
icon=icon_prefix + idname.lower(),
|
||||
cursor=cursor,
|
||||
data_block=idname,
|
||||
**tooldef_keywords,)))
|
||||
|
||||
for enum in type.bl_rna.properties[attr].enum_items_static:
|
||||
name = enum.name
|
||||
idname = enum.identifier
|
||||
if idname in exclude_filter:
|
||||
continue
|
||||
|
||||
if idname in combinekeys:
|
||||
tool_defs.append(combinekeys[idname])
|
||||
elif idname in parentmap:
|
||||
parentkey = parentmap[idname]
|
||||
|
||||
combinekeys[parentkey].append(ToolDef.from_dict(dict(idname=idname_prefix + name,
|
||||
label=name,
|
||||
icon=icon_prefix + idname.lower(),
|
||||
cursor=cursor,
|
||||
data_block=idname,
|
||||
**tooldef_keywords,)))
|
||||
else:
|
||||
tool_defs.append(ToolDef.from_dict(dict(idname=idname_prefix + name,
|
||||
label=name,
|
||||
icon=icon_prefix + idname.lower(),
|
||||
cursor=cursor,
|
||||
data_block=idname,
|
||||
**tooldef_keywords,)))
|
||||
|
||||
# finalize combined keys
|
||||
for k, v in combinekeys.items():
|
||||
tool_defs[tool_defs.index(v)] = tuple(v)
|
||||
|
||||
return tuple(tool_defs)
|
||||
|
||||
class _defs_sculpt:
|
||||
|
||||
@staticmethod
|
||||
|
@ -1229,12 +1306,32 @@ class _defs_sculpt:
|
|||
"SMOOTH" : ("ENHANCE_DETAILS",)
|
||||
}
|
||||
|
||||
def get_enabled(context, idname):
|
||||
if "multires" in idname.lower() or idname.lower() == "builtin_brush.displacement heal":
|
||||
print("IDNAME", idname)
|
||||
have_multires = False;
|
||||
ob = context.object
|
||||
|
||||
for mod in ob.modifiers:
|
||||
ok = mod.type == "MULTIRES"
|
||||
ok = ok and mod.sculpt_levels > 0
|
||||
ok = ok and mod.show_viewport
|
||||
|
||||
if ok:
|
||||
have_multires = True
|
||||
break
|
||||
|
||||
return have_multires
|
||||
|
||||
return True
|
||||
|
||||
return generate_from_enum_ex(context,
|
||||
idname_prefix="builtin_brush.",
|
||||
icon_prefix="brush.sculpt.",
|
||||
type=bpy.types.Brush,
|
||||
attr="sculpt_tool",
|
||||
exclude_filter=exclude_filter,
|
||||
tooldef_keywords={"get_enabled" : get_enabled},
|
||||
combine_map=combine_map)
|
||||
|
||||
@ToolDef.from_fn
|
||||
|
|
|
@ -1361,11 +1361,50 @@ class VIEW3D_PT_sculpt_automasking(Panel, View3DPaintPanel):
|
|||
brush,
|
||||
"automasking_boundary_edges_propagation_steps",
|
||||
ui_editing=False)
|
||||
UnifiedPaintPanel.channel_unified(layout.column(),
|
||||
|
||||
if "CONCAVITY" in sculpt.channels["automasking"].value:
|
||||
UnifiedPaintPanel.channel_unified(layout.column(),
|
||||
context,
|
||||
brush,
|
||||
"concave_mask_factor",
|
||||
ui_editing=False, slider=True, show_mappings=True)
|
||||
|
||||
enable_orig_normal = False
|
||||
|
||||
if "BRUSH_NORMAL" in sculpt.channels["automasking"].value:
|
||||
UnifiedPaintPanel.channel_unified(layout.column(),
|
||||
context,
|
||||
brush,
|
||||
"normal_mask_limit",
|
||||
ui_editing=False, slider=True, show_mappings=True)
|
||||
UnifiedPaintPanel.channel_unified(layout.column(),
|
||||
context,
|
||||
brush,
|
||||
"normal_mask_falloff",
|
||||
ui_editing=False, slider=True, show_mappings=True)
|
||||
enable_orig_normal = True
|
||||
|
||||
if "VIEW_NORMAL" in sculpt.channels["automasking"].value:
|
||||
UnifiedPaintPanel.channel_unified(layout.column(),
|
||||
context,
|
||||
brush,
|
||||
"view_normal_mask_limit",
|
||||
ui_editing=False, slider=True, show_mappings=True)
|
||||
UnifiedPaintPanel.channel_unified(layout.column(),
|
||||
context,
|
||||
brush,
|
||||
"view_normal_mask_falloff",
|
||||
ui_editing=False, slider=True, show_mappings=True)
|
||||
enable_orig_normal = True
|
||||
|
||||
sub = layout.row()
|
||||
sub.enabled = enable_orig_normal
|
||||
|
||||
UnifiedPaintPanel.channel_unified(sub,
|
||||
context,
|
||||
brush,
|
||||
"concave_mask_factor",
|
||||
ui_editing=False, slider=True, show_mappings=True)
|
||||
"automasking_use_original_normal",
|
||||
ui_editing=False, show_mappings=False)
|
||||
|
||||
|
||||
class VIEW3D_PT_sculpt_options_gravity(Panel, View3DPaintPanel):
|
||||
|
|
|
@ -270,9 +270,19 @@ MAKE_ENUM(blend,"Blending Mode","Brush blending mode",IMB_BLEND_MIX,{\
|
|||
{BRUSH_AUTOMASKING_INVERT_CONCAVITY, "INVERT_CONCAVITY", "NONE", "Invert Cavity", "Invert Cavity Map"},
|
||||
{BRUSH_AUTOMASKING_FACE_SETS, "FACE_SETS", "NONE", "Face Sets", ""},
|
||||
{BRUSH_AUTOMASKING_TOPOLOGY, "TOPOLOGY", "NONE", "Topology", ""},
|
||||
{BRUSH_AUTOMASKING_BRUSH_NORMAL, "BRUSH_NORMAL", "NONE", "Brush Normal", "Mask using normal at center of brush"},
|
||||
{BRUSH_AUTOMASKING_VIEW_NORMAL, "VIEW_NORMAL", "NONE", "View Normal", "Mask using view normal"},
|
||||
{-1},
|
||||
})
|
||||
|
||||
MAKE_FLOAT(normal_mask_limit, "Brush Normal Limit", "", M_PI*0.5f, 0.0001f, M_PI)
|
||||
MAKE_FLOAT(normal_mask_falloff, "Brush Normal Falloff", "", 0.1, 0.0, 1.0)
|
||||
|
||||
MAKE_FLOAT(view_normal_mask_limit, "View Limit", "", M_PI*0.5f, 0.0001f, M_PI)
|
||||
MAKE_FLOAT(view_normal_mask_falloff, "View Falloff", "", 0.1, 0.0, 1.0)
|
||||
|
||||
MAKE_BOOL_EX(automasking_use_original_normal, "Original Normal", "Use original normal for automasking", true, BRUSH_CHANNEL_NO_MAPPINGS)
|
||||
|
||||
MAKE_BOOL_EX(dyntopo_disabled,"Disable Dyntopo","",false,BRUSH_CHANNEL_NO_MAPPINGS)
|
||||
MAKE_FLAGS_EX(dyntopo_mode,"Dyntopo Operators","",DYNTOPO_COLLAPSE | DYNTOPO_CLEANUP | DYNTOPO_SUBDIVIDE,BRUSH_CHANNEL_INHERIT,{\
|
||||
{DYNTOPO_COLLAPSE, "COLLAPSE", "NONE", "Collapse", ""},
|
||||
|
|
|
@ -264,7 +264,9 @@ static bool check_builtin_init()
|
|||
//}
|
||||
|
||||
SUBTYPE_SET(smooth_stroke_radius, BRUSH_CHANNEL_PIXEL);
|
||||
|
||||
SUBTYPE_SET(normal_mask_limit, BRUSH_CHANNEL_ANGLE);
|
||||
SUBTYPE_SET(view_normal_mask_limit, BRUSH_CHANNEL_ANGLE);
|
||||
|
||||
SUBTYPE_SET(jitter_absolute, BRUSH_CHANNEL_PIXEL);
|
||||
|
||||
SUBTYPE_SET(radius, BRUSH_CHANNEL_PIXEL);
|
||||
|
@ -306,6 +308,11 @@ static bool check_builtin_init()
|
|||
SETCAT(concave_mask_factor, "Automasking");
|
||||
SETCAT(automasking, "Automasking");
|
||||
SETCAT(automasking_boundary_edges_propagation_steps, "Automasking");
|
||||
SETCAT(normal_mask_limit, "Automasking");
|
||||
SETCAT(view_normal_mask_limit, "Automasking");
|
||||
SETCAT(normal_mask_falloff, "Automasking");
|
||||
SETCAT(view_normal_mask_falloff, "Automasking");
|
||||
SETCAT(automasking_use_original_normal, "Automasking");
|
||||
|
||||
def = GETDEF(concave_mask_factor);
|
||||
def->mappings.pressure.inv = true;
|
||||
|
@ -1144,6 +1151,11 @@ void BKE_brush_builtin_patch(Brush *brush, int tool)
|
|||
ADDCH(automasking);
|
||||
ADDCH(automasking_boundary_edges_propagation_steps);
|
||||
ADDCH(concave_mask_factor);
|
||||
ADDCH(normal_mask_limit);
|
||||
ADDCH(automasking_use_original_normal);
|
||||
ADDCH(view_normal_mask_limit);
|
||||
ADDCH(normal_mask_falloff);
|
||||
ADDCH(view_normal_mask_falloff);
|
||||
|
||||
ADDCH(dyntopo_disabled);
|
||||
ADDCH(dyntopo_disable_smooth);
|
||||
|
@ -2045,6 +2057,12 @@ void BKE_brush_check_toolsettings(Sculpt *sd)
|
|||
ADDCH(automasking_boundary_edges_propagation_steps);
|
||||
ADDCH(concave_mask_factor);
|
||||
ADDCH(automasking);
|
||||
ADDCH(normal_mask_limit);
|
||||
ADDCH(automasking_use_original_normal);
|
||||
ADDCH(view_normal_mask_limit);
|
||||
ADDCH(normal_mask_falloff);
|
||||
ADDCH(view_normal_mask_falloff);
|
||||
|
||||
ADDCH(topology_rake_mode);
|
||||
|
||||
ADDCH(plane_offset);
|
||||
|
|
|
@ -574,12 +574,34 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Mesh *me,
|
|||
|
||||
if (layer == -1) {
|
||||
layer = CustomData_get_named_layer(cd_vdata, CD_PROP_COLOR, name);
|
||||
type = CD_PROP_COLOR;
|
||||
if (layer != -1) {
|
||||
type = CD_PROP_COLOR;
|
||||
domain = ATTR_DOMAIN_POINT;
|
||||
}
|
||||
}
|
||||
|
||||
if (layer == -1) {
|
||||
layer = CustomData_get_named_layer(cd_ldata, CD_PROP_COLOR, name);
|
||||
if (layer != -1) {
|
||||
type = CD_PROP_COLOR;
|
||||
domain = ATTR_DOMAIN_CORNER;
|
||||
}
|
||||
}
|
||||
|
||||
if (layer == -1) {
|
||||
layer = CustomData_get_named_layer(cd_vdata, CD_MLOOPCOL, name);
|
||||
if (layer != -1) {
|
||||
type = CD_MLOOPCOL;
|
||||
domain = ATTR_DOMAIN_POINT;
|
||||
}
|
||||
}
|
||||
|
||||
if (layer == -1) {
|
||||
layer = CustomData_get_named_layer(cd_ldata, CD_MLOOPCOL, name);
|
||||
type = CD_MCOL;
|
||||
if (layer != -1) {
|
||||
type = CD_MLOOPCOL;
|
||||
domain = ATTR_DOMAIN_CORNER;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0 /* Tangents are always from UV's - this will never happen. */
|
||||
|
@ -656,7 +678,10 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Mesh *me,
|
|||
break;
|
||||
}
|
||||
|
||||
case CD_MCOL:
|
||||
/* note that attr->type will always be CD_PROP_COLOR event for
|
||||
CD_MLOOPCOL layers, see node_shader_gpu_vertex_color in
|
||||
node_shader_vertex_color.cc
|
||||
*/
|
||||
case CD_MLOOPCOL:
|
||||
case CD_PROP_COLOR: {
|
||||
const AttributeRef *render = &me->attr_color_render;
|
||||
|
@ -667,15 +692,28 @@ static DRW_MeshCDMask mesh_cd_calc_used_gpu_layers(const Mesh *me,
|
|||
|
||||
if (layer == -1 && name[0] != '\0') {
|
||||
layer = CustomData_get_named_layer_index(cd_ldata, type, name);
|
||||
domain = layer != -1 ? ATTR_DOMAIN_CORNER : domain;
|
||||
|
||||
if (layer != -1) {
|
||||
domain = ATTR_DOMAIN_CORNER;
|
||||
}
|
||||
else {
|
||||
if (layer == -1) {
|
||||
layer = CustomData_get_named_layer_index(cd_vdata, type, name);
|
||||
domain = layer != -1 ? ATTR_DOMAIN_POINT : domain;
|
||||
}
|
||||
|
||||
if (layer == -1) {
|
||||
layer = CustomData_get_named_layer_index(cd_ldata, CD_MLOOPCOL, name);
|
||||
|
||||
if (layer != -1) {
|
||||
domain = ATTR_DOMAIN_CORNER;
|
||||
type = CD_MLOOPCOL;
|
||||
}
|
||||
}
|
||||
|
||||
if (layer == -1) {
|
||||
layer = CustomData_get_named_layer_index(cd_vdata, CD_MLOOPCOL, name);
|
||||
|
||||
if (layer != -1) {
|
||||
domain = ATTR_DOMAIN_POINT;
|
||||
type = CD_MLOOPCOL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -56,6 +56,7 @@
|
|||
#include "DNA_node_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_view3d_types.h"
|
||||
|
||||
#include "BKE_attribute.h"
|
||||
#include "BKE_brush.h"
|
||||
|
@ -2944,6 +2945,8 @@ static int sculpt_brush_needs_normal(const SculptSession *ss, const Brush *brush
|
|||
return ((SCULPT_TOOL_HAS_NORMAL_WEIGHT(SCULPT_get_tool(ss, brush)) &&
|
||||
(ss->cache->normal_weight > 0.0f)) ||
|
||||
|
||||
SCULPT_automasking_needs_normal(ss, brush) ||
|
||||
|
||||
ELEM(SCULPT_get_tool(ss, brush),
|
||||
SCULPT_TOOL_BLOB,
|
||||
SCULPT_TOOL_CREASE,
|
||||
|
@ -8436,6 +8439,13 @@ static bool sculpt_stroke_test_start(bContext *C, struct wmOperator *op, const f
|
|||
Brush *brush = BKE_paint_brush(&sd->paint);
|
||||
Object *ob = CTX_data_active_object(C);
|
||||
|
||||
if (SCULPT_TOOL_NEEDS_COLOR(brush->sculpt_tool)) {
|
||||
View3D *v3d = CTX_wm_view3d(C);
|
||||
if (v3d) {
|
||||
v3d->shading.color_type = V3D_SHADING_VERTEX_COLOR;
|
||||
}
|
||||
}
|
||||
|
||||
if (brush && brush->channels) {
|
||||
int tool = RNA_enum_get(op->ptr, "tool_override");
|
||||
BrushChannelSet *channels = brush->channels;
|
||||
|
|
|
@ -142,6 +142,50 @@ static bool SCULPT_automasking_needs_factors_cache(SculptSession *ss,
|
|||
return false;
|
||||
}
|
||||
|
||||
bool SCULPT_automasking_needs_normal(const SculptSession *ss, const Brush *brush)
|
||||
{
|
||||
int flags = SCULPT_get_int(ss, automasking, NULL, brush);
|
||||
|
||||
return flags & (BRUSH_AUTOMASKING_BRUSH_NORMAL | BRUSH_AUTOMASKING_VIEW_NORMAL);
|
||||
}
|
||||
|
||||
static float sculpt_automasking_normal_calc(AutomaskingCache *automasking,
|
||||
SculptSession *ss,
|
||||
SculptVertRef vert,
|
||||
float normal[3],
|
||||
float limit,
|
||||
float falloff)
|
||||
{
|
||||
float normal_v[3];
|
||||
|
||||
if (automasking->settings.original_normal) {
|
||||
SCULPT_vertex_check_origdata(ss, vert);
|
||||
copy_v3_v3(normal_v, SCULPT_vertex_origno_get(ss, vert));
|
||||
}
|
||||
else {
|
||||
SCULPT_vertex_normal_get(ss, vert, normal_v);
|
||||
}
|
||||
|
||||
float angle = saacos(dot_v3v3(normal, normal_v)) / M_PI;
|
||||
falloff *= 0.5;
|
||||
|
||||
/* note that limit is pre-divided by M_PI */
|
||||
|
||||
if (angle > limit - falloff && angle < limit + falloff) {
|
||||
float t = 1.0f - (angle - (limit - falloff)) / (2.0 * falloff);
|
||||
|
||||
/* smoothstep */
|
||||
t = t * t * (3.0 - 2.0 * t);
|
||||
|
||||
return t;
|
||||
}
|
||||
else if (angle > limit) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
float SCULPT_automasking_factor_get(AutomaskingCache *automasking,
|
||||
SculptSession *ss,
|
||||
SculptVertRef vert)
|
||||
|
@ -195,6 +239,32 @@ float SCULPT_automasking_factor_get(AutomaskingCache *automasking,
|
|||
}
|
||||
}
|
||||
|
||||
if (ss->cache && (automasking->settings.flags & BRUSH_AUTOMASKING_BRUSH_NORMAL)) {
|
||||
float normal[3];
|
||||
|
||||
copy_v3_v3(normal, ss->cache->initial_normal);
|
||||
|
||||
mask *= sculpt_automasking_normal_calc(automasking,
|
||||
ss,
|
||||
vert,
|
||||
normal,
|
||||
automasking->settings.normal_limit,
|
||||
automasking->settings.normal_falloff);
|
||||
}
|
||||
|
||||
if (ss->cache && (automasking->settings.flags & BRUSH_AUTOMASKING_VIEW_NORMAL)) {
|
||||
float normal[3];
|
||||
|
||||
copy_v3_v3(normal, ss->cache->view_normal);
|
||||
|
||||
mask *= sculpt_automasking_normal_calc(automasking,
|
||||
ss,
|
||||
vert,
|
||||
normal,
|
||||
automasking->settings.view_normal_limit,
|
||||
automasking->settings.view_normal_falloff);
|
||||
}
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
|
@ -394,6 +464,19 @@ static void SCULPT_automasking_cache_settings_update(AutomaskingCache *automaski
|
|||
|
||||
automasking->settings.initial_face_set = SCULPT_active_face_set_get(ss);
|
||||
automasking->settings.concave_factor = SCULPT_get_float(ss, concave_mask_factor, sd, brush);
|
||||
|
||||
/* pre-divide by M_PI */
|
||||
automasking->settings.normal_limit = SCULPT_get_float(ss, normal_mask_limit, sd, brush) / M_PI;
|
||||
automasking->settings.normal_falloff = SCULPT_get_float(ss, normal_mask_falloff, sd, brush);
|
||||
|
||||
automasking->settings.view_normal_limit = SCULPT_get_float(
|
||||
ss, view_normal_mask_limit, sd, brush) /
|
||||
M_PI;
|
||||
automasking->settings.view_normal_falloff = SCULPT_get_float(
|
||||
ss, view_normal_mask_falloff, sd, brush);
|
||||
|
||||
automasking->settings.original_normal = SCULPT_get_bool(
|
||||
ss, automasking_use_original_normal, sd, brush);
|
||||
}
|
||||
|
||||
void SCULPT_automasking_step_update(AutomaskingCache *automasking,
|
||||
|
|
|
@ -577,8 +577,9 @@ void SCULPT_pbvh_clear(Object *ob);
|
|||
float SCULPT_automasking_factor_get(struct AutomaskingCache *automasking,
|
||||
SculptSession *ss,
|
||||
SculptVertRef vert);
|
||||
bool SCULPT_automasking_needs_normal(const SculptSession *ss, const Brush *brush);
|
||||
|
||||
/* Returns the automasking cache depending on the active tool. Used for code that can run both for
|
||||
/* Returns the automasking cache depending on the active tool. Used for code that can run both for
|
||||
* brushes and filter. */
|
||||
struct AutomaskingCache *SCULPT_automasking_active_cache_get(SculptSession *ss);
|
||||
|
||||
|
@ -1297,6 +1298,9 @@ typedef struct AutomaskingSettings {
|
|||
int initial_face_set;
|
||||
int current_face_set; // used by faceset draw tool
|
||||
float concave_factor;
|
||||
float normal_limit, normal_falloff;
|
||||
float view_normal_limit, view_normal_falloff;
|
||||
bool original_normal;
|
||||
} AutomaskingSettings;
|
||||
|
||||
typedef struct AutomaskingCache {
|
||||
|
@ -1995,6 +1999,8 @@ void SCULPT_ensure_persistent_layers(SculptSession *ss, struct Object *ob);
|
|||
// these tools don't support dynamic pbvh splitting during the stroke
|
||||
#define DYNTOPO_HAS_DYNAMIC_SPLIT(tool) true
|
||||
|
||||
#define SCULPT_TOOL_NEEDS_COLOR(tool) ELEM(tool, SCULPT_TOOL_PAINT, SCULPT_TOOL_SMEAR)
|
||||
|
||||
/*get current symmetry pass index inclusive of both
|
||||
mirror and radial symmetry*/
|
||||
int SCULPT_get_symmetry_pass(const SculptSession *ss);
|
||||
|
|
|
@ -344,7 +344,9 @@ typedef enum eAutomasking_flag {
|
|||
BRUSH_AUTOMASKING_BOUNDARY_EDGES = (1 << 2),
|
||||
BRUSH_AUTOMASKING_BOUNDARY_FACE_SETS = (1 << 3),
|
||||
BRUSH_AUTOMASKING_CONCAVITY = (1 << 4),
|
||||
BRUSH_AUTOMASKING_INVERT_CONCAVITY = (1 << 5)
|
||||
BRUSH_AUTOMASKING_INVERT_CONCAVITY = (1 << 5),
|
||||
BRUSH_AUTOMASKING_BRUSH_NORMAL = (1<<6),
|
||||
BRUSH_AUTOMASKING_VIEW_NORMAL = (1 << 7),
|
||||
} eAutomasking_flag;
|
||||
|
||||
typedef enum ePaintBrush_flag {
|
||||
|
|
|
@ -156,6 +156,7 @@ enum {
|
|||
BRUSH_CHANNEL_COLOR,
|
||||
BRUSH_CHANNEL_FACTOR,
|
||||
BRUSH_CHANNEL_PERCENT,
|
||||
BRUSH_CHANNEL_PIXEL
|
||||
BRUSH_CHANNEL_PIXEL,
|
||||
BRUSH_CHANNEL_ANGLE
|
||||
};
|
||||
/* clang-format on */
|
||||
|
|
|
@ -125,6 +125,9 @@ struct StructRNA *rna_BrushChannel_refine(PointerRNA *ptr)
|
|||
case BRUSH_CHANNEL_PIXEL:
|
||||
subtype = PROP_PIXEL;
|
||||
break;
|
||||
case BRUSH_CHANNEL_ANGLE:
|
||||
subtype = PROP_ANGLE;
|
||||
break;
|
||||
default:
|
||||
subtype = PROP_NONE;
|
||||
break;
|
||||
|
|
Loading…
Reference in New Issue