Fix #139258: Grease Pencil: Strokes lose deform groups when moved to another layer

Strokes would lose their deform group values after moving them to a
different layer, because `vertex_group_names` weren't transferred to
the newly created `CurvesGeometry` inside `execute_realize_curve_tasks`.

This commit adds another version of `copy_vertex_group_names` for
Curves, and separates the duplicate code into `copy_vertex_group_name`,
which is used by both meshes and curves.

This also fixed strokes losing deform weights in multiple situations, such as:
- When performing a layer merge.
- When applying generative modifiers like Mirror or Array

Pull Request: https://projects.blender.org/blender/blender/pulls/142881
This commit is contained in:
Janne Nylander
2025-08-12 10:25:47 +02:00
committed by Falk David
parent 831969f4f0
commit c95aa8dbd1
2 changed files with 71 additions and 19 deletions

View File

@@ -21,6 +21,7 @@
#include "BLI_array_utils.hh"
#include "BLI_bounds.hh"
#include "BLI_listbase.h"
#include "BLI_math_geom.h"
#include "BLI_math_numbers.hh"
#include "BLI_math_vector.hh"
@@ -1947,15 +1948,32 @@ void apply_eval_grease_pencil_data(const GreasePencil &eval_grease_pencil,
}
}
/* Gather the original vertex group names. */
Set<StringRef> orig_vgroup_names;
LISTBASE_FOREACH (bDeformGroup *, dg, &orig_grease_pencil.vertex_group_names) {
orig_vgroup_names.add(dg->name);
}
/* Update the drawings. */
VectorSet<Drawing *> all_updated_drawings;
Set<StringRef> new_vgroup_names;
for (auto [layer_eval, layer_orig] : eval_to_orig_layer_map.items()) {
const Drawing *drawing_eval = merged_layers_grease_pencil.get_drawing_at(*layer_eval,
eval_frame);
Drawing *drawing_eval = merged_layers_grease_pencil.get_drawing_at(*layer_eval, eval_frame);
Drawing *drawing_orig = orig_grease_pencil.get_drawing_at(*layer_orig, eval_frame);
if (drawing_orig && drawing_eval) {
CurvesGeometry &eval_strokes = drawing_eval->strokes_for_write();
/* Check for new vertex groups in CurvesGeometry. */
LISTBASE_FOREACH (bDeformGroup *, dg, &eval_strokes.vertex_group_names) {
if (!orig_vgroup_names.contains(dg->name)) {
new_vgroup_names.add(dg->name);
}
}
/* Write the data to the original drawing. */
drawing_orig->strokes_for_write() = std::move(drawing_eval->strokes());
drawing_orig->strokes_for_write() = std::move(eval_strokes);
/* Anonymous attributes shouldn't be available on original geometry. */
drawing_orig->strokes_for_write().attributes_for_write().remove_anonymous();
drawing_orig->tag_topology_changed();
@@ -1963,6 +1981,13 @@ void apply_eval_grease_pencil_data(const GreasePencil &eval_grease_pencil,
}
}
/* Add new vertex groups to GreasePencil object. */
for (StringRef new_vgroup_name : new_vgroup_names) {
bDeformGroup *dst = MEM_callocN<bDeformGroup>(__func__);
new_vgroup_name.copy_utf8_truncated(dst->name);
BLI_addtail(&orig_grease_pencil.vertex_group_names, dst);
}
/* Get the original material pointers from the result geometry. */
VectorSet<Material *> original_materials;
const Span<Material *> eval_materials = Span{eval_grease_pencil.material_array,

View File

@@ -1663,6 +1663,26 @@ static void execute_realize_mesh_task(const RealizeInstancesOptions &options,
domain_to_range,
dst_attribute_writers);
}
static void copy_vertex_group_name(ListBase *dst_deform_group,
const OrderedAttributes &ordered_attributes,
const bDeformGroup &src_deform_group)
{
const StringRef src_name = src_deform_group.name;
const int attribute_index = ordered_attributes.ids.index_of_try(src_name);
if (attribute_index == -1) {
/* The attribute is not propagated to the result (possibly because the mesh isn't included
* in the realized output because of the #VariedDepthOptions input). */
return;
}
const bke::AttributeDomainAndType kind = ordered_attributes.kinds[attribute_index];
if (kind.domain != bke::AttrDomain::Point || kind.data_type != bke::AttrType::Float) {
/* Skip if the source attribute can't possibly contain vertex weights. */
return;
}
bDeformGroup *dst = MEM_callocN<bDeformGroup>(__func__);
src_name.copy_utf8_truncated(dst->name);
BLI_addtail(dst_deform_group, dst);
}
static void copy_vertex_group_names(Mesh &dst_mesh,
const OrderedAttributes &ordered_attributes,
@@ -1674,24 +1694,10 @@ static void copy_vertex_group_names(Mesh &dst_mesh,
}
for (const Mesh *mesh : src_meshes) {
LISTBASE_FOREACH (const bDeformGroup *, src, &mesh->vertex_group_names) {
const StringRef src_name = src->name;
const int attribute_index = ordered_attributes.ids.index_of_try(src_name);
if (attribute_index == -1) {
/* The attribute is not propagated to the result (possibly because the mesh isn't included
* in the realized output because of the #VariedDepthOptions input). */
if (existing_names.contains(src->name)) {
continue;
}
const bke::AttributeDomainAndType kind = ordered_attributes.kinds[attribute_index];
if (kind.domain != bke::AttrDomain::Point || kind.data_type != bke::AttrType::Float) {
/* Prefer using the highest priority domain and type from all input meshes. */
continue;
}
if (existing_names.contains(src_name)) {
continue;
}
bDeformGroup *dst = MEM_callocN<bDeformGroup>(__func__);
src_name.copy_utf8_truncated(dst->name);
BLI_addtail(&dst_mesh.vertex_group_names, dst);
copy_vertex_group_name(&dst_mesh.vertex_group_names, ordered_attributes, *src);
}
}
}
@@ -2060,6 +2066,25 @@ static void execute_realize_curve_task(const RealizeInstancesOptions &options,
dst_attribute_writers);
}
static void copy_vertex_group_names(CurvesGeometry &dst_curve,
const OrderedAttributes &ordered_attributes,
const Span<const Curves *> src_curves)
{
Set<StringRef> existing_names;
LISTBASE_FOREACH (const bDeformGroup *, defgroup, &dst_curve.vertex_group_names) {
existing_names.add(defgroup->name);
}
for (const Curves *src_curve : src_curves) {
LISTBASE_FOREACH (const bDeformGroup *, src, &src_curve->geometry.vertex_group_names) {
if (existing_names.contains(src->name)) {
continue;
}
copy_vertex_group_name(&dst_curve.vertex_group_names, ordered_attributes, *src);
existing_names.add(src->name);
}
}
}
static void execute_realize_curve_tasks(const RealizeInstancesOptions &options,
const AllCurvesInfo &all_curves_info,
const Span<RealizeCurveTask> tasks,
@@ -2105,6 +2130,8 @@ static void execute_realize_curve_tasks(const RealizeInstancesOptions &options,
const Curves &first_curves_id = *first_task.curve_info->curves;
bke::curves_copy_parameters(first_curves_id, *dst_curves_id);
copy_vertex_group_names(dst_curves, ordered_attributes, all_curves_info.order);
/* Prepare id attribute. */
SpanAttributeWriter<int> point_ids;
if (all_curves_info.create_id_attribute) {