GPv3: Add Catmull-Clark option in subdivide modifier

This adds the "Catmull-Clark" option to the subdivide modifier.
Since this option is creating 2^n segments, the "Simple" method was adjusted to do the same.
This is now consistent with the old GPv2 modifier.

Pull Request: https://projects.blender.org/blender/blender/pulls/117382
This commit is contained in:
YimingWu
2024-01-24 13:14:07 +01:00
committed by Falk David
parent d5766dfdce
commit 756f7cf1e8
3 changed files with 52 additions and 14 deletions

View File

@@ -2554,18 +2554,19 @@ typedef enum GreasePencilOpacityModifierFlag {
typedef struct GreasePencilSubdivModifierData {
ModifierData modifier;
GreasePencilModifierInfluenceData influence;
/** `GreasePencilSubdivModifierFlag`. */
int flag;
/** Number of subdivisions. */
/** #GreasePencilSubdivideType. */
int type;
/** Level of subdivisions, will generate 2^level segments. */
int level;
char _pad[8];
void *_pad1;
} GreasePencilSubdivModifierData;
typedef enum GreasePencilSubdivModifierFlag {
MOD_GREASE_PENCIL_SUBDIV_OPEN_INFLUENCE_PANEL = (1 << 0),
} GreasePencilSubdivModifierFlag;
typedef enum GreasePencilSubdivideType {
MOD_GREASE_PENCIL_SUBDIV_CATMULL = 0,
MOD_GREASE_PENCIL_SUBDIV_SIMPLE = 1,
} GreasePencilSubdivideType;
typedef struct GreasePencilColorModifierData {
ModifierData modifier;

View File

@@ -7776,6 +7776,12 @@ static void rna_def_modifier_grease_pencil_subdiv(BlenderRNA *brna)
StructRNA *srna;
PropertyRNA *prop;
static const EnumPropertyItem subdivision_type_items[] = {
{MOD_GREASE_PENCIL_SUBDIV_CATMULL, "CATMULL_CLARK", 0, "Catmull-Clark", ""},
{MOD_GREASE_PENCIL_SUBDIV_SIMPLE, "SIMPLE", 0, "Simple", ""},
{0, nullptr, 0, nullptr, nullptr},
};
srna = RNA_def_struct(brna, "GreasePencilSubdivModifier", "Modifier");
RNA_def_struct_ui_text(srna, "Subdivision Modifier", "Subdivide Stroke modifier");
RNA_def_struct_sdna(srna, "GreasePencilSubdivModifierData");
@@ -7793,11 +7799,16 @@ static void rna_def_modifier_grease_pencil_subdiv(BlenderRNA *brna)
prop = RNA_def_property(srna, "level", PROP_INT, PROP_NONE);
RNA_def_property_int_sdna(prop, nullptr, "level");
/* Since the new subdiv algorithm uses linear cut count, we set the limits as 2^n the old value
* to get the same range as before. */
RNA_def_property_range(prop, 0, 65536);
RNA_def_property_ui_range(prop, 0, 32, 1, 0);
RNA_def_property_ui_text(prop, "Level", "Number of subdivisions");
RNA_def_property_range(prop, 0, 16);
RNA_def_property_ui_range(prop, 0, 6, 1, 0);
RNA_def_property_ui_text(prop, "Level", "Level of subdivision");
prop = RNA_def_property(srna, "subdivision_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, nullptr, "type");
RNA_def_property_enum_items(prop, subdivision_type_items);
RNA_def_property_ui_text(prop, "Subdivision Type", "Select type of subdivision algorithm");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
RNA_define_lib_overridable(false);

View File

@@ -80,15 +80,40 @@ static void blend_read(BlendDataReader *reader, ModifierData *md)
static void subdivide_drawing(ModifierData &md, Object &ob, bke::greasepencil::Drawing &drawing)
{
GreasePencilSubdivModifierData &mmd = reinterpret_cast<GreasePencilSubdivModifierData &>(md);
const bool use_catmull_clark = mmd.type == MOD_GREASE_PENCIL_SUBDIV_CATMULL;
IndexMaskMemory memory;
const IndexMask strokes = modifier::greasepencil::get_filtered_stroke_mask(
&ob, drawing.strokes_for_write(), mmd.influence, memory);
const VArray<int> cuts = VArray<int>::ForSingle(mmd.level, drawing.strokes().points_num());
if (use_catmull_clark) {
bke::CurvesGeometry subdivided_curves = drawing.strokes();
for ([[maybe_unused]] const int level_i : IndexRange(mmd.level)) {
VArray<int> one_cut = VArray<int>::ForSingle(1, subdivided_curves.points_num());
subdivided_curves = geometry::subdivide_curves(
subdivided_curves, strokes, std::move(one_cut), {});
offset_indices::OffsetIndices<int> points_by_curve = subdivided_curves.points_by_curve();
MutableSpan<float3> positions = subdivided_curves.positions_for_write();
threading::parallel_for(subdivided_curves.curves_range(), 1024, [&](const IndexRange range) {
for (const int curve_i : range) {
const IndexRange points = points_by_curve[curve_i];
for (const int point_i : points.drop_front(1).drop_back(1)) {
positions[point_i] = math::interpolate(
positions[point_i],
math::interpolate(positions[point_i - 1], positions[point_i + 1], 0.5f),
0.5f);
}
}
});
}
drawing.strokes_for_write() = subdivided_curves;
}
else {
VArray<int> cuts = VArray<int>::ForSingle(math::pow(mmd.level,2), drawing.strokes().points_num());
drawing.strokes_for_write() = geometry::subdivide_curves(drawing.strokes(), strokes, cuts, {});
}
drawing.strokes_for_write() = geometry::subdivide_curves(
drawing.strokes(), strokes, std::move(cuts), {});
drawing.tag_topology_changed();
}
@@ -131,6 +156,7 @@ static void panel_draw(const bContext *C, Panel *panel)
uiLayoutSetPropSep(layout, true);
uiItemR(layout, ptr, "subdivision_type", UI_ITEM_NONE, nullptr, ICON_NONE);
uiItemR(layout, ptr, "level", UI_ITEM_NONE, IFACE_("Subdivisions"), ICON_NONE);
if (uiLayout *influence_panel = uiLayoutPanel(