WIP: uv-simple-select #1

Closed
Chris Blackbourn wants to merge 182 commits from uv-simple-select into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
10 changed files with 150 additions and 15 deletions
Showing only changes of commit 33fd7c1ce8 - Show all commits

View File

@ -522,7 +522,8 @@ class _draw_tool_settings_context_mode:
if curves_tool == 'COMB': if curves_tool == 'COMB':
layout.prop(brush, "falloff_shape", expand=True) layout.prop(brush, "falloff_shape", expand=True)
layout.popover("VIEW3D_PT_tools_brush_falloff") layout.popover("VIEW3D_PT_tools_brush_falloff", text="Brush Falloff")
layout.popover("VIEW3D_PT_curves_sculpt_parameter_falloff", text="Curve Falloff")
elif curves_tool == 'ADD': elif curves_tool == 'ADD':
layout.prop(brush, "falloff_shape", expand=True) layout.prop(brush, "falloff_shape", expand=True)
layout.prop(brush.curves_sculpt_settings, "add_amount") layout.prop(brush.curves_sculpt_settings, "add_amount")
@ -7944,6 +7945,28 @@ class VIEW3D_PT_curves_sculpt_add_shape(Panel):
col.prop(brush.curves_sculpt_settings, "points_per_curve", text="Points") col.prop(brush.curves_sculpt_settings, "points_per_curve", text="Points")
class VIEW3D_PT_curves_sculpt_parameter_falloff(Panel):
# Only for popover, these are dummy values.
bl_space_type = 'VIEW_3D'
bl_region_type = 'WINDOW'
bl_label = "Curves Sculpt Parameter Falloff"
def draw(self, context):
layout = self.layout
settings = UnifiedPaintPanel.paint_settings(context)
brush = settings.brush
layout.template_curve_mapping(brush.curves_sculpt_settings, "curve_parameter_falloff")
row = layout.row(align=True)
row.operator("brush.sculpt_curves_falloff_preset", icon='SMOOTHCURVE', text="").shape = 'SMOOTH'
row.operator("brush.sculpt_curves_falloff_preset", icon='SPHERECURVE', text="").shape = 'ROUND'
row.operator("brush.sculpt_curves_falloff_preset", icon='ROOTCURVE', text="").shape = 'ROOT'
row.operator("brush.sculpt_curves_falloff_preset", icon='SHARPCURVE', text="").shape = 'SHARP'
row.operator("brush.sculpt_curves_falloff_preset", icon='LINCURVE', text="").shape = 'LINE'
row.operator("brush.sculpt_curves_falloff_preset", icon='NOCURVE', text="").shape = 'MAX'
class VIEW3D_PT_curves_sculpt_grow_shrink_scaling(Panel): class VIEW3D_PT_curves_sculpt_grow_shrink_scaling(Panel):
# Only for popover, these are dummy values. # Only for popover, these are dummy values.
bl_space_type = 'VIEW_3D' bl_space_type = 'VIEW_3D'
@ -8221,6 +8244,7 @@ classes = (
TOPBAR_PT_gpencil_vertexcolor, TOPBAR_PT_gpencil_vertexcolor,
TOPBAR_PT_annotation_layers, TOPBAR_PT_annotation_layers,
VIEW3D_PT_curves_sculpt_add_shape, VIEW3D_PT_curves_sculpt_add_shape,
VIEW3D_PT_curves_sculpt_parameter_falloff,
VIEW3D_PT_curves_sculpt_grow_shrink_scaling, VIEW3D_PT_curves_sculpt_grow_shrink_scaling,
VIEW3D_PT_viewport_debug, VIEW3D_PT_viewport_debug,
) )

View File

