GPv3: Lattice modifier #117955

Merged
Lukas Tönne merged 9 commits from LukasTonne/blender:gp3-lattice-modifier into main 2024-02-08 14:09:20 +01:00
9 changed files with 308 additions and 0 deletions

View File

@ -189,6 +189,7 @@ class OBJECT_MT_modifier_add_deform(ModifierAddMenu, Menu):
if ob_type == 'VOLUME':
self.operator_modifier_add(layout, 'VOLUME_DISPLACE')
if ob_type == 'GREASEPENCIL':
self.operator_modifier_add(layout, 'GREASE_PENCIL_LATTICE')
self.operator_modifier_add(layout, 'GREASE_PENCIL_NOISE')
self.operator_modifier_add(layout, 'GREASE_PENCIL_OFFSET')
self.operator_modifier_add(layout, 'GREASE_PENCIL_SMOOTH')

View File

@ -872,4 +872,10 @@
.thickness = 0.02, \
}
#define _DNA_DEFAULT_GreasePencilLatticeModifierData \
{ \
.object = NULL, \
.strength = 1.0f, \
}
/* clang-format off */

View File

@ -102,6 +102,7 @@ typedef enum ModifierType {
eModifierType_GreasePencilNoise = 67,
eModifierType_GreasePencilMirror = 68,
eModifierType_GreasePencilThickness = 69,
eModifierType_GreasePencilLattice = 70,
NUM_MODIFIER_TYPES,
} ModifierType;
@ -2772,3 +2773,11 @@ typedef enum GreasePencilThicknessModifierFlag {
MOD_GREASE_PENCIL_THICK_NORMALIZE = (1 << 0),
MOD_GREASE_PENCIL_THICK_WEIGHT_FACTOR = (1 << 1),
} GreasePencilThicknessModifierFlag;
typedef struct GreasePencilLatticeModifierData {
ModifierData modifier;
GreasePencilModifierInfluenceData influence;
struct Object *object;
float strength;
char _pad[4];
} GreasePencilLatticeModifierData;

View File

@ -333,6 +333,7 @@ SDNA_DEFAULT_DECL_STRUCT(GreasePencilTintModifierData);
SDNA_DEFAULT_DECL_STRUCT(GreasePencilOffsetModifierData);
SDNA_DEFAULT_DECL_STRUCT(GreasePencilMirrorModifierData);
SDNA_DEFAULT_DECL_STRUCT(GreasePencilThickModifierData);
SDNA_DEFAULT_DECL_STRUCT(GreasePencilLatticeModifierData);
#undef SDNA_DEFAULT_DECL_STRUCT
@ -588,6 +589,7 @@ const void *DNA_default_table[SDNA_TYPE_MAX] = {
SDNA_DEFAULT_DECL(GreasePencilOffsetModifierData),
SDNA_DEFAULT_DECL(GreasePencilMirrorModifierData),
SDNA_DEFAULT_DECL(GreasePencilThickModifierData),
SDNA_DEFAULT_DECL(GreasePencilLatticeModifierData),
};
#undef SDNA_DEFAULT_DECL
#undef SDNA_DEFAULT_DECL_EX

View File

@ -321,6 +321,11 @@ const EnumPropertyItem rna_enum_object_modifier_type_items[] = {
ICON_MOD_THICKNESS,
"Thickness",
"Change stroke thickness"},
{eModifierType_GreasePencilLattice,
"GREASE_PENCIL_LATTICE",
ICON_MOD_LATTICE,
"Lattice",
"Deform strokes using a lattice object"},
RNA_ENUM_ITEM_HEADING(N_("Physics"), nullptr),
{eModifierType_Cloth, "CLOTH", ICON_MOD_CLOTH, "Cloth", ""},
@ -945,6 +950,7 @@ RNA_MOD_OBJECT_SET(Shrinkwrap, auxTarget, OB_MESH);
RNA_MOD_OBJECT_SET(SurfaceDeform, target, OB_MESH);
RNA_MOD_OBJECT_SET(GreasePencilMirror, object, OB_EMPTY);
RNA_MOD_OBJECT_SET(GreasePencilTint, object, OB_EMPTY);
LukasTonne marked this conversation as resolved
Review

