Ốp lát tiếng ồn perlin liền mạch, nhưng không lặp lại để tạo ra một thế giới 3D vô tận


8

Bây giờ tôi đã làm việc với một trò chơi 3D trong java bằng cách sử dụng LWJGL. Tôi đang cố gắng tạo địa hình 3D vô hạn được tạo theo thủ tục được tạo xung quanh người chơi.

Cho đến nay tôi có:

  • Các khối địa hình 3D được tải và không tải khi người chơi di chuyển. Các khối này được tạo thành từ các hình tam giác không phải hình tứ giác, và là các đỉnh 128x128.
  • Một lớp tiếng ồn Perlin có thể tạo ra tiếng ồn Perlin thành công. (Tôi nghĩ rằng nó thực sự là một cái gì đó gọi là nhiễu giá trị, nhưng nó hoạt động)
  • Một lớp thế giới xử lý việc tải và dỡ các khối, và áp dụng các bản đồ chiều cao cho các khối.

Tất cả điều này hoạt động như nó được mã hóa để làm, nhưng không phải là cách tôi muốn nó. Tôi không biết làm thế nào để giảm tiếng ồn một cách liền mạch.

Làm thế nào tôi có thể tạo ra các ô nhiễu, và hơn nữa, làm thế nào tôi có thể tạo ra các cấu trúc lớn như những ngọn núi chiếm tới hàng trăm khối.

Đây là những gì hiện đang xảy ra với các khối và tiếng ồn không ốp lát:

Điều này

Đây là mã tiếng ồn Perlin của tôi:

private float[][] perlinNoise(int width, int height, int octave, float[][] whiteNoise)
{
    float[][] result = new float[width][height];

    int samplePeriod = 1 << octave;
    float sampleFrequency = 1.0f / samplePeriod;

    for (int i = 0; i < width; i++)
    {
        int x1 = (i / samplePeriod) * samplePeriod;
        int x2 = (x1 + samplePeriod) % width;
        float xBlend = (i - x1) * sampleFrequency;

        for (int j = 0; j < height; j++)
        {
            int y1 = (j / samplePeriod) * samplePeriod;
            int y2 = (y1 + samplePeriod) % height;
            float yBlend = (j - y1) * sampleFrequency;

            float top = (float) MathHelper.interpolateLinear(whiteNoise[x1][y1], whiteNoise[x2][y1], xBlend);

            float bottom = (float) MathHelper.interpolateLinear(whiteNoise[x1][y2], whiteNoise[x2][y2], xBlend);

            result[i][j] = (float) MathHelper.interpolateLinear(top, bottom, yBlend);
        }
    }
    return result;
}

public float[][] generatePerlinNoise(int width, int height, Random random, int octaveCount)
{
    float[][] whiteNoise = new float[width][height];
    float[][][] totalNoise = new float[octaveCount][][];
    float[][] perlinNoise = new float[width][height];
    float amplitude = 1.0f;
    float totalAmplitude = 0.0f;
    float persistance = 0.5f;

    for (int i = 0; i < width; i++)
    {
        for (int j = 0; j < height; j++)
        {
            whiteNoise[i][j] = random.nextFloat() % 1;
        }
    }
    for (int i = 0; i < octaveCount; i++)
    {
        totalNoise[i] = perlinNoise(width, height, i, whiteNoise);
    }
    for (int o = octaveCount - 1; o >= 0; o--)
    {
        amplitude *= persistance;
        totalAmplitude += amplitude;

        for (int i = 0; i < width; i++)
        {
            for (int j = 0; j < height; j++)
            {
                perlinNoise[i][j] += totalNoise[o][i][j] * amplitude;
            }
        }
    }
    for (int i = 0; i < width; i++)
    {
        for (int j = 0; j < height; j++)
        {
            perlinNoise[i][j] /= totalAmplitude;
        }
    }
    return perlinNoise;
}

Tôi nghĩ cũng đáng để đề cập rằng tôi cũng đã hỏi về điều này trên StackOverflow .


1
Chỉ để bạn biết, nó sẽ không bao giờ HẤP DẪN, nhưng bạn có thể làm cho nó khá lớn (như, phạm vi của một số dấu phẩy động 32 hoặc 64 bit)
Alan Wolfe

