Blender V4.3
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
9#include "BKE_attribute.hh"
10#include "BKE_material.h"
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
33#include "UI_interface.hh"
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
49static void init_data(ModifierData *md)
50{
51 auto *smd = reinterpret_cast<GreasePencilShrinkwrapModifierData *>(md);
52
54
56 modifier::greasepencil::init_influence_data(&smd->influence, false);
57}
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 CustomData_MeshMasks mask = {0};
111
112 if (BKE_shrinkwrap_needs_normals(smd->shrink_type, smd->shrink_mode)) {
114 }
115
116 if (smd->target != nullptr) {
118 ctx->node, smd->target, DEG_OB_COMP_TRANSFORM, "Grease Pencil Shrinkwrap Modifier");
120 ctx->node, smd->target, DEG_OB_COMP_GEOMETRY, "Grease Pencil Shrinkwrap Modifier");
121 DEG_add_customdata_mask(ctx->node, smd->target, &mask);
122 if (smd->shrink_type == MOD_SHRINKWRAP_TARGET_PROJECT) {
124 }
125 }
126 if (smd->aux_target != nullptr) {
128 ctx->node, smd->aux_target, DEG_OB_COMP_TRANSFORM, "Grease Pencil Shrinkwrap Modifier");
130 ctx->node, smd->aux_target, DEG_OB_COMP_GEOMETRY, "Grease Pencil Shrinkwrap Modifier");
131 DEG_add_customdata_mask(ctx->node, smd->aux_target, &mask);
132 if (smd->shrink_type == MOD_SHRINKWRAP_TARGET_PROJECT) {
134 ctx->node, &smd->aux_target->id, DAG_EVAL_NEED_SHRINKWRAP_BOUNDARY);
135 }
136 }
137 DEG_add_depends_on_transform_relation(ctx->node, "Grease Pencil Shrinkwrap Modifier");
138}
139
141 const ModifierEvalContext &ctx,
143{
145 bke::CurvesGeometry &curves = drawing.strokes_for_write();
146 const OffsetIndices<int> points_by_curve = curves.points_by_curve();
147 const Span<MDeformVert> dverts = curves.deform_verts();
148 const MutableSpan<float3> positions = curves.positions_for_write();
149 const int defgrp_idx = BKE_object_defgroup_name_index(ctx.object,
151
152 /* Selected source curves. */
153 IndexMaskMemory curve_mask_memory;
155 ctx.object, drawing.strokes(), smd.influence, curve_mask_memory);
156
158 params.target = smd.target;
159 params.aux_target = smd.aux_target;
161 params.keep_distance = smd.keep_dist;
162 params.shrink_type = smd.shrink_type;
163 params.shrink_options = smd.shrink_opts;
164 params.shrink_mode = smd.shrink_mode;
165 params.projection_limit = smd.proj_limit;
166 params.projection_axis = smd.proj_axis;
167 params.subsurf_levels = smd.subsurf_levels;
168
169 curves_mask.foreach_index([&](const int curve_i) {
170 const IndexRange points = points_by_curve[curve_i];
171 const Span<MDeformVert> curve_dverts = dverts.is_empty() ? dverts : dverts.slice(points);
172 const MutableSpan<float3> curve_positions = positions.slice(points);
173
175 params, *ctx.object, *smd.cache_data, curve_dverts, defgrp_idx, curve_positions);
176 });
177
178 /* Optional smoothing after shrinkwrap. */
179 const VArray<bool> point_selection = VArray<bool>::ForSingle(true, curves.points_num());
180 const bool smooth_ends = false;
181 const bool keep_shape = true;
183 points_by_curve,
184 point_selection,
185 curves.cyclic(),
186 smd.smooth_step,
187 smd.smooth_factor,
188 smooth_ends,
189 keep_shape,
190 positions);
191
192 drawing.tag_positions_changed();
193}
194
196 const ModifierEvalContext &ctx)
197{
198 if (smd.cache_data) {
200 MEM_delete(smd.cache_data);
201 smd.cache_data = nullptr;
202 }
203 Object *target_ob = DEG_get_evaluated_object(ctx.depsgraph, smd.target);
205
206 smd.cache_data = MEM_new<ShrinkwrapTreeData>(__func__);
207 const bool tree_ok = BKE_shrinkwrap_init_tree(
208 smd.cache_data, target_mesh, smd.shrink_type, smd.shrink_mode, false);
209 if (!tree_ok) {
210 MEM_delete(smd.cache_data);
211 smd.cache_data = nullptr;
212 }
213}
214
216 const ModifierEvalContext *ctx,
217 bke::GeometrySet *geometry_set)
218{
222
223 auto &smd = *reinterpret_cast<GreasePencilShrinkwrapModifierData *>(md);
224 BLI_assert(smd.target != nullptr);
225 if (smd.target == ctx->object || smd.aux_target == ctx->object) {
226 return;
227 }
228 if (!geometry_set->has_grease_pencil()) {
229 return;
230 }
231 GreasePencil &grease_pencil = *geometry_set->get_grease_pencil_for_write();
232 const int frame = grease_pencil.runtime->eval_frame;
233
235
236 IndexMaskMemory mask_memory;
238 grease_pencil, smd.influence, mask_memory);
239
241 grease_pencil, layer_mask, frame);
243 [&](Drawing *drawing) { modify_drawing(smd, *ctx, *drawing); });
244}
245
246static void panel_draw(const bContext *C, Panel *panel)
247{
249
250 uiLayout *layout = panel->layout;
251
252 PointerRNA ob_ptr;
254 int wrap_method = RNA_enum_get(ptr, "wrap_method");
255 uiLayout *col, *row;
256
257 uiLayoutSetPropSep(layout, true);
258
259 uiItemR(layout, ptr, "wrap_method", UI_ITEM_NONE, nullptr, ICON_NONE);
260
261 if (ELEM(wrap_method,
265 {
266 uiItemR(layout, ptr, "wrap_mode", UI_ITEM_NONE, nullptr, ICON_NONE);
267 }
268
269 if (wrap_method == MOD_SHRINKWRAP_PROJECT) {
270 uiItemR(layout, ptr, "project_limit", UI_ITEM_NONE, IFACE_("Limit"), ICON_NONE);
271 uiItemR(layout, ptr, "subsurf_levels", UI_ITEM_NONE, nullptr, ICON_NONE);
272
273 col = uiLayoutColumn(layout, false);
274 row = uiLayoutRowWithHeading(col, true, IFACE_("Axis"));
275 uiItemR(row, ptr, "use_project_x", toggles_flag, nullptr, ICON_NONE);
276 uiItemR(row, ptr, "use_project_y", toggles_flag, nullptr, ICON_NONE);
277 uiItemR(row, ptr, "use_project_z", toggles_flag, nullptr, ICON_NONE);
278
279 uiItemR(col, ptr, "use_negative_direction", UI_ITEM_NONE, nullptr, ICON_NONE);
280 uiItemR(col, ptr, "use_positive_direction", UI_ITEM_NONE, nullptr, ICON_NONE);
281
282 uiItemR(layout, ptr, "cull_face", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
283 col = uiLayoutColumn(layout, false);
285 RNA_boolean_get(ptr, "use_negative_direction") &&
286 RNA_enum_get(ptr, "cull_face") != 0);
287 uiItemR(col, ptr, "use_invert_cull", UI_ITEM_NONE, nullptr, ICON_NONE);
288 }
289
290 uiItemR(layout, ptr, "target", UI_ITEM_NONE, nullptr, ICON_NONE);
291 if (wrap_method == MOD_SHRINKWRAP_PROJECT) {
292 uiItemR(layout, ptr, "auxiliary_target", UI_ITEM_NONE, nullptr, ICON_NONE);
293 }
294 uiItemR(layout, ptr, "offset", UI_ITEM_NONE, nullptr, ICON_NONE);
295
296 uiLayoutSetPropSep(layout, true);
297
298 uiItemR(layout, ptr, "smooth_factor", UI_ITEM_NONE, nullptr, ICON_NONE);
299 uiItemR(layout, ptr, "smooth_step", UI_ITEM_NONE, IFACE_("Repeat"), ICON_NONE);
300
301 if (uiLayout *influence_panel = uiLayoutPanelProp(
302 C, layout, ptr, "open_influence_panel", IFACE_("Influence")))
303 {
307 }
308
309 modifier_panel_end(layout, ptr);
310}
311
316
317static void blend_write(BlendWriter *writer, const ID * /*id_owner*/, const ModifierData *md)
318{
319 const auto *smd = reinterpret_cast<const GreasePencilShrinkwrapModifierData *>(md);
320
322 modifier::greasepencil::write_influence_data(writer, &smd->influence);
323}
324
325static void blend_read(BlendDataReader *reader, ModifierData *md)
326{
327 auto *smd = reinterpret_cast<GreasePencilShrinkwrapModifierData *>(md);
328
329 modifier::greasepencil::read_influence_data(reader, &smd->influence);
330}
331
332} // namespace blender
333
335 /*idname*/ "GreasePencilShrinkwrap",
336 /*name*/ N_("Shrinkwrap"),
337 /*struct_name*/ "GreasePencilShrinkwrapModifierData",
338 /*struct_size*/ sizeof(GreasePencilShrinkwrapModifierData),
339 /*srna*/ &RNA_GreasePencilShrinkwrapModifier,
343 /*icon*/ ICON_MOD_SHRINKWRAP,
344
345 /*copy_data*/ blender::copy_data,
346
347 /*deform_verts*/ nullptr,
348 /*deform_matrices*/ nullptr,
349 /*deform_verts_EM*/ nullptr,
350 /*deform_matrices_EM*/ nullptr,
351 /*modify_mesh*/ nullptr,
352 /*modify_geometry_set*/ blender::modify_geometry_set,
353
354 /*init_data*/ blender::init_data,
355 /*required_data_mask*/ nullptr,
356 /*free_data*/ blender::free_data,
357 /*is_disabled*/ blender::is_disabled,
358 /*update_depsgraph*/ blender::update_depsgraph,
359 /*depends_on_time*/ nullptr,
360 /*depends_on_normals*/ nullptr,
361 /*foreach_ID_link*/ blender::foreach_ID_link,
362 /*foreach_tex_link*/ nullptr,
363 /*free_runtime_data*/ nullptr,
364 /*panel_register*/ blender::panel_register,
365 /*blend_write*/ blender::blend_write,
366 /*blend_read*/ blender::blend_read,
367};
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:585
Low-level operations for grease pencil.
@ IDWALK_CB_NOP
General operations, lookup, etc. for materials.
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(*)(void *user_data, Object *ob, ID **idpoin, int cb_flag) IDWalkFunc
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_needs_normals(int shrinkType, int shrinkMode)
Definition shrinkwrap.cc:89
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:50
#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_customdata_mask(DepsNodeHandle *handle, Object *object, const CustomData_MeshMasks *masks)
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
Object * DEG_get_evaluated_object(const Depsgraph *depsgraph, Object *object)
#define CD_MASK_CUSTOMLOOPNORMAL
#define DNA_struct_default_get(struct_name)
@ MOD_SHRINKWRAP_TARGET_PROJECT
@ MOD_SHRINKWRAP_PROJECT
@ MOD_SHRINKWRAP_NEAREST_SURFACE
@ GREASE_PENCIL_INFLUENCE_INVERT_VERTEX_GROUP
struct GreasePencilShrinkwrapModifierData GreasePencilShrinkwrapModifierData
@ eModifierType_GreasePencilShrinkwrap
@ OB_MESH
static bool is_disabled
ModifierTypeInfo modifierType_GreasePencilShrinkwrap
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)
void uiLayoutSetActive(uiLayout *layout, bool active)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
uiLayout * uiLayoutRowWithHeading(uiLayout *layout, bool align, const char *heading)
#define UI_ITEM_NONE
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)
eUI_Item_Flag
@ UI_ITEM_R_TOGGLE
@ UI_ITEM_R_FORCE_BLANK_DECORATE
@ UI_ITEM_R_EXPAND
constexpr MutableSpan slice(const int64_t start, const int64_t size) const
Definition BLI_span.hh:574
constexpr Span slice(int64_t start, int64_t size) const
Definition BLI_span.hh:138
constexpr bool is_empty() const
Definition BLI_span.hh:261
static VArray ForSingle(T value, const int64_t size)
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_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)
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)
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:413
struct uiLayout * layout
GreasePencil * get_grease_pencil_for_write()
#define N_(msgid)
PointerRNA * ptr
Definition wm_files.cc:4126
uint8_t flag
Definition wm_window.cc:138