GPv3: Opacity modifier #116946

Merged
Lukas Tönne merged 52 commits from LukasTonne/blender:gp3-opacity-modifier into main 2024-01-16 16:56:22 +01:00
5 changed files with 140 additions and 76 deletions
Showing only changes of commit 25cd79488b - Show all commits

View File

@ -2486,35 +2486,48 @@ typedef enum VolumeToMeshFlag {
VOLUME_TO_MESH_USE_SMOOTH_SHADE = 1 << 0,
} VolumeToMeshFlag;
typedef struct GreasePencilModifierFilterData {
typedef struct GreasePencilModifierLayerFilter {
/** Filter by layer name. */
char layer_name[64];
/** Filter by stroke material. */
struct Material *material;
/** Filter by layer pass. */
int layer_pass;
/** GreasePencilModifierFilterFlag */
int flag;
} GreasePencilModifierLayerFilter;
typedef struct GreasePencilModifierMaterialFilter {
/** Filter by stroke material. */
struct Material *material;
/** Filter by material pass. */
int material_pass;
/** GreasePencilModifierFilterFlag */
int flag;
char _pad[4];
} GreasePencilModifierFilterData;
} GreasePencilModifierMaterialFilter;
typedef enum GreasePencilModifierFilterFlag {
GREASE_PENCIL_FILTER_USE_LAYER_PASS = (1 << 0),
GREASE_PENCIL_FILTER_USE_MATERIAL_PASS = (1 << 1),
GREASE_PENCIL_FILTER_INVERT_LAYER = (1 << 2),
GREASE_PENCIL_FILTER_INVERT_LAYER_PASS = (1 << 3),
GREASE_PENCIL_FILTER_INVERT_MATERIAL = (1 << 4),
GREASE_PENCIL_FILTER_INVERT_LAYER = (1 << 0),
GREASE_PENCIL_FILTER_USE_LAYER_PASS = (1 << 1),
GREASE_PENCIL_FILTER_INVERT_LAYER_PASS = (1 << 2),
GREASE_PENCIL_FILTER_INVERT_MATERIAL = (1 << 3),
GREASE_PENCIL_FILTER_USE_MATERIAL_PASS = (1 << 4),
GREASE_PENCIL_FILTER_INVERT_MATERIAL_PASS = (1 << 5),
} GreasePencilModifierFilterFlag;
/**
* Combined generic influence data for grease pencil modifiers.
* Not all parts may be used by all modifier types.
*/
typedef struct GreasePencilModifierInfluenceData {
GreasePencilModifierLayerFilter layer_filter;
GreasePencilModifierMaterialFilter material_filter;
} GreasePencilModifierInfluenceData;
typedef struct GreasePencilOpacityModifierData {
ModifierData modifier;
GreasePencilModifierInfluenceData influence;
/** GreasePencilOpacityModifierFlag */
int flag;
char _pad1[4];
GreasePencilModifierFilterData filter;
void *_pad2;
} GreasePencilOpacityModifierData;

View File

