From ee9a0f60141794fb7efd6b4e3f7c90da4dc6cfb8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Tue, 6 Feb 2024 12:36:17 +0100 Subject: [PATCH] GPv3: Handle vertex groups in the GPv2 conversion operator Copies vertex group names from the GPv2 object to the new GPv3 GreasePencil data block. Copies only those names to the drawings that are actually used by any of the strokes. Updates group indices in `MDeformVert` data to point to local Drawing groups. Pull Request: https://projects.blender.org/blender/blender/pulls/117860 --- .../blender/blenkernel/BKE_grease_pencil.hh | 1 + .../intern/grease_pencil_convert_legacy.cc | 78 ++++++++++++++++++- 2 files changed, 78 insertions(+), 1 deletion(-) diff --git a/source/blender/blenkernel/BKE_grease_pencil.hh b/source/blender/blenkernel/BKE_grease_pencil.hh index 549e1276465..2322df93546 100644 --- a/source/blender/blenkernel/BKE_grease_pencil.hh +++ b/source/blender/blenkernel/BKE_grease_pencil.hh @@ -706,6 +706,7 @@ TREENODE_COMMON_METHODS_FORWARD_IMPL(LayerGroup); namespace convert { void legacy_gpencil_frame_to_grease_pencil_drawing(const bGPDframe &gpf, + const ListBase &vertex_group_names, GreasePencilDrawing &r_drawing); void legacy_gpencil_to_grease_pencil(Main &main, GreasePencil &grease_pencil, bGPdata &gpd); diff --git a/source/blender/blenkernel/intern/grease_pencil_convert_legacy.cc b/source/blender/blenkernel/intern/grease_pencil_convert_legacy.cc index 88d65c8ccc2..6749724faee 100644 --- a/source/blender/blenkernel/intern/grease_pencil_convert_legacy.cc +++ b/source/blender/blenkernel/intern/grease_pencil_convert_legacy.cc @@ -8,6 +8,7 @@ #include "BKE_attribute.hh" #include "BKE_curves.hh" +#include "BKE_deform.hh" #include "BKE_grease_pencil.hh" #include "BKE_material.h" @@ -19,10 +20,52 @@ #include "DNA_gpencil_legacy_types.h" #include "DNA_grease_pencil_types.h" +#include "DNA_meshdata_types.h" namespace blender::bke::greasepencil::convert { +/** + * Find vertex groups that have assigned vertices in this drawing. + * Returns: + * - ListBase with used vertex group names (bDeformGroup) + * - Array of indices in the new vertex group list for remapping + */ +static void find_used_vertex_groups(const bGPDframe &gpf, + const ListBase &all_names, + ListBase &r_vertex_group_names, + Array &r_indices) +{ + const int num_vertex_groups = BLI_listbase_count(&all_names); + Array is_group_used(num_vertex_groups, false); + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf.strokes) { + if (!gps->dvert) { + continue; + } + Span dverts = {gps->dvert, gps->totpoints}; + for (const MDeformVert &dvert : dverts) { + for (const MDeformWeight &weight : Span{dvert.dw, dvert.totweight}) { + is_group_used[weight.def_nr] = true; + } + } + } + BLI_listbase_clear(&r_vertex_group_names); + r_indices.reinitialize(num_vertex_groups); + int new_group_i = 0; + int old_group_i; + LISTBASE_FOREACH_INDEX (const bDeformGroup *, def_group, &all_names, old_group_i) { + if (!is_group_used[old_group_i]) { + r_indices[old_group_i] = -1; + continue; + } + r_indices[old_group_i] = new_group_i++; + + bDeformGroup *def_group_copy = static_cast(MEM_dupallocN(def_group)); + BLI_addtail(&r_vertex_group_names, def_group_copy); + } +} + void legacy_gpencil_frame_to_grease_pencil_drawing(const bGPDframe &gpf, + const ListBase &vertex_group_names, GreasePencilDrawing &r_drawing) { /* Construct an empty CurvesGeometry in-place. */ @@ -54,6 +97,25 @@ void legacy_gpencil_frame_to_grease_pencil_drawing(const bGPDframe &gpf, /* All strokes are poly curves. */ curves.fill_curve_types(CURVE_TYPE_POLY); + /* Find used vertex groups in this drawing. */ + ListBase stroke_vertex_group_names; + Array stroke_def_nr_map; + find_used_vertex_groups(gpf, vertex_group_names, stroke_vertex_group_names, stroke_def_nr_map); + BLI_assert(BLI_listbase_is_empty(&curves.vertex_group_names)); + curves.vertex_group_names = stroke_vertex_group_names; + const bool use_dverts = !BLI_listbase_is_empty(&curves.vertex_group_names); + + /* Copy vertex weights and map the vertex group indices. */ + auto copy_dvert = [&](const MDeformVert &src_dvert, MDeformVert &dst_dvert) { + dst_dvert = src_dvert; + dst_dvert.dw = static_cast(MEM_dupallocN(src_dvert.dw)); + const MutableSpan vertex_weights = {dst_dvert.dw, dst_dvert.totweight}; + for (MDeformWeight &weight : vertex_weights) { + /* Map def_nr to the reduced vertex group list. */ + weight.def_nr = stroke_def_nr_map[weight.def_nr]; + } + }; + /* Point Attributes. */ MutableSpan positions = curves.positions_for_write(); MutableSpan radii = drawing.radii_for_write(); @@ -66,6 +128,8 @@ void legacy_gpencil_frame_to_grease_pencil_drawing(const bGPDframe &gpf, attributes.lookup_or_add_for_write_span("vertex_color", AttrDomain::Point); SpanAttributeWriter selection = attributes.lookup_or_add_for_write_span( ".selection", AttrDomain::Point); + MutableSpan dverts = use_dverts ? curves.wrap().deform_verts_for_write() : + MutableSpan(); /* Curve Attributes. */ SpanAttributeWriter stroke_cyclic = attributes.lookup_or_add_for_write_span( @@ -126,6 +190,8 @@ void legacy_gpencil_frame_to_grease_pencil_drawing(const bGPDframe &gpf, MutableSpan stroke_vertex_colors = vertex_colors.span.slice( stroke_points_range); MutableSpan stroke_selections = selection.span.slice(stroke_points_range); + MutableSpan stroke_dverts = use_dverts ? dverts.slice(stroke_points_range) : + MutableSpan(); /* Do first point. */ const bGPDspoint &first_pt = stroke_points.first(); @@ -143,6 +209,9 @@ void legacy_gpencil_frame_to_grease_pencil_drawing(const bGPDframe &gpf, stroke_rotations.first() = first_pt.uv_rot; stroke_vertex_colors.first() = ColorGeometry4f(first_pt.vert_color); stroke_selections.first() = (first_pt.flag & GP_SPOINT_SELECT) != 0; + if (use_dverts && gps->dvert) { + copy_dvert(gps->dvert[0], stroke_dverts.first()); + } /* Do the rest of the points. */ for (const int i : stroke_points.index_range().drop_back(1)) { @@ -156,6 +225,9 @@ void legacy_gpencil_frame_to_grease_pencil_drawing(const bGPDframe &gpf, stroke_rotations[point_i] = pt.uv_rot; stroke_vertex_colors[point_i] = ColorGeometry4f(pt.vert_color); stroke_selections[point_i] = (pt.flag & GP_SPOINT_SELECT) != 0; + if (use_dverts && gps->dvert) { + copy_dvert(gps->dvert[point_i], stroke_dverts[point_i]); + } } } @@ -225,7 +297,7 @@ void legacy_gpencil_to_grease_pencil(Main &bmain, GreasePencil &grease_pencil, b grease_pencil.drawing_array[i]); /* Convert the frame to a drawing. */ - legacy_gpencil_frame_to_grease_pencil_drawing(*gpf, drawing); + legacy_gpencil_frame_to_grease_pencil_drawing(*gpf, gpd.vertex_group_names, drawing); /* Add the frame to the layer. */ if (GreasePencilFrame *new_frame = new_layer.add_frame(gpf->framenum, i)) { @@ -242,6 +314,10 @@ void legacy_gpencil_to_grease_pencil(Main &bmain, GreasePencil &grease_pencil, b /* TODO: Update drawing user counts. */ } + /* Copy vertex group names and settings. */ + BKE_defgroup_copy_list(&grease_pencil.vertex_group_names, &gpd.vertex_group_names); + grease_pencil.vertex_group_active_index = gpd.vertex_group_active_index; + /* Convert the onion skinning settings. */ grease_pencil.onion_skinning_settings.opacity = gpd.onion_factor; grease_pencil.onion_skinning_settings.mode = gpd.onion_mode;