Bạn có thể muốn kiểm tra tiếng ồn được khấu hao thay vì perlin, có vẻ như nó có một số lợi ích tốt cho một thế giới thủ tục - như đọc truy cập ngẫu nhiên. jcgt.org/published/0003/02/02
Alan Wolfe

1
Tôi không có câu trả lời toàn diện cho bạn nhưng đây là một liên kết đến trình tạo bóng pixel webgl tạo ra một dãy núi liền mạch. Bạn có thể sẽ tìm thấy thông tin hữu ích trong đó! shadertoy.com/view/MdX3Rr
Alan Wolfe

1
Cuối cùng, đây là một liên kết đến một lời giải thích về "Wang ốp lát", đây là một kỹ thuật thực sự tuyệt vời để làm cho mọi thứ ra khỏi gạch mà kết quả cuối cùng trông không được lát gạch. blog.demofox.org/2014/08/13/wang-tiling
Alan Wolfe

@Alan Wolfe Cuối cùng tôi cũng có kế hoạch có một thế giới hình cầu, vì vậy về mặt kỹ thuật nó không cần phải là vô hạn, bởi vì cuối cùng bạn sẽ kết thúc nơi bạn bắt đầu nếu bạn đi trên một đường thẳng trong một thời gian dài. Nhưng tôi không nên chạy trước khi tôi có thể đi bộ, tôi cần phải làm cho tiếng ồn perlin hoạt động trước. Ngoài ra FYI, tôi dự định thực hiện điều này bằng cách ánh xạ các đỉnh của khối lập phương vào một hình cầu, trong đó mỗi mặt của khối là một lưới lớn các khối.
Kelan

Câu trả lời:


4

Cung cấp tín dụng cho Alan Wolfe cho những gì ông nói trên "gạch INFINITELY". Nhiễu perlin 2d (hoặc nhiễu đơn giản 2d) sẽ không có vấn đề về đường may khi bạn tránh xa các đường viền nhiễu (được xác định bằng cách giảm điểm floatin) Tham khảo hình ảnh: nhập mô tả hình ảnh ở đây

và nói rằng bạn có các khối với đỉnh 128X128, trong đoạn i, j bạn tính từng đỉnh là:

for x : 0 .. 128-1
 for y : 0 .. 128-1
  PerlinNoise2d.getValue(i*128 + x, j*128 + y)

này, sẽ cấp liền mạch giữa các khối.

Nếu bạn muốn mô phỏng một thế giới vô tận bất kể biên giới nhiễu, bạn có thể sử dụng nhiễu 3d và xem xét các giá trị trên bề mặt của một hình cầu .. nhưng đây là một câu chuyện khác.


Hmm ... tốt, điều này rất hữu ích, nhưng thực tế là tiếng ồn của tôi value noisechứ không phải perlin noiselà một vấn đề. Tôi đã sử dụng điều này để thực hiện nó, và bài viết không may được đặt tên perlin noisenhưng sau đó tôi phát hiện ra nó thực sự value noise. Tôi không thể tìm thấy bất kỳ hướng dẫn hữu ích về việc thực hiện tiếng ồn perlin trong java.
Kelan

Một điều khác vừa xảy ra với tôi là liệu cái này có hoạt động được với các khối ở các lưới điện âm không? sơ đồ của bạn bắt đầu từ 0,0 nhưng nó có thể bắt đầu tại Float.MIN_VALUE hoặc Double.MIN_VALUE không? Điều này sẽ có ảnh hưởng đến tiếng ồn được tạo ra với các hợp âm âm? Câu hỏi này có lẽ là ngu ngốc, nhưng xuất phát từ sự thiếu hiểu biết của tôi về tiếng ồn perlin.
Kelan

@NervezXx Lưu ý rằng trong Java, MIN_VALUE là giá trị khác không dương nhỏ nhất có thể, không phải giá trị âm lớn nhất.
Lars Viklund

Ồ, tôi chưa bao giờ biết điều này. Tôi biết rằng Integer.MIN_VALUE là một số âm thực sự lớn, vì vậy tôi nghĩ rằng nó giống nhau cho Double và Float.MIN_VALUE
Kelan
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.