Minecraftのようなエンジン用に浮遊陸地を生成するにはどうすればよいですか?


19

XNAでMinecraftのようなエンジンを作成しています。私がやりたいのは、このビデオに示すような浮島を作成することです。

http://www.youtube.com/watch?v=gqHVOEPQK5g&feature=related

ワールドジェネレーターを使用してこれをどのように複製しますか?Perlinノイズアルゴリズムを使用する必要がありますか?そのような土地を作るのにどのように役立つかわかりません。

以下は、私が使用しているパーリンノイズジェネレーターのコードです。

    private double[,] noiseValues;
    private float amplitude = 1;    // Max amplitude of the function
    private int frequency = 1;      // Frequency of the function

    /// <summary>
    /// Constructor
    /// </summary>
    /// 
    public PerlinNoise(int freq, float _amp)
    {
        Random rand = new Random(System.Environment.TickCount);
        noiseValues = new double[freq, freq];
        amplitude = _amp;
        frequency = freq;

        // Generate our noise values
        for (int i = 0; i < freq; i++)
        {
            for (int k = 0; k < freq; k++)
            {
                noiseValues[i, k] = rand.NextDouble();
            }
        }
    }

    /// <summary>
    /// Get the interpolated point from the noise graph using cosine interpolation
    /// </summary>
    /// <returns></returns>
    public double getInterpolatedPoint(int _xa, int _xb, int _ya, int _yb, double x, double y)
    {
        double i1 = interpolate(
            noiseValues[_xa % Frequency, _ya % frequency],
            noiseValues[_xb % Frequency, _ya % frequency]
            , x);

        double i2 = interpolate(
            noiseValues[_xa % Frequency, _yb % frequency],
            noiseValues[_xb % Frequency, _yb % frequency]
            , x);

        return interpolate(i1, i2, y);
    }

    public static double[,] SumNoiseFunctions(int width, int height, List<PerlinNoise> noiseFunctions)
    {
        double[,] summedValues = new double[width, height];

        // Sum each of the noise functions
        for (int i = 0; i < noiseFunctions.Count; i++)
        {
            double x_step = (float)width / (float)noiseFunctions[i].Frequency;
            double y_step = (float)height / (float)noiseFunctions[i].Frequency;

            for (int x = 0; x < width; x++)
            {
                for (int y = 0; y < height; y++)
                {
                    int a = (int)(x / x_step);
                    int b = a + 1;
                    int c = (int)(y / y_step);
                    int d = c + 1;

                    double intpl_val = noiseFunctions[i].getInterpolatedPoint(a, b, c, d, (x / x_step) - a, (y / y_step) - c);
                    summedValues[x, y] += intpl_val * noiseFunctions[i].Amplitude;
                }
            }
        }
        return summedValues;
    }

    /// <summary>
    /// Get the interpolated point from the noise graph using cosine interpolation
    /// </summary>
    /// <returns></returns>
    private double interpolate(double a, double b, double x)
    {
        double ft = x * Math.PI;
        double f = (1 - Math.Cos(ft)) * .5;

        // Returns a Y value between 0 and 1
        return a * (1 - f) + b * f;
    }

    public float Amplitude { get { return amplitude; } }
    public int Frequency { get { return frequency; } }

しかし、コードの作者はノイズを生成するために次のものを使用しているので、少なくとも理解できません。

    private Block[, ,] GenerateLandmass()
    {
        Block[, ,] blocks = new Block[300, 400, 300];

        List<PerlinNoise> perlins = new List<PerlinNoise>();
        perlins.Add(new PerlinNoise(36, 29));
        perlins.Add(new PerlinNoise(4, 33));

        double[,] noisemap = PerlinNoise.SumNoiseFunctions(300, 300, perlins); 

        int centrey = 400 / 2;

        for (short x = 0; x < blocks.GetLength(0); x++)
        {
            for (short y = 0; y < blocks.GetLength(1); y++)
            {
                for (short z = 0; z < blocks.GetLength(2); z++)
                {
                    blocks[x, y, z] = new Block(BlockType.none);
                }
            }
        }

        for (short x = 0; x < blocks.GetLength(0); x++)
        {
            for (short z = 0; z < blocks.GetLength(2); z++)
            {
                blocks[x, centrey - (int)noisemap[x, z], z].BlockType = BlockType.stone; 
            }
        }

        //blocks = GrowLandmass(blocks);

        return blocks;
    }

そして、ここは私が使用しているサイトです:http : //lotsacode.wordpress.com/2010/02/24/perlin-noise-in-c/

そして、Martin Sojkaが指定した方法でperlinノイズを実装しようとしています。

わかりましたので、これは私がこれまでのところ持っているものです:

ここに画像の説明を入力してください

回答:


21

