Fix T44791 triangles when painting on a texpaint plane

Problem was float precision issues across tile boundaries. Since we are
comparing pixels, give a small tolerance when comparing clipped vertices
against triangle lines.
This commit is contained in:
Antonis Ryakiotakis 2015-05-21 16:06:24 +02:00
parent 069adb8104
commit d3c67bc81e
Notes: blender-bot 2023-05-31 04:43:10 +02:00
Referenced by issue #44791, Unpaintable transparent triangles with texture paint
1 changed files with 25 additions and 18 deletions

View File

@ -1680,13 +1680,14 @@ static ProjPixel *project_paint_uvpixel_init(
}
static bool line_clip_rect2f(
const rctf *cliprect,
const rctf *rect,
const float l1[2], const float l2[2],
float l1_clip[2], float l2_clip[2])
{
/* first account for horizontal, then vertical lines */
/* horiz */
if (fabsf(l1[1] - l2[1]) < PROJ_GEOM_TOLERANCE) {
if (fabsf(l1[1] - l2[1]) < PROJ_PIXEL_TOLERANCE) {
/* is the line out of range on its Y axis? */
if (l1[1] < rect->ymin || l1[1] > rect->ymax) {
return 0;
@ -1697,7 +1698,7 @@ static bool line_clip_rect2f(
}
if (fabsf(l1[0] - l2[0]) < PROJ_GEOM_TOLERANCE) { /* this is a single point (or close to)*/
if (fabsf(l1[0] - l2[0]) < PROJ_PIXEL_TOLERANCE) { /* this is a single point (or close to)*/
if (BLI_rctf_isect_pt_v(rect, l1)) {
copy_v2_v2(l1_clip, l1);
copy_v2_v2(l2_clip, l2);
@ -1714,7 +1715,7 @@ static bool line_clip_rect2f(
CLAMP(l2_clip[0], rect->xmin, rect->xmax);
return 1;
}
else if (fabsf(l1[0] - l2[0]) < PROJ_GEOM_TOLERANCE) {
else if (fabsf(l1[0] - l2[0]) < PROJ_PIXEL_TOLERANCE) {
/* is the line out of range on its X axis? */
if (l1[0] < rect->xmin || l1[0] > rect->xmax) {
return 0;
@ -1725,7 +1726,7 @@ static bool line_clip_rect2f(
return 0;
}
if (fabsf(l1[1] - l2[1]) < PROJ_GEOM_TOLERANCE) { /* this is a single point (or close to)*/
if (fabsf(l1[1] - l2[1]) < PROJ_PIXEL_TOLERANCE) { /* this is a single point (or close to)*/
if (BLI_rctf_isect_pt_v(rect, l1)) {
copy_v2_v2(l1_clip, l1);
copy_v2_v2(l2_clip, l2);
@ -1764,7 +1765,7 @@ static bool line_clip_rect2f(
if (ok1 && ok2) return 1;
/* top/bottom */
if (line_isect_y(l1, l2, rect->ymin, &isect) && (isect >= rect->xmin) && (isect <= rect->xmax)) {
if (line_isect_y(l1, l2, rect->ymin, &isect) && (isect >= cliprect->xmin) && (isect <= cliprect->xmax)) {
if (l1[1] < l2[1]) { /* line 1 is outside */
l1_clip[0] = isect;
l1_clip[1] = rect->ymin;
@ -1779,7 +1780,7 @@ static bool line_clip_rect2f(
if (ok1 && ok2) return 1;
if (line_isect_y(l1, l2, rect->ymax, &isect) && (isect >= rect->xmin) && (isect <= rect->xmax)) {
if (line_isect_y(l1, l2, rect->ymax, &isect) && (isect >= cliprect->xmin) && (isect <= cliprect->xmax)) {
if (l1[1] > l2[1]) { /* line 1 is outside */
l1_clip[0] = isect;
l1_clip[1] = rect->ymax;
@ -1795,7 +1796,7 @@ static bool line_clip_rect2f(
if (ok1 && ok2) return 1;
/* left/right */
if (line_isect_x(l1, l2, rect->xmin, &isect) && (isect >= rect->ymin) && (isect <= rect->ymax)) {
if (line_isect_x(l1, l2, rect->xmin, &isect) && (isect >= cliprect->ymin) && (isect <= cliprect->ymax)) {
if (l1[0] < l2[0]) { /* line 1 is outside */
l1_clip[0] = rect->xmin;
l1_clip[1] = isect;
@ -1810,7 +1811,7 @@ static bool line_clip_rect2f(
if (ok1 && ok2) return 1;
if (line_isect_x(l1, l2, rect->xmax, &isect) && (isect >= rect->ymin) && (isect <= rect->ymax)) {
if (line_isect_x(l1, l2, rect->xmax, &isect) && (isect >= cliprect->ymin) && (isect <= cliprect->ymax)) {
if (l1[0] > l2[0]) { /* line 1 is outside */
l1_clip[0] = rect->xmax;
l1_clip[1] = isect;
@ -2108,6 +2109,7 @@ static bool line_rect_clip(
static void project_bucket_clip_face(
const bool is_ortho, const bool is_flip_object,
const rctf *cliprect,
const rctf *bucket_bounds,
const float *v1coSS, const float *v2coSS, const float *v3coSS,
const float *uv1co, const float *uv2co, const float *uv3co,
@ -2272,21 +2274,21 @@ static void project_bucket_clip_face(
if (inside_bucket_flag & ISECT_3) { copy_v2_v2(isectVCosSS[*tot], v3coSS); (*tot)++; }
if ((inside_bucket_flag & (ISECT_1 | ISECT_2)) != (ISECT_1 | ISECT_2)) {
if (line_clip_rect2f(bucket_bounds, v1coSS, v2coSS, v1_clipSS, v2_clipSS)) {
if (line_clip_rect2f(cliprect, bucket_bounds, v1coSS, v2coSS, v1_clipSS, v2_clipSS)) {
if ((inside_bucket_flag & ISECT_1) == 0) { copy_v2_v2(isectVCosSS[*tot], v1_clipSS); (*tot)++; }
if ((inside_bucket_flag & ISECT_2) == 0) { copy_v2_v2(isectVCosSS[*tot], v2_clipSS); (*tot)++; }
}
}
if ((inside_bucket_flag & (ISECT_2 | ISECT_3)) != (ISECT_2 | ISECT_3)) {
if (line_clip_rect2f(bucket_bounds, v2coSS, v3coSS, v1_clipSS, v2_clipSS)) {
if (line_clip_rect2f(cliprect, bucket_bounds, v2coSS, v3coSS, v1_clipSS, v2_clipSS)) {
if ((inside_bucket_flag & ISECT_2) == 0) { copy_v2_v2(isectVCosSS[*tot], v1_clipSS); (*tot)++; }
if ((inside_bucket_flag & ISECT_3) == 0) { copy_v2_v2(isectVCosSS[*tot], v2_clipSS); (*tot)++; }
}
}
if ((inside_bucket_flag & (ISECT_3 | ISECT_1)) != (ISECT_3 | ISECT_1)) {
if (line_clip_rect2f(bucket_bounds, v3coSS, v1coSS, v1_clipSS, v2_clipSS)) {
if (line_clip_rect2f(cliprect, bucket_bounds, v3coSS, v1coSS, v1_clipSS, v2_clipSS)) {
if ((inside_bucket_flag & ISECT_3) == 0) { copy_v2_v2(isectVCosSS[*tot], v1_clipSS); (*tot)++; }
if ((inside_bucket_flag & ISECT_1) == 0) { copy_v2_v2(isectVCosSS[*tot], v2_clipSS); (*tot)++; }
}
@ -2488,7 +2490,7 @@ static bool IsectPoly2Df_twoside(const float pt[2], float uv[][2], const int tot
static void project_paint_face_init(
const ProjPaintState *ps,
const int thread_index, const int bucket_index, const int face_index, const int image_index,
const rctf *bucket_bounds, ImBuf *ibuf, ImBuf **tmpibuf,
const rctf *clip_rect, const rctf *bucket_bounds, ImBuf *ibuf, ImBuf **tmpibuf,
const bool clamp_u, const bool clamp_v)
{
/* Projection vars, to get the 3D locations into screen space */
@ -2602,7 +2604,7 @@ static void project_paint_face_init(
/* This funtion gives is a concave polyline in UV space from the clipped quad and tri*/
project_bucket_clip_face(
is_ortho, is_flip_object,
bucket_bounds,
clip_rect, bucket_bounds,
v1coSS, v2coSS, v3coSS,
uv1co, uv2co, uv3co,
uv_clip, &uv_clip_tot,
@ -2774,7 +2776,7 @@ static void project_paint_face_init(
else fidx2 = (fidx1 == 2) ? 0 : fidx1 + 1; /* next fidx in the face (0,1,2) -> (1,2,0) */
if ((face_seam_flag & (1 << fidx1)) && /* 1<<fidx1 -> PROJ_FACE_SEAM# */
line_clip_rect2f(bucket_bounds, vCoSS[fidx1], vCoSS[fidx2], bucket_clip_edges[0], bucket_clip_edges[1]))
line_clip_rect2f(clip_rect, bucket_bounds, vCoSS[fidx1], vCoSS[fidx2], bucket_clip_edges[0], bucket_clip_edges[1]))
{
if (len_squared_v2v2(vCoSS[fidx1], vCoSS[fidx2]) > FLT_EPSILON) { /* avoid div by zero */
if (mf->v4) {
@ -2947,7 +2949,7 @@ static void project_bucket_bounds(const ProjPaintState *ps, const int bucket_x,
/* Fill this bucket with pixels from the faces that intersect it.
*
* have bucket_bounds as an argument so we don't need to give bucket_x/y the rect function needs */
static void project_bucket_init(const ProjPaintState *ps, const int thread_index, const int bucket_index, const rctf *bucket_bounds)
static void project_bucket_init(const ProjPaintState *ps, const int thread_index, const int bucket_index, const rctf *clip_rect, const rctf *bucket_bounds)
{
LinkNode *node;
int face_index, image_index = 0;
@ -2964,7 +2966,7 @@ static void project_bucket_init(const ProjPaintState *ps, const int thread_index
for (node = ps->bucketFaces[bucket_index]; node; node = node->next) {
project_paint_face_init(
ps, thread_index, bucket_index, GET_INT_FROM_POINTER(node->link), 0,
bucket_bounds, ibuf, &tmpibuf,
clip_rect, bucket_bounds, ibuf, &tmpibuf,
(ima->tpageflag & IMA_CLAMP_U) != 0, (ima->tpageflag & IMA_CLAMP_V) != 0);
}
}
@ -2991,7 +2993,7 @@ static void project_bucket_init(const ProjPaintState *ps, const int thread_index
project_paint_face_init(
ps, thread_index, bucket_index, face_index, image_index,
bucket_bounds, ibuf, &tmpibuf,
clip_rect, bucket_bounds, ibuf, &tmpibuf,
(ima->tpageflag & IMA_CLAMP_U) != 0, (ima->tpageflag & IMA_CLAMP_V) != 0);
}
}
@ -4563,8 +4565,13 @@ static void *do_projectpaint_thread(void *ph_v)
/* Check this bucket and its faces are initialized */
if (ps->bucketFlags[bucket_index] == PROJ_BUCKET_NULL) {
rctf clip_rect = bucket_bounds;
clip_rect.xmin -= PROJ_PIXEL_TOLERANCE;
clip_rect.xmax += PROJ_PIXEL_TOLERANCE;
clip_rect.ymin -= PROJ_PIXEL_TOLERANCE;
clip_rect.ymax += PROJ_PIXEL_TOLERANCE;
/* No pixels initialized */
project_bucket_init(ps, thread_index, bucket_index, &bucket_bounds);
project_bucket_init(ps, thread_index, bucket_index, &clip_rect, &bucket_bounds);
}
if (ps->source != PROJ_SRC_VIEW) {