How to fix seams between procedurally generated chunks in Unity?

53 views Asked by At

I've been making a procedurally generated 3d world and ran into an issue with seams at the edges of chunks. The seams look like this:

seams

I looked for information online and people said it had to do with different normals at the edge on the two meshes. So I made the mesh slightly bigger, calculated the normals, and then deleted the extra vertices. I was expecting this to fix the issue, but the edges still have visible seams (even though the normals at the edge vertices are equal). Anyone know how I can fix this?

My code:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class MeshGenerator : MonoBehaviour
{
    private Mesh mesh;
    private Vector3[] vertices;
    private int[] triangles;
    private Vector2[] UVs;
    //public Color[] colors;
    private Gradient gradient;
    public Vector3[] normals;
 
    private int xSize = 200;
    private int zSize = 200;
 
    private float xDim = 10;
    private float zDim = 10;
 
    private GameObject player;
    private int deleteDistance = 5;
    // Start is called before the first frame update
    void Start()
    {
        player = GameObject.Find("Player");
 
        mesh = new Mesh();
        GetComponent<MeshFilter>().mesh = mesh;
 
        xDim = GameObject.Find("TerrainGen").GetComponent<TerrainGen>().xDim;
        zDim = GameObject.Find("TerrainGen").GetComponent<TerrainGen>().zDim;
 
        xSize = GameObject.Find("TerrainGen").GetComponent<TerrainGen>().xSize;
        zSize = GameObject.Find("TerrainGen").GetComponent<TerrainGen>().zSize;
 
        CreateShape();
        UpdateMesh();
        normals = mesh.normals;
        normals = CalculateNormals();
 
        RemoveEdges();
        UpdateMesh();
 
        mesh.normals = normals; // normals have been changed in RemoveEdges()
 
        StartCoroutine(deleteMeshes());
    }
 
    // Update is called once per frame
    void Update()
    {
 
    }
 
    float fbm(float a, float b, int octaves, float amp, float freq)
    {
        float result = 0;
        float ampmod = amp;
        float freqmod = freq;
        for(int i = 0; i < octaves; i++)
        {
            result += ampmod * (Mathf.PerlinNoise(Mathf.Abs(Mathf.Pow(10,3)+a*freqmod), Mathf.Abs(Mathf.Pow(10, 3) + b *freqmod)) - 0.5f);
            ampmod = ampmod / 2;
            freqmod = freqmod * 2;
        }
 
        //calculate max and min
        float ampcalc = amp;
        float sum = 0;
        for(int i = 0; i < octaves; i++)
        {
            sum += 0.5f * ampcalc;
            ampcalc = ampcalc / 2f;
        }
        MeshRenderer rend = GetComponent<MeshRenderer>();
        rend.material.SetFloat("_Low", -1*sum);
        rend.material.SetFloat("_High", sum);
        return result;
    }
 
    void CreateShape()
    {
        //Creates a mesh slightly bigger than needed
        vertices = new Vector3[(xSize + 1 + 2) * (zSize + 1 + 2)];
        int i = 0;
        for(int z = 0; z <= zSize + 2; z++)
        {
            for(int x = 0; x <= xSize + 2; x++)
            {
                vertices[i] = new Vector3(x / (xSize/xDim), 0, z / (zSize/zDim));
                vertices[i].y = 3 * fbm((transform.position.x + vertices[i].x) * 0.0373f, (transform.position.z + vertices[i].z) * 0.0373f, 7, 3f, 2f);
                i++;
 
            }
        }
 
        triangles = new int[6 * (xSize+2) * (zSize+2)];
        int trindex = 0;
        int vertadd = 0;
        for(int z = 0; z < zSize+2; z++)
        {
            for (int x = 0; x < xSize+2; x++)
            {
                triangles[0 + trindex] = vertadd + 0;
                triangles[1 + trindex] = vertadd + xSize + 2 + 1;
                triangles[2 + trindex] = vertadd + 1;
                triangles[3 + trindex] = vertadd + xSize + 2 + 1;
                triangles[4 + trindex] = vertadd + xSize + 2 + 2;
                triangles[5 + trindex] = vertadd + 1;
                trindex += 6;
                vertadd++;
            }
            vertadd++;
        }
 
        UVs = new Vector2[vertices.Length];
        for (int j = 0; j < UVs.Length; j++)
        {
            UVs[j] = new Vector2(vertices[j].x / (xSize+2), vertices[j].z / (zSize+2));
        }        
    }
 
    void RemoveEdges()
    {
        Vector3[] newVerts = new Vector3[(xSize + 1) * (zSize + 1)];
        Vector3[] newNormals = new Vector3[(xSize + 1) * (zSize + 1)];
 
        for (int z = 1; z < zSize + 2; z++)
        {
            for(int x = 1; x < xSize + 2; x++)
            {
                newVerts[(z - 1) * (zSize + 1) + (x - 1)] = vertices[(zSize + 3) * z + x];
                newNormals[(z - 1) * (zSize + 1) + (x - 1)] = normals[(zSize + 3) * z + x];
            }
        }
        int[] newTriangles = new int[6 * (xSize) * (zSize)];
        int trindex = 0;
        int vertadd = 0;
        for (int z = 0; z < zSize; z++)
        {
            for (int x = 0; x < xSize; x++)
            {
                newTriangles[0 + trindex] = vertadd + 0;
                newTriangles[1 + trindex] = vertadd + xSize + 1;
                newTriangles[2 + trindex] = vertadd + 1;
                newTriangles[3 + trindex] = vertadd + xSize + 1;
                newTriangles[4 + trindex] = vertadd + xSize + 2;
                newTriangles[5 + trindex] = vertadd + 1;
                trindex += 6;
                vertadd++;
            }
            vertadd++;
        }
 
        Vector2[] newUVs = new Vector2[newVerts.Length];
        for (int j = 0; j < newUVs.Length; j++)
        {
            newUVs[j] = new Vector2(newVerts[j].x / (xSize + 2), newVerts[j].z / (zSize + 2));
        }
        vertices = newVerts;
        triangles = newTriangles;
        normals = newNormals;
        UVs = newUVs;
    }
 
    void UpdateMesh()
    {
        mesh.Clear();
        mesh.vertices = vertices;
        mesh.triangles = triangles;
        mesh.uv = UVs;
    }
 
    IEnumerator deleteMeshes()
    {
        while (true)
        {
            if(Mathf.Abs((transform.position.x + xDim/2 - player.transform.position.x)/xDim) >= (deleteDistance) || Mathf.Abs((transform.position.z + zDim/2 - player.transform.position.z) / zDim) >= (deleteDistance))
            {
                GameObject.Destroy(this.gameObject);
            }
            yield return new WaitForSeconds(1);
        }
    }
}
0

There are 0 answers