Blender V4.3
grease_pencil_weight_paint.hh
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#pragma once
6
7#include "BKE_brush.hh"
8#include "BKE_colortools.hh"
9#include "BKE_context.hh"
10#include "BKE_crazyspace.hh"
11#include "BKE_curves.hh"
12#include "BKE_deform.hh"
14#include "BKE_modifier.hh"
15#include "BKE_object_deform.h"
16#include "BKE_paint.hh"
17#include "BKE_scene.hh"
18
20
21#include "BLI_kdtree.h"
22#include "BLI_rect.h"
23
24#include "DNA_meshdata_types.h"
25
26#include "ED_grease_pencil.hh"
27#include "ED_view3d.hh"
28
30
32
33static constexpr float FIND_NEAREST_POINT_EPSILON = 1e-6f;
34static constexpr int BLUR_NEIGHBOUR_NUM = 5;
35static constexpr int SMEAR_NEIGHBOUR_NUM = 8;
36
38 public:
43
49
52
54
55 /* Flag for all stroke points in a drawing: true when the point was touched by the brush during
56 * a #GreasePencilStrokeOperation. */
59
60 /* Collected points under the brush in one #on_stroke_extended action. */
62 };
63
68
81
82 /* Flag for Auto-normalize weights of bone deformed vertex groups. */
84 /* Brush mode: normal, invert or smooth. */
86 /* Add or subtract weight? */
88 /* Active vertex group in GP object. */
90
91 /* Weight paint data per editable drawing. Stored per frame group. */
93
94 /* Set of bone-deformed vertex groups (object level). */
96 /* Set of locked vertex groups (object level). */
98
100
101 /* Apply a weight to a point under the brush. */
103 const float target_weight,
104 DrawingWeightData &drawing_weight)
105 {
106 /* Blend the current point weight with the target weight. */
107 const float old_weight = drawing_weight.deform_weights[point.drawing_point_index];
108 const float weight_delta = (this->invert_brush_weight ? (1.0f - target_weight) :
109 target_weight) -
110 old_weight;
111 drawing_weight.deform_weights.set(
112 point.drawing_point_index,
114 old_weight + math::interpolate(0.0f, weight_delta, point.influence), 0.0f, 1.0f));
115 }
116
117 /* Get brush settings (radius, strength etc.) */
118 void get_brush_settings(const bContext &C, const InputSample &start_sample)
119 {
120 using namespace blender::ed::greasepencil;
121
122 const Scene *scene = CTX_data_scene(&C);
123 this->object = CTX_data_active_object(&C);
124 this->grease_pencil = static_cast<GreasePencil *>(this->object->data);
126 Brush *brush = BKE_paint_brush(paint);
127
128 this->brush = brush;
129 this->initial_brush_radius = BKE_brush_size_get(scene, brush);
130 this->initial_brush_strength = BKE_brush_alpha_get(scene, brush);
131 this->brush_weight = BKE_brush_weight_get(scene, brush);
132 this->mouse_position_previous = start_sample.mouse_position;
133 this->invert_brush_weight = false;
134
136
137 /* Auto-normalize weights is only applied when the object is deformed by an armature. */
138 const ToolSettings *ts = CTX_data_tool_settings(&C);
139 this->auto_normalize = ts->auto_normalize &&
140 (BKE_modifiers_is_deformed_by_armature(this->object) != nullptr);
141 }
142
143 /* Get or create active vertex group in GP object. */
145 {
146 int object_defgroup_nr = BKE_object_defgroup_active_index_get(this->object) - 1;
147 if (object_defgroup_nr == -1) {
148 BKE_object_defgroup_add(this->object);
149 object_defgroup_nr = 0;
150 }
151 this->object_defgroup = static_cast<bDeformGroup *>(
152 BLI_findlink(BKE_object_defgroup_list(this->object), object_defgroup_nr));
153 }
154
155 /* Get locked and bone-deformed vertex groups in GP object. */
157 {
158 const ListBase *defgroups = BKE_object_defgroup_list(this->object);
159 LISTBASE_FOREACH (bDeformGroup *, dg, defgroups) {
160 if ((dg->flag & DG_LOCK_WEIGHT) != 0) {
161 this->object_locked_defgroups.add(dg->name);
162 }
163 }
164 this->object_bone_deformed_defgroups = ed::greasepencil::get_bone_deformed_vertex_group_names(
165 *this->object);
166 }
167
168 /* For each drawing, retrieve pointers to the vertex weight data of the active vertex group,
169 * so that we can read and write to them later. And create buffers for points under the brush
170 * during one #on_stroke_extended action. */
173 const int frame_group)
174 {
175 const Depsgraph *depsgraph = CTX_data_depsgraph_pointer(&C);
176 const Object *ob_eval = DEG_get_evaluated_object(depsgraph, this->object);
177 const RegionView3D *rv3d = CTX_wm_region_view3d(&C);
178 const ARegion *region = CTX_wm_region(&C);
179
180 this->drawing_weight_data[frame_group].reinitialize(drawings.size());
181
182 threading::parallel_for(drawings.index_range(), 1, [&](const IndexRange range) {
183 for (const int drawing_index : range) {
184 const ed::greasepencil::MutableDrawingInfo &drawing_info = drawings[drawing_index];
185 bke::CurvesGeometry &curves = drawing_info.drawing.strokes_for_write();
186
187 /* Find or create the active vertex group in the drawing. */
188 DrawingWeightData &drawing_weight_data =
189 this->drawing_weight_data[frame_group][drawing_index];
190 drawing_weight_data.active_vertex_group = bke::greasepencil::ensure_vertex_group(
191 this->object_defgroup->name, curves.vertex_group_names);
192
193 drawing_weight_data.multi_frame_falloff = drawing_info.multi_frame_falloff;
194 drawing_weight_data.deform_verts = curves.deform_verts_for_write();
195 drawing_weight_data.deform_weights = bke::varray_for_mutable_deform_verts(
196 drawing_weight_data.deform_verts, drawing_weight_data.active_vertex_group);
197
198 /* Create boolean arrays indicating whether a vertex group is locked/bone deformed
199 * or not. */
200 if (this->auto_normalize) {
201 LISTBASE_FOREACH (bDeformGroup *, dg, &curves.vertex_group_names) {
202 drawing_weight_data.locked_vgroups.append(
203 this->object_locked_defgroups.contains(dg->name));
204 drawing_weight_data.bone_deformed_vgroups.append(
205 this->object_bone_deformed_defgroups.contains(dg->name));
206 }
207 }
208
209 /* Convert stroke points to screen space positions. */
210 const bke::greasepencil::Layer &layer = this->grease_pencil->layer(
211 drawing_info.layer_index);
212 const float4x4 layer_to_world = layer.to_world_space(*ob_eval);
213 const float4x4 projection = ED_view3d_ob_project_mat_get_from_obmat(rv3d, layer_to_world);
214
215 bke::crazyspace::GeometryDeformation deformation =
216 bke::crazyspace::get_evaluated_grease_pencil_drawing_deformation(
217 ob_eval, *this->object, drawing_info.layer_index, drawing_info.frame_number);
218 drawing_weight_data.point_positions.reinitialize(deformation.positions.size());
219 threading::parallel_for(curves.points_range(), 1024, [&](const IndexRange point_range) {
220 for (const int point : point_range) {
221 drawing_weight_data.point_positions[point] = ED_view3d_project_float_v2_m4(
222 region, deformation.positions[point], projection);
223 }
224 });
225
226 /* Initialize the flag for stroke points being touched by the brush. */
227 drawing_weight_data.points_touched_by_brush_num = 0;
228 drawing_weight_data.points_touched_by_brush = Array<bool>(deformation.positions.size(),
229 false);
230 }
231 });
232 }
233
234 /* Get mouse position and pressure. */
235 void get_mouse_input_sample(const InputSample &input_sample,
236 const float brush_widen_factor = 1.0f)
237 {
238 this->mouse_position = input_sample.mouse_position;
239 this->brush_radius = this->initial_brush_radius;
240 if (BKE_brush_use_size_pressure(this->brush)) {
241 this->brush_radius *= input_sample.pressure;
242 }
243 this->brush_strength = this->initial_brush_strength;
244 if (BKE_brush_use_alpha_pressure(this->brush)) {
245 this->brush_strength *= input_sample.pressure;
246 }
247 this->brush_radius_wide = this->brush_radius * brush_widen_factor;
248
249 BLI_rctf_init(&this->brush_bbox,
250 this->mouse_position.x - this->brush_radius_wide,
251 this->mouse_position.x + this->brush_radius_wide,
252 this->mouse_position.y - this->brush_radius_wide,
253 this->mouse_position.y + this->brush_radius_wide);
254 }
255
256 /* Add a point to the brush buffer when it is within the brush radius. */
258 DrawingWeightData &drawing_weight,
259 const int point_index)
260 {
261 if (!BLI_rctf_isect_pt_v(&this->brush_bbox, point_position)) {
262 return;
263 }
264 const float dist_point_to_brush_center = math::distance(point_position, this->mouse_position);
265 if (dist_point_to_brush_center > this->brush_radius_wide) {
266 return;
267 }
268
269 /* Point is touched by the (wide) brush, set flag for that. */
270 if (!drawing_weight.points_touched_by_brush[point_index]) {
271 drawing_weight.points_touched_by_brush_num++;
272 }
273 drawing_weight.points_touched_by_brush[point_index] = true;
274
275 if (dist_point_to_brush_center > this->brush_radius) {
276 return;
277 }
278
279 /* When the point is under the brush, add it to the brush buffer. */
280 const float influence = drawing_weight.multi_frame_falloff * this->brush_strength *
282 this->brush, dist_point_to_brush_center, this->brush_radius);
283 if (influence != 0.0f) {
284 drawing_weight.points_in_brush.append({influence, point_index});
285 }
286 }
287
288 /* Create KDTree for all stroke points touched by the brush during a weight paint operation. */
290 {
291 /* Get number of stroke points touched by the brush. */
292 int point_num = 0;
293 for (const DrawingWeightData &drawing_weight : drawing_weights) {
294 point_num += drawing_weight.points_touched_by_brush_num;
295 }
296
297 /* Create KDTree of stroke points touched by the brush. */
298 KDTree_2d *touched_points = BLI_kdtree_2d_new(point_num);
299 Array<float> touched_points_weights(point_num);
300 int kdtree_index = 0;
301 for (const DrawingWeightData &drawing_weight : drawing_weights) {
302 for (const int point_index : drawing_weight.point_positions.index_range()) {
303 if (drawing_weight.points_touched_by_brush[point_index]) {
304 BLI_kdtree_2d_insert(
305 touched_points, kdtree_index, drawing_weight.point_positions[point_index]);
306 touched_points_weights[kdtree_index] = drawing_weight.deform_weights[point_index];
307 kdtree_index++;
308 }
309 }
310 }
311 BLI_kdtree_2d_balance(touched_points);
312
313 return {touched_points, touched_points_weights};
314 }
315};
316
317} // namespace blender::ed::sculpt_paint::greasepencil
bool BKE_brush_use_alpha_pressure(const Brush *brush)
Definition brush.cc:1096
float BKE_brush_weight_get(const Scene *scene, const Brush *brush)
Definition brush.cc:1160
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
bool BKE_brush_use_size_pressure(const Brush *brush)
Definition brush.cc:1091
float BKE_brush_alpha_get(const Scene *scene, const Brush *brush)
Definition brush.cc:1153
void BKE_curvemapping_init(CurveMapping *cumap)
Depsgraph * CTX_data_depsgraph_pointer(const bContext *C)
Object * CTX_data_active_object(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
ToolSettings * CTX_data_tool_settings(const bContext *C)
RegionView3D * CTX_wm_region_view3d(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
Low-level operations for curves.
support for deformation groups and hooks.
int BKE_object_defgroup_active_index_get(const Object *ob)
Definition deform.cc:601
const ListBase * BKE_object_defgroup_list(const Object *ob)
Definition deform.cc:579
Utility functions for vertex groups in grease pencil objects.
Object * BKE_modifiers_is_deformed_by_armature(Object *ob)
Functions for dealing with objects and deform verts, used by painting and tools.
struct bDeformGroup * BKE_object_defgroup_add(struct Object *ob)
Paint * BKE_paint_get_active_from_context(const bContext *C)
Definition paint.cc:477
Brush * BKE_paint_brush(Paint *paint)
Definition paint.cc:649
A KD-tree for nearest neighbor search.
#define LISTBASE_FOREACH(type, var, list)
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
bool BLI_rctf_isect_pt_v(const struct rctf *rect, const float xy[2])
void BLI_rctf_init(struct rctf *rect, float xmin, float xmax, float ymin, float ymax)
Definition rct.c:408
Object * DEG_get_evaluated_object(const Depsgraph *depsgraph, Object *object)
@ DG_LOCK_WEIGHT
void reinitialize(const int64_t new_size)
Definition BLI_array.hh:388
bool add(const Key &key)
Definition BLI_set.hh:248
constexpr int64_t size() const
Definition BLI_span.hh:253
constexpr IndexRange index_range() const
Definition BLI_span.hh:402
void set(const int64_t index, T value)
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 add_point_under_brush_to_brush_buffer(const float2 point_position, DrawingWeightData &drawing_weight, const int point_index)
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)
const Depsgraph * depsgraph
Set< std::string > get_bone_deformed_vertex_group_names(const Object &object)
float brush_radius(const Scene &scene, const Brush &brush, float pressure)
T clamp(const T &a, const T &min, const T &max)
T distance(const T &a, const T &b)
T interpolate(const T &a, const T &b, const FactorT &t)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
Definition BLI_task.hh:95
BrushStrokeMode
static float brush_strength(const Sculpt &sd, const blender::ed::sculpt_paint::StrokeCache &cache, const float feather, const UnifiedPaintSettings &ups, const PaintModeSettings &)
Definition sculpt.cc:2067
struct CurveMapping * curve