Làm cách nào tôi có thể tạo khối lượng đất nổi cho động cơ giống Minecraft?


19

Tôi đang tạo ra một công cụ giống như Minecraft trong XNA. Những gì tôi muốn làm là tạo các đảo nổi tương tự như đảo được hiển thị trong video này:

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

Làm thế nào tôi có thể tái tạo điều này bằng cách sử dụng một máy phát điện thế giới? Tôi có phải sử dụng một số thuật toán nhiễu Perlin không? Tôi không biết làm thế nào điều đó sẽ giúp tôi tạo ra những khối đất như thế.

Đây là mã cho trình tạo tiếng ồn perlin mà tôi đang sử dụng:

    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; } }

Nhưng điều là tác giả của mã sử dụng những điều sau đây để tạo ra tiếng ồn và tôi không hiểu nó ít nhất.

    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;
    }

Và đây là trang web tôi đang sử dụng: http://lotsacode.wordpress.com/2010/02/24/perlin-noise-in-c/ .

Và tôi đang cố gắng thực hiện tiếng ồn perlin theo cách được chỉ định bởi Martin Sojka.

Ok, đây là những gì tôi có được cho đến nay:

nhập mô tả hình ảnh ở đây

Câu trả lời:


21

Đối với vùng đất cơ sở, tạo hai trường nhiễu liên tục 2D (Perlin, Simplex, Wavelet, một tổ hợp của chúng - bất cứ điều gì phù hợp với bạn), một trường có tần số thấp. phần biên độ thấp cho giới hạn trên của đất, phần khác có cả tần số cao, phần biên độ cao và tần số thấp, biên độ cao cho giới hạn dưới của đất. Trong trường hợp giới hạn dưới cao hơn giới hạn cao hơn, không bao gồm bất kỳ voxels đất nào (hoặc bất cứ điều gì trò chơi của bạn sẽ được sử dụng để thể hiện địa hình). Kết quả cuối cùng trông giống như thế này ...


Nhưng đây là cho 2D phải không?
Darestium

Nhưng tôi khá thích nó :)
Darestium

4
2D / 3D - điều tương tự
Gavin Williams

OK, tôi sẽ cố gắng thực hiện nó vào ngày mai ... Chúc tôi may mắn;)
Darestium

@Dinoisium: Đây là một ví dụ 2D để dễ hình dung hơn. Phương pháp tương tự hoạt động cho bất kỳ số lượng kích thước (đại số) nào cao hơn một.
Martin Sojka

15

Một cái gì đó như thế này là đủ?

nhập mô tả hình ảnh ở đây

Nếu vậy, hãy kiểm tra bài viết này . Trích dẫn những phần có liên quan nhất:

Để có được tiếng ồn thú vị hơn, nhiều quãng tám của tiếng ồn đơn giản có thể được thêm vào với nhau. [...] Vì tôi muốn có được một loại đá nổi có dạng hình cầu, tôi cần nhân lên tiếng ồn với khoảng cách từ trung tâm. [...] Tôi cũng muốn tảng đá phẳng hơn ở phía trên so với phía dưới, do đó, hệ số nhân thứ hai là độ dốc theo hướng y. Kết hợp những thứ này lại với nhau và kéo dài y cho tiếng ồn trong khi nén bit x và za, chúng ta có được thứ gì đó giống như một tảng đá nổi. [...] Việc đào hang với một ví dụ khác về tiếng ồn bù lại một chút cũng khiến nó thú vị hơn.

  • Vì vậy, về cơ bản, bạn sẽ bắt đầu với một tập dữ liệu được tạo từ nhiễu đơn giản hoặc nhiễu perlin (hoặc đúng hơn là nhiều quãng tám nhiễu cộng lại với nhau ).
  • Sau đó định hình nó thành một cái gì đó gần với một vùng đất nổi bằng cách làm cho nó hình cầu hơn (bằng cách nhân tiếng ồn với khoảng cách của nó từ trung tâm ).
  • Và tạo mặt đất bằng cách làm cho nó phẳng hơn trên đỉnh (bằng cách nhân nó với một gradient dọc tức là bắt đầu với các giá trị thấp ở trên cùng và cao hơn về phía dưới).
  • Kết hợp cả ba và điều chỉnh hình dạng bằng cách điều chỉnh độ nhiễu dọc theo trục X / Y / Z (bài viết gợi ý kéo dài trên trục Y và nén trên trục X và Z ).
  • Một tiếng ồn bổ sung có thể được sử dụng để đào hang .

