c# - Unity 3D 中的程序地形编程

标签 c# unity3d perlin-noise procedural-generation

我正在尝试与程序生成相处,我绝对不是统一专家,但是我遵循了本指南:click并得到了一些结果。现在我有 2 个问题,我对如何解决它们有一些基本的想法,但是我想听听一些其他的意见。

(我已经在 Unity answers 上发布了这个问题,但是我根本没有得到任何回复,如果有一些信息缺失或者无法用几句话解释,请让我知道或给出一些建议如何找到这个信息)

主要问题是: block 之间的间隙:

enter image description here

如果我缩放,它们会消失,但纹理仍然不合适,这很了不起。

第二个,如你所见,我对地面上的红色(我真的不知道怎么称呼)标记有疑问。我尝试使用指南中的 Material ,但得到了相同的效果。

此外,Perlin Noise(我知道我可以使用 Diamond square 或 simplex)是伪随机算法,所以它会为相同的输入参数返回相同的值,这是否意味着我的 block 将始终相同?

我的代码(我正在使用指南中的 LibNoise 库):

    void Awake()
    {
        var settings = new TerrainChunkSettings(129, 129, 100, 40, FlatTexture, SteepTexture, TerrainMaterial);
        var noiseProvider = new NoiseProvider();
        for (var i = 0; i < 4; i++)
            for (var j = 0; j < 4; j++)
                new TerrainChunk(settings, noiseProvider, i, j).CreateTerrain();
    }
public class TerrainChunkSettings
{
    public int HeightmapResolution { get; private set; }

    public int AlphamapResolution { get; private set; }

    public int Length { get; private set; }

    public int Height { get; private set; }

    public Texture2D FlatTexture { get; private set; }

    public Texture2D SteepTexture { get; private set; }

    public Material TerrainMaterial { get; private set; }

    public TerrainChunkSettings(int heightmapResolution, int alphamapResolution, int length, int height, Texture2D flatTexture, Texture2D steepTexture, Material terrainMaterial)
    {
        HeightmapResolution = heightmapResolution;
        AlphamapResolution = alphamapResolution;
        Length = length;
        Height = height;
        FlatTexture = flatTexture;
        SteepTexture = steepTexture;
        TerrainMaterial = terrainMaterial;
    }
}

public class TerrainChunk
{
    private Terrain Terrain { get; set; }

    private TerrainChunkSettings Settings { get; set; }

    private NoiseProvider NoiseProvider { get; set; }

    public int X { get; private set; }

    public int Z { get; private set; }

    private TerrainData Data { get; set; }

    private float[,] Heightmap { get; set; }
    public TerrainChunk(TerrainChunkSettings settings, NoiseProvider noiseProvider, int x, int z)
    {
        X = x;
        Z = z;
        Settings = settings;
        NoiseProvider = noiseProvider;
    }

    public void CreateTerrain()
    {
        var terrainData = new TerrainData();
        terrainData.heightmapResolution = Settings.HeightmapResolution;
        terrainData.alphamapResolution = Settings.AlphamapResolution;

        var heightmap = GetHeightmap();
        terrainData.SetHeights(0, 0, heightmap);
        ApplyTextures(terrainData);
        terrainData.size = new Vector3(Settings.Length, Settings.Height, Settings.Length);

        var newTerrainGameObject = Terrain.CreateTerrainGameObject(terrainData);
        newTerrainGameObject.transform.position = new Vector3(X * Settings.Length, 0, Z * Settings.Length);
        Terrain = newTerrainGameObject.GetComponent<Terrain>();
        Terrain.Flush();
    }

    private float[,] GetHeightmap()
    {
        var heightmap = new float[Settings.HeightmapResolution, Settings.HeightmapResolution];

        for (var zRes = 0; zRes < Settings.HeightmapResolution; zRes++)
        {
            for (var xRes = 0; xRes < Settings.HeightmapResolution; xRes++)
            {
                var xCoordinate = X + (float)xRes / (Settings.HeightmapResolution - 1);
                var zCoordinate = Z + (float)zRes / (Settings.HeightmapResolution - 1);

                heightmap[zRes, xRes] = NoiseProvider.GetValue(xCoordinate, zCoordinate);
            }
        }

        return heightmap;
    }

    private void ApplyTextures(TerrainData terrainData)
    {
        var flatSplat = new SplatPrototype();
        var steepSplat = new SplatPrototype();

        flatSplat.texture = Settings.FlatTexture;
        steepSplat.texture = Settings.SteepTexture;

        terrainData.splatPrototypes = new SplatPrototype[]
        {
            flatSplat,
            steepSplat
        };

        terrainData.RefreshPrototypes();

        var splatMap = new float[terrainData.alphamapResolution, terrainData.alphamapResolution, 2];

        for (var zRes = 0; zRes < terrainData.alphamapHeight; zRes++)
        {
            for (var xRes = 0; xRes < terrainData.alphamapWidth; xRes++)
            {
                var normalizedX = (float)xRes / (terrainData.alphamapWidth - 1);
                var normalizedZ = (float)zRes / (terrainData.alphamapHeight - 1);

                var steepness = terrainData.GetSteepness(normalizedX, normalizedZ);
                var steepnessNormalized = Mathf.Clamp(steepness / 1.5f, 0, 1f);

                splatMap[zRes, xRes, 0] = 1f - steepnessNormalized;
                splatMap[zRes, xRes, 1] = steepnessNormalized;
            }
        }

        terrainData.SetAlphamaps(0, 0, splatMap);
    }
}

public interface INoiseProvider
{
    float GetValue(float x, float z);
}
public class NoiseProvider : INoiseProvider
{
    private Perlin PerlinNoiseGenerator;

    public NoiseProvider()
    {
        PerlinNoiseGenerator = new Perlin();
    }

    public float GetValue(float x, float z)
    {
        return (float)(PerlinNoiseGenerator.GetValue(x, 0, z) / 2f) + 0.5f;
    }
}

最佳答案

1) 主要问题是: block 之间的间隙

您可以使用 SetNeighbors(Terrain left, Terrain top, Terrain right, Terrain bottom);

将地形拼接在一起以确保它们获得相同的 LOD

来自documentation:

Lets you setup the connection between neighboring Terrains.

This ensures LOD matches up on neighboring terrains. Note that it is not enough to call this function on one Terrain, you need to set the neighbors of each terrain.

2)第二种:地上的红印

这个问题应该来自您在地形对象中使用的纹理。

关于c# - Unity 3D 中的程序地形编程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43202913/

相关文章:

c# - 给字符串一个空值

c# - 如何使用 ASP.NET CORE 3 在 Linux (Debian) 上保存图像

c# - 暂停时静音

python - Perlin 噪声伪影

java - 使用多个 Perlin 函数如何平滑地形

C# 方法重载解析不选择具体的泛型覆盖

c# - 服务模式 Entity Framework asp.net mvc

c# - 如何在 CustomEditor 中选择嵌套的 ReorderableList 中的元素?

c# - 将对象在 -45 到 45 度之间旋转未按预期运行

java - 定点柏林噪声返回输入点的总和作为输出