Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Seams problem on rendering a sub part of a texture using UV coordinates

Discussion in 'General Graphics' started by GuilhemGuilhem, Feb 11, 2016.

  1. GuilhemGuilhem

    GuilhemGuilhem

    Joined:
    Feb 11, 2016
    Posts:
    7
    Good morning everyone!

    I have a problem with a custom code I wrote for our 2D game. Initially we used sprites and atlases, but then we decided to have real time lighting. We switched to regular textures and materials, so we could attach normal maps easily.
    I had to write a crude atlas manager for those textures, so we could have large textures encompassing sub textures.
    Everything went fine until we realized that the seams of our sub textures are actually behaving abnormally:

    - Initial texture:


    - Here is what it sometimes looks like on the screen (10% of the time roughly): the seams may appear. The color is equal to a mix of the two closest colors: pure red (1,0,0,1) + pure green (0, 1, 0, 1) will give (1,.5,.5,1).


    - If adjoining two of those textures next to each other, it may also have a semi transparent seam:


    - What we expected instead:

    Here is the (much simplified) code that create the mesh:

    Code (CSharp):
    1. // The values for the texture given in the example are the following:
    2. int textureSize = 64; // total size of the texture
    3. int widthInPixel = 16; // size of a single sub texture.
    4. // We have 16 possible sub textures, numbered from 0 (top left) to 15 (bottom right)
    5. int index = 5; // we want sub texture number 5
    6. // this value will be used a lot in the following computations.
    7. int widthInRatio = width / textureSize;
    8.  
    9. // First, the vertices.
    10. Vector3[] vertices = new Vector3[4];
    11.  
    12. // We want to draw the texture from the top left corner of the game object position.
    13. // For this scenario, the mesh' size will be 1x1 units.
    14. vertices[0] = new Vector3(0f, 0f, 0f); // top left
    15. vertices[1] = new Vector3(1f, 0f, 0f); // top right
    16. vertices[2] = new Vector3(0f, -1f, 0f); // bottom left
    17. vertices[3] = new Vector3(1f, -1f, 0f); // bottom right
    18.  
    19. mesh.vertices = vertices;
    20.  
    21. // create the two triangles that will compose the square.
    22. // the first one is from vertice 0 -> 1 -> 2.
    23. // the second one is from vertice 3 -> 2 -> 1.
    24. int[] triangles = new int[6] { 0, 1, 2, 3, 2, 1 };
    25. mesh.triangles = triangles;
    26.  
    27. mesh.RecalculateNormals();
    28.  
    29. // create the list of tangents
    30. List<Vector4> list = new List<Vector4>();
    31. list.Add(new Vector4(1f, 0f, 0f, 1f)); // could it be that those need to be different?
    32. list.Add(new Vector4(1f, 0f, 0f, 1f)); // I have a feeling our problem could be here,
    33. list.Add(new Vector4(1f, 0f, 0f, 1f)); // but I do not know how to manipulate those.
    34. list.Add(new Vector4(1f, 0f, 0f, 1f));
    35.  
    36. mesh.SetTangents(list);
    37.  
    38. // set the mesh
    39. meshFilter.mesh = mesh;
    40.  
    41. // now compute the UV coordinates of our top left corner by finding which row and column correspond
    42. // to the texture index (5)
    43. float x = ((index * widthInPixel) % textureSize) / textureSize;
    44. float row = Mathf.Floor(index * widthInRatio);
    45. float y = 1f - row * widthInRatio;
    46.  
    47. Vector2[] uvs = new Vector2[4];
    48. uvs[0] = new Vector2(x, y); // top left
    49. uvs[1] = new Vector2(x + widthInRatio, y); //top right
    50. uvs[2] = new Vector2(x, y - widthInRatio); //bottomLeft
    51. uvs[3] = new Vector2(x + widthInRatio, y - widthInRatio); // bottomRight
    52.  
    53. mesh.uv = uvs;
    If anyone has some idea on how to fix this, we will take it!
     

    Attached Files:

  2. Teravisor

    Teravisor

    Joined:
    Dec 29, 2014
    Posts:
    654
    This most likely happens because of texture interpolation. Either set it to nearest or duplicate 1 pixel borders of your subtextures outwards. When set to interpolate, it probes neighbouring pixels (including those out of rectangle you take using UVs) and mixes them.
     
    Last edited: Feb 12, 2016
    theANMATOR2b likes this.
  3. l3fty

    l3fty

    Joined:
    Mar 23, 2013
    Posts:
    86
    Even point filtering (in 5.2.3 at least) seems to give some bleed over. I've noticed as I've recently converted a voxel project from 4.6 to 5.2.3, and in 4.6 it worked with no bleed over.
     
  4. GuilhemGuilhem

    GuilhemGuilhem

    Joined:
    Feb 11, 2016
    Posts:
    7
    Thank you a lot for your answers, you put a name on my problem and I was able to correctly search a solution for it!

    I solved it by using some code from here and there to modify our custom shader:

    Code (CSharp):
    1.  
    2.  
    3. v2f vert (appdata_t v)
    4. {
    5.  
    6. [...]
    7.  
    8. float hpcX = _ScreenParams.x * 0.5;
    9. float hpcY = _ScreenParams.y * 0.5;
    10. float hpcOX = -0.5;
    11. float hpcOY = 0.5;
    12.  
    13. // Snap
    14. float pos = floor((o.vertex.x / o.vertex.w) * hpcX + 0.5f) + hpcOX;
    15. o.vertex.x = pos / hpcX * o.vertex.w;
    16.  
    17. pos = floor((o.vertex.y / o.vertex.w) * hpcY + 0.5f) + hpcOY;
    18. o.vertex.y = pos / hpcY * o.vertex.w;
    19.  
    20. return o;
    21. }
    22.  
    Cheers!