Dynamic Paint: Fix adjacency computations at UV seams.

1. When adding one pixel border to UV islands prefer grid directions.
   This is more logical as it means neighbor pixels will commonly
   share a border, opposed to just corners.
2. Don't subtract 0.5 when converting float UVs to int in computing
   adjacency across a UV seam. Pixels cover a square with corners
   at int positions and adding/subtracting 0.5 is only for dealing
   with the center point of a pixel.
3. Use the neighbour_pixel field from the correct pixel, and check
   it's not back to the origin point.
4. In the connected UV case, ensure that the returned index actually
   refers to a valid active pixel.

This fixes paint spread not traversing some UV seams, while at the
same time spreading to random unrelated points on other seams.
The first problem is primarily fixed by 2, while the second one
is addressed by item 4.

Differential Revision: https://developer.blender.org/D2261
This commit is contained in:
Alexander Gavrilov 2016-09-27 11:13:04 +03:00
parent bde5eb8b63
commit 9a66d0ad1b
1 changed files with 35 additions and 9 deletions

View File

@ -101,6 +101,10 @@ static const float gaussianTotal = 3.309425f;
static int neighX[8] = {1, 1, 0, -1, -1, -1, 0, 1};
static int neighY[8] = {0, 1, 1, 1, 0, -1, -1, -1};
/* Neighbor x/y list that prioritizes grid directions over diagonals */
static int neighStraightX[8] = {1, 0, -1, 0, 1, -1, -1, 1};
static int neighStraightY[8] = {0, 1, 0, -1, 1, 1, -1, -1};
/* subframe_updateObject() flags */
#define SUBFRAME_RECURSION 5
/* surface_getBrushFlags() return vals */
@ -2233,9 +2237,12 @@ static void dynamic_paint_create_uv_surface_neighbor_cb(void *userdata, const in
point[0] = ((float)tx + 0.5f) / w;
point[1] = ((float)ty + 0.5f) / h;
/* search through defined area for neighbor */
for (int u = u_min; u <= u_max; u++) {
for (int v = v_min; v <= v_max; v++) {
/* search through defined area for neighbor, checking grid directions first */
for (int ni = 0; ni < 8; ni++) {
int u = neighStraightX[ni];
int v = neighStraightY[ni];
if (u >= u_min && u <= u_max && v >= v_min && v <= v_max) {
/* if not this pixel itself */
if (u != 0 || v != 0) {
const int ind = (tx + u) + w * (ty + v);
@ -2273,7 +2280,6 @@ static void dynamic_paint_create_uv_surface_neighbor_cb(void *userdata, const in
tPoint->v2 = mloop[mlooptri[i].tri[1]].v;
tPoint->v3 = mloop[mlooptri[i].tri[2]].v;
u = u_max + 1; /* make sure we exit outer loop as well */
break;
}
}
@ -2445,7 +2451,22 @@ static int dynamic_paint_find_neighbour_pixel(
((s_uv2[0] == t_uv1[0] && s_uv2[1] == t_uv1[1]) &&
(s_uv1[0] == t_uv2[0] && s_uv1[1] == t_uv2[1])))
{
return ((px + neighX[n_index]) + w * (py + neighY[n_index]));
final_index = x + w * y;
/* If not an active pixel, bail out */
if (tempPoints[final_index].tri_index == -1)
return NOT_FOUND;
/* If final point is an "edge pixel", use it's "real" neighbor instead */
if (tempPoints[final_index].neighbour_pixel != -1) {
final_index = tempPoints[final_index].neighbour_pixel;
/* If we ended up to our origin point */
if (final_index == (px + w * py))
return NOT_FOUND;
}
return final_index;
}
/*
@ -2467,8 +2488,8 @@ static int dynamic_paint_find_neighbour_pixel(
copy_v2_v2(pixel, mloopuv[mlooptri[target_tri].tri[target_uv1]].uv);
add_v2_v2(pixel, dir_vec);
pixel[0] = (pixel[0] * (float)w) - 0.5f;
pixel[1] = (pixel[1] * (float)h) - 0.5f;
pixel[0] = (pixel[0] * (float)w);
pixel[1] = (pixel[1] * (float)h);
final_pixel[0] = (int)floorf(pixel[0]);
final_pixel[1] = (int)floorf(pixel[1]);
@ -2487,8 +2508,13 @@ static int dynamic_paint_find_neighbour_pixel(
return NOT_FOUND;
/* If final point is an "edge pixel", use it's "real" neighbor instead */
if (tempPoints[final_index].neighbour_pixel != -1)
final_index = cPoint->neighbour_pixel;
if (tempPoints[final_index].neighbour_pixel != -1) {
final_index = tempPoints[final_index].neighbour_pixel;
/* If we ended up to our origin point */
if (final_index == (px + w * py))
return NOT_FOUND;
}
return final_index;
}