SebastianLague

Procgen E21 edge connection seam fix

Jun 8th, 2017
4,255
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 10.01 KB | None | 0 0
  1. using UnityEngine;
  2. using System.Collections;
  3.  
  4. public static class MeshGenerator {
  5.  
  6.  
  7.     public static MeshData GenerateTerrainMesh(float[,] heightMap, MeshSettings meshSettings, int levelOfDetail) {
  8.  
  9.         int skipIncrement = (levelOfDetail == 0) ? 1 : levelOfDetail * 2;
  10.         int numVertsPerLine = meshSettings.numVertsPerLine;
  11.  
  12.         Vector2 topLeft = new Vector2 (-1, 1) * meshSettings.meshWorldSize / 2f;
  13.  
  14.         MeshData meshData = new MeshData (numVertsPerLine, skipIncrement, meshSettings.useFlatShading);
  15.  
  16.         int[,] vertexIndicesMap = new int[numVertsPerLine, numVertsPerLine];
  17.         int meshVertexIndex = 0;
  18.         int outOfMeshVertexIndex = -1;
  19.  
  20.         for (int y = 0; y < numVertsPerLine; y++) {
  21.             for (int x = 0; x < numVertsPerLine; x++) {
  22.                 bool isOutOfMeshVertex = y == 0 || y == numVertsPerLine - 1 || x == 0 || x == numVertsPerLine - 1;
  23.                 bool isSkippedVertex = x > 2 && x < numVertsPerLine - 3 && y > 2 && y < numVertsPerLine - 3 && ((x - 2) % skipIncrement != 0 || (y - 2) % skipIncrement != 0);
  24.                 if (isOutOfMeshVertex) {
  25.                     vertexIndicesMap [x, y] = outOfMeshVertexIndex;
  26.                     outOfMeshVertexIndex--;
  27.                 } else if (!isSkippedVertex) {
  28.                     vertexIndicesMap [x, y] = meshVertexIndex;
  29.                     meshVertexIndex++;
  30.                 }
  31.             }
  32.         }
  33.  
  34.         for (int y = 0; y < numVertsPerLine; y++) {
  35.             for (int x = 0; x < numVertsPerLine; x++) {
  36.                 bool isSkippedVertex = x > 2 && x < numVertsPerLine - 3 && y > 2 && y < numVertsPerLine - 3 && ((x - 2) % skipIncrement != 0 || (y - 2) % skipIncrement != 0);
  37.  
  38.                 if (!isSkippedVertex) {
  39.                     bool isOutOfMeshVertex = y == 0 || y == numVertsPerLine - 1 || x == 0 || x == numVertsPerLine - 1;
  40.                     bool isMeshEdgeVertex = (y == 1 || y == numVertsPerLine - 2 || x == 1 || x == numVertsPerLine - 2) && !isOutOfMeshVertex;
  41.                     bool isMainVertex = (x - 2) % skipIncrement == 0 && (y - 2) % skipIncrement == 0 && !isOutOfMeshVertex && !isMeshEdgeVertex;
  42.                     bool isEdgeConnectionVertex = (y == 2 || y == numVertsPerLine - 3 || x == 2 || x == numVertsPerLine - 3) && !isOutOfMeshVertex && !isMeshEdgeVertex && !isMainVertex;
  43.  
  44.                     int vertexIndex = vertexIndicesMap [x, y];
  45.                     Vector2 percent = new Vector2 (x - 1, y - 1) / (numVertsPerLine - 3);
  46.                     Vector2 vertexPosition2D = topLeft + new Vector2 (percent.x, -percent.y) * meshSettings.meshWorldSize;
  47.                     float height = heightMap [x, y];
  48.  
  49.                     if (isEdgeConnectionVertex) {
  50.                         bool isVertical = x == 2 || x == numVertsPerLine - 3;
  51.                         int dstToMainVertexA = ((isVertical) ? y - 2 : x - 2) % skipIncrement;
  52.                         int dstToMainVertexB = skipIncrement - dstToMainVertexA;
  53.                         float dstPercentFromAToB = dstToMainVertexA / (float)skipIncrement;
  54.  
  55.                         Coord coordA = new Coord ((isVertical) ? x : x - dstToMainVertexA, (isVertical) ? y - dstToMainVertexA : y);
  56.                         Coord coordB = new Coord ((isVertical) ? x : x + dstToMainVertexB, (isVertical) ? y + dstToMainVertexB : y);
  57.  
  58.                         float heightMainVertexA = heightMap [coordA.x,coordA.y];
  59.                         float heightMainVertexB = heightMap [coordB.x,coordB.y];
  60.  
  61.                         height = heightMainVertexA * (1 - dstPercentFromAToB) + heightMainVertexB * dstPercentFromAToB;
  62.  
  63.                         EdgeConnectionVertexData edgeConnectionVertexData = new EdgeConnectionVertexData (vertexIndex, vertexIndicesMap [coordA.x, coordA.y], vertexIndicesMap [coordB.x, coordB.y], dstPercentFromAToB);
  64.                         meshData.DeclareEdgeConnectionVertex (edgeConnectionVertexData);
  65.                     }
  66.  
  67.                     meshData.AddVertex (new Vector3 (vertexPosition2D.x, height, vertexPosition2D.y), percent, vertexIndex);
  68.  
  69.                     bool createTriangle = x < numVertsPerLine - 1 && y < numVertsPerLine - 1 && (!isEdgeConnectionVertex || (x != 2 && y != 2));
  70.  
  71.                     if (createTriangle) {
  72.                         int currentIncrement = (isMainVertex && x != numVertsPerLine - 3 && y != numVertsPerLine - 3) ? skipIncrement : 1;
  73.  
  74.                         int a = vertexIndicesMap [x, y];
  75.                         int b = vertexIndicesMap [x + currentIncrement, y];
  76.                         int c = vertexIndicesMap [x, y + currentIncrement];
  77.                         int d = vertexIndicesMap [x + currentIncrement, y + currentIncrement];
  78.                         meshData.AddTriangle (a, d, c);
  79.                         meshData.AddTriangle (d, a, b);
  80.                     }
  81.                 }
  82.             }
  83.         }
  84.  
  85.         meshData.ProcessMesh ();
  86.  
  87.         return meshData;
  88.     }
  89.  
  90.     public struct Coord {
  91.         public readonly int x;
  92.         public readonly int y;
  93.  
  94.         public Coord (int x, int y)
  95.         {
  96.             this.x = x;
  97.             this.y = y;
  98.         }
  99.  
  100.     }
  101. }
  102. public class EdgeConnectionVertexData {
  103.     public int vertexIndex;
  104.     public int mainVertexAIndex;
  105.     public int mainVertexBIndex;
  106.     public float dstPercentFromAToB;
  107.  
  108.     public EdgeConnectionVertexData (int vertexIndex, int mainVertexAIndex, int mainVertexBIndex, float dstPercentFromAToB)
  109.     {
  110.         this.vertexIndex = vertexIndex;
  111.         this.mainVertexAIndex = mainVertexAIndex;
  112.         this.mainVertexBIndex = mainVertexBIndex;
  113.         this.dstPercentFromAToB = dstPercentFromAToB;
  114.     }
  115.    
  116.  
  117. }
  118. public class MeshData {
  119.     Vector3[] vertices;
  120.     int[] triangles;
  121.     Vector2[] uvs;
  122.     Vector3[] bakedNormals;
  123.  
  124.     Vector3[] outOfMeshVertices;
  125.     int[] outOfMeshTriangles;
  126.  
  127.     int triangleIndex;
  128.     int outOfMeshTriangleIndex;
  129.  
  130.     EdgeConnectionVertexData[] edgeConnectionVertices;
  131.     int edgeConnectionVertexIndex;
  132.  
  133.     bool useFlatShading;
  134.  
  135.     public MeshData(int numVertsPerLine, int skipIncrement, bool useFlatShading) {
  136.         this.useFlatShading = useFlatShading;
  137.  
  138.         int numMeshEdgeVertices = (numVertsPerLine - 2) * 4 - 4;
  139.         int numEdgeConnectionVertices = (skipIncrement - 1) * (numVertsPerLine - 5) / skipIncrement * 4;
  140.         int numMainVerticesPerLine = (numVertsPerLine - 5) / skipIncrement + 1;
  141.         int numMainVertices = numMainVerticesPerLine * numMainVerticesPerLine;
  142.  
  143.         vertices = new Vector3[numMeshEdgeVertices + numEdgeConnectionVertices + numMainVertices];
  144.         uvs = new Vector2[vertices.Length];
  145.         edgeConnectionVertices = new EdgeConnectionVertexData[numEdgeConnectionVertices];
  146.  
  147.         int numMeshEdgeTriangles = 8 * (numVertsPerLine - 4);
  148.         int numMainTriangles = (numMainVerticesPerLine - 1) * (numMainVerticesPerLine - 1) * 2;
  149.         triangles = new int[(numMeshEdgeTriangles + numMainTriangles) * 3];
  150.  
  151.         outOfMeshVertices = new Vector3[numVertsPerLine * 4 - 4];
  152.         outOfMeshTriangles = new int[24 * (numVertsPerLine-2)];
  153.     }
  154.  
  155.     public void AddVertex(Vector3 vertexPosition, Vector2 uv, int vertexIndex) {
  156.         if (vertexIndex < 0) {
  157.             outOfMeshVertices [-vertexIndex - 1] = vertexPosition;
  158.         } else {
  159.             vertices [vertexIndex] = vertexPosition;
  160.             uvs [vertexIndex] = uv;
  161.         }
  162.     }
  163.  
  164.     public void AddTriangle(int a, int b, int c) {
  165.         if (a < 0 || b < 0 || c < 0) {
  166.             outOfMeshTriangles [outOfMeshTriangleIndex] = a;
  167.             outOfMeshTriangles [outOfMeshTriangleIndex + 1] = b;
  168.             outOfMeshTriangles [outOfMeshTriangleIndex + 2] = c;
  169.             outOfMeshTriangleIndex += 3;
  170.         } else {
  171.             triangles [triangleIndex] = a;
  172.             triangles [triangleIndex + 1] = b;
  173.             triangles [triangleIndex + 2] = c;
  174.             triangleIndex += 3;
  175.         }
  176.     }
  177.  
  178.  
  179.     public void DeclareEdgeConnectionVertex(EdgeConnectionVertexData edgeConnectionVertexData) {
  180.         edgeConnectionVertices [edgeConnectionVertexIndex] = edgeConnectionVertexData;
  181.         edgeConnectionVertexIndex++;
  182.     }
  183.  
  184.     Vector3[] CalculateNormals() {
  185.  
  186.         Vector3[] vertexNormals = new Vector3[vertices.Length];
  187.         int triangleCount = triangles.Length / 3;
  188.         for (int i = 0; i < triangleCount; i++) {
  189.             int normalTriangleIndex = i * 3;
  190.             int vertexIndexA = triangles [normalTriangleIndex];
  191.             int vertexIndexB = triangles [normalTriangleIndex + 1];
  192.             int vertexIndexC = triangles [normalTriangleIndex + 2];
  193.  
  194.             Vector3 triangleNormal = SurfaceNormalFromIndices (vertexIndexA, vertexIndexB, vertexIndexC);
  195.             vertexNormals [vertexIndexA] += triangleNormal;
  196.             vertexNormals [vertexIndexB] += triangleNormal;
  197.             vertexNormals [vertexIndexC] += triangleNormal;
  198.         }
  199.  
  200.         int borderTriangleCount = outOfMeshTriangles.Length / 3;
  201.         for (int i = 0; i < borderTriangleCount; i++) {
  202.             int normalTriangleIndex = i * 3;
  203.             int vertexIndexA = outOfMeshTriangles [normalTriangleIndex];
  204.             int vertexIndexB = outOfMeshTriangles [normalTriangleIndex + 1];
  205.             int vertexIndexC = outOfMeshTriangles [normalTriangleIndex + 2];
  206.  
  207.             Vector3 triangleNormal = SurfaceNormalFromIndices (vertexIndexA, vertexIndexB, vertexIndexC);
  208.             if (vertexIndexA >= 0) {
  209.                 vertexNormals [vertexIndexA] += triangleNormal;
  210.             }
  211.             if (vertexIndexB >= 0) {
  212.                 vertexNormals [vertexIndexB] += triangleNormal;
  213.             }
  214.             if (vertexIndexC >= 0) {
  215.                 vertexNormals [vertexIndexC] += triangleNormal;
  216.             }
  217.         }
  218.  
  219.  
  220.         for (int i = 0; i < vertexNormals.Length; i++) {
  221.             vertexNormals [i].Normalize ();
  222.         }
  223.  
  224.         return vertexNormals;
  225.  
  226.     }
  227.  
  228.  
  229.     void ProcessEdgeConnectionVertices() {
  230.         foreach (EdgeConnectionVertexData e in edgeConnectionVertices) {
  231.             bakedNormals [e.vertexIndex] = bakedNormals [e.mainVertexAIndex] * (1 - e.dstPercentFromAToB) + bakedNormals [e.mainVertexBIndex] * e.dstPercentFromAToB;
  232.         }
  233.     }
  234.  
  235.     Vector3 SurfaceNormalFromIndices(int indexA, int indexB, int indexC) {
  236.         Vector3 pointA = (indexA < 0)?outOfMeshVertices[-indexA-1] : vertices [indexA];
  237.         Vector3 pointB = (indexB < 0)?outOfMeshVertices[-indexB-1] : vertices [indexB];
  238.         Vector3 pointC = (indexC < 0)?outOfMeshVertices[-indexC-1] : vertices [indexC];
  239.  
  240.         Vector3 sideAB = pointB - pointA;
  241.         Vector3 sideAC = pointC - pointA;
  242.         return Vector3.Cross (sideAB, sideAC).normalized;
  243.     }
  244.  
  245.     public void ProcessMesh() {
  246.         if (useFlatShading) {
  247.             FlatShading ();
  248.         } else {
  249.             BakeNormals ();
  250.             ProcessEdgeConnectionVertices();
  251.         }
  252.     }
  253.  
  254.     void BakeNormals() {
  255.         bakedNormals = CalculateNormals ();
  256.     }
  257.  
  258.     void FlatShading() {
  259.         Vector3[] flatShadedVertices = new Vector3[triangles.Length];
  260.         Vector2[] flatShadedUvs = new Vector2[triangles.Length];
  261.  
  262.         for (int i = 0; i < triangles.Length; i++) {
  263.             flatShadedVertices [i] = vertices [triangles [i]];
  264.             flatShadedUvs [i] = uvs [triangles [i]];
  265.             triangles [i] = i;
  266.         }
  267.  
  268.         vertices = flatShadedVertices;
  269.         uvs = flatShadedUvs;
  270.     }
  271.  
  272.     public Mesh CreateMesh() {
  273.         Mesh mesh = new Mesh ();
  274.         mesh.vertices = vertices;
  275.         mesh.triangles = triangles;
  276.         mesh.uv = uvs;
  277.         if (useFlatShading) {
  278.             mesh.RecalculateNormals ();
  279.         } else {
  280.             mesh.normals = bakedNormals;
  281.         }
  282.         return mesh;
  283.     }
  284.  
  285. }
Advertisement
Add Comment
Please, Sign In to add comment