Could you commit these changes seperately as a fix? Same for removing the rna setter functions below.

Could you commit these changes seperately as a fix? Same for removing the rna setter functions below.
RNA_MOD_OBJECT_SET(GreasePencilLattice, object, OB_LATTICE);
static void rna_HookModifier_object_set(PointerRNA *ptr,
PointerRNA value,
@ -1856,6 +1862,7 @@ RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(GreasePencilTint);
RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(GreasePencilSmooth);
RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(GreasePencilNoise);
RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(GreasePencilThick);
RNA_MOD_GREASE_PENCIL_MATERIAL_FILTER_SET(GreasePencilLattice);
RNA_MOD_GREASE_PENCIL_VERTEX_GROUP_SET(GreasePencilOffset);
RNA_MOD_GREASE_PENCIL_VERTEX_GROUP_SET(GreasePencilOpacity);
@ -1864,6 +1871,7 @@ RNA_MOD_GREASE_PENCIL_VERTEX_GROUP_SET(GreasePencilTint);
RNA_MOD_GREASE_PENCIL_VERTEX_GROUP_SET(GreasePencilSmooth);
RNA_MOD_GREASE_PENCIL_VERTEX_GROUP_SET(GreasePencilNoise);
RNA_MOD_GREASE_PENCIL_VERTEX_GROUP_SET(GreasePencilThick);
RNA_MOD_GREASE_PENCIL_VERTEX_GROUP_SET(GreasePencilLattice);
static void rna_GreasePencilOpacityModifier_opacity_factor_range(
PointerRNA *ptr, float *min, float *max, float *softmin, float *softmax)
@ -8401,6 +8409,46 @@ static void rna_def_modifier_grease_pencil_thickness(BlenderRNA *brna)
RNA_define_lib_overridable(false);
}
static void rna_def_modifier_grease_pencil_lattice(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "GreasePencilLatticeModifier", "Modifier");
RNA_def_struct_ui_text(
srna, "Grease Pencil Lattice Modifier", "Deform strokes using a lattice object");
RNA_def_struct_sdna(srna, "GreasePencilLatticeModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_LATTICE);
rna_def_modifier_grease_pencil_layer_filter(srna);
rna_def_modifier_grease_pencil_material_filter(
srna, "rna_GreasePencilLatticeModifier_material_filter_set");
rna_def_modifier_grease_pencil_vertex_group(
srna, "rna_GreasePencilLatticeModifier_vertex_group_name_set");
rna_def_modifier_panel_open_prop(srna, "open_influence_panel", 0);
RNA_define_lib_overridable(true);
prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
RNA_def_property_ui_text(prop, "Object", "Lattice object to deform with");
RNA_def_property_pointer_funcs(prop,
nullptr,
"rna_GreasePencilLatticeModifier_object_set",
nullptr,
"rna_Lattice_object_poll");
RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK);
RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_NONE);
RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
RNA_def_property_ui_range(prop, 0, 1, 10, 2);
RNA_def_property_ui_text(prop, "Strength", "Strength of modifier effect");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
RNA_define_lib_overridable(false);
}
void RNA_def_modifier(BlenderRNA *brna)
{
StructRNA *srna;
@ -8577,6 +8625,7 @@ void RNA_def_modifier(BlenderRNA *brna)
rna_def_modifier_grease_pencil_noise(brna);
rna_def_modifier_grease_pencil_mirror(brna);
rna_def_modifier_grease_pencil_thickness(brna);
rna_def_modifier_grease_pencil_lattice(brna);
}
#endif

View File

