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. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Texturing Greedy Mesh - missing UVs

Discussion in 'General Graphics' started by Sajgoniarz, Nov 2, 2018.

  1. Sajgoniarz

    Sajgoniarz

    Joined:
    Aug 7, 2014
    Posts:
    1
    Hello!

    Im working at my Boxel Engine, for performance reasons i picked up Greedy algorithm for generating my meshes, but I'm unable to texture it correctly, because there are no UV's in the meshes, since it threads all solid blocks as one surface. My current implementation :

    Code (CSharp):
    1. using System.Collections.Generic;
    2. using Assets.a3Engine.Types;
    3. using UnityEngine;
    4.  
    5. namespace a3Engine
    6. {
    7.     public static class MeshBuilder
    8.     {
    9.         public static MeshStruct BuildMesh(Chunk chunk)
    10.         {
    11.             int size = WorldManager.ChunkSize;
    12.  
    13.             Vector3[] normalDir =
    14.             {
    15.                 -Vector3.left,
    16.                 Vector3.up,
    17.                 Vector3.forward
    18.             };
    19.  
    20.             List<Vector3> vertices = new List<Vector3>();
    21.             List<Vector3> normals = new List<Vector3>();
    22.             List<int> elements = new List<int>();
    23.             MeshStruct meshStruct = new MeshStruct();
    24.  
    25.             int[] mask = new int[(size + 1) * (size + 1)];
    26.  
    27.             int index = 0;
    28.  
    29.             for (int d = 0; d < 3; d++)
    30.             {
    31.                 int i, j, k, l, w, h, u = (d + 1) % 3, v = (d + 2) % 3;
    32.  
    33.                 int[] x = new int[3];
    34.                 int[] q = new int[3];
    35.  
    36.                 q[d] = 1;
    37.  
    38.                 for (x[d] = -1; x[d] < size;)
    39.                 {
    40.                     int n = 0;
    41.                     for (x[v] = 0; x[v] < size; ++x[v])
    42.                     {
    43.                         for (x[u] = 0; x[u] < size; ++x[u], ++n)
    44.                         {
    45.                             Block aVoxel = chunk.GetBlock(x[0], x[1], x[2]);
    46.                             Block bVoxel = chunk.GetBlock(x[0] + q[0], x[1] + q[1], x[2] + q[2]);
    47.                             int a = 0, b = 0;
    48.  
    49.                             if (0 <= x[d] && aVoxel.Solid)
    50.                             {
    51.                                 a = 1;
    52.                             }
    53.  
    54.                             if (x[d] < size - 1 && bVoxel.Solid)
    55.                             {
    56.                                 b = 1;
    57.                             }
    58.  
    59.                             if (a == b)
    60.                             {
    61.                                 mask[n] = 0;
    62.                             }
    63.                             else if (a > 0)
    64.                             {
    65.                                 mask[n] = a;
    66.                             }
    67.                             else
    68.                             {
    69.                                 mask[n] = -b;
    70.                             }
    71.                         }
    72.                     }
    73.  
    74.                     ++x[d];
    75.  
    76.                     n = 0;
    77.                     for (j = 0; j < size; ++j)
    78.                     {
    79.                         for (i = 0; i < size;)
    80.                         {
    81.                             var c = mask[n];
    82.  
    83.                             if (c > -2)
    84.                             {
    85.                                 for (w = 1; c == mask[n + w] && i + w < size; ++w)
    86.                                 {
    87.                                 }
    88.  
    89.                                 bool done = false;
    90.                                 for (h = 1; j + h < size; ++h)
    91.                                 {
    92.                                     for (k = 0; k < w; ++k)
    93.                                     {
    94.                                         if (c != mask[n + k + h * size])
    95.                                         {
    96.                                             done = true;
    97.                                             break;
    98.                                         }
    99.                                     }
    100.  
    101.                                     if (done)
    102.                                         break;
    103.                                 }
    104.  
    105.                                 bool flip = false;
    106.  
    107.                                 x[u] = i;
    108.                                 x[v] = j;
    109.                                 int[] du = new int[3];
    110.                                 int[] dv = new int[3];
    111.  
    112.                                 if (c > -1)
    113.                                 {
    114.                                     du[u] = w;
    115.                                     dv[v] = h;
    116.                                 }
    117.                                 else
    118.                                 {
    119.                                     flip = true;
    120.                                     c = -c;
    121.                                     du[u] = w;
    122.                                     dv[v] = h;
    123.                                 }
    124.  
    125.                                 Vector3 v1 = new Vector3(x[0], x[1], x[2]);
    126.                                 Vector3 v2 = new Vector3(x[0] + du[0], x[1] + du[1], x[2] + du[2]);
    127.                                 Vector3 v3 = new Vector3(x[0] + du[0] + dv[0], x[1] + du[1] + dv[1],
    128.                                     x[2] + du[2] + dv[2]);
    129.                                 Vector3 v4 = new Vector3(x[0] + dv[0], x[1] + dv[1], x[2] + dv[2]);
    130.  
    131.                                 if (c > 0 && !flip)
    132.                                 {
    133.                                     vertices.Add(v1);
    134.                                     vertices.Add(v2);
    135.                                     vertices.Add(v3);
    136.                                     vertices.Add(v4);
    137.  
    138.                                     elements.Add(index);
    139.                                     elements.Add(index + 1);
    140.                                     elements.Add(index + 2);
    141.                                     elements.Add(index + 2);
    142.                                     elements.Add(index + 3);
    143.                                     elements.Add(index);
    144.  
    145.                                     Vector3 normal = normalDir[d];
    146.                                     normals.Add(normal);
    147.                                     normals.Add(normal);
    148.                                     normals.Add(normal);
    149.                                     normals.Add(normal);
    150.  
    151.                                     index += 4;
    152.                                 }
    153.                                 else if (flip)
    154.                                 {
    155.                                     vertices.Add(v4);
    156.                                     vertices.Add(v3);
    157.                                     vertices.Add(v2);
    158.                                     vertices.Add(v1);
    159.  
    160.                                     elements.Add(index);
    161.                                     elements.Add(index + 1);
    162.                                     elements.Add(index + 2);
    163.                                     elements.Add(index + 2);
    164.                                     elements.Add(index + 3);
    165.                                     elements.Add(index);
    166.  
    167.                                     Vector3 normal = -normalDir[d];
    168.                                     normals.Add(normal);
    169.                                     normals.Add(normal);
    170.                                     normals.Add(normal);
    171.                                     normals.Add(normal);
    172.  
    173.                                     index += 4;
    174.                                 }
    175.  
    176.                                 for (l = 0; l < h; ++l)
    177.                                 {
    178.                                     for (k = 0; k < w; ++k)
    179.                                     {
    180.                                         mask[n + k + l * size] = 0;
    181.                                     }
    182.                                 }
    183.  
    184.                                 i += w;
    185.                                 n += w;
    186.                             }
    187.                             else
    188.                             {
    189.                                 ++i;
    190.                                 ++n;
    191.                             }
    192.                         }
    193.                     }
    194.                 }
    195.             }
    196.  
    197.             meshStruct.vertices = vertices.ToArray();
    198.             meshStruct.triangles = elements.ToArray();
    199.             meshStruct.normals = normals.ToArray();
    200.  
    201.             return meshStruct;
    202.         }
    203.     }
    204. }
    I've tried to adopt Roboleary solution (https://github.com/roboleary/GreedyMesh) about 10 times, but i failed miserably, everytime ending with some twisted horrors.

    For now im using single Tri-Planar Shader to give my mesh reasonable look :

    Screenshot (42).png

    Can someone tweak my code, to create submeshes for different materials, show me shader to put correct material basing on chunk block or point me the way how can i retrieve uvs data?

    I read famous thread (https://forum.unity.com/threads/after-playing-minecraft.63149) but i found nothing useful there about texturing greedy mesh.
     
  2. Llama_w_2Ls

    Llama_w_2Ls

    Joined:
    May 16, 2020
    Posts:
    7
    I know this is a little late, but I did find out how to texture a greedy mesh without having to split it into submeshes.

    Obviously the main issue is tiling. If you set your uvs on a cuboid section of your mesh with sizes 1x1x5, the texture will be stretched on the z axis.

    If youre using a texture atlas, and you tile the uvs by the size in a shader or in your mesh code, the texture wont be stretched, but each cube in that cuboid section will be a different tile.

    This is because texture atlasas cant repeat.

    Texture ARRAYS are the solution. They can repeat and automatically tile.

    They place each tile on the texture atlas into an array with the z component of your uv that represents the depth or the index of that tile in the array.

    Create your texture array using the TextureArray2D class, with the correct indexes, so tile 3, 2 on a texture atlas with size 4x4, would have an index of 14.

    This is y × atlasWidth + x or in this case, 3 x 4 + 2.

    Next, you need to create your uvs using vector3's instead. So the uvs of a face on your greedy mesh would look like 5,2,8 for example, where 5 is the uv's x coord * by size X, 2 is the uv's y coord * by size Y, and 8 is the index in the texture array, which is the type of tile.

    So your complete uvs for one face may look like:

    0,0,5
    0,size.y,5
    size.x,0,5
    size.x, size.y, 5

    Lastly, pass this data into your mesh using mesh.SetUVs(Vector3[] uvs);

    Yout custom shader should use the z component of the uv to sample the correct texture.

    I will upload my shader graph soon to show you what the shader should look like.

    For more info, research more into texture arrays and how to create/use them.

    Hope this helps someone down the line. Reply if you want me to explain anything more!
     
    AldeRoberge likes this.