@ -1713,7 +1713,7 @@ static IDProperty **rna_NodesModifier_properties(PointerRNA *ptr)
return &settings->properties;
}
bool rna_GreasePencilModifierFilter_material_poll(PointerRNA *ptr, PointerRNA value)
bool rna_GreasePencilModifierMaterialFilter_material_poll(PointerRNA *ptr, PointerRNA value)
{
Object *ob = reinterpret_cast<Object *>(ptr->owner_id);
Material *ma = reinterpret_cast<Material *>(value.owner_id);
@ -1721,18 +1721,18 @@ bool rna_GreasePencilModifierFilter_material_poll(PointerRNA *ptr, PointerRNA va
return BKE_grease_pencil_object_material_index_get(ob, ma) != -1;
}
static void rna_GreasePencilModifierFilter_material_set(PointerRNA *ptr,
PointerRNA value,
ReportList *reports)
static void rna_GreasePencilModifierMaterialFilter_material_set(PointerRNA *ptr,
PointerRNA value,
ReportList *reports)
{
Object *ob = reinterpret_cast<Object *>(ptr->owner_id);
GreasePencilModifierFilterData *filter_data = static_cast<GreasePencilModifierFilterData *>(
GreasePencilModifierMaterialFilter *filter = static_cast<GreasePencilModifierMaterialFilter *>(
ptr->data);
Material *ma = reinterpret_cast<Material *>(value.owner_id);
if (ma == nullptr || BKE_grease_pencil_object_material_index_get(ob, ma) != -1) {
id_lib_extern(reinterpret_cast<ID *>(ob));
filter_data->material = ma;
filter->material = ma;
}
else {
BKE_reportf(
@ -7461,15 +7461,16 @@ static void rna_def_modifier_volume_to_mesh(BlenderRNA *brna)
RNA_define_lib_overridable(false);
}
static void rna_def_modifier_grease_pencil_filter(BlenderRNA *brna)
static void rna_def_modifier_grease_pencil_layer_filter(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "GreasePencilModifierFilter", nullptr);
RNA_def_struct_ui_text(
srna, "Grease Pencil Modifier Filter", "Filter settings for grease pencil modifiers");
RNA_def_struct_sdna(srna, "GreasePencilModifierFilterData");
srna = RNA_def_struct(brna, "GreasePencilModifierLayerFilter", nullptr);
RNA_def_struct_ui_text(srna,
"Grease Pencil Modifier Layer Filter",
"Layer filter settings for grease pencil modifiers");
RNA_def_struct_sdna(srna, "GreasePencilModifierLayerFilter");
RNA_define_lib_overridable(true);
@ -7499,13 +7500,29 @@ static void rna_def_modifier_grease_pencil_filter(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Invert Layer Pass", "Invert layer pass filter");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
RNA_define_lib_overridable(false);
}
static void rna_def_modifier_grease_pencil_material_filter(BlenderRNA *brna)
{
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "GreasePencilModifierMaterialFilter", nullptr);
RNA_def_struct_ui_text(srna,
"Grease Pencil Modifier Material Filter",
"Material filter settings for grease pencil modifiers");
RNA_def_struct_sdna(srna, "GreasePencilModifierMaterialFilter");
RNA_define_lib_overridable(true);
prop = RNA_def_property(srna, "material", PROP_POINTER, PROP_NONE);
RNA_def_property_flag(prop, PROP_EDITABLE);
RNA_def_property_pointer_funcs(prop,
nullptr,
"rna_GreasePencilModifierFilter_material_set",
"rna_GreasePencilModifierMaterialFilter_material_set",
nullptr,
"rna_GreasePencilModifierFilter_material_poll");
"rna_GreasePencilModifierMaterialFilter_material_poll");
RNA_def_property_ui_text(prop, "Material", "Material used for filtering");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
@ -7533,6 +7550,27 @@ static void rna_def_modifier_grease_pencil_filter(BlenderRNA *brna)
RNA_define_lib_overridable(false);
}
/** Utility function to register common influence properties for grease pencil modifiers. */
static void rna_def_modifier_grease_pencil_influence_properties(StructRNA *srna,
const char *layer_filter_sdna,
const char *material_filter_sdna)
{
PropertyRNA *prop;
if (layer_filter_sdna) {
prop = RNA_def_property(srna, "layer_filter", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, nullptr, layer_filter_sdna);
RNA_def_property_struct_type(prop, "GreasePencilModifierLayerFilter");
RNA_def_property_ui_text(prop, "Layer Filter", "Layer filter settings");
}
if (material_filter_sdna) {
prop = RNA_def_property(srna, "material_filter", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, nullptr, material_filter_sdna);
RNA_def_property_struct_type(prop, "GreasePencilModifierMaterialFilter");
RNA_def_property_ui_text(prop, "Material Filter", "Material filter settings");
}
}
static void rna_def_modifier_grease_pencil_opacity(BlenderRNA *brna)
{
StructRNA *srna;
@ -7543,10 +7581,8 @@ static void rna_def_modifier_grease_pencil_opacity(BlenderRNA *brna)
RNA_def_struct_sdna(srna, "GreasePencilOpacityModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_OPACITY);
prop = RNA_def_property(srna, "filter", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, nullptr, "filter");
RNA_def_property_struct_type(prop, "GreasePencilModifierFilter");
RNA_def_property_ui_text(prop, "Filter", "Filter settings");
rna_def_modifier_grease_pencil_influence_properties(
srna, "influence.layer_filter", "influence.material_filter");
prop = RNA_def_property(srna, "open_influence_panel", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(
@ -7723,7 +7759,8 @@ void RNA_def_modifier(BlenderRNA *brna)
rna_def_modifier_volume_displace(brna);
rna_def_modifier_volume_to_mesh(brna);
rna_def_modifier_grease_pencil_opacity(brna);
rna_def_modifier_grease_pencil_filter(brna);
rna_def_modifier_grease_pencil_layer_filter(brna);
rna_def_modifier_grease_pencil_material_filter(brna);
}
#endif

View File

@ -59,7 +59,7 @@ static void init_data(ModifierData *md)
sizeof(*(omd)) - OFFSETOF_STRUCT_AFTER(omd, modifier));
}
LukasTonne marked this conversation as resolved Outdated

You can write const auto * with the cast, it might keep it on one line

You can write `const auto *` with the cast, it might keep it on one line
greasepencil::init_filter_data(&omd->filter);
greasepencil::init_influence_data(&omd->influence);
}
static void copy_data(const ModifierData *md, ModifierData *target, const int flag)
@ -68,7 +68,7 @@ static void copy_data(const ModifierData *md, ModifierData *target, const int fl
GreasePencilOpacityModifierData *tomd = (GreasePencilOpacityModifierData *)target;
BKE_modifier_copydata_generic(md, target, flag);
greasepencil::copy_filter_data(&omd->filter, &tomd->filter, flag);
greasepencil::copy_influence_data(&omd->influence, &tomd->influence, flag);
}
static void required_data_mask(ModifierData *md, CustomData_MeshMasks *r_cddata_masks)
@ -82,14 +82,14 @@ static void required_data_mask(ModifierData *md, CustomData_MeshMasks *r_cddata_
static void foreach_ID_link(ModifierData *md, Object *ob, IDWalkFunc walk, void *user_data)
{
LukasTonne marked this conversation as resolved
Review

You should just be able to retrieve the vertex group as an attribute

You should just be able to retrieve the vertex group as an attribute
Review

Took some explaining from @filedescriptor how this works (maybe a good topic for technical docs?). As far as i understand the VArray wrapper for the curves->deform_verts() is ok here, since we're only using a single vertex group. For something like the armature modifier i'd guess we still want to use the MDeformVert directly.

Took some explaining from @filedescriptor how this works (maybe a good topic for technical docs?). As far as i understand the `VArray` wrapper for the `curves->deform_verts()` is ok here, since we're only using a single vertex group. For something like the armature modifier i'd guess we still want to use the `MDeformVert` directly.
Review

Right, exactly

Right, exactly
GreasePencilOpacityModifierData *omd = (GreasePencilOpacityModifierData *)md;
greasepencil::foreach_filter_ID_link(&omd->filter, ob, walk, user_data);
greasepencil::foreach_influence_ID_link(&omd->influence, ob, walk, user_data);
}
static void free_data(ModifierData *md)
{
GreasePencilOpacityModifierData *omd = (GreasePencilOpacityModifierData *)md;
greasepencil::free_filter_data(&omd->filter);
greasepencil::free_influence_data(&omd->influence);
}
static void modify_curves(ModifierData *md,
@ -105,7 +105,7 @@ static void modify_curves(ModifierData *md,
OffsetIndices<int> points_by_curve = curves.points_by_curve();
IndexMaskMemory mask_memory;
IndexMask curves_mask = greasepencil::get_filtered_stroke_mask(
ctx->object, curves, omd->filter, mask_memory);
ctx->object, curves, omd->influence.material_filter, mask_memory);
for (const int64_t i : curves_mask.index_range()) {
const int64_t curve_i = curves_mask[i];
for (const int64_t point_i : points_by_curve[curve_i]) {
@ -131,7 +131,7 @@ static void modify_geometry_set(ModifierData *md,
IndexMaskMemory mask_memory;
IndexMask layer_mask = greasepencil::get_filtered_layer_mask(
*grease_pencil, omd->filter, mask_memory);
*grease_pencil, omd->influence.layer_filter, mask_memory);

Wondering if this could be made much clean by using DefaultMixer?

Wondering if this could be made much clean by using `DefaultMixer`?

That seems a bit unnecessary here.

  • The attributes are all floats, no need to handle different types.
  • The math is weird and undocumented. In the "uniform" mode it uses 1 - current as some kind of cutoff point, and then allows ramping up the influence to 2.0, presumably so one can reach full opacity/hardness again. It all seems very ad-hoc.

I'd prefer to not try and "fix" this too much, since the primary purpose is compatibility with GP2.

That seems a bit unnecessary here. - The attributes are all floats, no need to handle different types. - The math is weird and undocumented. In the "uniform" mode it uses `1 - current` as some kind of cutoff point, and then allows ramping up the influence to 2.0, presumably so one can reach full opacity/hardness again. It all seems very ad-hoc. I'd prefer to not try and "fix" this too much, since the primary purpose is compatibility with GP2.
Vector<Drawing *> drawings = greasepencil::get_drawings_for_write(
*grease_pencil, layer_mask, frame);
for (Drawing *drawing : drawings) {
@ -149,8 +149,10 @@ static void panel_draw(const bContext *C, Panel *panel)
if (uiLayout *influence_panel = uiLayoutPanel(
C, layout, "Influence", ptr, "open_influence_panel"))
{
PointerRNA filter_ptr = RNA_pointer_get(ptr, "filter");
greasepencil::draw_filter_settings(C, influence_panel, &filter_ptr);
PointerRNA layer_filter_ptr = RNA_pointer_get(ptr, "layer_filter");
PointerRNA material_filter_ptr = RNA_pointer_get(ptr, "material_filter");
greasepencil::draw_layer_filter_settings(C, influence_panel, &layer_filter_ptr);
greasepencil::draw_material_filter_settings(C, influence_panel, &material_filter_ptr);
}
uiLayoutSetPropSep(layout, true);

View File

@ -36,31 +36,30 @@ namespace blender::greasepencil {
using bke::greasepencil::Drawing;
using bke::greasepencil::Layer;
void init_filter_data(GreasePencilModifierFilterData * /*filter_data*/) {}
void init_influence_data(GreasePencilModifierInfluenceData * /*influence_data*/) {}
void copy_filter_data(const GreasePencilModifierFilterData *filter_data_src,
GreasePencilModifierFilterData *filter_data_dst,
const int /*flag*/)
void copy_influence_data(const GreasePencilModifierInfluenceData *influence_data_src,
GreasePencilModifierInfluenceData *influence_data_dst,
const int /*flag*/)
{
memcpy(filter_data_dst, filter_data_src, sizeof(GreasePencilModifierFilterData));
memcpy(influence_data_dst, influence_data_src, sizeof(GreasePencilModifierInfluenceData));
}
void free_filter_data(GreasePencilModifierFilterData * /*filter_data*/) {}
void free_influence_data(GreasePencilModifierInfluenceData * /*influence_data*/) {}
void foreach_filter_ID_link(GreasePencilModifierFilterData *filter_data,
Object *ob,
IDWalkFunc walk,
void *user_data)
void foreach_influence_ID_link(GreasePencilModifierInfluenceData *influence_data,
Object *ob,
IDWalkFunc walk,
void *user_data)
{
walk(user_data, ob, (ID **)&filter_data->material, IDWALK_CB_USER);
walk(user_data, ob, (ID **)&influence_data->material_filter.material, IDWALK_CB_USER);
}
void draw_filter_settings(const bContext * /*C*/, uiLayout *layout, PointerRNA *ptr)
void draw_layer_filter_settings(const bContext * /*C*/, uiLayout *layout, PointerRNA *ptr)
{
PointerRNA ob_ptr = RNA_pointer_create(ptr->owner_id, &RNA_Object, ptr->owner_id);
PointerRNA obj_data_ptr = RNA_pointer_get(&ob_ptr, "data");
const bool use_layer_pass = RNA_boolean_get(ptr, "use_layer_pass");
const bool use_material_pass = RNA_boolean_get(ptr, "use_material_pass");
uiLayout *row, *col, *sub;
uiLayoutSetPropSep(layout, true);
@ -81,6 +80,16 @@ void draw_filter_settings(const bContext * /*C*/, uiLayout *layout, PointerRNA *
sub = uiLayoutRow(row, true);
uiLayoutSetPropDecorate(sub, false);
uiItemR(sub, ptr, "invert_layer_pass", UI_ITEM_NONE, "", ICON_ARROW_LEFTRIGHT);
}
void draw_material_filter_settings(const bContext * /*C*/, uiLayout *layout, PointerRNA *ptr)
{
PointerRNA ob_ptr = RNA_pointer_create(ptr->owner_id, &RNA_Object, ptr->owner_id);
PointerRNA obj_data_ptr = RNA_pointer_get(&ob_ptr, "data");
const bool use_material_pass = RNA_boolean_get(ptr, "use_material_pass");
uiLayout *row, *col, *sub;
uiLayoutSetPropSep(layout, true);
col = uiLayoutColumn(layout, true);
row = uiLayoutRow(col, true);
@ -157,18 +166,18 @@ static IndexMask get_filtered_layer_mask(const GreasePencil &grease_pencil,
}
IndexMask get_filtered_layer_mask(const GreasePencil &grease_pencil,
const GreasePencilModifierFilterData &filter_data,
const GreasePencilModifierLayerFilter &filter,
IndexMaskMemory &memory)
{
return get_filtered_layer_mask(grease_pencil,
filter_data.layer_name[0] != '\0' ?
std::make_optional<StringRef>(filter_data.layer_name) :
filter.layer_name[0] != '\0' ?
std::make_optional<StringRef>(filter.layer_name) :
std::nullopt,
(filter_data.flag & GREASE_PENCIL_FILTER_USE_LAYER_PASS) ?
std::make_optional<int>(filter_data.layer_pass) :
(filter.flag & GREASE_PENCIL_FILTER_USE_LAYER_PASS) ?
std::make_optional<int>(filter.layer_pass) :
std::nullopt,
filter_data.flag & GREASE_PENCIL_FILTER_INVERT_LAYER,
filter_data.flag & GREASE_PENCIL_FILTER_INVERT_LAYER_PASS,
filter.flag & GREASE_PENCIL_FILTER_INVERT_LAYER,
filter.flag & GREASE_PENCIL_FILTER_INVERT_LAYER_PASS,
memory);
}
@ -216,18 +225,18 @@ static IndexMask get_filtered_stroke_mask(const Object *ob,
IndexMask get_filtered_stroke_mask(const Object *ob,
const bke::CurvesGeometry &curves,
const GreasePencilModifierFilterData &filter_data,
const GreasePencilModifierMaterialFilter &filter,
IndexMaskMemory &memory)
{
/* TODO Add an option to toggle pass filter on and off, instead of using "pass > 0". */
return get_filtered_stroke_mask(ob,
curves,
filter_data.material,
(filter_data.flag & GREASE_PENCIL_FILTER_USE_MATERIAL_PASS) ?
std::make_optional<int>(filter_data.material_pass) :
filter.material,
(filter.flag & GREASE_PENCIL_FILTER_USE_MATERIAL_PASS) ?
std::make_optional<int>(filter.material_pass) :
std::nullopt,
filter_data.flag & GREASE_PENCIL_FILTER_INVERT_MATERIAL,
filter_data.flag & GREASE_PENCIL_FILTER_INVERT_MATERIAL_PASS,
filter.flag & GREASE_PENCIL_FILTER_INVERT_MATERIAL,
filter.flag & GREASE_PENCIL_FILTER_INVERT_MATERIAL_PASS,
memory);
}

View File

@ -16,7 +16,9 @@
struct ARegionType;
struct bContext;
struct GreasePencil;
struct GreasePencilModifierFilterData;
struct GreasePencilModifierInfluenceData;
struct GreasePencilModifierLayerFilter;
struct GreasePencilModifierMaterialFilter;
struct PanelType;
struct PointerRNA;
struct uiLayout;
@ -29,25 +31,26 @@ class Drawing;
namespace blender::greasepencil {
void init_filter_data(GreasePencilModifierFilterData *filter_data);
void copy_filter_data(const GreasePencilModifierFilterData *filter_data_src,
GreasePencilModifierFilterData *filter_data_dst,
int flag);
void free_filter_data(GreasePencilModifierFilterData *filter_data);
void foreach_filter_ID_link(GreasePencilModifierFilterData *filter_data,
Object *ob,
IDWalkFunc walk,
void *user_data);
void init_influence_data(GreasePencilModifierInfluenceData *influence_data);
void copy_influence_data(const GreasePencilModifierInfluenceData *influence_data_src,
GreasePencilModifierInfluenceData *influence_data_dst,
int flag);
void free_influence_data(GreasePencilModifierInfluenceData *influence_data);
void foreach_influence_ID_link(GreasePencilModifierInfluenceData *influence_data,
Object *ob,
IDWalkFunc walk,
void *user_data);
void draw_filter_settings(const bContext *C, uiLayout *layout, PointerRNA *ptr);
void draw_layer_filter_settings(const bContext *C, uiLayout *layout, PointerRNA *ptr);
void draw_material_filter_settings(const bContext *C, uiLayout *layout, PointerRNA *ptr);
IndexMask get_filtered_layer_mask(const GreasePencil &grease_pencil,
const GreasePencilModifierFilterData &filter_data,
const GreasePencilModifierLayerFilter &filter,
IndexMaskMemory &memory);
IndexMask get_filtered_stroke_mask(const Object *ob,
const bke::CurvesGeometry &curves,
const GreasePencilModifierFilterData &filter_data,
const GreasePencilModifierMaterialFilter &filter,
IndexMaskMemory &memory);
Vector<bke::greasepencil::Drawing *> get_drawings_for_write(GreasePencil &grease_pencil,