Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Help with texturing and using SetPixels

Discussion in 'Scripting' started by benjammin1391, Mar 4, 2015.

  1. benjammin1391

    benjammin1391

    Joined:
    Feb 10, 2015
    Posts:
    17
    Im working on a 2D tilemap for a game and Im running into a rather confusing problem.

    The way the system I use works is that first I generate an 2D array of enums, which represent all of the different tile types. This array works fine, its basically just a tile's X,Y coordinates and their type. That part isnt the issue.

    The issue comes when I try to generate the textured map. How I do this is I generate several square meshes, each one being 128 square Unity units.

    I then chop each mesh up into tile-sized section. Each tile is roughly one unit, so each mesh gets 128*128 of them. After that I move the new mesh to its position in the world, and I tell it to grab the tile data from the big array at the same position of the mesh's coordinates. (So the first mesh's first tile grabs the tile data in [0,0] of the array, and so on)

    The way I set the texture onto the tile is as follows:

    Code (CSharp):
    1.  
    2. for (int y = startY; y < startY + 128; y++)
    3. {
    4.      for (int x = startX; x < startX + 128; x++)
    5.      {
    6.         Color[] p = tiles[map.GetTileAt(x, y)];
    7.         mapTexture.SetPixels((int)(x * tileResolution), (int)(y * tileResolution), (int)(tileResolution), (int)(tileResolution), p);  
    8.      }
    9. }
    10.  
    startX and startY are the starting coordinates for the mesh. (So mesh 1 starts at (0,0) mesh 2 at (128,0) mesh 3 at (0,128) etc)

    The problem I run into is that any mesh generated after the first one does not work. When I create a map with one single mesh it textures fine, everything is dandy. However if I try and create more than one mesh Unity freezes up and stops responding. It does NOT outright crash, just freezes indefinitely.

    Now, Im thinking that the issue lies with my use of SetPixels, and I'm not feeding it the proper coordinates somehow. But I am not sure where my logic went wrong.

    If you need more information, here are the two problematic methods in full:

    Code (CSharp):
    1. Color[][] ChopUpTiles()
    2.     {
    3.         Debug.Log("Start chopping");
    4.         int numTilesPerRow = (int)(terrainTiles.width / tileResolution);
    5.         int numRows = (int)(terrainTiles.height / tileResolution);
    6.  
    7.         Color[][] tiles = new Color[numTilesPerRow * numRows][];
    8.         for (int y = 0; y < numRows; y++)
    9.         {
    10.             for (int x = 0; x < numTilesPerRow; x++)
    11.             {
    12.                 tiles[y * numTilesPerRow + x] = terrainTiles.GetPixels((x) * tileResolution, (y) * tileResolution, tileResolution, tileResolution);
    13.             }
    14.         }
    15.  
    16.         Debug.Log("End chopping");
    17.         return tiles;
    18.     }
    19.  
    20.     void BuildTexture(TDMap mapInput)
    21.     {
    22.         Debug.Log("Start a Texture");
    23.         map = mapInput;
    24.  
    25.         int texWidth = 128 * tileResolution;
    26.         int texHeight = 128 * tileResolution;
    27.         Texture2D mapTexture = new Texture2D(texWidth, texHeight);
    28.      
    29.         Color[][] tiles = ChopUpTiles();
    30.  
    31.         Debug.Log("Start texture loops");
    32.         for (int y = startY; y < startY + 128; y++)
    33.         {
    34.             for (int x = startX; x < startX + 128; x++)
    35.             {
    36.                 Color[] p = tiles[map.GetTileAt(x, y)];
    37.                 mapTexture.SetPixels((int)(x * tileResolution), (int)(y * tileResolution), (int)(tileResolution), (int)(tileResolution), p);
    38.              
    39.             }
    40.         }
    41.         Debug.Log("End texture loops");
    42.  
    43.         mapTexture.filterMode = FilterMode.Trilinear;
    44.         mapTexture.wrapMode = TextureWrapMode.Repeat;
    45.         mapTexture.Apply();
    46.  
    47.         MeshRenderer mesh_renderer = GetComponent<MeshRenderer>();
    48.  
    49.         mesh_renderer.sharedMaterials[0].mainTexture = mapTexture;
    50.         Debug.Log("End a texture");
    51.  
    52.     }
    terrainTiles is the texture file of all of my tile sprites
    tileResolution is the number of pixels in each tile (hard set to 64)

    I can also post more code if other aspects seem questionable.

    Please help, I am at my wits end here.
     
  2. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    I'd recommend setting the mesh UVs appropriately instead of using SetPixels. It will be much faster and use far less RAM.

    --Eric
     
  3. benjammin1391

    benjammin1391

    Joined:
    Feb 10, 2015
    Posts:
    17
    Issue is that the texture is all randomly generated. Every time a map is made the tile array is all different.

    So how would I go about doing uv mapping on something like that? I have little experience with it at all, and Ive probably bitten off way more than I can chew right now.
     
  4. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    UV mapping works the same regardless of what the texture is. e.g., you have a texture with 2x2 tiles, so to map the bottom-left tile, the UVs are (0, 0) in the bottom-left corner, (0, .5) for top-left, (.5, 0) for bottom-right, and (.5, .5) for top-right.

    --Eric
     
  5. benjammin1391

    benjammin1391

    Joined:
    Feb 10, 2015
    Posts:
    17
    Hmmm...

    Ok so heres where I build the actual meshes as of now:

    Code (CSharp):
    1. public void BuildMesh()
    2.     {
    3.         Debug.Log("Start a mesh");
    4.         Mesh m = new Mesh();
    5.         m.name = "ScriptedMesh";
    6.         m.vertices = new Vector3[]
    7.         {
    8.          new Vector3(startX, startY, 0),
    9.          new Vector3(startX+128, startY, 0),
    10.          new Vector3(startX+128, startY+128, 0),
    11.          new Vector3(startX, startY+128, 0)
    12.        };
    13.         m.uv = new Vector2[]
    14.         {
    15.          new Vector2 (0, 0),
    16.          new Vector2 (1, 0),
    17.          new Vector2(1, 1),
    18.          new Vector2 (0, 1)
    19.        };
    20.         m.triangles = new int[] { 0, 2, 1, 0, 3, 2 };
    21.         m.RecalculateNormals();
    22.         m.RecalculateBounds();
    23.         m.Optimize();
    24.  
    25.         // Assign our mesh to our filter/renderer/collider
    26.         MeshFilter mesh_filter = GetComponent<MeshFilter>();
    27.         MeshCollider mesh_collider = GetComponent<MeshCollider>();
    28.  
    29.         mesh_filter.mesh = m;
    30.         mesh_collider.sharedMesh = m;
    31.  
    32.         Debug.Log("End a mesh");
    33.         BuildTexture(map);
    34.     }
    Its a simple square mesh with 2 triangles that ends up being 128 units. Would I have to basically break up the section that does UVs to account for every single tile or what?

    Sorry if this is simple stuff, I have never manually generated UVs, usually I have em done in Maya or something...
     
  6. benjammin1391

    benjammin1391

    Joined:
    Feb 10, 2015
    Posts:
    17
    A day later and Im still stumped. Sorry if Im being a bother but I'm really having a rough time here.