Blender V4.3
curves_sculpt_smooth.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "BKE_brush.hh"
6#include "BKE_context.hh"
7#include "BKE_crazyspace.hh"
8#include "BKE_paint.hh"
9
10#include "ED_screen.hh"
11#include "ED_view3d.hh"
12
13#include "DEG_depsgraph.hh"
14
15#include "DNA_brush_types.h"
16
17#include "WM_api.hh"
18
20#include "BLI_task.hh"
21
23
25
27 private:
29 CurvesBrush3D brush_3d_;
30
32
33 public:
34 void on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) override;
35};
36
44
45 Object *object_ = nullptr;
46 Curves *curves_id_ = nullptr;
48
52
53 const CurvesSculpt *curves_sculpt_ = nullptr;
54 const Brush *brush_ = nullptr;
59
61
63
64 void execute(SmoothOperation &self, const bContext &C, const StrokeExtension &stroke_extension)
65 {
66 UNUSED_VARS(C, stroke_extension);
67 self_ = &self;
68
70 curves_id_ = static_cast<Curves *>(object_->data);
71 curves_ = &curves_id_->geometry.wrap();
72 if (curves_->curves_num() == 0) {
73 return;
74 }
75
80 brush_strength_ = brush_strength_get(*ctx_.scene, *brush_, stroke_extension);
81 brush_pos_re_ = stroke_extension.mouse_position;
82
84 ".selection", bke::AttrDomain::Point, 1.0f);
87
89 if (stroke_extension.is_first) {
90 if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
92 *ctx_.region,
93 *ctx_.v3d,
94 *ctx_.rv3d,
95 *object_,
98 }
99 }
100
101 Array<float> point_smooth_factors(curves_->points_num(), 0.0f);
102
103 if (falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
104 this->find_projected_smooth_factors_with_symmetry(point_smooth_factors);
105 }
106 else if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
107 this->find_spherical_smooth_factors_with_symmetry(point_smooth_factors);
108 }
109 else {
111 }
112
113 this->smooth(point_smooth_factors);
118 }
119
121 {
122 const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
124 for (const float4x4 &brush_transform : symmetry_brush_transforms) {
125 this->find_projected_smooth_factors(brush_transform, r_point_smooth_factors);
126 }
127 }
128
129 void find_projected_smooth_factors(const float4x4 &brush_transform,
130 MutableSpan<float> r_point_smooth_factors)
131 {
132 const float4x4 brush_transform_inv = math::invert(brush_transform);
133
134 const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
135 const float brush_radius_sq_re = pow2f(brush_radius_re);
136
138
139 const bke::crazyspace::GeometryDeformation deformation =
141 const OffsetIndices points_by_curve = curves_->points_by_curve();
142
143 curve_selection_.foreach_index(GrainSize(256), [&](const int curve_i) {
144 const IndexRange points = points_by_curve[curve_i];
145 for (const int point_i : points) {
146 const float3 &pos_cu = math::transform_point(brush_transform_inv,
147 deformation.positions[point_i]);
148 const float2 pos_re = ED_view3d_project_float_v2_m4(ctx_.region, pos_cu, projection);
149 const float dist_to_brush_sq_re = math::distance_squared(pos_re, brush_pos_re_);
150 if (dist_to_brush_sq_re > brush_radius_sq_re) {
151 continue;
152 }
153
154 const float dist_to_brush_re = std::sqrt(dist_to_brush_sq_re);
155 const float radius_falloff = BKE_brush_curve_strength(
156 brush_, dist_to_brush_re, brush_radius_re);
157 /* Used to make the brush easier to use. Otherwise a strength of 1 would be way too
158 * large. */
159 const float weight_factor = 0.1f;
160 const float weight = weight_factor * brush_strength_ * radius_falloff *
161 point_factors_[point_i];
162 math::max_inplace(r_point_smooth_factors[point_i], weight);
163 }
164 });
165 }
166
168 {
169 float3 brush_pos_wo;
171 ctx_.v3d,
172 ctx_.region,
175 brush_pos_wo);
176 const float3 brush_pos_cu = math::transform_point(transforms_.world_to_curves, brush_pos_wo);
177 const float brush_radius_cu = self_->brush_3d_.radius_cu * brush_radius_factor_;
178
179 const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
181 for (const float4x4 &brush_transform : symmetry_brush_transforms) {
182 this->find_spherical_smooth_factors(math::transform_point(brush_transform, brush_pos_cu),
183 brush_radius_cu,
184 r_point_smooth_factors);
185 }
186 }
187
188 void find_spherical_smooth_factors(const float3 &brush_pos_cu,
189 const float brush_radius_cu,
190 MutableSpan<float> r_point_smooth_factors)
191 {
192 const float brush_radius_sq_cu = pow2f(brush_radius_cu);
193 const bke::crazyspace::GeometryDeformation deformation =
195 const OffsetIndices points_by_curve = curves_->points_by_curve();
196
197 curve_selection_.foreach_index(GrainSize(256), [&](const int curve_i) {
198 const IndexRange points = points_by_curve[curve_i];
199 for (const int point_i : points) {
200 const float3 &pos_cu = deformation.positions[point_i];
201 const float dist_to_brush_sq_cu = math::distance_squared(pos_cu, brush_pos_cu);
202 if (dist_to_brush_sq_cu > brush_radius_sq_cu) {
203 continue;
204 }
205
206 const float dist_to_brush_cu = std::sqrt(dist_to_brush_sq_cu);
207 const float radius_falloff = BKE_brush_curve_strength(
208 brush_, dist_to_brush_cu, brush_radius_cu);
209 /* Used to make the brush easier to use. Otherwise a strength of 1 would be way too
210 * large. */
211 const float weight_factor = 0.1f;
212 const float weight = weight_factor * brush_strength_ * radius_falloff *
213 point_factors_[point_i];
214 math::max_inplace(r_point_smooth_factors[point_i], weight);
215 }
216 });
217 }
218
219 void smooth(const Span<float> point_smooth_factors)
220 {
221 const OffsetIndices points_by_curve = curves_->points_by_curve();
223
225 Vector<float3> old_positions;
226 for (const int curve_i : segment) {
227 const IndexRange points = points_by_curve[curve_i];
228 old_positions.clear();
229 old_positions.extend(positions.slice(points));
230 for (const int i : IndexRange(points.size()).drop_front(1).drop_back(1)) {
231 const int point_i = points[i];
232 const float smooth_factor = point_smooth_factors[point_i];
233 if (smooth_factor == 0.0f) {
234 continue;
235 }
236 /* Move towards the middle of the neighboring points. */
237 const float3 old_pos = old_positions[i];
238 const float3 &prev_pos = old_positions[i - 1];
239 const float3 &next_pos = old_positions[i + 1];
240 const float3 goal_pos = math::midpoint(prev_pos, next_pos);
241 const float3 new_pos = math::interpolate(old_pos, goal_pos, smooth_factor);
242 positions[point_i] = new_pos;
243 }
244 }
245 });
246 }
247};
248
250 const StrokeExtension &stroke_extension)
251{
252 SmoothOperationExecutor executor{C};
253 executor.execute(*this, C, stroke_extension);
254}
255
256std::unique_ptr<CurvesSculptStrokeOperation> new_smooth_operation()
257{
258 return std::make_unique<SmoothOperation>();
259}
260
261} // namespace blender::ed::sculpt_paint
int BKE_brush_size_get(const Scene *scene, const Brush *brush)
Definition brush.cc:1075
float BKE_brush_curve_strength(eBrushCurvePreset preset, const CurveMapping *cumap, float distance, float brush_radius)
Definition brush.cc:1388
Object * CTX_data_active_object(const bContext *C)
const Brush * BKE_paint_brush_for_read(const Paint *paint)
Definition paint.cc:654
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
MINLINE float pow2f(float x)
#define UNUSED_VARS(...)
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1041
eBrushFalloffShape
@ PAINT_FALLOFF_SHAPE_SPHERE
@ PAINT_FALLOFF_SHAPE_TUBE
eCurvesSymmetryType
void ED_region_tag_redraw(ARegion *region)
Definition area.cc:634
blender::float2 ED_view3d_project_float_v2_m4(const ARegion *region, const float co[3], const blender::float4x4 &mat)
void ED_view3d_win_to_3d(const View3D *v3d, const ARegion *region, const float depth_pt[3], const float mval[2], float r_out[3])
blender::float4x4 ED_view3d_ob_project_mat_get(const RegionView3D *rv3d, const Object *ob)
#define NC_GEOM
Definition WM_types.hh:360
#define ND_DATA
Definition WM_types.hh:475
PyObject * self
constexpr IndexRange drop_back(int64_t n) const
constexpr IndexRange drop_front(int64_t n) const
void extend(Span< T > array)
GAttributeReader lookup_or_default(StringRef attribute_id, AttrDomain domain, eCustomDataType data_type, const void *default_value=nullptr) const
MutableSpan< float3 > positions_for_write()
OffsetIndices< int > points_by_curve() const
void on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) override
void foreach_index(Fn &&fn) const
void foreach_segment(Fn &&fn) const
GeometryDeformation get_evaluated_curves_deformation(const Object *ob_eval, const Object &ob_orig)
IndexMask retrieve_selected_curves(const bke::CurvesGeometry &curves, IndexMaskMemory &memory)
std::optional< CurvesBrush3D > sample_curves_3d_brush(const Depsgraph &depsgraph, const ARegion &region, const View3D &v3d, const RegionView3D &rv3d, const Object &curves_object, const float2 &brush_pos_re, const float brush_radius_re)
std::unique_ptr< CurvesSculptStrokeOperation > new_smooth_operation()
float brush_strength_get(const Scene &scene, const Brush &brush, const StrokeExtension &stroke_extension)
Vector< float4x4 > get_symmetry_brush_transforms(const eCurvesSymmetryType symmetry)
float brush_radius_factor(const Brush &brush, const StrokeExtension &stroke_extension)
CartesianBasis invert(const CartesianBasis &basis)
T midpoint(const T &a, const T &b)
T interpolate(const T &a, const T &b, const FactorT &t)
T distance_squared(const VecBase< T, Size > &a, const VecBase< T, Size > &b)
void max_inplace(T &a, const T &b)
VecBase< T, 3 > transform_point(const CartesianBasis &basis, const VecBase< T, 3 > &v)
char falloff_shape
CurvesGeometry geometry
struct Object * surface
struct ToolSettings * toolsettings
CurvesSculpt * curves_sculpt
void find_spherical_smooth_factors(const float3 &brush_pos_cu, const float brush_radius_cu, MutableSpan< float > r_point_smooth_factors)
void find_projected_smooth_factors(const float4x4 &brush_transform, MutableSpan< float > r_point_smooth_factors)
void smooth(const Span< float > point_smooth_factors)
void execute(SmoothOperation &self, const bContext &C, const StrokeExtension &stroke_extension)
void find_spherical_smooth_factors_with_symmetry(MutableSpan< float > r_point_smooth_factors)
void find_projected_smooth_factors_with_symmetry(MutableSpan< float > r_point_smooth_factors)
void WM_main_add_notifier(uint type, void *reference)