Search Unity

custom shader multitexture seam problem

Discussion in 'Shaders' started by Chris-Crafty, Jan 15, 2016.

  1. Chris-Crafty

    Chris-Crafty

    Joined:
    May 7, 2013
    Posts:
    27
    Hello there! I'm trying to write one of my first shaders, solving a problem I have with displaying a high resolution game map.currently I use 12 square planes with different originally seamless textures on them, aligned perfectly to each other. At certain camera distances, there is still a seam visible because of - naturally - the imperfection of single precision floating point operations. My idea now was to instead of use 12 separate planes, I would use one plane and a shader that gets these 12 textures as a 3D texture, using whichever texture applies to the current uv position as a source.

    Aside from having problems with the 3D texture "filling" (they seem to overlay each other instead of being separate textures), I still get a seam at certain distances, which I can't really explain. Maybe one of the gurus here can help me out with this one or have a better alternative to realising this (e.g. using submaterials on a custom made plane, which would require reworking the underlying plane mesh every time the resolution of the map changes, but ok).

    I have simplified the code to just 2 textures for now, just to get the hang of it, but it still won't work. I have based my code on the "unlit" base shader of Unity:
    Code (csharp):
    1. Shader "Unlit/CraftyMapShader"
    2. {
    3.     Properties
    4.     {
    5.         _texsizeX("MapSizeX", Int) = 1
    6.         _texsizeY("MapSizeY", Int) = 1
    7.         // _MainTex ("Texture", 3D) = "white" {}
    8.         _Tex1("Texture 1", 2D) = "white" {}
    9.         _Tex2("Texture 2", 2D) = "white" {}
    10.     }
    11.     SubShader
    12.     {
    13.         Tags { "RenderType"="Opaque" }
    14.         LOD 100
    15.  
    16.         Pass
    17.         {
    18.             CGPROGRAM
    19.             #pragma vertex vert
    20.             #pragma fragment frag
    21.            
    22.             #include "UnityCG.cginc"
    23.  
    24.             struct appdata
    25.             {
    26.                 float4 vertex : POSITION;
    27.                 float2 uv : TEXCOORD0;
    28.             };
    29.  
    30.             struct v2f
    31.             {
    32.                 float2 uv : TEXCOORD0;
    33.                 float4 vertex : SV_POSITION;
    34.             };
    35.  
    36.             sampler2D _Tex1;
    37.             sampler2D _Tex2;
    38.             float _texsizeX;
    39.             float _texsizeY;
    40.  
    41.             v2f vert (appdata v)
    42.             {
    43.                 v2f o;
    44.                 o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
    45.                 o.uv = v.uv;
    46.                 return o;
    47.             }
    48.            
    49.             fixed4 frag(v2f i) : SV_Target
    50.             {
    51.                 int2 mypos = int2(floor(i.uv.x * _texsizeX), floor(i.uv.y * _texsizeY));
    52.                 float2 xuv = float2(i.uv.x * _texsizeX, i.uv.y * _texsizeY);
    53.                 float2 uv = float2(xuv.x - floor(xuv.x), i.uv.y - floor(xuv.y));
    54.                 if( mypos.x == 0 )
    55.                     return tex2D(_Tex1, uv);
    56.                 else
    57.                     return tex2D(_Tex2, uv);
    58.             }
    59.             ENDCG
    60.         }
    61.     }
    62. }
    And this is what happens:
    One distance is fine:


    And another is not


    Especially when using an animated zoom, these little one-pixel-lines are extremely annoying and especially visible. Any help would be greatly appreciated, thank you!
     
  2. jvo3dc

    jvo3dc

    Joined:
    Oct 11, 2013
    Posts:
    1,520
    Not really. If the vertices are actually at the exact same position, you'll see no seam. Any imperfection in the single precision floating point calculations will apply similarly to both sides.

    The sampling of the texture can go wrong though. Different mipmap levels are selected at different distances and whether the sampling is set to repeat or clamp, both are not 100% correct. The easiest way to solve is would be of course to just use one big texture, but I assume that's not an option.

    It might help to switch between a 4x3, 2x2 and 1x1 grid based on distance. Then at least the 1x1 version is perfect and the 4x3 and 2x2 versions should have no mipmap issues.
     
  3. Chris-Crafty

    Chris-Crafty

    Joined:
    May 7, 2013
    Posts:
    27
    You are absolutely right, by deactivating mipmaps alltogether, the error goes away, thank you very much!

    Now I have a followup question: As far as I am aware, Mipmaps are used to reduce load on the graphics card by using smaller versions of a texture to draw at higher distance from the camera. So, in my theory, and provided that this technique is only used in a very special "map" scene where there is only very few other textures present at all (36 setpass calls at the most), mipmapping shouldn't be necessary and I wouldn't loose anything. Is that correct, or do I overlook something?
     
  4. jvo3dc

    jvo3dc

    Joined:
    Oct 11, 2013
    Posts:
    1,520
    Mipmapping does reduce the load in terms of memory transfers. The main reason to use it is visual though. It removes aliasing at higher distances. In this special case you might not need it, depending on which zoom levels you offer. But I would use 4x3, 2x2 and 1x1 versions like I mentioned in which case only the 1x1 version needs mipmaps.