Advertisement
Guest User

MeshGenerator

a guest
Jun 29th, 2016
110
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 14.45 KB | None | 0 0
  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.     [HideInInspector] public bool is2D = false;
  13.  
  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);
  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.             CreateWallMesh();
  65.         }
  66.     }
  67.  
  68.     void CreateWallMesh()
  69.     {
  70.         CalculateMeshOutlines();
  71.  
  72.         List<Vector3> wallVertices = new List<Vector3>();
  73.         List<int> wallTriangles = new List<int>();
  74.         Mesh wallMesh = new Mesh();
  75.         float wallHeight = 5;
  76.  
  77.         foreach (List<int> outline in outlines)
  78.         {
  79.             for (int i = 0; i < outline.Count - 1; i++)
  80.             {
  81.                 int startIndex = wallVertices.Count;
  82.                 wallVertices.Add(vertices[outline[i]]); // left
  83.                 wallVertices.Add(vertices[outline[i + 1]]); // right
  84.                 wallVertices.Add(vertices[outline[i]] - Vector3.up * wallHeight); // bottom left
  85.                 wallVertices.Add(vertices[outline[i + 1]] - Vector3.up * wallHeight); // bottom right
  86.  
  87.                 wallTriangles.Add(startIndex + 0);
  88.                 wallTriangles.Add(startIndex + 2);
  89.                 wallTriangles.Add(startIndex + 3);
  90.  
  91.                 wallTriangles.Add(startIndex + 3);
  92.                 wallTriangles.Add(startIndex + 1);
  93.                 wallTriangles.Add(startIndex + 0);
  94.             }
  95.         }
  96.         wallMesh.vertices = wallVertices.ToArray();
  97.         wallMesh.triangles = wallTriangles.ToArray();
  98.         walls.mesh = wallMesh;
  99.  
  100.         MeshCollider wallCollider = walls.gameObject.AddComponent<MeshCollider>();
  101.         wallCollider.sharedMesh = wallMesh;
  102.     }
  103.  
  104.     void Generate2DColliders()
  105.     {
  106.  
  107.         EdgeCollider2D[] currentColliders = gameObject.GetComponents<EdgeCollider2D>();
  108.         for (int i = 0; i < currentColliders.Length; i++)
  109.         {
  110.             Destroy(currentColliders[i]);
  111.         }
  112.  
  113.         CalculateMeshOutlines();
  114.  
  115.         foreach (List<int> outline in outlines)
  116.         {
  117.             EdgeCollider2D edgeCollider = gameObject.AddComponent<EdgeCollider2D>();
  118.             Vector2[] edgePoints = new Vector2[outline.Count];
  119.  
  120.             for (int i = 0; i < outline.Count; i++)
  121.             {
  122.                 edgePoints[i] = new Vector2(vertices[outline[i]].x, vertices[outline[i]].z);
  123.             }
  124.             edgeCollider.points = edgePoints;
  125.         }
  126.  
  127.     }
  128.  
  129.     void TriangulateSquare(Square square)
  130.     {
  131.         switch (square.configuration)
  132.         {
  133.             case 0:
  134.                 break;
  135.  
  136.             // 1 points:
  137.             case 1:
  138.                 MeshFromPoints(square.centreLeft, square.centreBottom, square.bottomLeft);
  139.                 break;
  140.             case 2:
  141.                 MeshFromPoints(square.bottomRight, square.centreBottom, square.centreRight);
  142.                 break;
  143.             case 4:
  144.                 MeshFromPoints(square.topRight, square.centreRight, square.centreTop);
  145.                 break;
  146.             case 8:
  147.                 MeshFromPoints(square.topLeft, square.centreTop, square.centreLeft);
  148.                 break;
  149.  
  150.             // 2 points:
  151.             case 3:
  152.                 MeshFromPoints(square.centreRight, square.bottomRight, square.bottomLeft, square.centreLeft);
  153.                 break;
  154.             case 6:
  155.                 MeshFromPoints(square.centreTop, square.topRight, square.bottomRight, square.centreBottom);
  156.                 break;
  157.             case 9:
  158.                 MeshFromPoints(square.topLeft, square.centreTop, square.centreBottom, square.bottomLeft);
  159.                 break;
  160.             case 12:
  161.                 MeshFromPoints(square.topLeft, square.topRight, square.centreRight, square.centreLeft);
  162.                 break;
  163.             case 5:
  164.                 MeshFromPoints(square.centreTop, square.topRight, square.centreRight, square.centreBottom, square.bottomLeft, square.centreLeft);
  165.                 break;
  166.             case 10:
  167.                 MeshFromPoints(square.topLeft, square.centreTop, square.centreRight, square.bottomRight, square.centreBottom, square.centreLeft);
  168.                 break;
  169.  
  170.             // 3 point:
  171.             case 7:
  172.                 MeshFromPoints(square.centreTop, square.topRight, square.bottomRight, square.bottomLeft, square.centreLeft);
  173.                 break;
  174.             case 11:
  175.                 MeshFromPoints(square.topLeft, square.centreTop, square.centreRight, square.bottomRight, square.bottomLeft);
  176.                 break;
  177.             case 13:
  178.                 MeshFromPoints(square.topLeft, square.topRight, square.centreRight, square.centreBottom, square.bottomLeft);
  179.                 break;
  180.             case 14:
  181.                 MeshFromPoints(square.topLeft, square.topRight, square.bottomRight, square.centreBottom, square.centreLeft);
  182.                 break;
  183.  
  184.             // 4 point:
  185.             case 15:
  186.                 MeshFromPoints(square.topLeft, square.topRight, square.bottomRight, square.bottomLeft);
  187.                 checkedVertices.Add(square.topLeft.vertexIndex);
  188.                 checkedVertices.Add(square.topRight.vertexIndex);
  189.                 checkedVertices.Add(square.bottomRight.vertexIndex);
  190.                 checkedVertices.Add(square.bottomLeft.vertexIndex);
  191.                 break;
  192.         }
  193.  
  194.     }
  195.  
  196.     void MeshFromPoints(params Node[] points)
  197.     {
  198.         AssignVertices(points);
  199.  
  200.         if (points.Length >= 3)
  201.             CreateTriangle(points[0], points[1], points[2]);
  202.         if (points.Length >= 4)
  203.             CreateTriangle(points[0], points[2], points[3]);
  204.         if (points.Length >= 5)
  205.             CreateTriangle(points[0], points[3], points[4]);
  206.         if (points.Length >= 6)
  207.             CreateTriangle(points[0], points[4], points[5]);
  208.  
  209.     }
  210.  
  211.     void AssignVertices(Node[] points)
  212.     {
  213.         for (int i = 0; i < points.Length; i++)
  214.         {
  215.             if (points[i].vertexIndex == -1)
  216.             {
  217.                 points[i].vertexIndex = vertices.Count;
  218.                 vertices.Add(points[i].position);
  219.             }
  220.         }
  221.     }
  222.  
  223.     void CreateTriangle(Node a, Node b, Node c)
  224.     {
  225.         triangles.Add(a.vertexIndex);
  226.         triangles.Add(b.vertexIndex);
  227.         triangles.Add(c.vertexIndex);
  228.  
  229.         Triangle triangle = new Triangle(a.vertexIndex, b.vertexIndex, c.vertexIndex);
  230.         AddTriangleToDictionary(triangle.vertexIndexA, triangle);
  231.         AddTriangleToDictionary(triangle.vertexIndexB, triangle);
  232.         AddTriangleToDictionary(triangle.vertexIndexC, triangle);
  233.     }
  234.  
  235.     void AddTriangleToDictionary(int vertexIndexKey, Triangle triangle)
  236.     {
  237.         if (triangleDictionary.ContainsKey(vertexIndexKey))
  238.         {
  239.             triangleDictionary[vertexIndexKey].Add(triangle);
  240.         }
  241.         else {
  242.             List<Triangle> triangleList = new List<Triangle>();
  243.             triangleList.Add(triangle);
  244.             triangleDictionary.Add(vertexIndexKey, triangleList);
  245.         }
  246.     }
  247.  
  248.     void CalculateMeshOutlines()
  249.     {
  250.  
  251.         for (int vertexIndex = 0; vertexIndex < vertices.Count; vertexIndex++)
  252.         {
  253.             if (!checkedVertices.Contains(vertexIndex))
  254.             {
  255.                 int newOutlineVertex = GetConnectedOutlineVertex(vertexIndex);
  256.                 if (newOutlineVertex != -1)
  257.                 {
  258.                     checkedVertices.Add(vertexIndex);
  259.  
  260.                     List<int> newOutline = new List<int>();
  261.                     newOutline.Add(vertexIndex);
  262.                     outlines.Add(newOutline);
  263.                     FollowOutline(newOutlineVertex, outlines.Count - 1);
  264.                     outlines[outlines.Count - 1].Add(vertexIndex);
  265.                 }
  266.             }
  267.         }
  268.     }
  269.  
  270.     void FollowOutline(int vertexIndex, int outlineIndex)
  271.     {
  272.         outlines[outlineIndex].Add(vertexIndex);
  273.         checkedVertices.Add(vertexIndex);
  274.         int nextVertexIndex = GetConnectedOutlineVertex(vertexIndex);
  275.  
  276.         if (nextVertexIndex != -1)
  277.         {
  278.             FollowOutline(nextVertexIndex, outlineIndex);
  279.         }
  280.     }
  281.  
  282.     int GetConnectedOutlineVertex(int vertexIndex)
  283.     {
  284.         List<Triangle> trianglesContainingVertex = triangleDictionary[vertexIndex];
  285.  
  286.         for (int i = 0; i < trianglesContainingVertex.Count; i++)
  287.         {
  288.             Triangle triangle = trianglesContainingVertex[i];
  289.  
  290.             for (int j = 0; j < 3; j++)
  291.             {
  292.                 int vertexB = triangle[j];
  293.                 if (vertexB != vertexIndex && !checkedVertices.Contains(vertexB))
  294.                 {
  295.                     if (IsOutlineEdge(vertexIndex, vertexB))
  296.                     {
  297.                         return vertexB;
  298.                     }
  299.                 }
  300.             }
  301.         }
  302.  
  303.         return -1;
  304.     }
  305.  
  306.     bool IsOutlineEdge(int vertexA, int vertexB)
  307.     {
  308.         List<Triangle> trianglesContainingVertexA = triangleDictionary[vertexA];
  309.         int sharedTriangleCount = 0;
  310.  
  311.         for (int i = 0; i < trianglesContainingVertexA.Count; i++)
  312.         {
  313.             if (trianglesContainingVertexA[i].Contains(vertexB))
  314.             {
  315.                 sharedTriangleCount++;
  316.                 if (sharedTriangleCount > 1)
  317.                 {
  318.                     break;
  319.                 }
  320.             }
  321.         }
  322.         return sharedTriangleCount == 1;
  323.     }
  324.  
  325.     struct Triangle
  326.     {
  327.         public int vertexIndexA;
  328.         public int vertexIndexB;
  329.         public int vertexIndexC;
  330.         int[] vertices;
  331.  
  332.         public Triangle(int a, int b, int c)
  333.         {
  334.             vertexIndexA = a;
  335.             vertexIndexB = b;
  336.             vertexIndexC = c;
  337.  
  338.             vertices = new int[3];
  339.             vertices[0] = a;
  340.             vertices[1] = b;
  341.             vertices[2] = c;
  342.         }
  343.  
  344.         public int this[int i]
  345.         {
  346.             get
  347.             {
  348.                 return vertices[i];
  349.             }
  350.         }
  351.  
  352.  
  353.         public bool Contains(int vertexIndex)
  354.         {
  355.             return vertexIndex == vertexIndexA || vertexIndex == vertexIndexB || vertexIndex == vertexIndexC;
  356.         }
  357.     }
  358.  
  359.     public class SquareGrid
  360.     {
  361.         public Square[,] squares;
  362.  
  363.         public SquareGrid(int[,] map, float squareSize)
  364.         {
  365.             int nodeCountX = map.GetLength(0);
  366.             int nodeCountY = map.GetLength(1);
  367.             float mapWidth = nodeCountX * squareSize;
  368.             float mapHeight = nodeCountY * squareSize;
  369.  
  370.             ControlNode[,] controlNodes = new ControlNode[nodeCountX, nodeCountY];
  371.  
  372.             for (int x = 0; x < nodeCountX; x++)
  373.             {
  374.                 for (int y = 0; y < nodeCountY; y++)
  375.                 {
  376.                     Vector3 pos = new Vector3(-mapWidth / 2 + x * squareSize + squareSize / 2, 0, -mapHeight / 2 + y * squareSize + squareSize / 2);
  377.                     controlNodes[x, y] = new ControlNode(pos, map[x, y] == 1, squareSize);
  378.                 }
  379.             }
  380.  
  381.             squares = new Square[nodeCountX - 1, nodeCountY - 1];
  382.             for (int x = 0; x < nodeCountX - 1; x++)
  383.             {
  384.                 for (int y = 0; y < nodeCountY - 1; y++)
  385.                 {
  386.                     squares[x, y] = new Square(controlNodes[x, y + 1], controlNodes[x + 1, y + 1], controlNodes[x + 1, y], controlNodes[x, y]);
  387.                 }
  388.             }
  389.  
  390.         }
  391.     }
  392.  
  393.     public class Square
  394.     {
  395.  
  396.         public ControlNode topLeft, topRight, bottomRight, bottomLeft;
  397.         public Node centreTop, centreRight, centreBottom, centreLeft;
  398.         public int configuration;
  399.  
  400.         public Square(ControlNode _topLeft, ControlNode _topRight, ControlNode _bottomRight, ControlNode _bottomLeft)
  401.         {
  402.             topLeft = _topLeft;
  403.             topRight = _topRight;
  404.             bottomRight = _bottomRight;
  405.             bottomLeft = _bottomLeft;
  406.  
  407.             centreTop = topLeft.right;
  408.             centreRight = bottomRight.above;
  409.             centreBottom = bottomLeft.right;
  410.             centreLeft = bottomLeft.above;
  411.  
  412.             if (topLeft.active)
  413.                 configuration += 8;
  414.             if (topRight.active)
  415.                 configuration += 4;
  416.             if (bottomRight.active)
  417.                 configuration += 2;
  418.             if (bottomLeft.active)
  419.                 configuration += 1;
  420.         }
  421.  
  422.     }
  423.  
  424.     public class Node
  425.     {
  426.         public Vector3 position;
  427.         public int vertexIndex = -1;
  428.  
  429.         public Node(Vector3 _pos)
  430.         {
  431.             position = _pos;
  432.         }
  433.     }
  434.  
  435.     public class ControlNode : Node
  436.     {
  437.  
  438.         public bool active;
  439.         public Node above, right;
  440.  
  441.         public ControlNode(Vector3 _pos, bool _active, float squareSize) : base(_pos)
  442.         {
  443.             active = _active;
  444.             above = new Node(position + Vector3.forward * squareSize / 2f);
  445.             right = new Node(position + Vector3.right * squareSize / 2f);
  446.         }
  447.  
  448.     }
  449. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement