multithreading - Unity - block 之间的地形间隙无限大?

标签 multithreading unity-game-engine infinite terrain perlin-noise

所以我正在创建一个无尽的地形。

我可以创建地形,但我的 block 之间有间隙,并且它们没有正确对齐。

我认为问题可能是由我的噪声生成脚本引起的,但我不确定。

这是我的噪声生成脚本

public static class Noise_GENERATOR
    {
        public static float[,] GenerateNoise(int chunkSize, int octaves, int seed, float noiseScale, float persistence, float lacunarity, Vector2 offset)
        {
    
            float[,] noiseMap = new float[chunkSize, chunkSize];
    
            System.Random prng = new System.Random(seed);
            Vector2[] octaveOffsets = new Vector2[octaves];
    
            float maxPossibleHeight = 0;
            float amplitude = 1;
            float frequency = 1;
    
            for (int i = 0; i < octaves; i++)
            {
                float offsetX = prng.Next(-100000, 100000) + offset.x;
                float offsetY = prng.Next(-100000, 100000) + offset.y;
                octaveOffsets[i] = new Vector2(offsetX, offsetY);
    
                maxPossibleHeight += amplitude;
                amplitude *= persistence;
            }
    
            if (noiseScale <= 0)
            {
                noiseScale = 0.0001f;
            }
    
            float maxLocalNoiseHeight = float.MinValue;
            float minLocalNoiseHeight = float.MaxValue;
    
            float halfWidth = chunkSize / 2f;
            float halfHeight = chunkSize / 2f;
    
    
            for (int y = 0; y < chunkSize; y++)
            {
                for (int x = 0; x < chunkSize; x++)
                {
    
                    amplitude = 1;
                    frequency = 1;
                    float noiseHeight = 0;
    
                    for (int i = 0; i < octaves; i++)
                    {
                        float sampleX = (x-halfWidth + octaveOffsets[i].x) / noiseScale * frequency;
                        float sampleY = (y-halfHeight + octaveOffsets[i].y) / noiseScale * frequency;
    
                        float perlinValue = Mathf.PerlinNoise(sampleX, sampleY) * 2 - 1;
                        noiseHeight += perlinValue * amplitude;
    
                        amplitude *= persistence;
                        frequency *= lacunarity;
                    }
    
                    if (noiseHeight > maxLocalNoiseHeight)
                    {
                        maxLocalNoiseHeight = noiseHeight;
                    }
                    else if (noiseHeight < minLocalNoiseHeight)
                    {
                        minLocalNoiseHeight = noiseHeight;
                    }
                    noiseMap[x, y] = noiseHeight;
    
                    float normalizedHeight = (noiseMap[x, y] + 1) / (maxPossibleHeight / 0.9f);
                    noiseMap[x, y] = Mathf.Clamp(normalizedHeight, 0, int.MaxValue);
                }
            }
    
            return noiseMap;
        }
    }

为了生成网格的高度,我使用动画曲线并将其乘以 heightScale 变量。

                 float height = heightCurve.Evaluate(noiseMap[x, y]) * elevationScale;

These gaps are created betwean chunks This is how the gaps looks like in the Y noise offset enter image description here

我考虑过访问每个地形 block 并获取边缘的高度并将它们匹配在一起,但这看起来非常奇怪,我不知道如何正确执行。

编辑:这里以防万一我的网格生成器脚本以及我如何创建地形 block

    public  static class Mesh_GENERATOR 
{
    public static MeshData GenerateChunkMesh(int chunkSize,float[,] noiseMapData,float elevationScale,AnimationCurve terrainCurve,int LODlevel )
    {
        float[,] noiseMap = noiseMapData;
        AnimationCurve heightCurve = new AnimationCurve(terrainCurve.keys);
        //Setup variables
        Vector3[] vertices = new Vector3[chunkSize * chunkSize];
        int[] triangles = new int[(chunkSize - 1) * (chunkSize - 1) * 6];
        Vector2[] uvs = new Vector2[chunkSize * chunkSize];
        int triangle = 0;

        int levelOfDetailIncrement = (LODlevel == 0) ? 1 : LODlevel * 2;
        int numberOfVerticesPerRow = (chunkSize) / levelOfDetailIncrement + 1;
 
        for (int y = 0; y < chunkSize; y++)
        {
            for (int x = 0; x < chunkSize; x++)
            {
                int i = y * chunkSize + x;

                //Create vertices at position and center mesh

                float height = heightCurve.Evaluate(noiseMap[x, y]) * elevationScale;
                Vector2 percentPosition = new Vector2(x / (chunkSize - 1f), y / (chunkSize -1f ));

                Vector3 vertPosition = new Vector3(percentPosition.x * 2 - 1, 0, percentPosition.y * 2 - 1) * chunkSize/2;

                vertPosition.y = height;
                vertices[i] = vertPosition;
               
                uvs[i] = new Vector2((float)x / chunkSize, (float)y / chunkSize);

                //Construct triangles
                if (x != chunkSize - 1 && y != chunkSize - 1)
                {
                    triangles[triangle + 0] = i + chunkSize;
                    triangles[triangle + 1] = i + chunkSize + 1;
                    triangles[triangle + 2] = i;

                    triangles[triangle + 3] = i + chunkSize + 1;
                    triangles[triangle + 4] = i + 1;
                    triangles[triangle + 5] = i;
                    triangle += 6;
                }
            }
        }

        MeshData meshData = new MeshData(chunkSize, vertices, triangles, uvs);
        return meshData;
    }
}

