Fix #133969: Crazyspace broken with bezier curves and armature modifier

The issue was that the topology of the drawing changes when the bezier
curves get resampled to poly curves in the armature modifier.
This means that the crazyspace code fails to find deformed positions
with the same length as the original positions.

The fix does multiple things:
* First, we make sure that we create an `GeometryComponentEditData` in
  weight paint mode.
* When the armature modifier runs, we remember the current positions in
  this component.
* Then, we store the curve offsets and weights _before_ converting the
   bezier curves.
* Finally we deform the positions stored in the edit hint component
   (which have the same length as the original positions).

Since the resampling just adds new points, there might be a way to
avoid running the armature deformation a second time on the edit
hints, but I'll leave that for another day as a performance improvement.
In any case, this is only done when we actually need the deformation
(e.g. in weight paint mode when we paint the weights).

Pull Request: https://projects.blender.org/blender/blender/pulls/134030
This commit is contained in:
Falk David
2025-02-06 11:14:23 +01:00
parent 734af8206c
commit 8af27ce27e
2 changed files with 41 additions and 4 deletions

View File

@@ -2201,9 +2201,14 @@ void BKE_grease_pencil_data_update(Depsgraph *depsgraph, Scene *scene, Object *o
if (layer_attributes.contains("tint_color") || layer_attributes.contains("radius_offset")) {
grease_pencil_do_layer_adjustments(*geometry_set.get_grease_pencil_for_write());
}
/* Only add the edit hint component in edit mode or sculpt mode for now so users can properly
* select deformed drawings. */
if (ELEM(object->mode, OB_MODE_EDIT, OB_MODE_SCULPT_GREASE_PENCIL)) {
/* Only add the edit hint component in modes where users can potentially interact with deformed
* drawings. */
if (ELEM(object->mode,
OB_MODE_EDIT,
OB_MODE_SCULPT_GREASE_PENCIL,
OB_MODE_VERTEX_GREASE_PENCIL,
OB_MODE_WEIGHT_GREASE_PENCIL))
{
GeometryComponentEditData &edit_component =
geometry_set.get_component_for_write<GeometryComponentEditData>();
edit_component.grease_pencil_edit_hints_ = std::make_unique<GreasePencilEditHints>(

View File

@@ -116,7 +116,21 @@ static void modify_curves(ModifierData &md,
bke::GreasePencilDrawingEditHints *edit_hints)
{
auto &amd = reinterpret_cast<GreasePencilArmatureModifierData &>(md);
modifier::greasepencil::ensure_no_bezier_curves(drawing);
const bool has_bezier_curves = drawing.strokes().has_curve_with_type(
CurveType::CURVE_TYPE_BEZIER);
Array<int> orig_offsets;
Array<MDeformVert> orig_dverts;
OffsetIndices<int> orig_points_by_curve;
if (has_bezier_curves) {
if (edit_hints) {
orig_dverts = drawing.strokes().deform_verts();
orig_offsets = drawing.strokes().offsets();
orig_points_by_curve = OffsetIndices<int>(orig_offsets.as_span());
}
modifier::greasepencil::ensure_no_bezier_curves(drawing);
}
bke::CurvesGeometry &curves = drawing.strokes_for_write();
/* The influence flag is where the "invert" flag is stored,
@@ -144,12 +158,16 @@ static void modify_curves(ModifierData &md,
Span<float3> old_positions = {static_cast<const float3 *>(old_positions_data.data),
curves.points_num()};
std::optional<MutableSpan<float3>> deform_positions;
std::optional<MutableSpan<float3x3>> deform_mats;
if (edit_hints) {
if (!edit_hints->deform_mats.has_value()) {
edit_hints->deform_mats.emplace(drawing.strokes().points_num(), float3x3::identity());
}
deform_mats = edit_hints->deform_mats->as_mutable_span();
if (has_bezier_curves) {
deform_positions = edit_hints->positions_for_write();
}
}
curves_mask.foreach_index(blender::GrainSize(128), [&](const int curve_i) {
@@ -171,6 +189,18 @@ static void modify_curves(ModifierData &md,
dverts.slice(points),
deformflag,
amd.influence.vertex_group_name);
if (deform_positions) {
const IndexRange orig_points = orig_points_by_curve[curve_i];
BKE_armature_deform_coords_with_curves(*amd.object,
*ctx.object,
&curves.vertex_group_names,
deform_positions->slice(orig_points),
{},
{},
orig_dverts.as_span().slice(orig_points),
deformflag,
amd.influence.vertex_group_name);
}
});
drawing.tag_positions_changed();
@@ -187,6 +217,8 @@ static void modify_geometry_set(ModifierData *md,
if (!geometry_set->has_grease_pencil()) {
return;
}
bke::GeometryComponentEditData::remember_deformed_positions_if_necessary(*geometry_set);
GreasePencil &grease_pencil = *geometry_set->get_grease_pencil_for_write();
const GreasePencil &grease_pencil_orig = *reinterpret_cast<GreasePencil *>(
DEG_get_original_id(&grease_pencil.id));