@ -45,6 +45,7 @@ set(SRC
intern/MOD_explode.cc
intern/MOD_fluid.cc
intern/MOD_grease_pencil_color.cc
intern/MOD_grease_pencil_lattice.cc
intern/MOD_grease_pencil_mirror.cc
intern/MOD_grease_pencil_noise.cc
intern/MOD_grease_pencil_offset.cc

View File

@ -82,6 +82,7 @@ extern ModifierTypeInfo modifierType_GreasePencilOffset;
extern ModifierTypeInfo modifierType_GreasePencilNoise;
extern ModifierTypeInfo modifierType_GreasePencilMirror;
extern ModifierTypeInfo modifierType_GreasePencilThickness;
extern ModifierTypeInfo modifierType_GreasePencilLattice;
/* MOD_util.cc */

View File

@ -0,0 +1,238 @@
/* SPDX-FileCopyrightText: 2024 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup modifiers
*/
#include "DNA_defaults.h"
#include "DNA_modifier_types.h"
#include "DNA_scene_types.h"
#include "BKE_colortools.hh"
#include "BKE_curves.hh"
#include "BKE_geometry_set.hh"
#include "BKE_grease_pencil.hh"
#include "BKE_lattice.hh"
#include "BKE_lib_query.hh"
#include "BKE_modifier.hh"
#include "BKE_screen.hh"
#include "BLO_read_write.hh"
#include "UI_interface.hh"
#include "UI_resources.hh"
#include "BLT_translation.h"
#include "WM_types.hh"
#include "RNA_access.hh"
#include "RNA_enum_types.hh"
#include "RNA_prototypes.h"
#include "MOD_grease_pencil_util.hh"
#include "MOD_modifiertypes.hh"
#include "MOD_ui_common.hh"
namespace blender {
using bke::greasepencil::Drawing;
using bke::greasepencil::FramesMapKey;
using bke::greasepencil::Layer;
static void init_data(ModifierData *md)
{
auto *lmd = reinterpret_cast<GreasePencilLatticeModifierData *>(md);
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(lmd, modifier));
MEMCPY_STRUCT_AFTER(lmd, DNA_struct_default_get(GreasePencilLatticeModifierData), modifier);
modifier::greasepencil::init_influence_data(&lmd->influence, false);
}
static void copy_data(const ModifierData *md, ModifierData *target, const int flag)
{
const auto *lmd = reinterpret_cast<const GreasePencilLatticeModifierData *>(md);
auto *tlmd = reinterpret_cast<GreasePencilLatticeModifierData *>(target);
modifier::greasepencil::free_influence_data(&tlmd->influence);
BKE_modifier_copydata_generic(md, target, flag);
modifier::greasepencil::copy_influence_data(&lmd->influence, &tlmd->influence, flag);
}
static void free_data(ModifierData *md)
{
auto *lmd = reinterpret_cast<GreasePencilLatticeModifierData *>(md);
modifier::greasepencil::free_influence_data(&lmd->influence);
}
static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
{
auto *lmd = reinterpret_cast<GreasePencilLatticeModifierData *>(md);
modifier::greasepencil::foreach_influence_ID_link(&lmd->influence, ob, walk, user_data);
walk(user_data, ob, (ID **)&lmd->object, IDWALK_CB_NOP);
}
static void update_depsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
{
auto *lmd = reinterpret_cast<GreasePencilLatticeModifierData *>(md);
if (lmd->object != nullptr) {
DEG_add_object_relation(
ctx->node, lmd->object, DEG_OB_COMP_TRANSFORM, "Grease Pencil Lattice Modifier");
DEG_add_object_relation(
ctx->node, lmd->object, DEG_OB_COMP_GEOMETRY, "Grease Pencil Lattice Modifier");
}
DEG_add_depends_on_transform_relation(ctx->node, "Grease Pencil Lattice Modifier");
}
static bool is_disabled(const Scene * /*scene*/, ModifierData *md, bool /*use_render_params*/)
{
auto *lmd = reinterpret_cast<GreasePencilLatticeModifierData *>(md);
/* The object type check is only needed here in case we have a placeholder
* object assigned (because the library containing the lattice is missing).
*
* In other cases it should be impossible to have a type mismatch.
*/
return lmd->object == nullptr || lmd->object->type != OB_LATTICE;
}
static void modify_curves(ModifierData *md,
const ModifierEvalContext *ctx,
const LatticeDeformData &cache_data,
Drawing &drawing)
{
const auto *lmd = reinterpret_cast<GreasePencilLatticeModifierData *>(md);
bke::CurvesGeometry &curves = drawing.strokes_for_write();
IndexMaskMemory mask_memory;
const IndexMask curves_mask = modifier::greasepencil::get_filtered_stroke_mask(
ctx->object, curves, lmd->influence, mask_memory);
const OffsetIndices<int> points_by_curve = curves.points_by_curve();
MutableSpan<float3> positions = curves.positions_for_write();
const VArray<float> vgroup_weights = modifier::greasepencil::get_influence_vertex_weights(
curves, lmd->influence);
curves_mask.foreach_index(GrainSize(512), [&](const int64_t curve_i) {
const IndexRange points = points_by_curve[curve_i];
for (const int64_t point_i : points) {
const float weight = vgroup_weights[point_i];
BKE_lattice_deform_data_eval_co(const_cast<LatticeDeformData *>(&cache_data),
positions[point_i],
lmd->strength * weight);
}
});
LukasTonne marked this conversation as resolved
Review

Looks like the drawing needs a positions changed tag too

Looks like the drawing needs a positions changed tag too
drawing.tag_positions_changed();
LukasTonne marked this conversation as resolved Outdated

Tagging the drawing will tag the curves geometry, so this line can be removed now.

Tagging the drawing will tag the curves geometry, so this line can be removed now.
}
static void modify_geometry_set(ModifierData *md,
const ModifierEvalContext *ctx,
bke::GeometrySet *geometry_set)
{
const auto *lmd = reinterpret_cast<GreasePencilLatticeModifierData *>(md);
BLI_assert(lmd->object != nullptr && lmd->object->type == OB_LATTICE);
LatticeDeformData *cache_data = BKE_lattice_deform_data_create(lmd->object, ctx->object);
if (!geometry_set->has_grease_pencil()) {
return;
LukasTonne marked this conversation as resolved
Review

We've been using this pattern in other modifiers, which is a bit nicer imho:

if (!geometry_set->has_grease_pencil()) {
  return;
}
GreasePencil &grease_pencil = *geometry_set->get_grease_pencil_for_write();
We've been using this pattern in other modifiers, which is a bit nicer imho: ``` if (!geometry_set->has_grease_pencil()) { return; } GreasePencil &grease_pencil = *geometry_set->get_grease_pencil_for_write(); ```
}
GreasePencil &grease_pencil = *geometry_set->get_grease_pencil_for_write();
IndexMaskMemory mask_memory;
const IndexMask layer_mask = modifier::greasepencil::get_filtered_layer_mask(
LukasTonne marked this conversation as resolved
Review

I haven't thought about this before, but I think we should call

GeometryComponentEditData::remember_deformed_positions_if_necessary(geometry_set);

in modifiers that deform the drawings.

Maybe this should be done as a seperate PR though.

I haven't thought about this before, but I think we should call ``` GeometryComponentEditData::remember_deformed_positions_if_necessary(geometry_set); ``` in modifiers that deform the drawings. Maybe this should be done as a seperate PR though.
Review

Added a note to #106665, will ignore it here for now.

Added a note to #106665, will ignore it here for now.
grease_pencil, lmd->influence, mask_memory);
const int frame = grease_pencil.runtime->eval_frame;
const Vector<Drawing *> drawings = modifier::greasepencil::get_drawings_for_write(
grease_pencil, layer_mask, frame);
threading::parallel_for_each(
drawings, [&](Drawing *drawing) { modify_curves(md, ctx, *cache_data, *drawing); });
BKE_lattice_deform_data_destroy(cache_data);
}
static void panel_draw(const bContext *C, Panel *panel)
{
uiLayout *layout = panel->layout;
PointerRNA ob_ptr;
PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr);
uiLayoutSetPropSep(layout, true);
uiItemR(layout, ptr, "object", UI_ITEM_NONE, nullptr, ICON_NONE);
uiItemR(layout, ptr, "strength", UI_ITEM_R_SLIDER, nullptr, ICON_NONE);
if (uiLayout *influence_panel = uiLayoutPanelProp(
C, layout, ptr, "open_influence_panel", "Influence"))
{
modifier::greasepencil::draw_layer_filter_settings(C, influence_panel, ptr);
modifier::greasepencil::draw_material_filter_settings(C, influence_panel, ptr);
modifier::greasepencil::draw_vertex_group_settings(C, influence_panel, ptr);
}
modifier_panel_end(layout, ptr);
}
static void panel_register(ARegionType *region_type)
{
modifier_panel_register(region_type, eModifierType_GreasePencilLattice, panel_draw);
}
static void blend_write(BlendWriter *writer, const ID * /*id_owner*/, const ModifierData *md)
{
const auto *lmd = reinterpret_cast<const GreasePencilLatticeModifierData *>(md);
BLO_write_struct(writer, GreasePencilLatticeModifierData, lmd);
modifier::greasepencil::write_influence_data(writer, &lmd->influence);
}
static void blend_read(BlendDataReader *reader, ModifierData *md)
{
auto *lmd = reinterpret_cast<GreasePencilLatticeModifierData *>(md);
modifier::greasepencil::read_influence_data(reader, &lmd->influence);
}
} // namespace blender
ModifierTypeInfo modifierType_GreasePencilLattice = {
/*idname*/ "GreasePencilLattice",
/*name*/ N_("Lattice"),
/*struct_name*/ "GreasePencilLatticeModifierData",
/*struct_size*/ sizeof(GreasePencilLatticeModifierData),
/*srna*/ &RNA_GreasePencilLatticeModifier,
/*type*/ ModifierTypeType::OnlyDeform,
/*flags*/ eModifierTypeFlag_AcceptsGreasePencil | eModifierTypeFlag_SupportsEditmode |
eModifierTypeFlag_EnableInEditmode | eModifierTypeFlag_SupportsMapping,
/*icon*/ ICON_MOD_LATTICE,
/*copy_data*/ blender::copy_data,
/*deform_verts*/ nullptr,
/*deform_matrices*/ nullptr,
/*deform_verts_EM*/ nullptr,
/*deform_matrices_EM*/ nullptr,
/*modify_mesh*/ nullptr,
/*modify_geometry_set*/ blender::modify_geometry_set,
/*init_data*/ blender::init_data,
/*required_data_mask*/ nullptr,
/*free_data*/ blender::free_data,
/*is_disabled*/ blender::is_disabled,
/*update_depsgraph*/ blender::update_depsgraph,
/*depends_on_time*/ nullptr,
/*depends_on_normals*/ nullptr,
/*foreach_ID_link*/ blender::foreach_ID_link,
/*foreach_tex_link*/ nullptr,
/*free_runtime_data*/ nullptr,
/*panel_register*/ blender::panel_register,
/*blend_write*/ blender::blend_write,
/*blend_read*/ blender::blend_read,
/*foreach_cache*/ nullptr,
};

View File

@ -279,5 +279,6 @@ void modifier_type_init(ModifierTypeInfo *types[])
INIT_TYPE(GreasePencilNoise);
INIT_TYPE(GreasePencilMirror);
INIT_TYPE(GreasePencilThickness);
INIT_TYPE(GreasePencilLattice);
#undef INIT_TYPE
}