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);
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. */
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;
241 this->brush_radius *= input_sample.pressure;
242 }
245 this->brush_strength *= input_sample.pressure;
246 }
247 this->brush_radius_wide = this->brush_radius * brush_widen_factor;
248
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
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
BPy_StructRNA * depsgraph
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)
Set< std::string > get_bone_deformed_vertex_group_names(const Object &object)
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
VecBase< float, 2 > float2
BrushStrokeMode