@ -100,6 +100,8 @@ static void brush_copy_data(Main * /*bmain*/, ID *id_dst, const ID *id_src, cons
if (brush_src->curves_sculpt_settings != nullptr) { if (brush_src->curves_sculpt_settings != nullptr) {
brush_dst->curves_sculpt_settings = MEM_cnew<BrushCurvesSculptSettings>( brush_dst->curves_sculpt_settings = MEM_cnew<BrushCurvesSculptSettings>(
__func__, *(brush_src->curves_sculpt_settings)); __func__, *(brush_src->curves_sculpt_settings));
brush_dst->curves_sculpt_settings->curve_parameter_falloff = BKE_curvemapping_copy(
brush_src->curves_sculpt_settings->curve_parameter_falloff);
} }
/* enable fake user by default */ /* enable fake user by default */
@ -130,6 +132,7 @@ static void brush_free_data(ID *id)
MEM_SAFE_FREE(brush->gpencil_settings); MEM_SAFE_FREE(brush->gpencil_settings);
} }
if (brush->curves_sculpt_settings != nullptr) { if (brush->curves_sculpt_settings != nullptr) {
BKE_curvemapping_free(brush->curves_sculpt_settings->curve_parameter_falloff);
MEM_freeN(brush->curves_sculpt_settings); MEM_freeN(brush->curves_sculpt_settings);
} }
@ -255,6 +258,7 @@ static void brush_blend_write(BlendWriter *writer, ID *id, const void *id_addres
} }
if (brush->curves_sculpt_settings) { if (brush->curves_sculpt_settings) {
BLO_write_struct(writer, BrushCurvesSculptSettings, brush->curves_sculpt_settings); BLO_write_struct(writer, BrushCurvesSculptSettings, brush->curves_sculpt_settings);
BKE_curvemapping_blend_write(writer, brush->curves_sculpt_settings->curve_parameter_falloff);
} }
if (brush->gradient) { if (brush->gradient) {
BLO_write_struct(writer, ColorBand, brush->gradient); BLO_write_struct(writer, ColorBand, brush->gradient);
@ -337,6 +341,12 @@ static void brush_blend_read_data(BlendDataReader *reader, ID *id)
} }
BLO_read_data_address(reader, &brush->curves_sculpt_settings); BLO_read_data_address(reader, &brush->curves_sculpt_settings);
if (brush->curves_sculpt_settings) {
BLO_read_data_address(reader, &brush->curves_sculpt_settings->curve_parameter_falloff);
if (brush->curves_sculpt_settings->curve_parameter_falloff) {
BKE_curvemapping_blend_read(reader, brush->curves_sculpt_settings->curve_parameter_falloff);
}
}
brush->preview = nullptr; brush->preview = nullptr;
brush->icon_imbuf = nullptr; brush->icon_imbuf = nullptr;
@ -1583,6 +1593,7 @@ void BKE_brush_init_curves_sculpt_settings(Brush *brush)
settings->minimum_length = 0.01f; settings->minimum_length = 0.01f;
settings->curve_length = 0.3f; settings->curve_length = 0.3f;
settings->density_add_attempts = 100; settings->density_add_attempts = 100;
settings->curve_parameter_falloff = BKE_curvemapping_add(1, 0.0f, 0.0f, 1.0f, 1.0f);
} }
struct Brush *BKE_brush_first_search(struct Main *bmain, const eObjectMode ob_mode) struct Brush *BKE_brush_first_search(struct Main *bmain, const eObjectMode ob_mode)

View File

@ -3952,6 +3952,15 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain)
} }
} }
LISTBASE_FOREACH (Brush *, brush, &bmain->brushes) {
if (brush->ob_mode == OB_MODE_SCULPT_CURVES) {
if (brush->curves_sculpt_settings->curve_parameter_falloff == nullptr) {
brush->curves_sculpt_settings->curve_parameter_falloff = BKE_curvemapping_add(
1, 0.0f, 0.0f, 1.0f, 1.0f);
}
}
}
/* Keep this block, even when empty. */ /* Keep this block, even when empty. */
} }
} }

View File

