Perlines Rauschen nahtlos kacheln, ohne es zu wiederholen, um eine unendliche 3D-Welt zu erzeugen


8

Ich arbeite seit einiger Zeit mit LWJGL an einem 3D-Spiel in Java. Ich versuche, prozedural erzeugtes unendliches 3D-Terrain zu erstellen, das um den Player herum erzeugt wird.

Bisher habe ich:

  • 3D-Geländestücke, die beim Bewegen des Spielers geladen und entladen werden. Diese Stücke bestehen aus Dreiecken, nicht aus Quads, und sind 128 x 128 Eckpunkte.
  • Eine Perlin-Rauschklasse, die erfolgreich Perlin-Rauschen erzeugen kann. (Ich denke, es ist eigentlich so etwas wie Wertrauschen, aber es funktioniert)
  • Eine Weltklasse, die das Laden und Entladen von Chunks und das Anwenden der Höhenkarten auf die Chunks übernimmt.

All dies funktioniert so, wie es codiert ist, aber nicht so, wie ich es möchte. Ich weiß nicht, wie ich den Lärm nahtlos kacheln soll.

Wie würde ich die Lärmkachel herstellen und wie würde ich darüber hinaus große Strukturen wie Berge erzeugen, die wahrscheinlich bis zu Hunderte von Brocken einnehmen?

Folgendes passiert derzeit mit den nicht kachelnden Brocken und Geräuschen:

Diese

Hier ist mein Perlin-Rauschcode:

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

Ich denke, es wäre auch erwähnenswert, dass ich auch bei StackOverflow danach gefragt habe .


1
Nur damit Sie wissen, wird es niemals UNENDLICH kacheln, aber Sie könnten es ziemlich groß machen (wie den Bereich einer 32- oder 64-Bit-Gleitkommazahl)
Alan Wolfe

Vielleicht möchten Sie amortisiertes Rauschen anstelle von Perlin ausprobieren. Es sieht so aus, als hätte es einige nette Vorteile für eine prozedurale Welt - wie das Lesen mit wahlfreiem Zugriff. jcgt.org/published/0003/02/02
Alan Wolfe

1
Ich habe keine umfassende Antwort für Sie, aber hier ist ein Link zu einem Webgl-Pixel-Shader, der eine nahtlose Bergkette erzeugt. Sie werden wahrscheinlich nützliche Informationen darin finden! shadertoy.com/view/MdX3Rr
Alan Wolfe

1
Zum Schluss hier ein Link zu einer Erklärung von "Wang Tiling", einer wirklich großartigen Technik, um Dinge aus Kacheln zu machen, bei denen das Endergebnis überhaupt nicht gekachelt aussieht. blog.demofox.org/2014/08/13/wang-tiling
Alan Wolfe

@Alan Wolfe Ich habe irgendwann vor, eine sphärische Welt zu haben, also muss sie technisch gesehen nicht unendlich sein, weil du irgendwann dort landen würdest, wo du angefangen hast, wenn du lange Zeit in einer geraden Linie gegangen wärst. Aber ich sollte nicht rennen, bevor ich laufen kann, ich muss zuerst Perlingeräusche zum Laufen bringen. Zu Ihrer Information habe ich vor, dies zu tun, indem ich die Eckpunkte eines Würfels einer Kugel zuordne, bei der jede Seite des Würfels ein großes Gitter aus Stücken ist.
Kelan

Antworten:


4

Alan Wolfe wurde für das, was er auf "INFINITELY tile" sagte, gewürdigt. Ein 2d-Perlin-Rauschen (oder ein 2d-einfaches Rauschen) hat kein Nahtproblem, sofern Sie sich von Rauschgrenzen fernhalten (definiert durch Fließkommadimensionierung). Referenzieren des Bildes: Geben Sie hier die Bildbeschreibung ein

und sagte, dass Sie Chunks mit 128X128 Vertex haben, in Chunk i, j berechnen Sie jeden Vertex als:

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

Dies wird nahtlos zwischen Chunks gewähren.

Wenn Sie eine unendliche Welt unabhängig von Rauschgrenzen simulieren möchten, können Sie ein 3D-Rauschen verwenden und die Werte auf der Oberfläche einer Kugel berücksichtigen. Dies ist jedoch eine andere Geschichte.


Hmm ... nun, das ist sehr nützlich, aber die Tatsache, dass mein Lärm value noiseeher ist als perlin noiseein Problem. Ich habe dies verwendet , um es zu implementieren, und der Artikel hat leider den Namen, perlin noiseaber ich habe später herausgefunden, dass es tatsächlich so ist value noise. Ich kann überhaupt kein nützliches Tutorial zu einer Perlin Noise-Implementierung in Java finden.
Kelan

Eine andere Sache, die mir gerade eingefallen ist, ist, ob dies für Brocken mit negativen Gitterkoordinaten funktioniert. Ihr Diagramm beginnt bei 0,0, aber könnte es bei Float.MIN_VALUE oder Double.MIN_VALUE beginnen? Würde sich dies auf das mit negativen Koordinaten erzeugte Rauschen auswirken? Diese Frage ist wahrscheinlich dumm, kommt aber von meinem Unverständnis für Perlin-Lärm.
Kelan

@NervezXx Beachten Sie, dass MIN_VALUE in Java der kleinstmögliche positive Wert ungleich Null und nicht der größte negative Wert ist.
Lars Viklund

Oh, das habe ich nie gewusst. Ich weiß, dass Integer.MIN_VALUE eine wirklich große negative Zahl ist, also dachte ich, dass es für Double und Float.MIN_VALUE
Kelan
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.