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();
}
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
}