ベースランドでは、2つの2D連続ノイズフィールド(Perlin、Simplex、Wavelet、それらの組み合わせ-あなたに合ったもの)を作成します。1つはほとんど周波数が低いものです。土地の上限には低振幅部分、土地の下限には高周波数、高振幅部分と低周波数、高振幅の両方が含まれます。下限が上限を超える場合、土地のボクセル(または地形を表現するためにゲームで使用するもの)を含めないでください。最終結果はおおよそ次のようになります...


しかし、これは2D向けですか?
ダレスチウム

しかし、私はそれがとても好きです:)
ダレステ​​ィウム

4
2D / 3D-同じこと
Gavin Williams

OK、それを
明日

@Darestium:視覚化を容易にする2Dの例です。同じ方法は、1より大きい任意の数の(代数的)次元に対して機能します。
マーティン・ソイカ

15

このようなもので十分でしょうか?

ここに画像の説明を入力してください

その場合は、この記事を確認してください。最も関連性の高い部分を引用:

より興味深いノイズを得るために、複数オクターブのシンプレックスノイズを一緒に追加できます。[...]ほぼ球形の浮遊岩を取得したいので、中心からの距離でノイズを乗算する必要があります。[...]また、岩は底よりも上部が平らになるようにしたいので、2番目の増倍率はy方向の勾配です。これらを組み合わせて、xとzaビットを圧縮しながらノイズのためにyを引き伸ばすと、浮遊岩のようなものが得られます。[...]ノイズオフセットの別のインスタンスで洞窟を少し掘り下げると、さらに興味深いものになります。

  • したがって、基本的には、シンプレックスノイズまたはパーリンノイズ(または複数のオクターブのノイズを加算)から生成されたデータセットから開始します。
  • 次に、球体をより球状にすることにより(ノイズを中心からの距離で乗算することにより)、浮遊する陸地により近いものに成形します。
  • そして、上部の近くで平らにすることで地面を作成します(垂直勾配を掛けることで、つまり上部で低い値から開始し、下部に向かって高くなります)。
  • これら3つを組み合わせて、X / Y / Z軸に沿ってノイズをスケーリングすることで形状を調整します(この記事では、Y軸でストレッチし、X軸とZ軸で圧縮することを提案しています)。
  • 洞窟の掘削には、追加のノイズパスを使用することができます。

はい、私はこのようなものが反抗的に私が欲しいものだと思う。問題は、パーリンノイズの経験がほとんどないため、生成できるのは基本的な山だけであり、「複数オクターブのノイズを加算する」方法については何も考えていないということです。stackoverflow.com/questions/4753055 / ...から降りてC#に移植しました。元の投稿に私のバージョンを追加します...そのような大規模な土地をどのように達成するか、例を挙げてください。コード?
ダレスチウム

2
それが私が記事をリンクした理由です。すべての手順の説明と最後にソースコードがあります。あなたはそれを勉強しようとするべきです。
デヴィッドゴーベイア

4
  1. 既存の3Dグリッドを使用して、島の上部の高さを決定します。平面に点を散乱させ、それらの点に立方体を配置することにより、2D平面に島のセットを作成します(XY平面と呼びます)。凝集力を使用して、それらをひとまとめにして近づけます。穴を埋めると、島の頂上セットができます。
  2. CAを使用する-島を下方に成長させる同様の方法。(a)初期ポイントをプロットしたZレベルから開始し、その現在のZレベルの各セルについて、XY平面内の隣接数が0から8までの場合、次に低いレベルまで拡張する機会を決定します(斜めの隣人が含まれます)、たとえば、各隣人に最大80%の確率で10%の確率を割り当てます。開始面の各セルに対してこれを計算します。(b)次に、この可能性に対してランダム化し、パーセンテージの範囲内にある場合は下方に拡張します。すすぎ、ステップ2を繰り返して(次のレベルに進み、各ボクセルの近傍を決定し、そのボクセルを下方に延長します)、延長がなくなるまで繰り返します。島のXY中心に向かうボクセルには、通常、より多くの近隣が存在するため、近隣の数のアプローチにより、下向きの拡張は円錐を形成する必要があります。

ステップ2の擬似コード:

int planeNeighbours[x][y]; //stores how many neighbours each voxel in this plane has

for each z level (starting at level where you plotted your points)
    for each x, y voxel in z level
        for each neighbour space bordering this voxel
            if neighbour exists
                ++planeNeighbours[x][y];
    for each x, y voxel in z level
        chance = random(0,8); //depends on your RNG implementation
        if chance < planeNeighbours[x][y]
            worldGrid[x][y][z+1] = new cube

島の生成が完了したら、必要に応じて空間内で島を上下に移動して、高さを変えることができます。


OK、私はあなたの方法にひびがありました、そしてそれは内側ではなく外側に地形を成長させているようです。私は...コードを投稿します
Darestium
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.