@ -18,6 +18,7 @@
#include "BKE_attribute_math.hh" #include "BKE_attribute_math.hh"
#include "BKE_brush.h" #include "BKE_brush.h"
#include "BKE_bvhutils.h" #include "BKE_bvhutils.h"
#include "BKE_colortools.h"
#include "BKE_context.h" #include "BKE_context.h"
#include "BKE_crazyspace.hh" #include "BKE_crazyspace.hh"
#include "BKE_curves.hh" #include "BKE_curves.hh"
@ -69,6 +70,8 @@ class CombOperation : public CurvesSculptStrokeOperation {
/** Solver for length and collision constraints. */ /** Solver for length and collision constraints. */
CurvesConstraintSolver constraint_solver_; CurvesConstraintSolver constraint_solver_;
Array<float> curve_lengths_;
friend struct CombOperationExecutor; friend struct CombOperationExecutor;
public: public:
@ -146,6 +149,17 @@ struct CombOperationExecutor {
} }
self_->constraint_solver_.initialize( self_->constraint_solver_.initialize(
*curves_orig_, curve_selection_, curves_id_orig_->flag & CV_SCULPT_COLLISION_ENABLED); *curves_orig_, curve_selection_, curves_id_orig_->flag & CV_SCULPT_COLLISION_ENABLED);
self_->curve_lengths_.reinitialize(curves_orig_->curves_num());
const Span<float> segment_lengths = self_->constraint_solver_.segment_lengths();
const OffsetIndices points_by_curve = curves_orig_->points_by_curve();
threading::parallel_for(curve_selection_.index_range(), 512, [&](const IndexRange range) {
for (const int curve_i : curve_selection_.slice(range)) {
const IndexRange points = points_by_curve[curve_i];
const Span<float> lengths = segment_lengths.slice(points.drop_back(1));
self_->curve_lengths_[curve_i] = std::accumulate(lengths.begin(), lengths.end(), 0.0f);
}
});
/* Combing does nothing when there is no mouse movement, so return directly. */ /* Combing does nothing when there is no mouse movement, so return directly. */
return; return;
} }
@ -204,11 +218,23 @@ struct CombOperationExecutor {
const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_; const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
const float brush_radius_sq_re = pow2f(brush_radius_re); const float brush_radius_sq_re = pow2f(brush_radius_re);
CurveMapping &curve_parameter_falloff_mapping =
*brush_->curves_sculpt_settings->curve_parameter_falloff;
BKE_curvemapping_init(&curve_parameter_falloff_mapping);
const Span<float> segment_lengths = self_->constraint_solver_.segment_lengths();
threading::parallel_for(curve_selection_.index_range(), 256, [&](const IndexRange range) { threading::parallel_for(curve_selection_.index_range(), 256, [&](const IndexRange range) {
for (const int curve_i : curve_selection_.slice(range)) { for (const int curve_i : curve_selection_.slice(range)) {
bool curve_changed = false; bool curve_changed = false;
const IndexRange points = points_by_curve[curve_i]; const IndexRange points = points_by_curve[curve_i];
const float total_length = self_->curve_lengths_[curve_i];
const float total_length_inv = safe_divide(1.0f, total_length);
float current_length = 0.0f;
for (const int point_i : points.drop_front(1)) { for (const int point_i : points.drop_front(1)) {
current_length += segment_lengths[point_i - 1];
const float3 old_pos_cu = deformation.positions[point_i]; const float3 old_pos_cu = deformation.positions[point_i];
const float3 old_symm_pos_cu = math::transform_point(brush_transform_inv, old_pos_cu); const float3 old_symm_pos_cu = math::transform_point(brush_transform_inv, old_pos_cu);
@ -228,8 +254,12 @@ struct CombOperationExecutor {
/* A falloff that is based on how far away the point is from the stroke. */ /* A falloff that is based on how far away the point is from the stroke. */
const float radius_falloff = BKE_brush_curve_strength( const float radius_falloff = BKE_brush_curve_strength(
brush_, distance_to_brush_re, brush_radius_re); brush_, distance_to_brush_re, brush_radius_re);
const float curve_parameter = current_length * total_length_inv;
const float curve_falloff = BKE_curvemapping_evaluateF(
&curve_parameter_falloff_mapping, 0, curve_parameter);
/* Combine the falloff and brush strength. */ /* Combine the falloff and brush strength. */
const float weight = brush_strength_ * radius_falloff * point_factors_[point_i]; const float weight = brush_strength_ * curve_falloff * radius_falloff *
point_factors_[point_i];
/* Offset the old point position in screen space and transform it back into 3D space. /* Offset the old point position in screen space and transform it back into 3D space.
*/ */
@ -304,15 +334,26 @@ struct CombOperationExecutor {
const float brush_radius_sq_cu = pow2f(brush_radius_cu); const float brush_radius_sq_cu = pow2f(brush_radius_cu);
const float3 brush_diff_cu = brush_end_cu - brush_start_cu; const float3 brush_diff_cu = brush_end_cu - brush_start_cu;
CurveMapping &curve_parameter_falloff_mapping =
*brush_->curves_sculpt_settings->curve_parameter_falloff;
BKE_curvemapping_init(&curve_parameter_falloff_mapping);
const bke::crazyspace::GeometryDeformation deformation = const bke::crazyspace::GeometryDeformation deformation =
bke::crazyspace::get_evaluated_curves_deformation(*ctx_.depsgraph, *curves_ob_orig_); bke::crazyspace::get_evaluated_curves_deformation(*ctx_.depsgraph, *curves_ob_orig_);
const OffsetIndices points_by_curve = curves_orig_->points_by_curve(); const OffsetIndices points_by_curve = curves_orig_->points_by_curve();
const Span<float> segment_lengths = self_->constraint_solver_.segment_lengths();
threading::parallel_for(curve_selection_.index_range(), 256, [&](const IndexRange range) { threading::parallel_for(curve_selection_.index_range(), 256, [&](const IndexRange range) {
for (const int curve_i : curve_selection_.slice(range)) { for (const int curve_i : curve_selection_.slice(range)) {
bool curve_changed = false; bool curve_changed = false;
const IndexRange points = points_by_curve[curve_i]; const IndexRange points = points_by_curve[curve_i];
const float total_length = self_->curve_lengths_[curve_i];
const float total_length_inv = safe_divide(1.0f, total_length);
float current_length = 0.0f;
for (const int point_i : points.drop_front(1)) { for (const int point_i : points.drop_front(1)) {
current_length += segment_lengths[point_i - 1];
const float3 pos_old_cu = deformation.positions[point_i]; const float3 pos_old_cu = deformation.positions[point_i];
/* Compute distance to the brush. */ /* Compute distance to the brush. */
@ -328,8 +369,12 @@ struct CombOperationExecutor {
/* A falloff that is based on how far away the point is from the stroke. */ /* A falloff that is based on how far away the point is from the stroke. */
const float radius_falloff = BKE_brush_curve_strength( const float radius_falloff = BKE_brush_curve_strength(
brush_, distance_to_brush_cu, brush_radius_cu); brush_, distance_to_brush_cu, brush_radius_cu);
const float curve_parameter = current_length * total_length_inv;
const float curve_falloff = BKE_curvemapping_evaluateF(
&curve_parameter_falloff_mapping, 0, curve_parameter);
/* Combine the falloff and brush strength. */ /* Combine the falloff and brush strength. */
const float weight = brush_strength_ * radius_falloff * point_factors_[point_i]; const float weight = brush_strength_ * curve_falloff * radius_falloff *
point_factors_[point_i];
const float3 translation_eval_cu = weight * brush_diff_cu; const float3 translation_eval_cu = weight * brush_diff_cu;
const float3 translation_orig_cu = deformation.translation_from_deformed_to_original( const float3 translation_orig_cu = deformation.translation_from_deformed_to_original(

View File

@ -163,6 +163,11 @@ struct CurvesConstraintSolver {
const IndexMask curve_selection, const IndexMask curve_selection,
const Mesh *surface, const Mesh *surface,
const CurvesSurfaceTransforms &transforms); const CurvesSurfaceTransforms &transforms);
Span<float> segment_lengths() const
{
return segment_lengths_;
}
}; };
} // namespace blender::ed::sculpt_paint } // namespace blender::ed::sculpt_paint

View File

@ -373,6 +373,7 @@ void paint_sample_color(
void paint_stroke_operator_properties(struct wmOperatorType *ot); void paint_stroke_operator_properties(struct wmOperatorType *ot);
void BRUSH_OT_curve_preset(struct wmOperatorType *ot); void BRUSH_OT_curve_preset(struct wmOperatorType *ot);
void BRUSH_OT_sculpt_curves_falloff_preset(struct wmOperatorType *ot);
void PAINT_OT_face_select_linked(struct wmOperatorType *ot); void PAINT_OT_face_select_linked(struct wmOperatorType *ot);
void PAINT_OT_face_select_linked_pick(struct wmOperatorType *ot); void PAINT_OT_face_select_linked_pick(struct wmOperatorType *ot);

View File

@ -1421,6 +1421,7 @@ void ED_operatortypes_paint(void)
WM_operatortype_append(BRUSH_OT_add_gpencil); WM_operatortype_append(BRUSH_OT_add_gpencil);
WM_operatortype_append(BRUSH_OT_scale_size); WM_operatortype_append(BRUSH_OT_scale_size);
WM_operatortype_append(BRUSH_OT_curve_preset); WM_operatortype_append(BRUSH_OT_curve_preset);
WM_operatortype_append(BRUSH_OT_sculpt_curves_falloff_preset);
WM_operatortype_append(BRUSH_OT_reset); WM_operatortype_append(BRUSH_OT_reset);
WM_operatortype_append(BRUSH_OT_stencil_control); WM_operatortype_append(BRUSH_OT_stencil_control);
WM_operatortype_append(BRUSH_OT_stencil_fit_image_aspect); WM_operatortype_append(BRUSH_OT_stencil_fit_image_aspect);

View File

@ -25,6 +25,7 @@
#include "BLT_translation.h" #include "BLT_translation.h"
#include "BKE_brush.h" #include "BKE_brush.h"
#include "BKE_colortools.h"
#include "BKE_context.h" #include "BKE_context.h"
#include "BKE_customdata.h" #include "BKE_customdata.h"
#include "BKE_image.h" #include "BKE_image.h"
@ -569,9 +570,6 @@ static bool brush_curve_preset_poll(bContext *C)
return br && br->curve; return br && br->curve;
} }
void BRUSH_OT_curve_preset(wmOperatorType *ot)
{
PropertyRNA *prop;
static const EnumPropertyItem prop_shape_items[] = { static const EnumPropertyItem prop_shape_items[] = {
{CURVE_PRESET_SHARP, "SHARP", 0, "Sharp", ""}, {CURVE_PRESET_SHARP, "SHARP", 0, "Sharp", ""},
{CURVE_PRESET_SMOOTH, "SMOOTH", 0, "Smooth", ""}, {CURVE_PRESET_SMOOTH, "SMOOTH", 0, "Smooth", ""},
@ -582,6 +580,8 @@ void BRUSH_OT_curve_preset(wmOperatorType *ot)
{0, NULL, 0, NULL, NULL}, {0, NULL, 0, NULL, NULL},
}; };
void BRUSH_OT_curve_preset(wmOperatorType *ot)
{
ot->name = "Preset"; ot->name = "Preset";
ot->description = "Set brush shape"; ot->description = "Set brush shape";
ot->idname = "BRUSH_OT_curve_preset"; ot->idname = "BRUSH_OT_curve_preset";
@ -589,6 +589,38 @@ void BRUSH_OT_curve_preset(wmOperatorType *ot)
ot->exec = brush_curve_preset_exec; ot->exec = brush_curve_preset_exec;
ot->poll = brush_curve_preset_poll; ot->poll = brush_curve_preset_poll;
PropertyRNA *prop;
prop = RNA_def_enum(ot->srna, "shape", prop_shape_items, CURVE_PRESET_SMOOTH, "Mode", "");
RNA_def_property_translation_context(prop,
BLT_I18NCONTEXT_ID_CURVE_LEGACY); /* Abusing id_curve :/ */
}
static bool brush_sculpt_curves_falloff_preset_poll(bContext *C)
{
Brush *br = BKE_paint_brush(BKE_paint_get_active_from_context(C));
return br && br->curves_sculpt_settings && br->curves_sculpt_settings->curve_parameter_falloff;
}
static int brush_sculpt_curves_falloff_preset_exec(bContext *C, wmOperator *op)
{
Brush *brush = BKE_paint_brush(BKE_paint_get_active_from_context(C));
CurveMapping *mapping = brush->curves_sculpt_settings->curve_parameter_falloff;
mapping->preset = RNA_enum_get(op->ptr, "shape");
CurveMap *map = mapping->cm;
BKE_curvemap_reset(map, &mapping->clipr, mapping->preset, CURVEMAP_SLOPE_POSITIVE);
return OPERATOR_FINISHED;
}
void BRUSH_OT_sculpt_curves_falloff_preset(wmOperatorType *ot)
{
ot->name = "Curve Falloff Preset";
ot->description = "Set Curve Falloff Preset";
ot->idname = "BRUSH_OT_sculpt_curves_falloff_preset";
ot->exec = brush_sculpt_curves_falloff_preset_exec;
ot->poll = brush_sculpt_curves_falloff_preset_poll;
PropertyRNA *prop;
prop = RNA_def_enum(ot->srna, "shape", prop_shape_items, CURVE_PRESET_SMOOTH, "Mode", ""); prop = RNA_def_enum(ot->srna, "shape", prop_shape_items, CURVE_PRESET_SMOOTH, "Mode", "");
RNA_def_property_translation_context(prop, RNA_def_property_translation_context(prop,
BLT_I18NCONTEXT_ID_CURVE_LEGACY); /* Abusing id_curve :/ */ BLT_I18NCONTEXT_ID_CURVE_LEGACY); /* Abusing id_curve :/ */

View File

@ -162,7 +162,8 @@ typedef struct BrushCurvesSculptSettings {
int density_add_attempts; int density_add_attempts;
/** #eBrushCurvesSculptDensityMode. */ /** #eBrushCurvesSculptDensityMode. */
uint8_t density_mode; uint8_t density_mode;
char _pad[7]; char _pad[3];
struct CurveMapping *curve_parameter_falloff;
} BrushCurvesSculptSettings; } BrushCurvesSculptSettings;
typedef struct Brush { typedef struct Brush {

View File

@ -2106,6 +2106,12 @@ static void rna_def_curves_sculpt_options(BlenderRNA *brna)
RNA_def_property_enum_items(prop, density_mode_items); RNA_def_property_enum_items(prop, density_mode_items);
RNA_def_property_ui_text( RNA_def_property_ui_text(
prop, "Density Mode", "Determines whether the brush adds or removes curves"); prop, "Density Mode", "Determines whether the brush adds or removes curves");
prop = RNA_def_property(srna, "curve_parameter_falloff", PROP_POINTER, PROP_NONE);
RNA_def_property_struct_type(prop, "CurveMapping");
RNA_def_property_ui_text(prop,
"Curve Parameter Falloff",
"Falloff that is applied from the tip to the root of each curve");
} }
static void rna_def_brush(BlenderRNA *brna) static void rna_def_brush(BlenderRNA *brna)