Fix #108880: Skin and Miffor modifiers cause mesh collapse

Before 4369627e71, the Mirror modifier merge did not interpolate
customdata.

Previously, the customdata was simply copied from the original vertex
during the merge, resulting in the retention of flags such as
`MVERT_SKIN_ROOT`.

This fix could just repeat that behavior for mirror. But these flags
can be useful in other cases, so this commit re-adds them to the
resulting merged vertex.

Although this can generate geometries with multiple roots on the same
island, there are different scenarios in which this can happen.
Therefore, multiple roots on the same island is not necessarily
considered a bug.
This commit is contained in:
Germano Cavalcante
2023-06-12 18:01:03 -03:00
parent 7f9021a92f
commit f8617fe71b

View File

@@ -1455,6 +1455,8 @@ static void customdata_weld(
int src_i, dest_i;
int j;
int vs_flag = 0;
/* interpolates a layer at a time */
dest_i = 0;
for (src_i = 0; src_i < source->totlayer; src_i++) {
@@ -1475,7 +1477,21 @@ static void customdata_weld(
/* if we found a matching layer, add the data */
if (dest->layers[dest_i].type == type) {
void *src_data = source->layers[src_i].data;
if (CustomData_layer_has_interp(dest, dest_i)) {
if (type == CD_MVERT_SKIN) {
/* The `typeInfo->interp` of #CD_MVERT_SKIN does not include the flags, so #MVERT_SKIN_ROOT
* and #MVERT_SKIN_LOOSE are lost after the interpolation.
*
* This behavior is not incorrect. Ideally, islands should be checked to avoid repeated
* roots.
*
* However, for now, to prevent the loss of flags, they are simply re-added if any of the
* merged vertices have them. */
for (j = 0; j < count; j++) {
MVertSkin *vs = &((MVertSkin *)src_data)[src_indices[j]];
vs_flag |= vs->flag;
}
}
else if (CustomData_layer_has_interp(dest, dest_i)) {
/* Already calculated.
* TODO: Optimize by exposing `typeInfo->interp`. */
}
@@ -1505,7 +1521,11 @@ static void customdata_weld(
for (dest_i = 0; dest_i < dest->totlayer; dest_i++) {
CustomDataLayer *layer_dst = &dest->layers[dest_i];
const eCustomDataType type = eCustomDataType(layer_dst->type);
if (CustomData_layer_has_interp(dest, dest_i)) {
if (type == CD_MVERT_SKIN) {
MVertSkin *vs = &((MVertSkin *)layer_dst->data)[dest_index];
vs->flag = vs_flag;
}
else if (CustomData_layer_has_interp(dest, dest_i)) {
/* Already calculated. */
}
else if (CustomData_layer_has_math(dest, dest_i)) {