diff options
Diffstat (limited to 'source/blender/blenkernel/intern/shrinkwrap.c')
-rw-r--r-- | source/blender/blenkernel/intern/shrinkwrap.c | 89 |
1 files changed, 74 insertions, 15 deletions
diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c index b5888856250..21b21d6ddd8 100644 --- a/source/blender/blenkernel/intern/shrinkwrap.c +++ b/source/blender/blenkernel/intern/shrinkwrap.c @@ -363,7 +363,7 @@ static void shrinkwrap_calc_normal_projection_cb_ex( } if (hit->index != -1) { - madd_v3_v3v3fl(hit->co, hit->co, tmp_no, calc->keepDist); + BKE_shrinkwrap_snap_point_to_surface(calc->smd->shrinkMode, hit->co, hit->no, calc->keepDist, tmp_co, hit->co); interp_v3_v3v3(co, co, hit->co, weight); } } @@ -541,26 +541,85 @@ static void shrinkwrap_calc_nearest_surface_point_cb_ex( /* Found the nearest vertex */ if (nearest->index != -1) { - if (calc->smd->shrinkOpts & MOD_SHRINKWRAP_KEEP_ABOVE_SURFACE) { - /* Make the vertex stay on the front side of the face */ - madd_v3_v3v3fl(tmp_co, nearest->co, nearest->no, calc->keepDist); + BKE_shrinkwrap_snap_point_to_surface(calc->smd->shrinkMode, nearest->co, nearest->no, calc->keepDist, tmp_co, tmp_co); + + /* Convert the coordinates back to mesh coordinates */ + BLI_space_transform_invert(&calc->local2target, tmp_co); + interp_v3_v3v3(co, co, tmp_co, weight); /* linear interpolation */ + } +} + +/* Helper for MOD_SHRINKWRAP_INSIDE, MOD_SHRINKWRAP_OUTSIDE and MOD_SHRINKWRAP_OUTSIDE_SURFACE. */ +static void shrinkwrap_snap_with_side(float r_point_co[3], const float point_co[3], const float hit_co[3], const float hit_no[3], float goal_dist, float forcesign, bool forcesnap) +{ + float dist = len_v3v3(point_co, hit_co); + + /* If exactly on the surface, push out along normal */ + if (dist < FLT_EPSILON) { + madd_v3_v3v3fl(r_point_co, hit_co, hit_no, goal_dist * forcesign); + } + /* Move to the correct side if needed */ + else { + float delta[3]; + sub_v3_v3v3(delta, point_co, hit_co); + float dsign = signf(dot_v3v3(delta, hit_no)); + + /* If on the wrong side or too close, move to correct */ + if (forcesnap || dsign * forcesign < 0 || dist < goal_dist) { + interp_v3_v3v3(r_point_co, point_co, hit_co, (dist - goal_dist * dsign * forcesign) / dist); } else { - /* Adjusting the vertex weight, - * so that after interpolating it keeps a certain distance from the nearest position */ - const float dist = sasqrt(nearest->dist_sq); - if (dist > FLT_EPSILON) { - /* linear interpolation */ - interp_v3_v3v3(tmp_co, tmp_co, nearest->co, (dist - calc->keepDist) / dist); + copy_v3_v3(r_point_co, point_co); + } + } +} + +/** + * Apply the shrink to surface modes to the given original coordinates and nearest point. + * r_point_co may be the same memory location as point_co, hit_co, or hit_no. + */ +void BKE_shrinkwrap_snap_point_to_surface( + int mode, const float hit_co[3], const float hit_no[3], float goal_dist, + const float point_co[3], float r_point_co[3]) +{ + float dist; + + switch (mode) { + /* Offsets along the line between point_co and hit_co. */ + case MOD_SHRINKWRAP_ON_SURFACE: + if (goal_dist > 0 && (dist = len_v3v3(point_co, hit_co)) > FLT_EPSILON) { + interp_v3_v3v3(r_point_co, point_co, hit_co, (dist - goal_dist) / dist); } else { - copy_v3_v3(tmp_co, nearest->co); + copy_v3_v3(r_point_co, hit_co); } - } + break; - /* Convert the coordinates back to mesh coordinates */ - BLI_space_transform_invert(&calc->local2target, tmp_co); - interp_v3_v3v3(co, co, tmp_co, weight); /* linear interpolation */ + case MOD_SHRINKWRAP_INSIDE: + shrinkwrap_snap_with_side(r_point_co, point_co, hit_co, hit_no, goal_dist, -1, false); + break; + + case MOD_SHRINKWRAP_OUTSIDE: + shrinkwrap_snap_with_side(r_point_co, point_co, hit_co, hit_no, goal_dist, +1, false); + break; + + case MOD_SHRINKWRAP_OUTSIDE_SURFACE: + if (goal_dist > 0) { + shrinkwrap_snap_with_side(r_point_co, point_co, hit_co, hit_no, goal_dist, +1, true); + } + else { + copy_v3_v3(r_point_co, hit_co); + } + break; + + /* Offsets along the normal */ + case MOD_SHRINKWRAP_ABOVE_SURFACE: + madd_v3_v3v3fl(r_point_co, hit_co, hit_no, goal_dist); + break; + + default: + printf("Unknown Shrinkwrap surface snap mode: %d\n", mode); + copy_v3_v3(r_point_co, hit_co); } } |