程序岛屿地形生成

时间:2015-05-07 20:06:25

标签: c# unity3d terrain perlin-noise procedural-generation

编辑:在尝试了一些事情之后重写了我的问题并使其更具体。

嗨,所以我正在创建一个带有程序生成的地图的移动RTS游戏。我已经研究了如何创建一个带有基本perlin噪声的地形,并尝试将https://gamedev.stackexchange.com/questions/54276/a-simple-method-to-create-island-map-mask方法集成到一个岛上。这是迄今为止的结果:

enter image description here

http://www-cs-students.stanford.edu/~amitp/game-programming/polygon-map-generation/下面的图片显示了我所追求的地形。那里的教程很棒但是过于密集,因此是帖子。

我希望随机形状的岛屿具有Perlin噪声产生的陆地质量,被水包围。

This is the kind of shaping I want

编辑:基本的Perlin terrain gen现在正在工作=)

这是我的代码。附加到null的脚本,带有一个按钮以激活Begin():

using UnityEngine;
using System.Collections;
using System.Runtime.InteropServices;

public class Gen_Perlin : MonoBehaviour {

public float Tiling = 0.5f;
private bool active = false;
public int mapHeight = 10;

public void Begin()
{
    if (active == false) {
        TerrainData terrainData = new TerrainData ();
        const int size = 513;
        terrainData.heightmapResolution = size;
        terrainData.size = new Vector3 (2000, mapHeight, 2000);

        terrainData.heightmapResolution = 513;
        terrainData.baseMapResolution = 1024;
        terrainData.SetDetailResolution (1024, 1024);

        Terrain.CreateTerrainGameObject (terrainData);
        GameObject obj = GameObject.Find ("Terrain");
        obj.transform.parent = this.transform;

        if (obj.GetComponent<Terrain> ()) {
            GenerateHeights (obj.GetComponent<Terrain> (), Tiling);
        }
    } else {
        GameObject obj = GameObject.Find ("Terrain");
        if (obj.GetComponent<Terrain> ()) {
            GenerateHeights (obj.GetComponent<Terrain> (), Tiling);
        }
    }
}

public void GenerateHeights(Terrain terrain, float tileSize)
{
    Debug.Log ("Start_Height_Gen");
    float[,] heights = new float[terrain.terrainData.heightmapWidth, terrain.terrainData.heightmapHeight];

    for (int i = 0; i < terrain.terrainData.heightmapWidth; i++)
    {
        for (int k = 0; k < terrain.terrainData.heightmapHeight; k++)
        {
            heights[i, k] = 0.25f + Mathf.PerlinNoise(((float)i / (float)terrain.terrainData.heightmapWidth) * tileSize, ((float)k / (float)terrain.terrainData.heightmapHeight) * tileSize);
            heights[i, k] *= makeMask( terrain.terrainData.heightmapWidth, terrain.terrainData.heightmapHeight, i, k, heights[i, k] );
        }
    }
    terrain.terrainData.SetHeights(0, 0, heights);
}

public static float makeMask( int width, int height, int posX, int posY, float oldValue ) {
    int minVal = ( ( ( height + width ) / 2 ) / 100 * 2 );
    int maxVal = ( ( ( height + width ) / 2 ) / 100 * 10 );
    if( getDistanceToEdge( posX, posY, width, height ) <= minVal ) {
        return 0;
    } else if( getDistanceToEdge( posX, posY, width, height ) >= maxVal ) {
        return oldValue;
    } else {
        float factor = getFactor( getDistanceToEdge( posX, posY, width, height ), minVal, maxVal );
        return oldValue * factor;
    }
}

private static float getFactor( int val, int min, int max ) {
    int full = max - min;
    int part = val - min;
    float factor = (float)part / (float)full;
    return factor;
}

public static int getDistanceToEdge( int x, int y, int width, int height ) {
    int[] distances = new int[]{ y, x, ( width - x ), ( height - y ) };
    int min = distances[ 0 ];
    foreach( var val in distances ) {
        if( val < min ) {
            min = val;
        }
    }
    return min;
}

}

2 个答案:

答案 0 :(得分:2)

是的。有问题的文章使用的是Waaay复杂方法。

执行此操作的最佳方法是采用一个表示基本孤岛形状的函数,高度值介于0到1之间。对于图片中的孤岛类型,您基本上希望某些东西可以平滑地从边缘,然后在想要湖泊的地方平稳地回落到零。

现在,您可以将该表面添加到基本的分形表面(如果要在低海拔高度保持尖峰度),或者将其相乘(如果希望较低的海拔高度平滑)。然后,定义一个高度,在该高度以下是水。

这是我用Terragen渲染的非常快速的方法:

Ring Island - Quick and Dirty attempt

我使用了一种功能,该功能从地图的边缘到中间的中间呈环形上升,然后再次下降,以匹配与文章中类似的形状。实际上,您可能只用它来获得岛的形状,然后雕刻与轮廓匹配的地形,然后掩埋其他所有东西。

我使用了自己的分形景观生成器,如下所述:https://fractal-landscapes.co.uk用于基本分形。

这是修改格局的C#代码:

public void MakeRingIsland()
{
    this.Normalize(32768);
    var ld2 = (double) linearDimension / 2;
    var ld4 = 4 / (double) linearDimension;
    for (var y = 0u; y < linearDimension; y++)
    {
        var yMul = y * linearDimension;
        for (var x = 0u; x < linearDimension; x++)
        {
            var yCoord = (y - ld2) * ld4;
            var xCoord = (x - ld2) * ld4;
            var dist = Math.Sqrt(xCoord * xCoord + yCoord * yCoord);
            var htMul = dist > 2 ? 0 : 
                (dist < 1 ? 
                    dist + dist - dist * dist : 
                    1 - (dist - 1) * (dist - 1));
            var height = samples[x + yMul];
            samples[x + yMul] = (int) (height + htMul * 32768);
        }
    }
}

答案 1 :(得分:1)

您展示的图片来自article,描述如何生成