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가 지정한 방식으로 펄린 노이즈를 구현하려고합니다.

좋아, 이것이 내가 지금까지 얻은 것입니다.

여기에 이미지 설명을 입력하십시오

답변:


21

베이스 랜드의 경우, 주로 저주파를 갖는 2 개의 2D 연속 노이즈 필드 (Perlin, Simplex, Wavelet, 이들의 조합)를 만드십시오. 땅의 상한을위한 낮은 진폭 부분, 다른 하나는 땅의 하한을위한 높은 주파수, 높은 진폭 부분 및 낮은 주파수, 높은 진폭을 갖는다. 하한이 상한을 초과하는 경우, 랜드 복셀 (또는 게임이 지형을 나타내는 데 사용하는 것)을 포함하지 마십시오. 최종 결과는 대략 다음과 같습니다.


그러나 이것은 2D를위한 것입니까?
Darestium

그러나 나는 그것을 아주 좋아합니다 :)
Darestium

4
2D / 3D-같은 것
개빈 윌리엄스

알았어,
악당

@Darestium :보다 쉬운 시각화를위한 2D 예제입니다. 동일한 방법이 1보다 큰 (대수) 치수에 대해 작동합니다.
Martin Sojka

15

이것으로 충분할까요?

여기에 이미지 설명을 입력하십시오

그렇다면 이 기사를 확인 하십시오 . 가장 관련성이 높은 부품 인용 :

보다 흥미로운 노이즈를 얻기 위해 여러 옥타브의 단순한 노이즈를 함께 추가 할 수 있습니다. [...] 대략 구면에 떠 다니는 떠 다니는 암석을 만들고 싶기 때문에 잡음을 중심으로부터의 거리와 곱해야합니다. [...] 또한 바위가 바닥보다 바닥에서 더 평평 해지기를 원하므로 두 번째 곱셈 계수는 y 방향의 기울기입니다. x와 za 비트를 압축하는 동안 이들을 결합하고 y를 늘려 노이즈를 늘리면 플로팅 록과 같은 효과가 나타납니다. [...] 또 다른 노이즈 오프셋 인스턴스로 동굴을 발굴하면 더 흥미로워집니다.

  • 따라서 기본적으로 단순 또는 펄린 노이즈 (또는 여러 옥타브 노이즈가 함께 추가됨 ) 에서 생성 된 데이터 세트로 시작 합니다.
  • 그런 다음 노이즈를 중심으로부터의 거리 에 곱하여 구형 으로 만들어 부유하는 육상 질량에 더 가까운 모양으로 만듭니다 .
  • 그리고 상단 근처에서 평평 하게함으로써 지상을 만듭니다 ( 예 : 상단에서 낮은 값으로 시작하여 하단으로 갈수록 수직 기울기 ).
  • 이 세 가지를 결합 하고 X / Y / Z 축을 따라 노이즈를 스케일링 하여 모양을 조정 합니다 (이 기사에서는 Y 축에서 스트레칭 및 X 및 Z 축에서 압축 제안 ).
  • 동굴 을 발굴하는 데 추가 소음 통과가 사용될 수 있습니다 .

그렇습니다, 나는 이것과 같은 것이 내가 원하는 바라고 생각합니다. 문제는 펄린 노이즈에 대한 경험이 거의 없기 때문에 내가 생성 할 수있는 유일한 것은 실제로 기본적인 산이며 "여러 옥타브의 노이즈를 함께 추가하는 방법"에 대한 아이디어가 없을 것입니다. stackoverflow.com/questions/4753055 / ...에서 내려서 C #으로 포팅했습니다. 원래 게시물에 내 버전을 추가하겠습니다 ... 어떻게 그런 토지 질량을 달성 할 수 있는지에 대한 예를 들어 주시겠습니까? 코드?
Darestium

2
그렇기 때문에 기사를 연결했습니다. 모든 단계에 대한 설명과 끝에 소스 코드가 있습니다. 당신은 그것을 공부하려고합니다.
David Gouveia

4
  1. 기존 3D 그리드를 사용하여 섬 상단을 원하는 높이로 결정하십시오. 평면을 통해 점을 산란 한 다음 해당 점에 큐브를 배치하여 해당 2D 평면에 아일랜드 세트 (XY 평면이라고 함)를 작성하십시오. 응집력을 사용하여 덩어리로 서로 더 가깝게 잡아 당깁니다. 구멍을 채우면 일련의 섬 꼭대기가 있습니다.
  2. CA 사용섬을 아래쪽으로 자라는 비슷한 방법입니다. (a) 현재 Z 레벨의 각 셀에 대해 초기 지점을 플로팅 한 Z 레벨에서 시작하여 XY 평면의 이웃 수가 주어진 경우 0에서 8까지의 다음 하위 레벨로 확장 될 가능성을 결정합니다 ( 예를 들어 각 이웃에 대해 10 % 확률을 최대 80 %까지 할당하십시오. 시작 평면의 각 셀에 대해 이것을 계산하십시오. (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

섬 생성이 완료되면 공간에서 위아래로 이동하여 높이를 다르게 할 수 있습니다.


좋아, 나는 당신의 방법에 균열이 있었고 그것은 안쪽이 아닌 바깥쪽으로 지형을 성장시키는 것 같습니다. 코드를 게시하겠습니다 ...
Darestium
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.