Fix T91444: Edge Loop Preview fails with two Mirror Modifiers

The mirror modifiers merge option caused unnecessary re-ordering
to the vertex array with original vertices merging into their copies.

While this wasn't an error, it meant creating a 1:1 mapping from input
vertices to their final output wasn't reliable (when looping over
vertices first to last) as is done in
BKE_editmesh_vert_coords_when_deformed.

As merging in either direction is supported, keep the source meshes
vertices in-order since it allows the vertex coordinates to be extracted.

NOTE: Since this change introduce issues for some cases (e.g. bound
modifiers like SurfaceDeform), this change is only applied to newly
created modifiers, existing ones will still use the old incorrect merge
behavior.

Reviewed By: @brecht

Maniphest Tasks: T93321, T91444

Differential Revision: https://developer.blender.org/D13355
This commit is contained in:
Bastien Montagne
2021-11-12 18:07:07 +11:00
committed by Bastien Montagne
parent e6cd4761e7
commit a0acb9bd0c
6 changed files with 68 additions and 21 deletions

View File

@@ -137,7 +137,8 @@ void BKE_mesh_mirror_apply_mirror_on_axis(struct Main *bmain,
Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd,
Object *ob,
const Mesh *mesh,
const int axis)
const int axis,
const bool use_correct_order_on_merge)
{
const float tolerance_sq = mmd->tolerance * mmd->tolerance;
const bool do_vtargetmap = (mmd->flag & MOD_MIR_NO_MERGE) == 0;
@@ -260,21 +261,51 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd,
mul_m4_v3(mtx, mv->co);
if (do_vtargetmap) {
/* compare location of the original and mirrored vertex, to see if they
* should be mapped for merging */
if (UNLIKELY(len_squared_v3v3(mv_prev->co, mv->co) < tolerance_sq)) {
*vtmap_a = maxVerts + i;
tot_vtargetmap++;
/* Compare location of the original and mirrored vertex,
* to see if they should be mapped for merging.
*
* Always merge from the copied into the original vertices so it's possible to
* generate a 1:1 mapping by scanning vertices from the beginning of the array
* as is done in #BKE_editmesh_vert_coords_when_deformed. Without this,
* the coordinates returned will sometimes point to the copied vertex locations, see:
* T91444.
*
* However, such a change also affects non-versionable things like some modifiers binding, so
* we cannot enforce that behavior on existing modifiers, in which case we keep using the
* old, incorrect behavior of merging the source vertex into its copy.
*/
if (use_correct_order_on_merge) {
if (UNLIKELY(len_squared_v3v3(mv_prev->co, mv->co) < tolerance_sq)) {
*vtmap_b = i;
tot_vtargetmap++;
/* average location */
mid_v3_v3v3(mv->co, mv_prev->co, mv->co);
copy_v3_v3(mv_prev->co, mv->co);
}
else {
/* average location */
mid_v3_v3v3(mv->co, mv_prev->co, mv->co);
copy_v3_v3(mv_prev->co, mv->co);
}
else {
*vtmap_b = -1;
}
/* Fill here to avoid 2x loops. */
*vtmap_a = -1;
}
else {
if (UNLIKELY(len_squared_v3v3(mv_prev->co, mv->co) < tolerance_sq)) {
*vtmap_a = maxVerts + i;
tot_vtargetmap++;
*vtmap_b = -1; /* fill here to avoid 2x loops */
/* average location */
mid_v3_v3v3(mv->co, mv_prev->co, mv->co);
copy_v3_v3(mv_prev->co, mv->co);
}
else {
*vtmap_a = -1;
}
/* Fill here to avoid 2x loops. */
*vtmap_b = -1;
}
vtmap_a++;
vtmap_b++;