Fix T81988: Surface Deform "Bind" causes vertices to spike

Surface deform weight calculation assigned weights in a non-uniform
way that caused vertices to deform upon binding.

This was caused by the face-corner angle being used in
calculations which where squared & scaled.
Causing a triangle fan of many thin faces to have a much greater
influence compared to the same shape made from a single triangle.

Change the calculation of the weight so each face-corner is scaled
by it's angle.
This commit is contained in:
Campbell Barton 2020-11-03 20:26:36 +11:00
parent d93a6cdf00
commit fc9f1b1754
Notes: blender-bot 2023-02-14 02:22:13 +01:00
Referenced by issue #81988, Surface Deform modifier results in arbitrary vertices extending away from the object's origin, rather than responding to the target mesh
1 changed files with 18 additions and 17 deletions

View File

@ -424,15 +424,9 @@ static void freeBindData(SDefBindWeightData *const bwdata)
MEM_freeN(bwdata);
}
BLI_INLINE float computeAngularWeight(const float point_angle, const float edgemid_angle)
BLI_INLINE float computeAngularWeight(const float point_angle)
{
float weight;
weight = point_angle;
weight /= edgemid_angle;
weight *= M_PI_2;
return sinf(weight);
return sinf(point_angle * M_PI_2);
}
BLI_INLINE SDefBindWeightData *computeBindWeights(SDefBindCalcData *const data,
@ -658,15 +652,12 @@ BLI_INLINE SDefBindWeightData *computeBindWeights(SDefBindCalcData *const data,
/* Compute angular weight component */
if (epolys->num == 1) {
ang_weights[0] = computeAngularWeight(bpolys[0]->point_edgemid_angles[edge_on_poly[0]],
bpolys[0]->edgemid_angle);
ang_weights[0] = computeAngularWeight(bpolys[0]->point_edgemid_angles[edge_on_poly[0]]);
bpolys[0]->weight_angular *= ang_weights[0] * ang_weights[0];
}
else if (epolys->num == 2) {
ang_weights[0] = computeAngularWeight(bpolys[0]->point_edgemid_angles[edge_on_poly[0]],
bpolys[0]->edgemid_angle);
ang_weights[1] = computeAngularWeight(bpolys[1]->point_edgemid_angles[edge_on_poly[1]],
bpolys[1]->edgemid_angle);
ang_weights[0] = computeAngularWeight(bpolys[0]->point_edgemid_angles[edge_on_poly[0]]);
ang_weights[1] = computeAngularWeight(bpolys[1]->point_edgemid_angles[edge_on_poly[1]]);
bpolys[0]->weight_angular *= ang_weights[0] * ang_weights[1];
bpolys[1]->weight_angular *= ang_weights[0] * ang_weights[1];
@ -707,9 +698,14 @@ BLI_INLINE SDefBindWeightData *computeBindWeights(SDefBindCalcData *const data,
bpoly->dominant_angle_weight = sinf(bpoly->dominant_angle_weight * M_PI_2);
/* Compute quadratic angular scale interpolation weight */
scale_weight = bpoly->point_edgemid_angles[bpoly->dominant_edge] / bpoly->edgemid_angle;
scale_weight /= scale_weight +
(bpoly->point_edgemid_angles[!bpoly->dominant_edge] / bpoly->edgemid_angle);
{
const float edge_angle_a = bpoly->point_edgemid_angles[bpoly->dominant_edge];
const float edge_angle_b = bpoly->point_edgemid_angles[!bpoly->dominant_edge];
/* Clamp so skinny faces with near zero `edgemid_angle`
* won't cause numeric problems. see T81988. */
scale_weight = edge_angle_a / max_ff(edge_angle_a, bpoly->edgemid_angle);
scale_weight /= scale_weight + (edge_angle_b / max_ff(edge_angle_b, bpoly->edgemid_angle));
}
sqr = scale_weight * scale_weight;
inv_sqr = 1.0f - scale_weight;
@ -776,6 +772,11 @@ BLI_INLINE SDefBindWeightData *computeBindWeights(SDefBindCalcData *const data,
bpoly->weight = 1.0f / bpoly->weight_angular / bpoly->weight_dist_proj / bpoly->weight_dist;
}
/* Apply after other kinds of scaling so the faces corner angle is always
* scaled in a uniform way, preventing heavily sub-divided triangle fans
* from having a lop-sided influence on the weighting, see T81988. */
bpoly->weight *= bpoly->edgemid_angle / M_PI;
tot_weight += bpoly->weight;
}