Search Unity

UV mapping procedurally generated wall

Discussion in 'Scripting' started by brandontod97, Mar 22, 2019.

  1. brandontod97

    brandontod97

    Joined:
    Jul 25, 2017
    Posts:
    2
    Using the unity cave tutorial (Cave Tutorial) and the other forum thread on procedural uv mapping (Forum link post 89), we were able to map textures on to the generated walls. However, a weird distortion effect appears in an arc shape when moving the camera (See attached picture).

    We think it has to do with the uv mapping as only the walls are affected, and it happens with any texture applied to the walls.

    All other code is the same as in the cave tutorial.

    Any help is appreciated.

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4.  
    5. public class MeshGenerator : MonoBehaviour
    6. {
    7.  
    8.     public SquareGrid squareGrid;
    9.     public MeshFilter walls;
    10.     public MeshFilter cave;
    11.  
    12.     public bool is2D;
    13.     public float wallHeight = 5;
    14.     List<Vector3> vertices;
    15.     List<int> triangles;
    16.  
    17.     Dictionary<int, List<Triangle>> triangleDictionary = new Dictionary<int, List<Triangle>>();
    18.     List<List<int>> outlines = new List<List<int>>();
    19.     HashSet<int> checkedVertices = new HashSet<int>();
    20.  
    21.     public void GenerateMesh(int[,] map, float squareSize)
    22.     {
    23.  
    24.         triangleDictionary.Clear();
    25.         outlines.Clear();
    26.         checkedVertices.Clear();
    27.  
    28.         squareGrid = new SquareGrid(map, squareSize, wallHeight);
    29.  
    30.         vertices = new List<Vector3>();
    31.         triangles = new List<int>();
    32.  
    33.         for (int x = 0; x < squareGrid.squares.GetLength(0); x++)
    34.         {
    35.             for (int y = 0; y < squareGrid.squares.GetLength(1); y++)
    36.             {
    37.                 TriangulateSquare(squareGrid.squares[x, y]);
    38.             }
    39.         }
    40.  
    41.         Mesh mesh = new Mesh();
    42.         cave.mesh = mesh;
    43.  
    44.         mesh.vertices = vertices.ToArray();
    45.         mesh.triangles = triangles.ToArray();
    46.         mesh.RecalculateNormals();
    47.  
    48.         int tileAmount = 10;
    49.         Vector2[] uvs = new Vector2[vertices.Count];
    50.         for (int i = 0; i < vertices.Count; i++)
    51.         {
    52.             float percentX = Mathf.InverseLerp(-map.GetLength(0) / 2 * squareSize, map.GetLength(0) / 2 * squareSize, vertices[i].x) * tileAmount;
    53.             float percentY = Mathf.InverseLerp(-map.GetLength(0) / 2 * squareSize, map.GetLength(0) / 2 * squareSize, vertices[i].z) * tileAmount;
    54.             uvs[i] = new Vector2(percentX, percentY);
    55.         }
    56.         mesh.uv = uvs;
    57.  
    58.  
    59.         if (is2D)
    60.         {
    61.             Generate2DColliders();
    62.         }
    63.         else
    64.         {
    65.             CreateWallMesh();
    66.  
    67.             // Use a copy of the mesh!
    68.             //Mesh tempMesh = Instantiate(walls.mesh);
    69.             //UVMapper.BoxUV(tempMesh, transform);
    70.  
    71.             //GetComponent<MeshFilter>().sharedMesh = tempMesh;
    72.         }
    73.     }
    74.  
    75.     void CreateWallMesh()
    76.     {
    77.  
    78.         CalculateMeshOutlines();
    79.  
    80.         List<Vector3> wallVertices = new List<Vector3>();
    81.         List<int> wallTriangles = new List<int>();
    82.         Mesh wallMesh = new Mesh();
    83.        
    84.  
    85.         foreach (List<int> outline in outlines)
    86.         {
    87.             for (int i = 0; i < outline.Count - 1; i++)
    88.             {
    89.                 int startIndex = wallVertices.Count;
    90.                 wallVertices.Add(vertices[outline[i]]); // left
    91.                 wallVertices.Add(vertices[outline[i + 1]]); // right
    92.                 wallVertices.Add(vertices[outline[i]] - Vector3.up * wallHeight); // bottom left
    93.                 wallVertices.Add(vertices[outline[i + 1]] - Vector3.up * wallHeight); // bottom right
    94.  
    95.                 wallTriangles.Add(startIndex + 0);
    96.                 wallTriangles.Add(startIndex + 2);
    97.                 wallTriangles.Add(startIndex + 3);
    98.  
    99.                 wallTriangles.Add(startIndex + 3);
    100.                 wallTriangles.Add(startIndex + 1);
    101.                 wallTriangles.Add(startIndex + 0);
    102.             }
    103.         }
    104.         wallMesh.vertices = wallVertices.ToArray();
    105.         wallMesh.triangles = wallTriangles.ToArray();
    106.         walls.mesh = wallMesh;
    107.  
    108.         //GENERATE UV COORDINATES HERE
    109.         Vector2[] uvs = new Vector2[wallVertices.Count];
    110.         int march = 0;
    111.         for (int i = 0; i < wallVertices.Count; i++)
    112.         {
    113.             switch (march)
    114.             {
    115.                 case 0:
    116.                     uvs[i] = new Vector2(0, 1);
    117.                     march++;
    118.                     break;
    119.                 case 1:
    120.                     uvs[i] = new Vector2(0.5f, 1);
    121.                     march++;
    122.                     break;
    123.                 case 2:
    124.                     uvs[i] = new Vector2(0, 0);
    125.                     march++;
    126.                     break;
    127.                 case 3:
    128.                     uvs[i] = new Vector2(0.5f, 0);
    129.                     march++;
    130.                     break;
    131.                 case 4:
    132.                     uvs[i] = new Vector2(0.5f, 1);
    133.                     march++;
    134.                     break;
    135.                 case 5:
    136.                     uvs[i] = new Vector2(1, 1);
    137.                     march++;
    138.                     break;
    139.                 case 6:
    140.                     uvs[i] = new Vector2(0.5f, 0);
    141.                     march++;
    142.                     break;
    143.                 case 7:
    144.                     uvs[i] = new Vector2(1, 0);
    145.                     march = 0;
    146.                     break;
    147.             }
    148.         }
    149.         wallMesh.uv = uvs;
    150.  
    151.         MeshCollider wallCollider = walls.gameObject.GetComponent<MeshCollider>();
    152.         wallCollider.sharedMesh = wallMesh;
    153.     }
    154.  
    155.     void Generate2DColliders()
    156.     {
    157.  
    158.         EdgeCollider2D[] currentColliders = gameObject.GetComponents<EdgeCollider2D>();
    159.         for (int i = 0; i < currentColliders.Length; i++)
    160.         {
    161.             Destroy(currentColliders[i]);
    162.         }
    163.  
    164.         CalculateMeshOutlines();
    165.  
    166.         foreach (List<int> outline in outlines)
    167.         {
    168.             EdgeCollider2D edgeCollider = gameObject.AddComponent<EdgeCollider2D>();
    169.             Vector2[] edgePoints = new Vector2[outline.Count];
    170.  
    171.             for (int i = 0; i < outline.Count; i++)
    172.             {
    173.                 edgePoints[i] = new Vector2(vertices[outline[i]].x, vertices[outline[i]].z);
    174.             }
    175.             edgeCollider.points = edgePoints;
    176.         }
    177.  
    178.     }
    179.  
    180.     void TriangulateSquare(Square square)
    181.     {
    182.         switch (square.configuration)
    183.         {
    184.             case 0:
    185.                 break;
    186.  
    187.             // 1 points:
    188.             case 1:
    189.                 MeshFromPoints(square.centreLeft, square.centreBottom, square.bottomLeft);
    190.                 break;
    191.             case 2:
    192.                 MeshFromPoints(square.bottomRight, square.centreBottom, square.centreRight);
    193.                 break;
    194.             case 4:
    195.                 MeshFromPoints(square.topRight, square.centreRight, square.centreTop);
    196.                 break;
    197.             case 8:
    198.                 MeshFromPoints(square.topLeft, square.centreTop, square.centreLeft);
    199.                 break;
    200.  
    201.             // 2 points:
    202.             case 3:
    203.                 MeshFromPoints(square.centreRight, square.bottomRight, square.bottomLeft, square.centreLeft);
    204.                 break;
    205.             case 6:
    206.                 MeshFromPoints(square.centreTop, square.topRight, square.bottomRight, square.centreBottom);
    207.                 break;
    208.             case 9:
    209.                 MeshFromPoints(square.topLeft, square.centreTop, square.centreBottom, square.bottomLeft);
    210.                 break;
    211.             case 12:
    212.                 MeshFromPoints(square.topLeft, square.topRight, square.centreRight, square.centreLeft);
    213.                 break;
    214.             case 5:
    215.                 MeshFromPoints(square.centreTop, square.topRight, square.centreRight, square.centreBottom, square.bottomLeft, square.centreLeft);
    216.                 break;
    217.             case 10:
    218.                 MeshFromPoints(square.topLeft, square.centreTop, square.centreRight, square.bottomRight, square.centreBottom, square.centreLeft);
    219.                 break;
    220.  
    221.             // 3 point:
    222.             case 7:
    223.                 MeshFromPoints(square.centreTop, square.topRight, square.bottomRight, square.bottomLeft, square.centreLeft);
    224.                 break;
    225.             case 11:
    226.                 MeshFromPoints(square.topLeft, square.centreTop, square.centreRight, square.bottomRight, square.bottomLeft);
    227.                 break;
    228.             case 13:
    229.                 MeshFromPoints(square.topLeft, square.topRight, square.centreRight, square.centreBottom, square.bottomLeft);
    230.                 break;
    231.             case 14:
    232.                 MeshFromPoints(square.topLeft, square.topRight, square.bottomRight, square.centreBottom, square.centreLeft);
    233.                 break;
    234.  
    235.             // 4 point:
    236.             case 15:
    237.                 MeshFromPoints(square.topLeft, square.topRight, square.bottomRight, square.bottomLeft);
    238.                 checkedVertices.Add(square.topLeft.vertexIndex);
    239.                 checkedVertices.Add(square.topRight.vertexIndex);
    240.                 checkedVertices.Add(square.bottomRight.vertexIndex);
    241.                 checkedVertices.Add(square.bottomLeft.vertexIndex);
    242.                 break;
    243.         }
    244.  
    245.     }
    246.  
    247.     void MeshFromPoints(params Node[] points)
    248.     {
    249.         AssignVertices(points);
    250.  
    251.         if (points.Length >= 3)
    252.             CreateTriangle(points[0], points[1], points[2]);
    253.         if (points.Length >= 4)
    254.             CreateTriangle(points[0], points[2], points[3]);
    255.         if (points.Length >= 5)
    256.             CreateTriangle(points[0], points[3], points[4]);
    257.         if (points.Length >= 6)
    258.             CreateTriangle(points[0], points[4], points[5]);
    259.  
    260.     }
    261.  
    262.     void AssignVertices(Node[] points)
    263.     {
    264.         for (int i = 0; i < points.Length; i++)
    265.         {
    266.             if (points[i].vertexIndex == -1)
    267.             {
    268.                 points[i].vertexIndex = vertices.Count;
    269.                 vertices.Add(points[i].position);
    270.             }
    271.         }
    272.     }
    273.  
    274.     void CreateTriangle(Node a, Node b, Node c)
    275.     {
    276.         triangles.Add(a.vertexIndex);
    277.         triangles.Add(b.vertexIndex);
    278.         triangles.Add(c.vertexIndex);
    279.  
    280.         Triangle triangle = new Triangle(a.vertexIndex, b.vertexIndex, c.vertexIndex);
    281.         AddTriangleToDictionary(triangle.vertexIndexA, triangle);
    282.         AddTriangleToDictionary(triangle.vertexIndexB, triangle);
    283.         AddTriangleToDictionary(triangle.vertexIndexC, triangle);
    284.     }
    285.  
    286.     void AddTriangleToDictionary(int vertexIndexKey, Triangle triangle)
    287.     {
    288.         if (triangleDictionary.ContainsKey(vertexIndexKey))
    289.         {
    290.             triangleDictionary[vertexIndexKey].Add(triangle);
    291.         }
    292.         else
    293.         {
    294.             List<Triangle> triangleList = new List<Triangle>();
    295.             triangleList.Add(triangle);
    296.             triangleDictionary.Add(vertexIndexKey, triangleList);
    297.         }
    298.     }
    299.  
    300.     void CalculateMeshOutlines()
    301.     {
    302.  
    303.         for (int vertexIndex = 0; vertexIndex < vertices.Count; vertexIndex++)
    304.         {
    305.             if (!checkedVertices.Contains(vertexIndex))
    306.             {
    307.                 int newOutlineVertex = GetConnectedOutlineVertex(vertexIndex);
    308.                 if (newOutlineVertex != -1)
    309.                 {
    310.                     checkedVertices.Add(vertexIndex);
    311.  
    312.                     List<int> newOutline = new List<int>();
    313.                     newOutline.Add(vertexIndex);
    314.                     outlines.Add(newOutline);
    315.                     FollowOutline(newOutlineVertex, outlines.Count - 1);
    316.                     outlines[outlines.Count - 1].Add(vertexIndex);
    317.                 }
    318.             }
    319.         }
    320.     }
    321.  
    322.     void FollowOutline(int vertexIndex, int outlineIndex)
    323.     {
    324.         outlines[outlineIndex].Add(vertexIndex);
    325.         checkedVertices.Add(vertexIndex);
    326.         int nextVertexIndex = GetConnectedOutlineVertex(vertexIndex);
    327.  
    328.         if (nextVertexIndex != -1)
    329.         {
    330.             FollowOutline(nextVertexIndex, outlineIndex);
    331.         }
    332.     }
    333.  
    334.     int GetConnectedOutlineVertex(int vertexIndex)
    335.     {
    336.         List<Triangle> trianglesContainingVertex = triangleDictionary[vertexIndex];
    337.  
    338.         for (int i = 0; i < trianglesContainingVertex.Count; i++)
    339.         {
    340.             Triangle triangle = trianglesContainingVertex[i];
    341.  
    342.             for (int j = 0; j < 3; j++)
    343.             {
    344.                 int vertexB = triangle[j];
    345.                 if (vertexB != vertexIndex && !checkedVertices.Contains(vertexB))
    346.                 {
    347.                     if (IsOutlineEdge(vertexIndex, vertexB))
    348.                     {
    349.                         return vertexB;
    350.                     }
    351.                 }
    352.             }
    353.         }
    354.  
    355.         return -1;
    356.     }
    357.  
    358.     bool IsOutlineEdge(int vertexA, int vertexB)
    359.     {
    360.         List<Triangle> trianglesContainingVertexA = triangleDictionary[vertexA];
    361.         int sharedTriangleCount = 0;
    362.  
    363.         for (int i = 0; i < trianglesContainingVertexA.Count; i++)
    364.         {
    365.             if (trianglesContainingVertexA[i].Contains(vertexB))
    366.             {
    367.                 sharedTriangleCount++;
    368.                 if (sharedTriangleCount > 1)
    369.                 {
    370.                     break;
    371.                 }
    372.             }
    373.         }
    374.         return sharedTriangleCount == 1;
    375.     }
    376.  
    377.     struct Triangle
    378.     {
    379.         public int vertexIndexA;
    380.         public int vertexIndexB;
    381.         public int vertexIndexC;
    382.         int[] vertices;
    383.  
    384.         public Triangle(int a, int b, int c)
    385.         {
    386.             vertexIndexA = a;
    387.             vertexIndexB = b;
    388.             vertexIndexC = c;
    389.  
    390.             vertices = new int[3];
    391.             vertices[0] = a;
    392.             vertices[1] = b;
    393.             vertices[2] = c;
    394.         }
    395.  
    396.         public int this[int i]
    397.         {
    398.             get
    399.             {
    400.                 return vertices[i];
    401.             }
    402.         }
    403.  
    404.  
    405.         public bool Contains(int vertexIndex)
    406.         {
    407.             return vertexIndex == vertexIndexA || vertexIndex == vertexIndexB || vertexIndex == vertexIndexC;
    408.         }
    409.     }
    410.  
    411.     public class SquareGrid
    412.     {
    413.         public Square[,] squares;
    414.      
    415.  
    416.         public SquareGrid(int[,] map, float squareSize, float _wallHeight)
    417.         {
    418.             int nodeCountX = map.GetLength(0);
    419.             int nodeCountY = map.GetLength(1);
    420.             float mapWidth = nodeCountX * squareSize;
    421.             float mapHeight = nodeCountY * squareSize;
    422.  
    423.             ControlNode[,] controlNodes = new ControlNode[nodeCountX, nodeCountY];
    424.  
    425.             for (int x = 0; x < nodeCountX; x++)
    426.             {
    427.                 for (int y = 0; y < nodeCountY; y++)
    428.                 {
    429.                     Vector3 pos = new Vector3(-mapWidth / 2 + x * squareSize + squareSize / 2, 0, -mapHeight / 2 + y * squareSize + squareSize / 2); //SETS X TO BE _wallHeight (Note:By default wallHeight is negative)
    430.                     controlNodes[x, y] = new ControlNode(pos, map[x, y] == 1, squareSize); //LOOKS FOR 0 INSTEAD OF 1
    431.                 }
    432.             }
    433.  
    434.             squares = new Square[nodeCountX - 1, nodeCountY - 1];
    435.             for (int x = 0; x < nodeCountX - 1; x++)
    436.             {
    437.                 for (int y = 0; y < nodeCountY - 1; y++)
    438.                 {
    439.                     squares[x, y] = new Square(controlNodes[x, y + 1], controlNodes[x + 1, y + 1], controlNodes[x + 1, y], controlNodes[x, y]);
    440.                 }
    441.             }
    442.  
    443.             //for (int x = 0; x < nodeCountX; x++)
    444.             //{
    445.             //    for (int y = 0; y < nodeCountY; y++)
    446.             //    {
    447.             //        Vector3 pos = new Vector3(-mapWidth / 2 + x * squareSize + squareSize / 2, 0, -mapHeight / 2 + y * squareSize + squareSize / 2);
    448.             //        controlNodes[x, y] = new ControlNode(pos, map[x, y] == 1, squareSize);
    449.             //    }
    450.             //}
    451.  
    452.             //squares = new Square[nodeCountX - 1, nodeCountY - 1];
    453.             //for (int x = 0; x < nodeCountX - 1; x++)
    454.             //{
    455.             //    for (int y = 0; y < nodeCountY - 1; y++)
    456.             //    {
    457.             //        squares[x, y] = new Square(controlNodes[x, y + 1], controlNodes[x + 1, y + 1], controlNodes[x + 1, y], controlNodes[x, y]);
    458.             //    }
    459.             //}
    460.  
    461.         }
    462.     }
    463.  
    464.     public class Square
    465.     {
    466.  
    467.         public ControlNode topLeft, topRight, bottomRight, bottomLeft;
    468.         public Node centreTop, centreRight, centreBottom, centreLeft;
    469.         public int configuration;
    470.  
    471.         public Square(ControlNode _topLeft, ControlNode _topRight, ControlNode _bottomRight, ControlNode _bottomLeft)
    472.         {
    473.             topLeft = _topLeft;
    474.             topRight = _topRight;
    475.             bottomRight = _bottomRight;
    476.             bottomLeft = _bottomLeft;
    477.  
    478.             centreTop = topLeft.right;
    479.             centreRight = bottomRight.above;
    480.             centreBottom = bottomLeft.right;
    481.             centreLeft = bottomLeft.above;
    482.  
    483.             if (topLeft.active)
    484.                 configuration += 8;
    485.             if (topRight.active)
    486.                 configuration += 4;
    487.             if (bottomRight.active)
    488.                 configuration += 2;
    489.             if (bottomLeft.active)
    490.                 configuration += 1;
    491.         }
    492.  
    493.     }
    494.  
    495.     public class Node
    496.     {
    497.         public Vector3 position;
    498.         public int vertexIndex = -1;
    499.  
    500.         public Node(Vector3 _pos)
    501.         {
    502.             position = _pos;
    503.         }
    504.     }
    505.  
    506.     public class ControlNode : Node
    507.     {
    508.  
    509.         public bool active;
    510.         public Node above, right;
    511.  
    512.         public ControlNode(Vector3 _pos, bool _active, float squareSize) : base(_pos)
    513.         {
    514.             active = _active;
    515.             above = new Node(position + Vector3.forward * squareSize / 2f);
    516.             right = new Node(position + Vector3.right * squareSize / 2f);
    517.         }
    518.  
    519.     }
    520. }
     

    Attached Files:

  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,745
    Cut down your built geometry so it's just a single UV-mapped quad "wall." Does the same problem occur?