Search Unity

Question White pixels on opposite side of tile

Discussion in 'Shaders' started by deffan, Nov 16, 2022.

  1. deffan

    deffan

    Joined:
    May 24, 2015
    Posts:
    7
    Hi,
    I had this issue for quite some time now and I am unable to solve it.

    When using this tile, with black on one side, and white on the other...


    When I move the camera, I see these white pixels coming and going along the tile.


    But this only seems to happen with tiles that have extreme black and extreme white on opposite sides.
    Other tiles with varying colors do not experience this problem...

    If I add a 1px black line on the white side, the issue disappears... but obviously then there will be a black line on the white side, which I don't want.


    The tiles are read from a texture atlas.
    I have tried to add padding/margins/empty space between the tiles, but this has no effect.
    I have tried to change the texture settings to anything imaginable, but this has no effect.
    I have tried to read smaller parts of the tile (in the Shader), but this has no effect.

    Anyone has any clues?
     
  2. Invertex

    Invertex

    Joined:
    Nov 7, 2013
    Posts:
    1,550
    The fact the issue disappears when adding a pixel line to the left side implies that how your sampling the sub-texture of the atlas is creating a scenario where sometimes the UV value loops back over to the other side of the sampling region instead of simply clamping.
    This gradient is part of a larger image that is imported and sliced using the Sprite Editor right? If not, then make sure the Texture Repeat settings are set to Clamp as well.
     
  3. deffan

    deffan

    Joined:
    May 24, 2015
    Posts:
    7
    Well, there is something like that going on...

    This is a 4096x4096 PNG file (tile atlas) I made myself.

    I changed the texture shape to 2D array to see if UNITY_SAMPLE_TEX2DARRAY made any difference - It did not.
    The texture is clamp.
    There is no filter.
    There is no compression.
    There are no mipmaps.
    I tried adding space (everything between 1px and 100px) between tiles, transparent and filled black.
    But nothing seems to help.

    I should mention that this is a procedurally generated mesh, and I am using a Surface Shader. There are no UVS on this mesh, so I am using world coordinates as UV. Then I am adding data into the Uv, Uv1, Uv2 etc, which I then read in the shader to figure out what tiles to paint. I am painting 16x16 tiles on each mesh.

    What I actually want to accomplish here is to use this gradient to blend between biomes. In this case Forest <> Desert. And this works well in my opinion except for these small random white pixels...
     
  4. deffan

    deffan

    Joined:
    May 24, 2015
    Posts:
    7
    I will paste my Shader code here, if anyone can see anything obviously wrong. (I am not very good at shaders).

    Code (CSharp):
    1. Shader "Custom/testshader"
    2. {
    3.     Properties
    4.     {
    5.         _DiffuseMap("Diffuse Map", 2D) = "white" {}
    6.         _DiffuseMap2("Diffuse Map 2", 2D) = "white" {}
    7.         _DiffuseMap3("Diffuse Map 3", 2D) = "white" {}
    8.         _DiffuseMap4("Diffuse Map 4", 2D) = "white" {}
    9.         _DiffuseMap5("Diffuse Map 5", 2D) = "white" {}
    10.     }
    11.  
    12.     SubShader
    13.     {
    14.         Tags{ "RenderType" = "Opaque" "Queue" = "Geometry" }
    15.         LOD 0
    16.  
    17.         CGPROGRAM
    18.         #pragma surface surf Standard fullforwardshadows
    19.         #pragma target 4.0
    20.  
    21.         sampler2D _DiffuseMap;
    22.  
    23.         struct Input
    24.         {
    25.             float4 screenPos;
    26.             float3 worldPos;
    27.             float3 worldNormal;
    28.             float2 uv_DiffuseMap : TEXCOORD0;
    29.             float2 uv2_DiffuseMap2 : TEXCOORD1;
    30.             float2 uv3_DiffuseMap3 : TEXCOORD2;
    31.             float2 uv4_DiffuseMap4 : TEXCOORD3;
    32.         };
    33.  
    34.         void surf(Input IN, inout SurfaceOutputStandard o)
    35.         {
    36.             float originalTileOffset = 0.0625f;        // tilesize(256) / texturesize(4096)
    37.             float yCoord = (1 - (IN.uv_DiffuseMap.y * originalTileOffset));    // Biome
    38.             float xCoord = (IN.uv_DiffuseMap.x * originalTileOffset);        // X TILE POS
    39.             float xCoordOther = (2 * originalTileOffset);                    // X TILE POS for the "other biome"
    40.  
    41.             float2 offsetY = float2(xCoord, yCoord);
    42.             float2 offsetX = float2(0, yCoord );
    43.             float2 offsetZ = float2(0, yCoord );
    44.  
    45.             // UVs are just world coordinates
    46.             float2 yUV = IN.worldPos.xz;
    47.             float2 xUV = IN.worldPos.zy;
    48.             float2 zUV = IN.worldPos.xy;
    49.  
    50.             // For blending towards sand at water level
    51.             float blendAmount = (1 - IN.worldNormal.y) / 4.0f;
    52.  
    53.             // If we are below 10, we are just sand.
    54.             if (IN.worldPos.y < 10)
    55.             {
    56.                 offsetY = float2(originalTileOffset, yCoord);
    57.                 offsetX = float2(originalTileOffset, yCoord);
    58.                 offsetZ = float2(originalTileOffset, yCoord);
    59.             }
    60.  
    61.             // SIDE X
    62.             float4 x = tex2D(_DiffuseMap, frac(xUV) * originalTileOffset + offsetX);
    63.  
    64.             // SIDE Z  
    65.             float4 z = tex2D(_DiffuseMap, frac(zUV) * originalTileOffset + offsetZ);
    66.  
    67.             // TOP / BOTTOM
    68.             float4 y = tex2D(_DiffuseMap, frac(yUV) * originalTileOffset + offsetY);
    69.  
    70.             // Biome blending
    71.             if (IN.uv3_DiffuseMap3.x >= 0)
    72.             {
    73.                 // Other biome tile (normal tile)
    74.                 float4 newy = y;
    75.                 float4 newx = x;
    76.                 float4 newz = z;
    77.                 if (IN.worldPos.y > 10)
    78.                 {
    79.                     // Recalculate for other-biome
    80.                     yCoord = (1 - (IN.uv3_DiffuseMap3.y * originalTileOffset));
    81.                     offsetY = float2(xCoordOther, yCoord);
    82.                     offsetX = float2(0, yCoord);
    83.                     offsetZ = float2(0, yCoord);
    84.  
    85.                     newy = tex2D(_DiffuseMap, frac(yUV) * originalTileOffset + offsetY);
    86.                     newx = tex2D(_DiffuseMap, frac(xUV) * originalTileOffset + offsetX);
    87.                     newz = tex2D(_DiffuseMap, frac(zUV) * originalTileOffset + offsetZ);
    88.                 }
    89.  
    90.                 // Blackwhite tile
    91.                 float blackWhiteTile_Y = (1 - (IN.uv2_DiffuseMap2.y * originalTileOffset));
    92.                 float4 y2 = tex2D(_DiffuseMap, frac(yUV) * originalTileOffset + float2(IN.uv3_DiffuseMap3.x * originalTileOffset, blackWhiteTile_Y));
    93.  
    94.                 y = lerp(y, newy, y2);
    95.                 x = lerp(x, newx, y2);
    96.                 z = lerp(z, newz, y2);
    97.             }
    98.  
    99.             // BLEND SAND WATER LEVEL
    100.             if (IN.worldPos.y > 10 && IN.worldPos.y < 12)
    101.             {
    102.                 // Sand
    103.                 float4 yy = tex2D(_DiffuseMap, frac(yUV) * originalTileOffset + float2(originalTileOffset, yCoord)); // sand
    104.                 float blendAmountS = (12 - IN.worldPos.y) / 2.0f;
    105.  
    106.                 y = lerp(y, yy, blendAmountS);
    107.                 x = lerp(x, y, blendAmountS);
    108.                 z = lerp(z, y, blendAmountS);
    109.             }
    110.  
    111.             // Dark waters
    112.             if (IN.worldPos.y < 5)
    113.             {
    114.                 float blendAmountW = (5 - IN.worldPos.y) / 2.0f;
    115.                 y = lerp(y, 0, blendAmountW);
    116.                 x = lerp(x, 0, blendAmountW);
    117.                 z = lerp(z, 0, blendAmountW);
    118.             }
    119.  
    120.             // Noise to "randomly" darken spots, making it more "realistic" or "varied"
    121.             y = lerp(y - IN.uv2_DiffuseMap2.x, y, y);
    122.  
    123.             float3 projNormal = saturate(pow(IN.worldNormal, 2));
    124.  
    125.             o.Albedo = lerp(o.Albedo, y, projNormal.y);
    126.             o.Albedo = lerp(o.Albedo, z, projNormal.z);
    127.             o.Albedo = lerp(o.Albedo, x, projNormal.x);
    128.         }
    129.         ENDCG
    130.  
    131.     }
    132.     Fallback "Diffuse"
    133. }