Vâng, tôi nghĩ rằng một cái gì đó như thế này là thách thức những gì tôi muốn. Có một điều là tôi có ít kinh nghiệm về tiếng ồn perlin nên điều duy nhất tôi có thể tạo ra là những ngọn núi thực sự cơ bản và sẽ không có ý tưởng nào về cách thêm "nhiều quãng tám tiếng ồn). Đối với thế hệ tiếng ồn perlin tôi đang sử dụng mã rằng tôi đã tắt stackoverflow.com/questions/4853055/ và chuyển nó sang C #. Ill thêm phiên bản của tôi vào bài viết gốc ... Bạn có sẵn lòng cho tôi một ví dụ về cách tôi sẽ đạt được khối lượng đất như vậy với điều đó không mã?
Darestium

2
Đó là lý do tại sao tôi liên kết bài viết. Nó có một lời giải thích về tất cả các bước và mã nguồn ở cuối. Bạn nên cố gắng nghiên cứu điều đó.
David Gouveia

4
  1. Sử dụng lưới 3D hiện tại của bạn, quyết định độ cao mà bạn muốn đỉnh đảo đạt được. Tạo một tập hợp các đảo trong mặt phẳng 2D đó (hãy gọi nó là mặt phẳng XY) bằng cách phân tán các điểm qua mặt phẳng, sau đó đặt các khối tại các điểm đó. Sử dụng sự gắn kết để kéo chúng lại gần nhau hơn trong các cụm. Điền vào bất kỳ lỗ nào và bạn có một bộ đảo.
  2. Sử dụng CAphương pháp-fax để phát triển các hòn đảo xuống dưới. (a) Bắt đầu từ cấp Z nơi bạn đã vẽ các điểm ban đầu của mình, cho mỗi ô ở cấp Z hiện tại đó, xác định cơ hội kéo dài xuống cấp thấp hơn tiếp theo với số lượng lân cận trong mặt phẳng XY, từ 0 đến 8 ( hàng xóm chéo được bao gồm), ví dụ: chỉ định 10% cơ hội cho mỗi hàng xóm, tối đa 80% cơ hội. Tính toán này cho mỗi ô trong mặt phẳng bắt đầu. (b) Sau đó, ngẫu nhiên chống lại cơ hội này và kéo dài xuống dưới nếu bạn nằm trong phạm vi tỷ lệ phần trăm. Rửa sạch, lặp lại bước 2 (chuyển sang cấp độ tiếp theo, xác định hàng xóm cho mỗi voxel, kéo dài xuống dưới cho voxel đó) cho đến khi không còn phần mở rộng nào xảy ra. Phần mở rộng đi xuống của bạn sẽ tạo thành một hình nón do cách tiếp cận số lượng hàng xóm, bởi vì những voxels đó hướng về trung tâm XY của đảo thường sẽ có nhiều hàng xóm hơn.

Mã giả cho bước 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

Khi các đảo của bạn được tạo xong, bạn có thể tùy ý di chuyển chúng lên và xuống trong không gian để có chúng ở các độ cao khác nhau.


OK, tôi đã có một vết nứt theo phương pháp của bạn và nó dường như đang phát triển địa hình ra bên ngoài thay vì vào bên trong. Tôi sẽ đăng mã ...
Darestium
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.