Blender V5.0
MOD_grease_pencil_shrinkwrap.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
8
9#include "BKE_attribute.hh"
10#include "BKE_material.hh"
11
12#include "DNA_defaults.h"
13#include "DNA_meshdata_types.h"
14#include "DNA_modifier_types.h"
15#include "DNA_scene_types.h"
16
17#include "BKE_curves.hh"
18#include "BKE_deform.hh"
19#include "BKE_geometry_set.hh"
20#include "BKE_grease_pencil.hh"
21#include "BKE_instances.hh"
22#include "BKE_lib_query.hh"
23#include "BKE_modifier.hh"
24#include "BKE_screen.hh"
25#include "BKE_shrinkwrap.hh"
26
27#include "BLO_read_write.hh"
28
30
31#include "GEO_smooth_curves.hh"
32
34#include "UI_resources.hh"
35
36#include "BLT_translation.hh"
37
38#include "WM_api.hh"
39#include "WM_types.hh"
40
41#include "RNA_access.hh"
42#include "RNA_prototypes.hh"
43
45#include "MOD_ui_common.hh"
46
47namespace blender {
48
58
59static void copy_data(const ModifierData *md, ModifierData *target, const int flag)
60{
61 const auto *smd = reinterpret_cast<const GreasePencilShrinkwrapModifierData *>(md);
62 auto *tsmd = reinterpret_cast<GreasePencilShrinkwrapModifierData *>(target);
63
65
67 modifier::greasepencil::copy_influence_data(&smd->influence, &tsmd->influence, flag);
68}
69
70static void free_data(ModifierData *md)
71{
72 auto *smd = reinterpret_cast<GreasePencilShrinkwrapModifierData *>(md);
74
75 if (smd->cache_data) {
76 BKE_shrinkwrap_free_tree(smd->cache_data);
77 MEM_delete(smd->cache_data);
78 }
79}
80
81static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
82{
83 auto *smd = reinterpret_cast<GreasePencilShrinkwrapModifierData *>(md);
84 modifier::greasepencil::foreach_influence_ID_link(&smd->influence, ob, walk, user_data);
85 walk(user_data, ob, (ID **)&smd->target, IDWALK_CB_NOP);
86 walk(user_data, ob, (ID **)&smd->aux_target, IDWALK_CB_NOP);
87}
88
89static bool is_disabled(const Scene * /*scene*/, ModifierData *md, bool /*use_render_params*/)
90{
91 auto *smd = reinterpret_cast<GreasePencilShrinkwrapModifierData *>(md);
92
93 /* The object type check is only needed here in case we have a placeholder
94 * object assigned (because the library containing the mesh is missing).
95 *
96 * In other cases it should be impossible to have a type mismatch.
97 */
98 if (smd->target == nullptr || smd->target->type != OB_MESH) {
99 return true;
100 }
101 if (smd->aux_target != nullptr && smd->aux_target->type != OB_MESH) {
102 return true;
103 }
104 return false;
105}
106
108{
109 auto *smd = reinterpret_cast<GreasePencilShrinkwrapModifierData *>(md);
110
111 if (smd->target != nullptr) {
113 ctx->node, smd->target, DEG_OB_COMP_TRANSFORM, "Grease Pencil Shrinkwrap Modifier");
115 ctx->node, smd->target, DEG_OB_COMP_GEOMETRY, "Grease Pencil Shrinkwrap Modifier");
116 if (smd->shrink_type == MOD_SHRINKWRAP_TARGET_PROJECT) {
118 }
119 }
120 if (smd->aux_target != nullptr) {
122 ctx->node, smd->aux_target, DEG_OB_COMP_TRANSFORM, "Grease Pencil Shrinkwrap Modifier");
124 ctx->node, smd->aux_target, DEG_OB_COMP_GEOMETRY, "Grease Pencil Shrinkwrap Modifier");
125 if (smd->shrink_type == MOD_SHRINKWRAP_TARGET_PROJECT) {
127 ctx->node, &smd->aux_target->id, DAG_EVAL_NEED_SHRINKWRAP_BOUNDARY);
128 }
129 }
130 DEG_add_depends_on_transform_relation(ctx->node, "Grease Pencil Shrinkwrap Modifier");
131}
132
134 const ModifierEvalContext &ctx,
136{
138 bke::CurvesGeometry &curves = drawing.strokes_for_write();
139 const OffsetIndices<int> points_by_curve = curves.points_by_curve();
140 const Span<MDeformVert> dverts = curves.deform_verts();
141 const MutableSpan<float3> positions = curves.positions_for_write();
142 const int defgrp_idx = BKE_object_defgroup_name_index(ctx.object,
144
145 /* Selected source curves. */
146 IndexMaskMemory curve_mask_memory;
148 ctx.object, drawing.strokes(), smd.influence, curve_mask_memory);
149
151 params.target = smd.target;
152 params.aux_target = smd.aux_target;
154 params.keep_distance = smd.keep_dist;
155 params.shrink_type = smd.shrink_type;
156 params.shrink_options = smd.shrink_opts;
157 params.shrink_mode = smd.shrink_mode;
158 params.projection_limit = smd.proj_limit;
159 params.projection_axis = smd.proj_axis;
160 params.subsurf_levels = smd.subsurf_levels;
161
162 curves_mask.foreach_index([&](const int curve_i) {
163 const IndexRange points = points_by_curve[curve_i];
164 const Span<MDeformVert> curve_dverts = dverts.is_empty() ? dverts : dverts.slice(points);
165 const MutableSpan<float3> curve_positions = positions.slice(points);
166
168 params, *ctx.object, *smd.cache_data, curve_dverts, defgrp_idx, curve_positions);
169 });
170
171 /* Optional smoothing after shrinkwrap. */
172 const VArray<bool> point_selection = VArray<bool>::from_single(true, curves.points_num());
173 const bool smooth_ends = false;
174 const bool keep_shape = true;
176 points_by_curve,
177 point_selection,
178 curves.cyclic(),
179 smd.smooth_step,
180 smd.smooth_factor,
181 smooth_ends,
182 keep_shape,
183 positions);
184
185 drawing.tag_positions_changed();
186}
187
189 const ModifierEvalContext &ctx)
190{
191 if (smd.cache_data) {
193 MEM_delete(smd.cache_data);
194 smd.cache_data = nullptr;
195 }
196 Object *target_ob = DEG_get_evaluated(ctx.depsgraph, smd.target);
198
199 smd.cache_data = MEM_new<ShrinkwrapTreeData>(__func__);
200 const bool tree_ok = BKE_shrinkwrap_init_tree(
201 smd.cache_data, target_mesh, smd.shrink_type, smd.shrink_mode, false);
202 if (!tree_ok) {
203 MEM_delete(smd.cache_data);
204 smd.cache_data = nullptr;
205 }
206}
207
209 const ModifierEvalContext *ctx,
210 bke::GeometrySet *geometry_set)
211{
215
216 auto &smd = *reinterpret_cast<GreasePencilShrinkwrapModifierData *>(md);
217 BLI_assert(smd.target != nullptr);
218 if (smd.target == ctx->object || smd.aux_target == ctx->object) {
219 return;
220 }
221 if (!geometry_set->has_grease_pencil()) {
222 return;
223 }
224 GreasePencil &grease_pencil = *geometry_set->get_grease_pencil_for_write();
225 const int frame = grease_pencil.runtime->eval_frame;
226
228 if (!smd.cache_data) {
229 return;
230 }
231
232 IndexMaskMemory mask_memory;
234 grease_pencil, smd.influence, mask_memory);
235
237 grease_pencil, layer_mask, frame);
239 [&](Drawing *drawing) { modify_drawing(smd, *ctx, *drawing); });
240}
241
242static void panel_draw(const bContext *C, Panel *panel)
243{
245
246 uiLayout *layout = panel->layout;
247
248 PointerRNA ob_ptr;
250 int wrap_method = RNA_enum_get(ptr, "wrap_method");
251 uiLayout *col, *row;
252
253 layout->use_property_split_set(true);
254
255 layout->prop(ptr, "wrap_method", UI_ITEM_NONE, std::nullopt, ICON_NONE);
256
257 if (ELEM(wrap_method,
261 {
262 layout->prop(ptr, "wrap_mode", UI_ITEM_NONE, std::nullopt, ICON_NONE);
263 }
264
265 if (wrap_method == MOD_SHRINKWRAP_PROJECT) {
266 layout->prop(ptr, "project_limit", UI_ITEM_NONE, IFACE_("Limit"), ICON_NONE);
267 layout->prop(ptr, "subsurf_levels", UI_ITEM_NONE, std::nullopt, ICON_NONE);
268
269 col = &layout->column(false);
270 row = &col->row(true, IFACE_("Axis"));
271 row->prop(ptr, "use_project_x", toggles_flag, std::nullopt, ICON_NONE);
272 row->prop(ptr, "use_project_y", toggles_flag, std::nullopt, ICON_NONE);
273 row->prop(ptr, "use_project_z", toggles_flag, std::nullopt, ICON_NONE);
274
275 col->prop(ptr, "use_negative_direction", UI_ITEM_NONE, std::nullopt, ICON_NONE);
276 col->prop(ptr, "use_positive_direction", UI_ITEM_NONE, std::nullopt, ICON_NONE);
277
278 layout->prop(ptr, "cull_face", UI_ITEM_R_EXPAND, std::nullopt, ICON_NONE);
279 col = &layout->column(false);
280 col->active_set(RNA_boolean_get(ptr, "use_negative_direction") &&
281 RNA_enum_get(ptr, "cull_face") != 0);
282 col->prop(ptr, "use_invert_cull", UI_ITEM_NONE, std::nullopt, ICON_NONE);
283 }
284
285 layout->prop(ptr, "target", UI_ITEM_NONE, std::nullopt, ICON_NONE);
286 if (wrap_method == MOD_SHRINKWRAP_PROJECT) {
287 layout->prop(ptr, "auxiliary_target", UI_ITEM_NONE, std::nullopt, ICON_NONE);
288 }
289 layout->prop(ptr, "offset", UI_ITEM_NONE, std::nullopt, ICON_NONE);
290
291 layout->use_property_split_set(true);
292
293 layout->prop(ptr, "smooth_factor", UI_ITEM_NONE, std::nullopt, ICON_NONE);
294 layout->prop(ptr, "smooth_step", UI_ITEM_NONE, IFACE_("Repeat"), ICON_NONE);
295
296 if (uiLayout *influence_panel = layout->panel_prop(
297 C, ptr, "open_influence_panel", IFACE_("Influence")))
298 {
302 }
303
305}
306
311
312static void blend_write(BlendWriter *writer, const ID * /*id_owner*/, const ModifierData *md)
313{
314 const auto *smd = reinterpret_cast<const GreasePencilShrinkwrapModifierData *>(md);
315
317 modifier::greasepencil::write_influence_data(writer, &smd->influence);
318}
319
320static void blend_read(BlendDataReader *reader, ModifierData *md)
321{
322 auto *smd = reinterpret_cast<GreasePencilShrinkwrapModifierData *>(md);
323
324 modifier::greasepencil::read_influence_data(reader, &smd->influence);
325}
326
327} // namespace blender
328
330 /*idname*/ "GreasePencilShrinkwrap",
331 /*name*/ N_("Shrinkwrap"),
332 /*struct_name*/ "GreasePencilShrinkwrapModifierData",
333 /*struct_size*/ sizeof(GreasePencilShrinkwrapModifierData),
334 /*srna*/ &RNA_GreasePencilShrinkwrapModifier,
338 /*icon*/ ICON_MOD_SHRINKWRAP,
339
340 /*copy_data*/ blender::copy_data,
341
342 /*deform_verts*/ nullptr,
343 /*deform_matrices*/ nullptr,
344 /*deform_verts_EM*/ nullptr,
345 /*deform_matrices_EM*/ nullptr,
346 /*modify_mesh*/ nullptr,
347 /*modify_geometry_set*/ blender::modify_geometry_set,
348
349 /*init_data*/ blender::init_data,
350 /*required_data_mask*/ nullptr,
351 /*free_data*/ blender::free_data,
352 /*is_disabled*/ blender::is_disabled,
353 /*update_depsgraph*/ blender::update_depsgraph,
354 /*depends_on_time*/ nullptr,
355 /*depends_on_normals*/ nullptr,
356 /*foreach_ID_link*/ blender::foreach_ID_link,
357 /*foreach_tex_link*/ nullptr,
358 /*free_runtime_data*/ nullptr,
359 /*panel_register*/ blender::panel_register,
360 /*blend_write*/ blender::blend_write,
361 /*blend_read*/ blender::blend_read,
362};
Low-level operations for curves.
support for deformation groups and hooks.
int BKE_object_defgroup_name_index(const Object *ob, blender::StringRef name)
Definition deform.cc:591
Low-level operations for grease pencil.
@ IDWALK_CB_NOP
General operations, lookup, etc. for materials.
void(*)(void *user_data, Object *ob, ID **idpoin, LibraryForeachIDCallbackFlag cb_flag) IDWalkFunc
Mesh * BKE_modifier_get_evaluated_mesh_from_evaluated_object(Object *ob_eval)
void BKE_modifier_copydata_generic(const ModifierData *md, ModifierData *md_dst, int flag)
@ eModifierTypeFlag_SupportsMapping
@ eModifierTypeFlag_AcceptsGreasePencil
@ eModifierTypeFlag_EnableInEditmode
@ eModifierTypeFlag_SupportsEditmode
void BKE_shrinkwrap_free_tree(ShrinkwrapTreeData *data)
void shrinkwrapParams_deform(const ShrinkwrapParams &params, Object &object, ShrinkwrapTreeData &tree, blender::Span< MDeformVert > dvert, int defgrp_index, blender::MutableSpan< blender::float3 > positions)
bool BKE_shrinkwrap_init_tree(ShrinkwrapTreeData *data, Mesh *mesh, int shrinkType, int shrinkMode, bool force_normals)
Definition shrinkwrap.cc:96
#define BLI_assert(a)
Definition BLI_assert.h:46
#define ELEM(...)
#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)
@ DAG_EVAL_NEED_SHRINKWRAP_BOUNDARY
void DEG_add_depends_on_transform_relation(DepsNodeHandle *node_handle, const char *description)
void DEG_add_object_relation(DepsNodeHandle *node_handle, Object *object, eDepsObjectComponentType component, const char *description)
void DEG_add_special_eval_flag(DepsNodeHandle *handle, ID *id, uint32_t flag)
@ DEG_OB_COMP_GEOMETRY
@ DEG_OB_COMP_TRANSFORM
T * DEG_get_evaluated(const Depsgraph *depsgraph, T *id)
#define DNA_struct_default_get(struct_name)
@ MOD_SHRINKWRAP_TARGET_PROJECT
@ MOD_SHRINKWRAP_PROJECT
@ MOD_SHRINKWRAP_NEAREST_SURFACE
@ GREASE_PENCIL_INFLUENCE_INVERT_VERTEX_GROUP
@ eModifierType_GreasePencilShrinkwrap
@ OB_MESH
static bool is_disabled
ModifierTypeInfo modifierType_GreasePencilShrinkwrap
PanelType * modifier_panel_register(ARegionType *region_type, ModifierType type, PanelDrawFn draw)
PointerRNA * modifier_panel_get_property_pointers(Panel *panel, PointerRNA *r_ob_ptr)
void modifier_error_message_draw(uiLayout *layout, PointerRNA *ptr)
#define C
Definition RandGen.cpp:29
@ UI_ITEM_R_TOGGLE
@ UI_ITEM_R_FORCE_BLANK_DECORATE
@ UI_ITEM_R_EXPAND
#define UI_ITEM_NONE
constexpr MutableSpan slice(const int64_t start, const int64_t size) const
Definition BLI_span.hh:573
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:137
constexpr bool is_empty() const
Definition BLI_span.hh:260
static VArray from_single(T value, const int64_t size)
MutableSpan< float3 > positions_for_write()
OffsetIndices< int > points_by_curve() const
Span< MDeformVert > deform_verts() const
VArray< bool > cyclic() const
bke::CurvesGeometry & strokes_for_write()
const bke::CurvesGeometry & strokes() const
void foreach_index(Fn &&fn) const
uint col
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void smooth_curve_attribute(const IndexMask &curves_to_smooth, const OffsetIndices< int > points_by_curve, const VArray< bool > &point_selection, const VArray< bool > &cyclic, int iterations, float influence, bool smooth_ends, bool keep_shape, GMutableSpan attribute_data)
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_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)
static IndexMask get_filtered_layer_mask(const GreasePencil &grease_pencil, const std::optional< StringRef > tree_node_name_filter, const std::optional< int > layer_pass_filter, const bool layer_filter_invert, const bool layer_pass_filter_invert, IndexMaskMemory &memory)
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:56
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)
static void modify_geometry_set(ModifierData *md, const ModifierEvalContext *ctx, bke::GeometrySet *geometry_set)
static void free_data(ModifierData *md)
static void panel_register(ARegionType *region_type)
static void modify_drawing(const GreasePencilArrayModifierData &mmd, const ModifierEvalContext &ctx, bke::greasepencil::Drawing &drawing)
static void update_depsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
static void ensure_shrinkwrap_cache_data(GreasePencilShrinkwrapModifierData &smd, const ModifierEvalContext &ctx)
static bool is_disabled(const Scene *, ModifierData *md, bool)
static void blend_read(BlendDataReader *reader, ModifierData *md)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
int RNA_enum_get(PointerRNA *ptr, const char *name)
struct ShrinkwrapTreeData * cache_data
GreasePencilModifierInfluenceData influence
GreasePencilRuntimeHandle * runtime
Definition DNA_ID.h:414
struct uiLayout * layout
GreasePencil * get_grease_pencil_for_write()
PanelLayout panel_prop(const bContext *C, PointerRNA *open_prop_owner, blender::StringRefNull open_prop_name)
uiLayout & column(bool align)
void use_property_split_set(bool value)
void prop(PointerRNA *ptr, PropertyRNA *prop, int index, int value, eUI_Item_Flag flag, std::optional< blender::StringRef > name_opt, int icon, std::optional< blender::StringRef > placeholder=std::nullopt)
#define N_(msgid)
PointerRNA * ptr
Definition wm_files.cc:4238
uint8_t flag
Definition wm_window.cc:145