Blender V4.3
curves_sculpt_snake_hook.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 <algorithm>
6
8
9#include "BLI_kdtree.h"
11#include "BLI_math_geom.h"
13#include "BLI_rand.hh"
14#include "BLI_vector.hh"
15
16#include "DEG_depsgraph.hh"
17
18#include "BKE_attribute.hh"
19#include "BKE_attribute_math.hh"
20#include "BKE_brush.hh"
21#include "BKE_bvhutils.hh"
22#include "BKE_context.hh"
23#include "BKE_curves.hh"
24#include "BKE_mesh.hh"
25#include "BKE_mesh_runtime.hh"
26#include "BKE_paint.hh"
27
28#include "DNA_brush_enums.h"
29#include "DNA_brush_types.h"
30#include "DNA_curves_types.h"
31#include "DNA_object_types.h"
32#include "DNA_screen_types.h"
33#include "DNA_space_types.h"
34
35#include "ED_screen.hh"
36#include "ED_view3d.hh"
37
38#include "WM_api.hh"
39
49
51
56 private:
57 float2 last_mouse_position_re_;
58
59 CurvesBrush3D brush_3d_;
60
62
63 public:
64 void on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) override;
65};
66
74
75 const CurvesSculpt *curves_sculpt_ = nullptr;
76 const Brush *brush_ = nullptr;
80
81 Object *object_ = nullptr;
82 Curves *curves_id_ = nullptr;
84
88
90
94
96
98 const bContext &C,
99 const StrokeExtension &stroke_extension)
100 {
101 BLI_SCOPED_DEFER([&]() { self.last_mouse_position_re_ = stroke_extension.mouse_position; });
102
103 self_ = &self;
105
108
110 brush_radius_factor_ = brush_radius_factor(*brush_, stroke_extension);
111 brush_strength_ = brush_strength_get(*ctx_.scene, *brush_, stroke_extension);
112
114
115 curves_id_ = static_cast<Curves *>(object_->data);
116 curves_ = &curves_id_->geometry.wrap();
117 if (curves_->curves_num() == 0) {
118 return;
119 }
120
122
124 ".selection", bke::AttrDomain::Curve, 1.0f);
126
127 brush_pos_prev_re_ = self.last_mouse_position_re_;
128 brush_pos_re_ = stroke_extension.mouse_position;
130
131 if (stroke_extension.is_first) {
132 if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
133 std::optional<CurvesBrush3D> brush_3d = sample_curves_3d_brush(*ctx_.depsgraph,
134 *ctx_.region,
135 *ctx_.v3d,
136 *ctx_.rv3d,
137 *object_,
140 if (brush_3d.has_value()) {
141 self_->brush_3d_ = *brush_3d;
142 }
143 }
144 return;
145 }
146
147 if (falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) {
149 }
150 else if (falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) {
152 }
153 else {
155 }
156
157 curves_->tag_positions_changed();
161 }
162
164 {
165 const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
167 for (const float4x4 &brush_transform : symmetry_brush_transforms) {
168 this->projected_snake_hook(brush_transform);
169 }
170 }
171
172 void projected_snake_hook(const float4x4 &brush_transform)
173 {
174 const float4x4 brush_transform_inv = math::invert(brush_transform);
175 const bke::crazyspace::GeometryDeformation deformation =
177 const OffsetIndices points_by_curve = curves_->points_by_curve();
178
180
182
183 const float brush_radius_re = brush_radius_base_re_ * brush_radius_factor_;
184 const float brush_radius_sq_re = pow2f(brush_radius_re);
185
187 MoveAndResampleBuffers resample_buffer;
188 for (const int curve_i : segment) {
189 const IndexRange points = points_by_curve[curve_i];
190 const int last_point_i = points.last();
191 const float3 old_pos_cu = deformation.positions[last_point_i];
192 const float3 old_symm_pos_cu = math::transform_point(brush_transform_inv, old_pos_cu);
193
194 const float2 old_symm_pos_re = ED_view3d_project_float_v2_m4(
195 ctx_.region, old_symm_pos_cu, projection);
196
197 const float distance_to_brush_sq_re = math::distance_squared(old_symm_pos_re,
199 if (distance_to_brush_sq_re > brush_radius_sq_re) {
200 continue;
201 }
202
203 const float radius_falloff = BKE_brush_curve_strength(
204 brush_, std::sqrt(distance_to_brush_sq_re), brush_radius_re);
205 const float weight = brush_strength_ * radius_falloff * curve_factors_[curve_i];
206
207 const float2 new_symm_pos_re = old_symm_pos_re + brush_pos_diff_re_ * weight;
208 float3 new_symm_pos_wo;
210 ctx_.region,
212 new_symm_pos_re,
213 new_symm_pos_wo);
214 const float3 new_pos_cu = math::transform_point(
215 brush_transform, math::transform_point(transforms_.world_to_curves, new_symm_pos_wo));
216 const float3 translation_eval = new_pos_cu - old_pos_cu;
217 const float3 translation_orig = deformation.translation_from_deformed_to_original(
218 last_point_i, translation_eval);
219
220 const float3 last_point_cu = positions_cu[last_point_i] + translation_orig;
221 move_last_point_and_resample(resample_buffer, positions_cu.slice(points), last_point_cu);
222 }
223 });
224 }
225
227 {
228 float3 brush_start_wo, brush_end_wo;
230 ctx_.v3d,
231 ctx_.region,
234 brush_start_wo);
236 ctx_.v3d,
237 ctx_.region,
240 brush_end_wo);
242 brush_start_wo);
243 const float3 brush_end_cu = math::transform_point(transforms_.world_to_curves, brush_end_wo);
244
245 const float brush_radius_cu = self_->brush_3d_.radius_cu * brush_radius_factor_;
246
247 const Vector<float4x4> symmetry_brush_transforms = get_symmetry_brush_transforms(
249 for (const float4x4 &brush_transform : symmetry_brush_transforms) {
250 this->spherical_snake_hook(math::transform_point(brush_transform, brush_start_cu),
251 math::transform_point(brush_transform, brush_end_cu),
252 brush_radius_cu);
253 }
254 }
255
256 void spherical_snake_hook(const float3 &brush_start_cu,
257 const float3 &brush_end_cu,
258 const float brush_radius_cu)
259 {
260 const bke::crazyspace::GeometryDeformation deformation =
262 const OffsetIndices points_by_curve = curves_->points_by_curve();
263
265 const float3 brush_diff_cu = brush_end_cu - brush_start_cu;
266 const float brush_radius_sq_cu = pow2f(brush_radius_cu);
267
269 MoveAndResampleBuffers resample_buffer;
270 for (const int curve_i : segment) {
271 const IndexRange points = points_by_curve[curve_i];
272 const int last_point_i = points.last();
273 const float3 old_pos_cu = deformation.positions[last_point_i];
274
275 const float distance_to_brush_sq_cu = dist_squared_to_line_segment_v3(
276 old_pos_cu, brush_start_cu, brush_end_cu);
277 if (distance_to_brush_sq_cu > brush_radius_sq_cu) {
278 continue;
279 }
280
281 const float distance_to_brush_cu = std::sqrt(distance_to_brush_sq_cu);
282
283 const float radius_falloff = BKE_brush_curve_strength(
284 brush_, distance_to_brush_cu, brush_radius_cu);
285 const float weight = brush_strength_ * radius_falloff * curve_factors_[curve_i];
286
287 const float3 translation_eval = weight * brush_diff_cu;
288 const float3 translation_orig = deformation.translation_from_deformed_to_original(
289 last_point_i, translation_eval);
290
291 const float3 last_point_cu = positions_cu[last_point_i] + translation_orig;
292 move_last_point_and_resample(resample_buffer, positions_cu.slice(points), last_point_cu);
293 }
294 });
295 }
296};
297
299 const StrokeExtension &stroke_extension)
300{
301 SnakeHookOperatorExecutor executor{C};
302 executor.execute(*this, C, stroke_extension);
303}
304
305std::unique_ptr<CurvesSculptStrokeOperation> new_snake_hook_operation()
306{
307 return std::make_unique<SnakeHookOperation>();
308}
309
310} // 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)
Low-level operations for curves.
const Brush * BKE_paint_brush_for_read(const Paint *paint)
Definition paint.cc:654
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
A KD-tree for nearest neighbor search.
MINLINE float pow2f(float x)
float dist_squared_to_line_segment_v3(const float p[3], const float l1[3], const float l2[3])
Definition math_geom.cc:517
#define BLI_SCOPED_DEFER(function_to_defer)
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
Object is a sort of wrapper for general info.
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 MutableSpan slice(const int64_t start, const int64_t size) const
Definition BLI_span.hh:574
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_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_snake_hook_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)
void move_last_point_and_resample(MoveAndResampleBuffers &buffer, MutableSpan< float3 > positions, const float3 &new_last_position)
CartesianBasis invert(const CartesianBasis &basis)
T distance_squared(const VecBase< T, Size > &a, const VecBase< T, Size > &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 spherical_snake_hook(const float3 &brush_start_cu, const float3 &brush_end_cu, const float brush_radius_cu)
void execute(SnakeHookOperation &self, const bContext &C, const StrokeExtension &stroke_extension)
void WM_main_add_notifier(uint type, void *reference)