Blender V5.0
grease_pencil_weight_blur.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
6
8
10 /* Apply the Blur tool to a point under the brush. */
11 void apply_blur_brush(const BrushPoint &point,
12 DrawingWeightData &drawing_weight,
13 PointsTouchedByBrush &touched_points)
14 {
15 /* Find the nearest neighbors of the to-be-blurred point. The point itself is included. */
16 KDTreeNearest_2d nearest_points[BLUR_NEIGHBOUR_NUM];
17 const int point_num = BLI_kdtree_2d_find_nearest_n(
18 touched_points.kdtree,
19 drawing_weight.point_positions[point.drawing_point_index],
20 nearest_points,
22
23 if (point_num <= 1) {
24 return;
25 }
26
27 /* Calculate the blurred weight for the point (A). For this we use a weighted average of the
28 * point weights, based on the distance of the neighbor point to A. So points closer to A
29 * contribute more to the average than points farther away from A. */
30 float distance_sum = 0.0f;
31 for (const int i : IndexRange(point_num)) {
32 distance_sum += nearest_points[i].dist;
33 }
34 if (distance_sum == 0.0f) {
35 return;
36 }
37 float blur_weight_sum = 0.0f;
38 for (const int i : IndexRange(point_num)) {
39 blur_weight_sum += (1.0f - nearest_points[i].dist / distance_sum) *
40 touched_points.weights[nearest_points[i].index];
41 }
42 const float blur_weight = blur_weight_sum / (point_num - 1);
43
44 apply_weight_to_point(point, blur_weight, drawing_weight);
45 }
46
47 public:
48 void on_stroke_begin(const bContext &C, const InputSample &start_sample) override
49 {
50 using namespace blender::ed::greasepencil;
51
52 this->get_brush_settings(C, start_sample);
55
56 /* Get editable drawings grouped per frame number. When multi-frame editing is disabled, this
57 * is just one group for the current frame. When multi-frame editing is enabled, the selected
58 * keyframes are grouped per frame number. This way we can use Blur on multiple layers
59 * together instead of on every layer individually. */
60 const Scene *scene = CTX_data_scene(&C);
61 Array<Vector<MutableDrawingInfo>> drawings_per_frame =
63
64 this->drawing_weight_data = Array<Array<DrawingWeightData>>(drawings_per_frame.size());
65
66 /* Get weight data for all drawings in this frame group. */
67 for (const int frame_group : drawings_per_frame.index_range()) {
68 const Vector<MutableDrawingInfo> &drawings = drawings_per_frame[frame_group];
69 this->init_weight_data_for_drawings(C, drawings, frame_group);
70 }
71 }
72
73 void on_stroke_extended(const bContext &C, const InputSample &extension_sample) override
74 {
75 using namespace blender::ed::greasepencil;
76
77 this->get_mouse_input_sample(extension_sample, 1.3f);
78
79 /* Iterate over the drawings grouped per frame number. Collect all stroke points under the
80 * brush and blur them. */
81 std::atomic<bool> drawing_changed = false;
83 this->drawing_weight_data.index_range(), [&](const int frame_group) {
84 Array<DrawingWeightData> &drawing_weights = this->drawing_weight_data[frame_group];
85
86 /* For all layers at this key frame, collect the stroke points under the brush in a
87 * buffer. */
88 threading::parallel_for_each(drawing_weights, [&](DrawingWeightData &drawing_weight) {
89 for (const int point_index : drawing_weight.point_positions.index_range()) {
90 const float2 &co = drawing_weight.point_positions[point_index];
91
92 /* When the point is under the brush, add it to the brush point buffer. */
93 this->add_point_under_brush_to_brush_buffer(co, drawing_weight, point_index);
94 }
95 });
96
97 /* Create a KDTree with all stroke points touched by the brush during the weight paint
98 * operation. */
100 drawing_weights);
101
102 /* Apply the Blur brush to all points in the brush buffer. */
103 threading::parallel_for_each(drawing_weights, [&](DrawingWeightData &drawing_weight) {
104 bool point_changed = false;
105 for (const BrushPoint &point : drawing_weight.points_in_brush) {
106 if (drawing_weight.point_is_read_only[point.drawing_point_index]) {
107 continue;
108 }
109
110 this->apply_blur_brush(point, drawing_weight, touched_points);
111 point_changed = true;
112
113 /* Normalize weights of bone-deformed vertex groups to 1.0f. */
114 if (this->auto_normalize) {
116 drawing_weight.active_vertex_group,
117 drawing_weight.locked_vgroups,
118 drawing_weight.bone_deformed_vgroups);
119 }
120 }
121
122 if (point_changed) {
123 drawing_changed.store(true, std::memory_order_relaxed);
124 }
125 drawing_weight.points_in_brush.clear();
126 });
127
128 BLI_kdtree_2d_free(touched_points.kdtree);
129 });
130
131 if (drawing_changed) {
134 }
135 }
136
137 void on_stroke_done(const bContext & /*C*/) override {}
138};
139
140std::unique_ptr<GreasePencilStrokeOperation> new_weight_paint_blur_operation()
141{
142 return std::make_unique<BlurWeightPaintOperation>();
143}
144
145} // namespace blender::ed::sculpt_paint::greasepencil
Scene * CTX_data_scene(const bContext *C)
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1074
#define C
Definition RandGen.cpp:29
#define NC_GEOM
Definition WM_types.hh:393
#define ND_DATA
Definition WM_types.hh:509
int64_t size() const
Definition BLI_array.hh:256
IndexRange index_range() const
Definition BLI_array.hh:360
void on_stroke_begin(const bContext &C, const InputSample &start_sample) override
void on_stroke_extended(const bContext &C, const InputSample &extension_sample) override
void get_mouse_input_sample(const InputSample &input_sample, const float brush_widen_factor=1.0f)
PointsTouchedByBrush create_affected_points_kdtree(const Span< DrawingWeightData > drawing_weights)
void get_brush_settings(const bContext &C, const InputSample &start_sample)
void init_weight_data_for_drawings(const bContext &C, const Span< ed::greasepencil::MutableDrawingInfo > &drawings, const int frame_group)
void apply_weight_to_point(const BrushPoint &point, const float target_weight, DrawingWeightData &drawing_weight)
void normalize_vertex_weights(MDeformVert &dvert, const int active_vertex_group, const Span< bool > vertex_group_is_locked, const Span< bool > vertex_group_is_bone_deformed)
Array< Vector< MutableDrawingInfo > > retrieve_editable_drawings_grouped_per_frame(const Scene &scene, GreasePencil &grease_pencil)
std::unique_ptr< GreasePencilStrokeOperation > new_weight_paint_blur_operation()
void parallel_for_each(Range &&range, const Function &function)
Definition BLI_task.hh:56
i
Definition text_draw.cc:230
void WM_event_add_notifier(const bContext *C, uint type, void *reference)