public class MeshData
{
    public int chunkSize;
    public Vector3[] vertices;
    public int[] triangles;
    public Vector2[] uvs;

    public Mesh mesh;

    public MeshData(int chunkSize,Vector3[] vertices,int[] triangles, Vector2[] uvs)
    {
        this.chunkSize = chunkSize;
        this.vertices = vertices;
        this.triangles = triangles;
        this.uvs = uvs;
    }

    public Mesh CreateMesh()
    {
       if(mesh == null) { mesh = new Mesh(); } else { mesh.Clear(); }

        mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32;
        mesh.vertices = vertices;
        mesh.triangles = triangles;
        mesh.uv = uvs;
        mesh.RecalculateNormals();


        return mesh;
    }
}

这是我的 TerrainChunk

    public class TerrainChunk
    {

        GameObject meshObject;
        Vector2 position;
        Bounds bounds;

        MeshRenderer meshRenderer;
        MeshFilter meshFilter;



        public TerrainChunk(Vector2 coord, int chunkSize, Transform parent,Material terrainMaterial)
        {
            position = coord * chunkSize;

            bounds = new Bounds(position, Vector2.one * chunkSize);
            Vector3 positionV3 = new Vector3(position.x , 0, position.y  );
            Debug.Log("CHUNK: COORD" + coord + "POSITION" + position + "POSITION3V" + positionV3);

            meshObject = new GameObject("Terrain Chunk");
            meshFilter = meshObject.AddComponent<MeshFilter>();
            meshRenderer = meshObject.AddComponent<MeshRenderer>();
            meshRenderer.material = terrainMaterial;


            meshObject.transform.position = positionV3;
            meshObject.transform.parent = parent;

            SetVisible(false);

            worldGenerator.RequestMapData(position,OnNoiseDataReceived);

        }
        

        void OnNoiseDataReceived(MapData mapData)
        {
            worldGenerator.RequestMeshData(mapData, OnMeshDataReceived);

        }

        void OnMeshDataReceived(MeshData meshData)
        {
            meshFilter.mesh = meshData.CreateMesh();
        }

        public void UpdateTerrainChunk(Vector2 viewerPosition, int maxRenderDistance)
        {
            float viewerDstFromNearestEdge = Mathf.Sqrt(bounds.SqrDistance(viewerPosition));
            bool visible = viewerDstFromNearestEdge <= maxRenderDistance;
            SetVisible(visible);
        }

        public void SetVisible(bool visible)
        {
            meshObject.SetActive(visible);
        }

        public bool IsVisible()
        {
            return meshObject.activeSelf;
        }
    }
}

最佳答案

如果我正确理解了你所有的值和变量。

问题可能出在噪声发生器上。

您需要将 chunkSize 创建为大 1,因此如果您传递 250,则需要传递 251,因为噪声生成器中的 for 循环停止于 249 而不是 250。(我对此可能是错误的) ,如果执行此操作,网格生成器现在将具有用于计算的正确值。

所以你的 chunksize 变量应该是这样的

chunkSize = chunkSize + 1;

现在仍然会有较小的间隙,并且网格会相互夹住,因此要解决此问题,您需要定位 block ,然后按以下方式执行 ->

(如果您的坐标作为从世界生成器对象创建 block 的方向 -> 例如,指向北的 block 的值为 x:0 y:1,指向西的 block 的值为 x :-1 y:0、NorthWest block x:-1 y:-1 等),您可能需要将 0.5f 更改为您的值,以便 block 正确对齐。

Vector3 positionV3 = new Vector3(position.x + (coord.x + 0.5f), 0, position.y + (coord.y + 0.5f) );

地形中仍然可能存在一些可见的较小间隙,但这可以通过使用值来修复,或者您可以尝试访问每个 block 并获取边缘顶点及其高度,并以这种方式将 block 连接在一起。

关于multithreading - Unity - block 之间的地形间隙无限大?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70474512/

相关文章:

Java 线程和关闭 Hook

java - Java-Android 中的多线程

ios - IOS中的Unity3d游戏切换到第二个场景后崩溃?

java - LinkedList 陷入无限循环。尝试获取下一个节点

java - SQL DB 查询的单独线程

c++ - 多线程/ fork 服务器守护进程的模型

ios - 用于 Unity 的 ios 插件中的多线程

unity-game-engine - 如何获取igidBody2d在局部空间中的速度

html - 淡入和脉冲文本,暂停,然后循环淡出 CSS3 关键帧?

c++ - 为什么循环不中断?