Blender V4.3
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> 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 for (const BrushPoint &point : drawing_weight.points_in_brush) {
105 this->apply_blur_brush(point, drawing_weight, touched_points);
106
107 /* Normalize weights of bone-deformed vertex groups to 1.0f. */
108 if (this->auto_normalize) {
109 normalize_vertex_weights(drawing_weight.deform_verts[point.drawing_point_index],
110 drawing_weight.active_vertex_group,
111 drawing_weight.locked_vgroups,
112 drawing_weight.bone_deformed_vgroups);
113 }
114 }
115
116 if (!drawing_weight.points_in_brush.is_empty()) {
117 changed = true;
118 drawing_weight.points_in_brush.clear();
119 }
120 });
121
122 BLI_kdtree_2d_free(touched_points.kdtree);
123 });
124
125 if (changed) {
128 }
129 }
130
131 void on_stroke_done(const bContext & /*C*/) override {}
132};
133
134std::unique_ptr<GreasePencilStrokeOperation> new_weight_paint_blur_operation()
135{
136 return std::make_unique<BlurWeightPaintOperation>();
137}
138
139} // 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:1041
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a point
#define C
Definition RandGen.cpp:29
#define NC_GEOM
Definition WM_types.hh:360
#define ND_DATA
Definition WM_types.hh:475
int64_t size() const
Definition BLI_array.hh:245
IndexRange index_range() const
Definition BLI_array.hh:349
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:58
void WM_event_add_notifier(const bContext *C, uint type, void *reference)