GPv3: Handle vertex groups in the GPv2 conversion operator #117860

Merged
Lukas Tönne merged 12 commits from LukasTonne/blender:gp3-vertex-group-conversion into main 2024-02-06 12:36:26 +01:00
2 changed files with 78 additions and 1 deletions

View File

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

View File

@ -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,
LukasTonne marked this conversation as resolved Outdated

I suppose this might as well be std::pair

I suppose this might as well be `std::pair`

No practical advantage that i know of to use pair instead of tuple. pair implies a deeper reason there's 2 of them, which is not the case. I just prefer tuple for this purpose.

No practical advantage that i know of to use `pair` instead of `tuple`. `pair` implies a deeper reason there's 2 of them, which is not the case. I just prefer tuple for this purpose.
const ListBase &all_names,
ListBase &r_vertex_group_names,
Array<int> &r_indices)
{
LukasTonne marked this conversation as resolved Outdated

Vector -> Array here since it isn't grown or resized

`Vector` -> `Array` here since it isn't grown or resized
const int num_vertex_groups = BLI_listbase_count(&all_names);
Array<int> is_group_used(num_vertex_groups, false);
LISTBASE_FOREACH (bGPDstroke *, gps, &gpf.strokes) {
if (!gps->dvert) {
continue;
}
Span<MDeformVert> dverts = {gps->dvert, gps->totpoints};
for (const MDeformVert &dvert : dverts) {
LukasTonne marked this conversation as resolved
Review

Should we check if the weight is > 0 ?

Should we check if the weight is > 0 ?
Review

I think this might alter behavior in cases where the vertex weight is ignored and only membership in the group is taken into account. Not sure if such cases exist in GP2 modifiers, but i'd rather forego some minor optimization and be safe in this regard.

I think this might alter behavior in cases where the vertex weight is ignored and only membership in the group is taken into account. Not sure if such cases exist in GP2 modifiers, but i'd rather forego some minor optimization and be safe in this regard.
for (const MDeformWeight &weight : Span<MDeformWeight>{dvert.dw, dvert.totweight}) {
is_group_used[weight.def_nr] = true;
}
}
}
BLI_listbase_clear(&r_vertex_group_names);
LukasTonne marked this conversation as resolved Outdated

Array here too

`Array` here too
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<bDeformGroup *>(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<int> 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<MDeformWeight *>(MEM_dupallocN(src_dvert.dw));
const MutableSpan<MDeformWeight> vertex_weights = {dst_dvert.dw, dst_dvert.totweight};
for (MDeformWeight &weight : vertex_weights) {
/* Map def_nr to the reduced vertex group list. */
LukasTonne marked this conversation as resolved
Review

Apparently apple builds don't like this:
https://builder.blender.org/admin/#/builders/134/builds/3618

error: capturing a structured binding is not yet supported in OpenMP

Apparently apple builds don't like this: https://builder.blender.org/admin/#/builders/134/builds/3618 > error: capturing a structured binding is not yet supported in OpenMP
Review

Probably an clang bug: https://github.com/llvm/llvm-project/issues/66999
Using C style return values now.

Probably an clang bug: https://github.com/llvm/llvm-project/issues/66999 Using C style return values now.
weight.def_nr = stroke_def_nr_map[weight.def_nr];
}
};
/* Point Attributes. */
MutableSpan<float3> positions = curves.positions_for_write();
MutableSpan<float> 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<ColorGeometry4f>("vertex_color", AttrDomain::Point);
SpanAttributeWriter<bool> selection = attributes.lookup_or_add_for_write_span<bool>(
".selection", AttrDomain::Point);
MutableSpan<MDeformVert> dverts = use_dverts ? curves.wrap().deform_verts_for_write() :
MutableSpan<MDeformVert>();
/* Curve Attributes. */
SpanAttributeWriter<bool> stroke_cyclic = attributes.lookup_or_add_for_write_span<bool>(
@ -126,6 +190,8 @@ void legacy_gpencil_frame_to_grease_pencil_drawing(const bGPDframe &gpf,
MutableSpan<ColorGeometry4f> stroke_vertex_colors = vertex_colors.span.slice(
stroke_points_range);
MutableSpan<bool> stroke_selections = selection.span.slice(stroke_points_range);
MutableSpan<MDeformVert> stroke_dverts = use_dverts ? dverts.slice(stroke_points_range) :
MutableSpan<MDeformVert>();
/* 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;