Blender V4.3
MOD_grease_pencil_hook.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2005 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include "BLI_index_mask.hh"
10#include "BLI_math_rotation.hh"
11#include "BLI_string.h" /* For #STRNCPY. */
12
13#include "BLT_translation.hh"
14
15#include "BLO_read_write.hh"
16
17#include "DNA_defaults.h"
18#include "DNA_modifier_types.h"
19#include "DNA_screen_types.h"
20
21#include "RNA_access.hh"
22
23#include "BKE_action.hh"
24#include "BKE_colortools.hh"
25#include "BKE_curves.hh"
26#include "BKE_geometry_set.hh"
27#include "BKE_grease_pencil.hh"
28#include "BKE_lib_query.hh"
29#include "BKE_modifier.hh"
30#include "BKE_object_types.hh"
31
32#include "UI_interface.hh"
33#include "UI_resources.hh"
34
36#include "MOD_modifiertypes.hh"
37#include "MOD_ui_common.hh"
38
39#include "RNA_prototypes.hh"
40
41namespace blender {
42
43static void init_data(ModifierData *md)
44{
45 auto *gpmd = reinterpret_cast<GreasePencilHookModifierData *>(md);
46
48
50 modifier::greasepencil::init_influence_data(&gpmd->influence, true);
51}
52
53static void copy_data(const ModifierData *md, ModifierData *target, const int flag)
54{
55 const auto *gmd = reinterpret_cast<const GreasePencilHookModifierData *>(md);
56 auto *tgmd = reinterpret_cast<GreasePencilHookModifierData *>(target);
57
59 modifier::greasepencil::copy_influence_data(&gmd->influence, &tgmd->influence, flag);
60}
61
62static void free_data(ModifierData *md)
63{
64 auto *mmd = reinterpret_cast<GreasePencilHookModifierData *>(md);
65
67}
68
69static bool is_disabled(const Scene * /*scene*/, ModifierData *md, bool /*use_render_params*/)
70{
71 auto *mmd = reinterpret_cast<GreasePencilHookModifierData *>(md);
72
73 return (mmd->object == nullptr);
74}
75
77{
78 auto *mmd = reinterpret_cast<GreasePencilHookModifierData *>(md);
79 if (mmd->object != nullptr) {
80 DEG_add_object_relation(ctx->node, mmd->object, DEG_OB_COMP_TRANSFORM, "Hook Modifier");
81 }
82 DEG_add_object_relation(ctx->node, ctx->object, DEG_OB_COMP_TRANSFORM, "Hook Modifier");
83}
84
85static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
86{
87 auto *mmd = reinterpret_cast<GreasePencilHookModifierData *>(md);
88
89 modifier::greasepencil::foreach_influence_ID_link(&mmd->influence, ob, walk, user_data);
90
91 walk(user_data, ob, (ID **)&mmd->object, IDWALK_CB_NOP);
92}
93
94static void blend_write(BlendWriter *writer, const ID * /*id_owner*/, const ModifierData *md)
95{
96 const auto *mmd = reinterpret_cast<const GreasePencilHookModifierData *>(md);
97
99 modifier::greasepencil::write_influence_data(writer, &mmd->influence);
100}
101
102static void blend_read(BlendDataReader *reader, ModifierData *md)
103{
104 auto *mmd = reinterpret_cast<GreasePencilHookModifierData *>(md);
105 modifier::greasepencil::read_influence_data(reader, &mmd->influence);
106}
107
108/* Calculate the factor of falloff. */
109static float hook_falloff(const float falloff,
110 const int falloff_type,
111 const float falloff_sq,
112 const float fac_orig,
113 const CurveMapping *curfalloff,
114 const float len_sq)
115{
116 BLI_assert(falloff_sq);
117 if (len_sq > falloff_sq) {
118 return 0.0f;
119 }
120 if (len_sq <= 0.0f) {
121 return fac_orig;
122 }
123 if (falloff_type == MOD_GREASE_PENCIL_HOOK_Falloff_Const) {
124 return fac_orig;
125 }
126 else if (falloff_type == MOD_GREASE_PENCIL_HOOK_Falloff_InvSquare) {
127 /* Avoid sqrt below. */
128 return (1.0f - (len_sq / falloff_sq)) * fac_orig;
129 }
130
131 float fac = 1.0f - (math::sqrt(len_sq) / falloff);
132
133 switch (falloff_type) {
135 return BKE_curvemapping_evaluateF(curfalloff, 0, fac) * fac_orig;
137 return fac * fac * fac_orig;
139 return (3.0f * fac * fac - 2.0f * fac * fac * fac) * fac_orig;
141 return math::sqrt(fac) * fac_orig;
142 break;
144 return math::sqrt(2 * fac - fac * fac) * fac_orig;
146 ATTR_FALLTHROUGH; /* Pass. */
147 default:
148 return fac * fac_orig;
149 }
150}
151
152static void deform_drawing(const ModifierData &md,
153 const Object &ob,
155{
156 const auto &mmd = reinterpret_cast<const GreasePencilHookModifierData &>(md);
158 bke::CurvesGeometry &curves = drawing.strokes_for_write();
159
160 if (curves.points_num() == 0) {
161 return;
162 }
163 IndexMaskMemory memory;
165 &ob, curves, mmd.influence, memory);
166 if (strokes.is_empty()) {
167 return;
168 }
169
171 curves, mmd.influence);
172
173 const int falloff_type = mmd.falloff_type;
174 const float falloff = (mmd.falloff_type == eHook_Falloff_None) ? 0.0f : mmd.falloff;
175 const float falloff_sq = square_f(falloff);
176 const float fac_orig = mmd.force;
177 const bool use_falloff = falloff_sq != 0.0f;
178 const bool use_uniform = (mmd.flag & MOD_GREASE_PENCIL_HOOK_UNIFORM_SPACE) != 0;
179
180 const float3x3 mat_uniform = use_uniform ? float3x3(float4x4(mmd.parentinv)) :
182 const float3 cent = use_uniform ? math::transform_point(mat_uniform, float3(mmd.cent)) :
183 float3(mmd.cent);
184
185 float4x4 dmat;
186 /* Get world-space matrix of target, corrected for the space the verts are in. */
187 if (mmd.subtarget[0]) {
188 bPoseChannel *pchan = BKE_pose_channel_find_name(mmd.object->pose, mmd.subtarget);
189 if (pchan) {
190 /* Bone target if there's a matching pose-channel. */
191 dmat = mmd.object->object_to_world() * float4x4(pchan->pose_mat);
192 }
193 }
194 else {
195 /* Just object target. */
196 dmat = mmd.object->object_to_world();
197 }
198 float4x4 use_mat = ob.world_to_object() * dmat * float4x4(mmd.parentinv);
199
200 auto get_weight = [&](const int point) {
201 const float weight = input_weights[point];
202 if (mmd.influence.flag & GREASE_PENCIL_INFLUENCE_INVERT_VERTEX_GROUP) {
203 return 1.0f - weight;
204 }
205 return weight;
206 };
207
208 const OffsetIndices<int> points_by_curve = curves.points_by_curve();
209 MutableSpan<float3> positions = curves.positions_for_write();
210
211 strokes.foreach_index(blender::GrainSize(128), [&](const int stroke) {
212 const IndexRange points_range = points_by_curve[stroke].index_range();
213 for (const int point_i : points_range) {
214 const int point = point_i + points_by_curve[stroke].first();
215 const float weight = get_weight(point);
216 if (weight < 0.0f) {
217 continue;
218 }
219
220 float fac;
221 if (use_falloff) {
222 float len_sq;
223 if (use_uniform) {
224 const float3 co_uniform = math::transform_point(mat_uniform, positions[point]);
225 len_sq = math::distance(cent, co_uniform);
226 }
227 else {
228 len_sq = math::distance(cent, positions[point]);
229 }
230 fac = hook_falloff(
231 falloff, falloff_type, falloff_sq, fac_orig, mmd.influence.custom_curve, len_sq);
232 }
233 else {
234 fac = fac_orig;
235 }
236
237 if (fac != 0.0f) {
238 const float3 co_tmp = math::transform_point(use_mat, positions[point]);
239 positions[point] = math::interpolate(positions[point], co_tmp, fac * weight);
240 }
241 }
242 });
243
244 drawing.tag_positions_changed();
245}
246
248 const ModifierEvalContext *ctx,
249 bke::GeometrySet *geometry_set)
250{
251 const GreasePencilHookModifierData *mmd = reinterpret_cast<GreasePencilHookModifierData *>(md);
252
253 if (!geometry_set->has_grease_pencil()) {
254 return;
255 }
256
257 GreasePencil &grease_pencil = *geometry_set->get_grease_pencil_for_write();
258
259 const int current_frame = grease_pencil.runtime->eval_frame;
260
261 IndexMaskMemory mask_memory;
263 grease_pencil, mmd->influence, mask_memory);
265 modifier::greasepencil::get_drawings_for_write(grease_pencil, layer_mask, current_frame);
266
268 deform_drawing(*md, *ctx->object, *drawing);
269 });
270}
271
272static void panel_draw(const bContext *C, Panel *panel)
273{
274 uiLayout *layout = panel->layout;
275
276 PointerRNA ob_ptr;
278
279 PointerRNA hook_object_ptr = RNA_pointer_get(ptr, "object");
280
281 uiLayoutSetPropSep(layout, true);
282
283 uiLayout *col = uiLayoutColumn(layout, false);
284 uiItemR(col, ptr, "object", UI_ITEM_NONE, nullptr, ICON_NONE);
285 if (!RNA_pointer_is_null(&hook_object_ptr) &&
286 RNA_enum_get(&hook_object_ptr, "type") == OB_ARMATURE)
287 {
288 PointerRNA hook_object_data_ptr = RNA_pointer_get(&hook_object_ptr, "data");
290 col, ptr, "subtarget", &hook_object_data_ptr, "bones", IFACE_("Bone"), ICON_NONE);
291 }
292
293 uiItemR(layout, ptr, "strength", UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
294
295 if (uiLayout *sub = uiLayoutPanelProp(C, layout, ptr, "open_falloff_panel", IFACE_("Falloff"))) {
296 uiLayoutSetPropSep(sub, true);
297
298 uiItemR(sub, ptr, "falloff_type", UI_ITEM_NONE, IFACE_("Type"), ICON_NONE);
299
300 bool use_falloff = RNA_enum_get(ptr, "falloff_type") != eWarp_Falloff_None;
301
302 uiLayout *row = uiLayoutRow(sub, false);
303 uiLayoutSetActive(row, use_falloff);
304 uiItemR(row, ptr, "falloff_radius", UI_ITEM_NONE, nullptr, ICON_NONE);
305
306 uiItemR(sub, ptr, "use_falloff_uniform", UI_ITEM_NONE, nullptr, ICON_NONE);
307
308 if (RNA_enum_get(ptr, "falloff_type") == eWarp_Falloff_Curve) {
309 uiTemplateCurveMapping(sub, ptr, "custom_curve", 0, false, false, false, false);
310 }
311 }
312
313 if (uiLayout *influence_panel = uiLayoutPanelProp(
314 C, layout, ptr, "open_influence_panel", IFACE_("Influence")))
315 {
319 }
320
321 modifier_panel_end(layout, ptr);
322}
323
328
329} // namespace blender
330
332 /*idname*/ "GreasePencilHookModifier",
333 /*name*/ N_("Hook"),
334 /*struct_name*/ "GreasePencilHookModifierData",
335 /*struct_size*/ sizeof(GreasePencilHookModifierData),
336 /*srna*/ &RNA_GreasePencilHookModifier,
338 /*flags*/
341 /*icon*/ ICON_HOOK,
342
343 /*copy_data*/ blender::copy_data,
344
345 /*deform_verts*/ nullptr,
346 /*deform_matrices*/ nullptr,
347 /*deform_verts_EM*/ nullptr,
348 /*deform_matrices_EM*/ nullptr,
349 /*modify_mesh*/ nullptr,
350 /*modify_geometry_set*/ blender::modify_geometry_set,
351
352 /*init_data*/ blender::init_data,
353 /*required_data_mask*/ nullptr,
354 /*free_data*/ blender::free_data,
355 /*is_disabled*/ blender::is_disabled,
356 /*update_depsgraph*/ blender::update_depsgraph,
357 /*depends_on_time*/ nullptr,
358 /*depends_on_normals*/ nullptr,
359 /*foreach_ID_link*/ blender::foreach_ID_link,
360 /*foreach_tex_link*/ nullptr,
361 /*free_runtime_data*/ nullptr,
362 /*panel_register*/ blender::panel_register,
363 /*blend_write*/ blender::blend_write,
364 /*blend_read*/ blender::blend_read,
365};
Blender kernel action and pose functionality.
bPoseChannel * BKE_pose_channel_find_name(const bPose *pose, const char *name)
float BKE_curvemapping_evaluateF(const CurveMapping *cumap, int cur, float value)
Low-level operations for curves.
Low-level operations for grease pencil.
@ IDWALK_CB_NOP
void BKE_modifier_copydata_generic(const ModifierData *md, ModifierData *md_dst, int flag)
@ eModifierTypeFlag_SupportsMapping
@ eModifierTypeFlag_AcceptsGreasePencil
@ eModifierTypeFlag_EnableInEditmode
@ eModifierTypeFlag_SupportsEditmode
void(*)(void *user_data, Object *ob, ID **idpoin, int cb_flag) IDWalkFunc
#define BLI_assert(a)
Definition BLI_assert.h:50
#define ATTR_FALLTHROUGH
MINLINE float square_f(float a)
#define MEMCMP_STRUCT_AFTER_IS_ZERO(struct_var, member)
#define MEMCPY_STRUCT_AFTER(struct_dst, struct_src, member)
#define BLO_write_struct(writer, struct_name, data_ptr)
#define IFACE_(msgid)
void DEG_add_object_relation(DepsNodeHandle *node_handle, Object *object, eDepsObjectComponentType component, const char *description)
@ DEG_OB_COMP_TRANSFORM
#define DNA_struct_default_get(struct_name)
@ eWarp_Falloff_Curve
@ eWarp_Falloff_None
@ GREASE_PENCIL_INFLUENCE_INVERT_VERTEX_GROUP
@ MOD_GREASE_PENCIL_HOOK_UNIFORM_SPACE
@ eModifierType_GreasePencilHook
@ MOD_GREASE_PENCIL_HOOK_Falloff_Root
@ MOD_GREASE_PENCIL_HOOK_Falloff_InvSquare
@ MOD_GREASE_PENCIL_HOOK_Falloff_Const
@ MOD_GREASE_PENCIL_HOOK_Falloff_Linear
@ MOD_GREASE_PENCIL_HOOK_Falloff_Sphere
@ MOD_GREASE_PENCIL_HOOK_Falloff_Smooth
@ MOD_GREASE_PENCIL_HOOK_Falloff_Curve
@ MOD_GREASE_PENCIL_HOOK_Falloff_Sharp
struct GreasePencilHookModifierData GreasePencilHookModifierData
@ eHook_Falloff_None
@ OB_ARMATURE
static bool is_disabled
ModifierTypeInfo modifierType_GreasePencilHook
void modifier_panel_end(uiLayout *layout, PointerRNA *ptr)
PanelType * modifier_panel_register(ARegionType *region_type, ModifierType type, PanelDrawFn draw)
PointerRNA * modifier_panel_get_property_pointers(Panel *panel, PointerRNA *r_ob_ptr)
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
void uiLayoutSetActive(uiLayout *layout, bool active)
void uiTemplateCurveMapping(uiLayout *layout, PointerRNA *ptr, const char *propname, int type, bool levels, bool brush, bool neg_slope, bool tone)
uiLayout * uiLayoutRow(uiLayout *layout, bool align)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
#define UI_ITEM_NONE
void uiItemPointerR(uiLayout *layout, PointerRNA *ptr, const char *propname, PointerRNA *searchptr, const char *searchpropname, const char *name, int icon)
PanelLayout uiLayoutPanelProp(const bContext *C, uiLayout *layout, PointerRNA *open_prop_owner, const char *open_prop_name)
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, eUI_Item_Flag flag, const char *name, int icon)
@ UI_ITEM_R_SLIDER
bke::CurvesGeometry & strokes_for_write()
void foreach_index(Fn &&fn) const
uint col
T sqrt(const T &a)
T distance(const T &a, const T &b)
T interpolate(const T &a, const T &b, const FactorT &t)
VecBase< T, 3 > transform_point(const CartesianBasis &basis, const VecBase< T, 3 > &v)
void read_influence_data(BlendDataReader *reader, GreasePencilModifierInfluenceData *influence_data)
void init_influence_data(GreasePencilModifierInfluenceData *influence_data, const bool has_custom_curve)
static IndexMask get_filtered_layer_mask(const GreasePencil &grease_pencil, const std::optional< StringRef > layer_name_filter, const std::optional< int > layer_pass_filter, const bool layer_filter_invert, const bool layer_pass_filter_invert, IndexMaskMemory &memory)
static IndexMask get_filtered_stroke_mask(const Object *ob, const bke::CurvesGeometry &curves, const Material *material_filter, const std::optional< int > material_pass_filter, const bool material_filter_invert, const bool material_pass_filter_invert, IndexMaskMemory &memory)
void write_influence_data(BlendWriter *writer, const GreasePencilModifierInfluenceData *influence_data)
void draw_vertex_group_settings(const bContext *, uiLayout *layout, PointerRNA *ptr)
VArray< float > get_influence_vertex_weights(const bke::CurvesGeometry &curves, const GreasePencilModifierInfluenceData &influence_data)
Vector< bke::greasepencil::Drawing * > get_drawings_for_write(GreasePencil &grease_pencil, const IndexMask &layer_mask, const int frame)
void draw_material_filter_settings(const bContext *, uiLayout *layout, PointerRNA *ptr)
void draw_layer_filter_settings(const bContext *, uiLayout *layout, PointerRNA *ptr)
void free_influence_data(GreasePencilModifierInfluenceData *influence_data)
void foreach_influence_ID_link(GreasePencilModifierInfluenceData *influence_data, Object *ob, IDWalkFunc walk, void *user_data)
void copy_influence_data(const GreasePencilModifierInfluenceData *influence_data_src, GreasePencilModifierInfluenceData *influence_data_dst, const int)
void ensure_no_bezier_curves(Drawing &drawing)
void parallel_for_each(Range &&range, const Function &function)
Definition BLI_task.hh:58
static void copy_data(const ModifierData *md, ModifierData *target, const int flag)
static void blend_write(BlendWriter *writer, const ID *, const ModifierData *md)
static void init_data(ModifierData *md)
static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
static void panel_draw(const bContext *C, Panel *panel)
MatBase< float, 4, 4 > float4x4
static void modify_geometry_set(ModifierData *md, const ModifierEvalContext *ctx, bke::GeometrySet *geometry_set)
static void deform_drawing(const ModifierData &md, const Object &ob, bke::greasepencil::Drawing &drawing)
static void free_data(ModifierData *md)
static void panel_register(ARegionType *region_type)
MatBase< float, 3, 3 > float3x3
static float hook_falloff(const float falloff, const int falloff_type, const float falloff_sq, const float fac_orig, const CurveMapping *curfalloff, const float len_sq)
static void update_depsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
VecBase< float, 3 > float3
static bool is_disabled(const Scene *, ModifierData *md, bool)
static void blend_read(BlendDataReader *reader, ModifierData *md)
PointerRNA RNA_pointer_get(PointerRNA *ptr, const char *name)
bool RNA_pointer_is_null(const PointerRNA *ptr)
int RNA_enum_get(PointerRNA *ptr, const char *name)
GreasePencilModifierInfluenceData influence
GreasePencilRuntimeHandle * runtime
Definition DNA_ID.h:413
struct uiLayout * layout
float pose_mat[4][4]
GreasePencil * get_grease_pencil_for_write()
#define N_(msgid)
PointerRNA * ptr
Definition wm_files.cc:4126
uint8_t flag
Definition wm_window.cc:138