GPv3: Lattice modifier

Ported lattice modifier from GPv2.

The `LatticeDeformData` is no longer stored in the modifier data, but calculated on-the-fly like in the mesh deform modifier. This is quite trivial data and only stores deformed positions of the lattice, so not really worth the effort and complexity of caching it.

Pull Request: https://projects.blender.org/blender/blender/pulls/117955
This commit is contained in:
Lukas Tönne 2024-02-08 14:09:11 +01:00
parent 9c0bb3d8f9
commit da2d3be202
9 changed files with 308 additions and 0 deletions

@ -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')

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

@ -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;

@ -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

@ -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);
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

@ -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

@ -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 */

@ -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);
}
});
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;
}
GreasePencil &grease_pencil = *geometry_set->get_grease_pencil_for_write();
IndexMaskMemory mask_memory;
const IndexMask layer_mask = modifier::greasepencil::get_filtered_layer_mask(
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,
};

@ -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
}