Fix: Sample pressure properly for 3D curves sculpt brushes

For the "Sphere" 3D brushes, the depth and radius are only sampled at
the beginning of the stroke. This didn't work when tablet pressure is
used as a factor for the brush radius. Now the 3D brush depth is found
with the max radius (as if the pressure was 1.0), but the pressure
factor is used afterwards.

Restructuring the way the brush executors stored the radius made
the change a bit clearer, which is where most of the diff comes from.

Differential Revision: https://developer.blender.org/D15002
This commit is contained in:
Hans Goudey 2022-05-23 09:44:12 +02:00
parent f93b237194
commit 8f3847aef3
6 changed files with 69 additions and 35 deletions

View File

@ -86,7 +86,8 @@ struct CombOperationExecutor {
const CurvesSculpt *curves_sculpt_ = nullptr;
const Brush *brush_ = nullptr;
float brush_radius_re_;
float brush_radius_base_re_;
float brush_radius_factor_;
float brush_strength_;
eBrushFalloffShape falloff_shape_;
@ -126,7 +127,8 @@ struct CombOperationExecutor {
curves_sculpt_ = scene_->toolsettings->curves_sculpt;
brush_ = BKE_paint_brush_for_read(&curves_sculpt_->paint);
brush_radius_re_ = brush_radius_get(*scene_, *brush_, stroke_extension);
brush_radius_base_re_ = BKE_brush_size_get(scene_, brush_);
brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension);
brush_strength_ = brush_strength_get(*scene_, *brush_, stroke_extension);
curves_to_world_mat_ = object_->obmat;
@ -212,7 +214,8 @@ struct CombOperationExecutor {
float4x4 projection;
ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values);
const float brush_radius_sq_re = pow2f(brush_radius_re_);
const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
const float brush_radius_sq_re = pow2f(brush_radius_re);
threading::parallel_for(curves_->curves_range(), 256, [&](const IndexRange curves_range) {
Vector<int> &local_changed_curves = r_changed_curves.local();
@ -236,7 +239,7 @@ struct CombOperationExecutor {
const float distance_to_brush_re = std::sqrt(distance_to_brush_sq_re);
/* A falloff that is based on how far away the point is from the stroke. */
const float radius_falloff = BKE_brush_curve_strength(
brush_, distance_to_brush_re, brush_radius_re_);
brush_, distance_to_brush_re, brush_radius_re);
/* Combine the falloff and brush strength. */
const float weight = brush_strength_ * radius_falloff;
@ -280,7 +283,7 @@ struct CombOperationExecutor {
const float3 brush_start_cu = world_to_curves_mat_ * brush_start_wo;
const float3 brush_end_cu = world_to_curves_mat_ * brush_end_wo;
const float brush_radius_cu = self_->brush_3d_.radius_cu;
const float brush_radius_cu = self_->brush_3d_.radius_cu * brush_radius_factor_;
const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
eCurvesSymmetryType(curves_id_->symmetry));
@ -342,7 +345,7 @@ struct CombOperationExecutor {
void initialize_spherical_brush_reference_point()
{
std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush(
*depsgraph_, *region_, *v3d_, *rv3d_, *object_, brush_pos_re_, brush_radius_re_);
*depsgraph_, *region_, *v3d_, *rv3d_, *object_, brush_pos_re_, brush_radius_base_re_);
if (brush_3d.has_value()) {
self_->brush_3d_ = *brush_3d;
}

View File

@ -74,7 +74,8 @@ struct DeleteOperationExecutor {
const CurvesSculpt *curves_sculpt_ = nullptr;
const Brush *brush_ = nullptr;
float brush_radius_re_;
float brush_radius_base_re_;
float brush_radius_factor_;
float2 brush_pos_re_;
@ -97,7 +98,8 @@ struct DeleteOperationExecutor {
curves_sculpt_ = scene_->toolsettings->curves_sculpt;
brush_ = BKE_paint_brush_for_read(&curves_sculpt_->paint);
brush_radius_re_ = brush_radius_get(*scene_, *brush_, stroke_extension);
brush_radius_base_re_ = BKE_brush_size_get(scene_, brush_);
brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension);
brush_pos_re_ = stroke_extension.mouse_position;
@ -155,7 +157,8 @@ struct DeleteOperationExecutor {
Span<float3> positions_cu = curves_->positions();
const float brush_radius_sq_re = pow2f(brush_radius_re_);
const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
const float brush_radius_sq_re = pow2f(brush_radius_re);
threading::parallel_for(curves_->curves_range(), 512, [&](IndexRange curve_range) {
for (const int curve_i : curve_range) {
@ -204,7 +207,7 @@ struct DeleteOperationExecutor {
{
Span<float3> positions_cu = curves_->positions();
const float brush_radius_cu = self_->brush_3d_.radius_cu;
const float brush_radius_cu = self_->brush_3d_.radius_cu * brush_radius_factor_;
const float brush_radius_sq_cu = pow2f(brush_radius_cu);
threading::parallel_for(curves_->curves_range(), 512, [&](IndexRange curve_range) {
@ -228,7 +231,7 @@ struct DeleteOperationExecutor {
void initialize_spherical_brush_reference_point()
{
std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush(
*depsgraph_, *region_, *v3d_, *rv3d_, *object_, brush_pos_re_, brush_radius_re_);
*depsgraph_, *region_, *v3d_, *rv3d_, *object_, brush_pos_re_, brush_radius_base_re_);
if (brush_3d.has_value()) {
self_->brush_3d_ = *brush_3d;
}

View File

@ -283,9 +283,10 @@ struct CurvesEffectOperationExecutor {
CurvesGeometry *curves_ = nullptr;
const Brush *brush_ = nullptr;
float brush_radius_re_;
float brush_radius_sq_re_;
float brush_radius_base_re_;
float brush_radius_factor_;
float brush_strength_;
eBrushFalloffShape falloff_shape_;
float4x4 curves_to_world_mat_;
@ -321,9 +322,12 @@ struct CurvesEffectOperationExecutor {
const CurvesSculpt &curves_sculpt = *scene_->toolsettings->curves_sculpt;
brush_ = BKE_paint_brush_for_read(&curves_sculpt.paint);
brush_radius_re_ = brush_radius_get(*scene_, *brush_, stroke_extension);
brush_strength_ = brush_strength_get(*scene_, *brush_, stroke_extension);
brush_radius_sq_re_ = pow2f(brush_radius_re_);
brush_radius_base_re_ = BKE_brush_size_get(scene_, brush_);
brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension);
brush_strength_ = brush_strength_get(*scene_, *brush_, stroke_extension);
falloff_shape_ = eBrushFalloffShape(brush_->falloff_shape);
curves_to_world_mat_ = object_->obmat;
@ -341,7 +345,7 @@ struct CurvesEffectOperationExecutor {
*rv3d_,
*object_,
stroke_extension.mouse_position,
brush_radius_re_)) {
brush_radius_base_re_)) {
self.brush_3d_ = *brush_3d;
}
}
@ -385,6 +389,9 @@ struct CurvesEffectOperationExecutor {
symmetry_brush_transforms_inv.append(brush_transform.inverted());
}
const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
const float brush_radius_sq_re = pow2f(brush_radius_re);
threading::parallel_for(curves_->curves_range(), 256, [&](const IndexRange curves_range) {
Influences &local_influences = influences_for_thread.local();
@ -414,13 +421,13 @@ struct CurvesEffectOperationExecutor {
p1_re,
p2_re);
if (dist_to_brush_sq_re > brush_radius_sq_re_) {
if (dist_to_brush_sq_re > brush_radius_sq_re) {
continue;
}
const float dist_to_brush_re = std::sqrt(dist_to_brush_sq_re);
const float radius_falloff = BKE_brush_curve_strength(
brush_, dist_to_brush_re, brush_radius_re_);
brush_, dist_to_brush_re, brush_radius_re);
const float weight = brush_strength_ * radius_falloff;
const float3 closest_on_segment_cu = math::interpolate(
@ -473,7 +480,7 @@ struct CurvesEffectOperationExecutor {
const float3 brush_pos_end_cu = world_to_curves_mat_ * brush_pos_end_wo;
const float3 brush_pos_diff_cu = brush_pos_end_cu - brush_pos_start_cu;
const float brush_pos_diff_length_cu = math::length(brush_pos_diff_cu);
const float brush_radius_cu = self_->brush_3d_.radius_cu;
const float brush_radius_cu = self_->brush_3d_.radius_cu * brush_radius_factor_;
const float brush_radius_sq_cu = pow2f(brush_radius_cu);
const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(

View File

@ -16,6 +16,8 @@ struct RegionView3D;
struct Depsgraph;
struct View3D;
struct Object;
struct Brush;
struct Scene;
namespace blender::ed::sculpt_paint {
@ -27,10 +29,12 @@ struct StrokeExtension {
float pressure;
};
float brush_radius_factor(const Brush &brush, const StrokeExtension &stroke_extension);
float brush_radius_get(const Scene &scene,
const Brush &brush,
const StrokeExtension &stroke_extension);
float brush_strength_factor(const Brush &brush, const StrokeExtension &stroke_extension);
float brush_strength_get(const Scene &scene,
const Brush &brush,
const StrokeExtension &stroke_extension);

View File

@ -74,26 +74,34 @@ using blender::bke::CurvesGeometry;
/** \name * SCULPT_CURVES_OT_brush_stroke
* \{ */
float brush_radius_factor(const Brush &brush, const StrokeExtension &stroke_extension)
{
if (BKE_brush_use_size_pressure(&brush)) {
return stroke_extension.pressure;
}
return 1.0f;
}
float brush_radius_get(const Scene &scene,
const Brush &brush,
const StrokeExtension &stroke_extension)
{
const float initial_radius = BKE_brush_size_get(&scene, &brush);
if (BKE_brush_use_size_pressure(&brush)) {
return initial_radius * stroke_extension.pressure;
return BKE_brush_size_get(&scene, &brush) * brush_radius_factor(brush, stroke_extension);
}
float brush_strength_factor(const Brush &brush, const StrokeExtension &stroke_extension)
{
if (BKE_brush_use_alpha_pressure(&brush)) {
return stroke_extension.pressure;
}
return initial_radius;
return 1.0f;
}
float brush_strength_get(const Scene &scene,
const Brush &brush,
const StrokeExtension &stroke_extension)
{
const float initial_radius = BKE_brush_alpha_get(&scene, &brush);
if (BKE_brush_use_alpha_pressure(&brush)) {
return initial_radius * stroke_extension.pressure;
}
return initial_radius;
return BKE_brush_alpha_get(&scene, &brush) * brush_strength_factor(brush, stroke_extension);
}
static std::unique_ptr<CurvesSculptStrokeOperation> start_brush_operation(bContext &C,

View File

@ -80,8 +80,10 @@ struct SnakeHookOperatorExecutor {
const CurvesSculpt *curves_sculpt_ = nullptr;
const Brush *brush_ = nullptr;
float brush_radius_re_;
float brush_radius_base_re_;
float brush_radius_factor_;
float brush_strength_;
eBrushFalloffShape falloff_shape_;
Object *object_ = nullptr;
@ -112,8 +114,11 @@ struct SnakeHookOperatorExecutor {
curves_sculpt_ = scene_->toolsettings->curves_sculpt;
brush_ = BKE_paint_brush_for_read(&curves_sculpt_->paint);
brush_radius_re_ = brush_radius_get(*scene_, *brush_, stroke_extension);
brush_radius_base_re_ = BKE_brush_size_get(scene_, brush_);
brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension);
brush_strength_ = brush_strength_get(*scene_, *brush_, stroke_extension);
falloff_shape_ = static_cast<eBrushFalloffShape>(brush_->falloff_shape);
curves_to_world_mat_ = object_->obmat;
@ -132,7 +137,7 @@ struct SnakeHookOperatorExecutor {
if (stroke_extension.is_first) {
if (falloff_shape_ == PAINT_FALLOFF_SHAPE_SPHERE) {
std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush(
*depsgraph_, *region_, *v3d_, *rv3d_, *object_, brush_pos_re_, brush_radius_re_);
*depsgraph_, *region_, *v3d_, *rv3d_, *object_, brush_pos_re_, brush_radius_base_re_);
if (brush_3d.has_value()) {
self_->brush_3d_ = *brush_3d;
}
@ -174,6 +179,9 @@ struct SnakeHookOperatorExecutor {
float4x4 projection;
ED_view3d_ob_project_mat_get(rv3d_, object_, projection.values);
const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
const float brush_radius_sq_re = pow2f(brush_radius_re);
threading::parallel_for(curves_->curves_range(), 256, [&](const IndexRange curves_range) {
for (const int curve_i : curves_range) {
const IndexRange points = curves_->points_for_curve(curve_i);
@ -183,13 +191,14 @@ struct SnakeHookOperatorExecutor {
float2 old_pos_re;
ED_view3d_project_float_v2_m4(region_, old_pos_cu, old_pos_re, projection.values);
const float distance_to_brush_re = math::distance(old_pos_re, brush_pos_prev_re_);
if (distance_to_brush_re > brush_radius_re_) {
const float distance_to_brush_sq_re = math::distance_squared(old_pos_re,
brush_pos_prev_re_);
if (distance_to_brush_sq_re > brush_radius_sq_re) {
continue;
}
const float radius_falloff = BKE_brush_curve_strength(
brush_, distance_to_brush_re, brush_radius_re_);
brush_, std::sqrt(distance_to_brush_sq_re), brush_radius_re);
const float weight = brush_strength_ * radius_falloff;
const float2 new_position_re = old_pos_re + brush_pos_diff_re_ * weight;
@ -222,7 +231,7 @@ struct SnakeHookOperatorExecutor {
const float3 brush_start_cu = world_to_curves_mat_ * brush_start_wo;
const float3 brush_end_cu = world_to_curves_mat_ * brush_end_wo;
const float brush_radius_cu = self_->brush_3d_.radius_cu;
const float brush_radius_cu = self_->brush_3d_.radius_cu * brush_radius_factor_;
const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
eCurvesSymmetryType(curves_id_->symmetry));