Blender V4.3
MOD_grease_pencil_multiply.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 "MEM_guardedalloc.h"
10
11#include "BLI_math_matrix.hh"
12
13#include "DNA_defaults.h"
14#include "DNA_material_types.h"
15#include "DNA_modifier_types.h"
16#include "DNA_scene_types.h"
17
18#include "BKE_attribute.hh"
19#include "BKE_curves.hh"
20#include "BKE_geometry_set.hh"
21#include "BKE_grease_pencil.hh"
22#include "BKE_instances.hh"
23#include "BKE_lib_query.hh"
24#include "BKE_material.h"
25#include "BKE_modifier.hh"
26#include "BKE_screen.hh"
27
28#include "BLO_read_write.hh"
29
31
33
34#include "UI_interface.hh"
35#include "UI_resources.hh"
36
37#include "BLT_translation.hh"
38
39#include "WM_types.hh"
40
41#include "RNA_access.hh"
42#include "RNA_enum_types.hh"
43#include "RNA_prototypes.hh"
44
46#include "MOD_modifiertypes.hh"
47#include "MOD_ui_common.hh"
48
49namespace blender {
50
51using bke::greasepencil::Drawing;
52
53static void init_data(ModifierData *md)
54{
55 auto *mmd = reinterpret_cast<GreasePencilMultiModifierData *>(md);
56
58
61}
62
63static void copy_data(const ModifierData *md, ModifierData *target, const int flag)
64{
65 const auto *mmd = reinterpret_cast<const GreasePencilMultiModifierData *>(md);
66 auto *tmmd = reinterpret_cast<GreasePencilMultiModifierData *>(target);
67
69 modifier::greasepencil::copy_influence_data(&mmd->influence, &tmmd->influence, flag);
70}
71
72static void free_data(ModifierData *md)
73{
74 auto *mmd = reinterpret_cast<GreasePencilMultiModifierData *>(md);
76}
77
78static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
79{
80 auto *mmd = reinterpret_cast<GreasePencilMultiModifierData *>(md);
81 modifier::greasepencil::foreach_influence_ID_link(&mmd->influence, ob, walk, user_data);
82}
83
84static bool is_disabled(const Scene * /*scene*/, ModifierData *md, bool /*use_render_params*/)
85{
86 auto *mmd = reinterpret_cast<GreasePencilMultiModifierData *>(md);
87 if (mmd->duplications <= 1) {
88 return true;
89 }
90 return false;
91}
92
94 const IndexMask curves_mask,
95 const IndexMask unselected_mask,
96 const int count,
97 int &r_original_point_count)
98{
99 bke::CurvesGeometry masked_curves = bke::curves_copy_curve_selection(curves, curves_mask, {});
101 curves, unselected_mask, {});
102
103 r_original_point_count = masked_curves.points_num();
104
105 Curves *masked_curves_id = bke::curves_new_nomain(masked_curves);
106 Curves *unselected_curves_id = bke::curves_new_nomain(unselected_curves);
107
108 bke::GeometrySet masked_geo = bke::GeometrySet::from_curves(masked_curves_id);
109 bke::GeometrySet unselected_geo = bke::GeometrySet::from_curves(unselected_curves_id);
110
111 std::unique_ptr<bke::Instances> instances = std::make_unique<bke::Instances>();
112 const int masked_handle = instances->add_reference(bke::InstanceReference{masked_geo});
113 const int unselected_handle = instances->add_reference(bke::InstanceReference{unselected_geo});
114
115 for ([[maybe_unused]] const int i : IndexRange(count)) {
116 instances->add_instance(masked_handle, float4x4::identity());
117 }
118 instances->add_instance(unselected_handle, float4x4::identity());
119
121 options.keep_original_ids = true;
122 options.realize_instance_attributes = true;
124 bke::GeometrySet::from_instances(instances.release()), options);
125 return std::move(result_geo.get_curves_for_write()->geometry.wrap());
126}
127
129 const ModifierEvalContext &ctx,
130 Drawing &drawing)
131{
132 bke::CurvesGeometry &curves = drawing.strokes_for_write();
133
134 IndexMaskMemory mask_memory;
136 ctx.object, curves, mmd.influence, mask_memory);
137
138 if (curves_mask.is_empty()) {
139 return;
140 }
141
142 const IndexMask unselected_mask = curves_mask.complement(curves.curves_range(), mask_memory);
143
144 int src_point_count;
145 bke::CurvesGeometry duplicated_strokes = duplicate_strokes(
146 curves, curves_mask, unselected_mask, mmd.duplications, src_point_count);
147
148 const float offset = math::length(math::to_scale(ctx.object->object_to_world())) * mmd.offset;
149 const float distance = mmd.distance;
150 const bool use_fading = (mmd.flag & MOD_GREASE_PENCIL_MULTIPLY_ENABLE_FADING) != 0;
151 const float fading_thickness = mmd.fading_thickness;
152 const float fading_opacity = mmd.fading_opacity;
153 const float fading_center = mmd.fading_center;
154
155 MutableSpan<float3> positions = duplicated_strokes.positions_for_write();
156 const Span<float3> tangents = duplicated_strokes.evaluated_tangents();
157 const Span<float3> normals = drawing.curve_plane_normals();
158
159 bke::MutableAttributeAccessor attributes = duplicated_strokes.attributes_for_write();
160 bke::SpanAttributeWriter<float> opacities = attributes.lookup_or_add_for_write_span<float>(
161 "opacity", bke::AttrDomain::Point);
162 bke::SpanAttributeWriter<float> radii = attributes.lookup_or_add_for_write_span<float>(
163 "radius", bke::AttrDomain::Point);
164
165 const OffsetIndices<int> points_by_curve = curves.points_by_curve();
166
167 Array<float3> pos_l(src_point_count);
168 Array<float3> pos_r(src_point_count);
169
170 threading::parallel_for(curves.curves_range(), 128, [&](const IndexRange range) {
171 for (const int curve : range) {
172 for (const int point : points_by_curve[curve]) {
173 const float3 miter = math::cross(normals[curve], tangents[point]) * distance;
174 pos_l[point] = positions[point] + miter;
175 pos_r[point] = positions[point] - miter;
176 }
177 }
178 });
179
180 const Span<float3> stroke_pos_l = pos_l.as_span();
181 const Span<float3> stroke_pos_r = pos_r.as_span();
182
183 for (const int i : IndexRange(mmd.duplications)) {
185 const IndexRange stroke = IndexRange(src_point_count * i, src_point_count);
186 MutableSpan<float3> instance_positions = positions.slice(stroke);
187 MutableSpan<float> instance_opacity = opacities.span.slice(stroke);
188 MutableSpan<float> instance_radii = radii.span.slice(stroke);
189 const float offset_fac = (mmd.duplications == 1) ?
190 0.5f :
191 (1.0f - (float(i) / float(mmd.duplications - 1)));
192 const float fading_fac = fabsf(offset_fac - fading_center);
193 const float thickness_factor = use_fading ? mix2(fading_fac, 1.0f, 1.0f - fading_thickness) :
194 1.0f;
195 const float opacity_factor = use_fading ? mix2(fading_fac, 1.0f, 1.0f - fading_opacity) : 1.0f;
196 threading::parallel_for(instance_positions.index_range(), 512, [&](const IndexRange range) {
197 for (const int point : range) {
198 const float fac = mix2(float(i) / float(mmd.duplications - 1), 1 + offset, offset);
199 const int old_point = point % src_point_count;
200 instance_positions[point] = mix2(fac, stroke_pos_l[old_point], stroke_pos_r[old_point]);
201 instance_radii[point] *= thickness_factor;
202 instance_opacity[point] *= opacity_factor;
203 }
204 });
205 }
206
207 radii.finish();
208 opacities.finish();
209
210 curves = std::move(duplicated_strokes);
211 drawing.tag_topology_changed();
212}
213
215 const ModifierEvalContext *ctx,
216 bke::GeometrySet *geometry_set)
217{
218 auto *mmd = reinterpret_cast<GreasePencilMultiModifierData *>(md);
219
220 if (!geometry_set->has_grease_pencil()) {
221 return;
222 }
223 GreasePencil &grease_pencil = *geometry_set->get_grease_pencil_for_write();
224 const int frame = grease_pencil.runtime->eval_frame;
225
226 IndexMaskMemory memory;
227 const IndexMask layer_mask = modifier::greasepencil::get_filtered_layer_mask(
228 grease_pencil, mmd->influence, memory);
229 const Vector<Drawing *> drawings = modifier::greasepencil::get_drawings_for_write(
230 grease_pencil, layer_mask, frame);
231 threading::parallel_for_each(drawings,
232 [&](Drawing *drawing) { generate_curves(*mmd, *ctx, *drawing); });
233}
234
235static void panel_draw(const bContext *C, Panel *panel)
236{
237 uiLayout *layout = panel->layout;
238
239 PointerRNA ob_ptr;
241
242 uiLayoutSetPropSep(layout, true);
243
244 uiItemR(layout, ptr, "duplicates", UI_ITEM_NONE, nullptr, ICON_NONE);
245
246 uiLayout *col = uiLayoutColumn(layout, false);
247 uiLayoutSetActive(col, RNA_int_get(ptr, "duplicates") > 0);
248 uiItemR(col, ptr, "distance", UI_ITEM_NONE, nullptr, ICON_NONE);
249 uiItemR(col, ptr, "offset", UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
250
251 if (uiLayout *fade_panel = uiLayoutPanelProp(
252 C, layout, ptr, "open_fading_panel", IFACE_("Fade")))
253 {
254 uiLayoutSetPropSep(fade_panel, true);
255 uiItemR(fade_panel, ptr, "use_fade", UI_ITEM_NONE, nullptr, ICON_NONE);
256
257 uiLayout *sub = uiLayoutColumn(fade_panel, false);
258 uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_fade"));
259
260 uiItemR(sub, ptr, "fading_center", UI_ITEM_NONE, nullptr, ICON_NONE);
261 uiItemR(sub, ptr, "fading_thickness", UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
262 uiItemR(sub, ptr, "fading_opacity", UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
263 }
264
265 if (uiLayout *influence_panel = uiLayoutPanelProp(
266 C, layout, ptr, "open_influence_panel", IFACE_("Influence")))
267 {
268 modifier::greasepencil::draw_layer_filter_settings(C, influence_panel, ptr);
269 modifier::greasepencil::draw_material_filter_settings(C, influence_panel, ptr);
270 }
271
272 modifier_panel_end(layout, ptr);
273}
274
279
280static void blend_write(BlendWriter *writer, const ID * /*id_owner*/, const ModifierData *md)
281{
282 const auto *mmd = reinterpret_cast<const GreasePencilMultiModifierData *>(md);
283
285 modifier::greasepencil::write_influence_data(writer, &mmd->influence);
286}
287
288static void blend_read(BlendDataReader *reader, ModifierData *md)
289{
290 auto *mmd = reinterpret_cast<GreasePencilMultiModifierData *>(md);
291
292 modifier::greasepencil::read_influence_data(reader, &mmd->influence);
293}
294
295} // namespace blender
296
298 /*idname*/ "GreasePencilMultiply",
299 /*name*/ N_("Multiple Strokes"),
300 /*struct_name*/ "GreasePencilMultiModifierData",
301 /*struct_size*/ sizeof(GreasePencilMultiModifierData),
302 /*srna*/ &RNA_GreasePencilMultiplyModifier,
306 /*icon*/ ICON_MOD_CURVE,
307
308 /*copy_data*/ blender::copy_data,
309
310 /*deform_verts*/ nullptr,
311 /*deform_matrices*/ nullptr,
312 /*deform_verts_EM*/ nullptr,
313 /*deform_matrices_EM*/ nullptr,
314 /*modify_mesh*/ nullptr,
315 /*modify_geometry_set*/ blender::modify_geometry_set,
316
317 /*init_data*/ blender::init_data,
318 /*required_data_mask*/ nullptr,
319 /*free_data*/ blender::free_data,
320 /*is_disabled*/ blender::is_disabled,
321 /*update_depsgraph*/ nullptr,
322 /*depends_on_time*/ nullptr,
323 /*depends_on_normals*/ nullptr,
324 /*foreach_ID_link*/ blender::foreach_ID_link,
325 /*foreach_tex_link*/ nullptr,
326 /*free_runtime_data*/ nullptr,
327 /*panel_register*/ blender::panel_register,
328 /*blend_write*/ blender::blend_write,
329 /*blend_read*/ blender::blend_read,
330};
Low-level operations for curves.
Low-level operations for grease pencil.
General operations, lookup, etc. for materials.
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 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)
#define DNA_struct_default_get(struct_name)
@ MOD_GREASE_PENCIL_MULTIPLY_ENABLE_FADING
@ eModifierType_GreasePencilMultiply
struct GreasePencilMultiModifierData GreasePencilMultiModifierData
static bool is_disabled
Read Guarded memory(de)allocation.
static void panel_register(ARegionType *region_type)
static void blend_read(BlendDataReader *, ModifierData *md)
static void panel_draw(const bContext *, Panel *panel)
static void blend_write(BlendWriter *writer, const ID *, const ModifierData *md)
Definition MOD_bevel.cc:440
ModifierTypeInfo modifierType_GreasePencilMultiply
static void modify_geometry_set(ModifierData *md, const ModifierEvalContext *ctx, blender::bke::GeometrySet *geometry_set)
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)
#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)
@ UI_ITEM_R_SLIDER
MutableSpan< float3 > positions_for_write()
MutableAttributeAccessor attributes_for_write()
Span< float3 > evaluated_tangents() const
Span< float3 > curve_plane_normals() const
bke::CurvesGeometry & strokes_for_write()
IndexMask complement(const IndexMask &universe, IndexMaskMemory &memory) const
CCL_NAMESPACE_BEGIN struct Options options
#define fabsf(x)
draw_view in_light_buf[] float
uint col
int count
T mix2(float factor, const T &a, const T &b)
CurvesGeometry curves_copy_curve_selection(const CurvesGeometry &curves, const IndexMask &curves_to_copy, const AttributeFilter &attribute_filter)
Curves * curves_new_nomain(int points_num, int curves_num)
bke::GeometrySet realize_instances(bke::GeometrySet geometry_set, const RealizeInstancesOptions &options)
T length(const VecBase< T, Size > &a)
VecBase< T, 3 > to_scale(const MatBase< T, NumCol, NumRow > &mat)
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 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 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
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 bke::CurvesGeometry duplicate_strokes(const bke::CurvesGeometry &curves, const IndexMask curves_mask, const IndexMask unselected_mask, const int count, int &r_original_point_count)
static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
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 bool is_disabled(const Scene *, ModifierData *md, bool)
static void blend_read(BlendDataReader *reader, ModifierData *md)
static void generate_curves(GreasePencilMultiModifierData &mmd, const ModifierEvalContext &ctx, Drawing &drawing)
int RNA_int_get(PointerRNA *ptr, const char *name)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
CurvesGeometry geometry
GreasePencilModifierInfluenceData influence
GreasePencilRuntimeHandle * runtime
Definition DNA_ID.h:413
struct uiLayout * layout
static GeometrySet from_instances(Instances *instances, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
static GeometrySet from_curves(Curves *curves, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
GreasePencil * get_grease_pencil_for_write()
#define N_(msgid)
PointerRNA * ptr
Definition wm_files.cc:4126
uint8_t flag
Definition wm_window.cc:138