// GPU edge padding / texture dilation against visible UV seams. // // Between the UV islands there is an unpainted border (gutter). During bilinear // sampling at an island edge, the GPU mixes the painted edge with the unpainted // base color -> bright seam lines. This pass "bleeds" the painted color up to // _Pad texels beyond the island edges. // // The dilation source is exclusively painted texels (alpha > 0). The padding // texels produced get alpha = 0 -> next frame they are NO LONGER a source, so the // padding does not grow unbounded (it stays at _Pad texels). The threshold is > 0 // (not >= 0.5) so soft, partially transparent brush edges count as painted too. Shader "Hidden/MeshPaintDilate" { Properties { _MainTex ("Texture", 2D) = "white" {} } SubShader { Tags { "RenderType" = "Opaque" } Pass { ZTest Always ZWrite Off Cull Off Blend Off CGPROGRAM #pragma vertex vert_img #pragma fragment frag #include "UnityCG.cginc" sampler2D _MainTex; float4 _MainTex_TexelSize; // (1/w, 1/h, w, h) int _Pad; #define MAXPAD 16 fixed4 frag (v2f_img i) : SV_Target { fixed4 c = tex2D(_MainTex, i.uv); if (c.a > 0.0) return c; // already painted (even partially) -> leave unchanged float2 ts = _MainTex_TexelSize.xy; float best = 1e20; fixed3 bestCol = c.rgb; bool found = false; // Search the neighborhood (up to _Pad texels) for the nearest painted texel. [loop] for (int y = -MAXPAD; y <= MAXPAD; y++) { if (abs(y) > _Pad) continue; [loop] for (int x = -MAXPAD; x <= MAXPAD; x++) { if (abs(x) > _Pad) continue; fixed4 s = tex2D(_MainTex, i.uv + float2(x, y) * ts); if (s.a > 0.0) { float dd = (float)(x * x + y * y); if (dd < best) { best = dd; bestCol = s.rgb; found = true; } } } } // Gutter: color of the nearest painted texel, but alpha = 0 (not a source). if (found) return fixed4(bestCol, 0.0); return c; // out of range -> base color unchanged } ENDCG } } Fallback Off }