Seite 1 von 1

Terrain Generation in Java

Verfasst: 27.03.2023, 18:40
von focus0941
Vielleicht kennt sich jemand gut genug aus, um eine Klasse in der Programmiersprache Java zu erstellen, die pro Chunk einen Array, und wenn der Spieler weiter läuft neue erstellt. Außerdem müsste man diese auch laden und entladen können.

Re: Terrain Generation in Java

Verfasst: 27.03.2023, 19:56
von Schrompf
Machen wird es für Dich niemand, schätze ich mal. Fang mal damit an, dass Du ein Quadrat auf den Boden zauberst, das Du aus vielen kleinen Quadraten zusammenbaust. Dann stufenweise erweitern: die Höhe mit irgendnem Sinus in Wellen versetzen. Dann viele solche Quadrate. Dann mit der Kamerabewegung hinten wegschmeißen und vorne dranbauen. Dann die Höhen aus nem Bild laden und anwenden. Und so weiter.

Re: Terrain Generation in Java

Verfasst: 27.03.2023, 20:54
von Jonathan
Wie so eine Klasse aussehen würde ist ja auch komplett abhängig von der umgebenden 3D Engine. Man kann vlt. über allgemeine Techniken reden, die Implementation selber lässt sich aber sicherlich nicht so isoliert betrachten.

Worum geht es hier überhaupt? Mir fehlt irgendwie ein wenig Kontext...

Re: Terrain Generation in Java

Verfasst: 27.03.2023, 21:11
von focus0941
Also das Quadrat aus vielen kleineren hab ich schon und ich kann auch eine Sinusfunktion darauf anwenden. Und kleine Hügel zu Schönheit.

Re: Terrain Generation in Java

Verfasst: 27.03.2023, 21:26
von Schrompf
Ja, prima! Erster Schritt vollbracht! Sieht sogar aus, als hättest Du schon ordentliche Normalen. Jetzt müsstest Du den Sinus aus der globalen Position der Vertizes ableiten, also erst VertexPos mit Modell-Matrix transformieren und dann daraus Sinus ziehen. Dann ergeben die Quadrate eine durchgehende Fläche.

Als nächstes brauchst Du dann irgendne Datenquelle von Höhendaten. Immer nur Sinus-Höhe laaaangweilt. Notfalls füllst Du Dir mit einem Malprogramm Deiner Wahl ein Bild mit nem grauen Fraktal, Perlin Noise oder so. Und daraus nimmst Du dann die Höhenwerte für Deine Vertizes.

Re: Terrain Generation in Java

Verfasst: 29.03.2023, 09:30
von focus0941
Ich verstehe nicht so recht, wie ich das umsetzten soll.
Die Sinusfunktion ist in einer anderen Klasse, aber diese erstellt das Modell für das Terrain.

Code: Alles auswählen

private RawModel generateTerrain(Loader loader) {
        int VERTEX_COUNT = SIZE + 1;
        int count = VERTEX_COUNT * VERTEX_COUNT;

        heights = new float[VERTEX_COUNT][VERTEX_COUNT];

        float[] vertices = new float[count * 3];
        float[] normals = new float[count * 3];
        float[] textureCoords = new float[count * 2];

        int[] indices = new int[6 * (VERTEX_COUNT - 1) * (VERTEX_COUNT - 1)];
        int vertexPointer = 0;

        float[][] generatedHeight = HeightsGenerator.getHeights(SIZE, OCTAVE_COUNT, PERSISTENCE, seed);

        for(int i=0; i<VERTEX_COUNT; i++) {
            for(int j=0; j<VERTEX_COUNT; j++) {
                vertices[vertexPointer * 3] = (float)j / ((float)VERTEX_COUNT - 1) * SIZE;

                float height = getHeight(j, i, generatedHeight);

                heights[j][i] = height;

                vertices[vertexPointer * 3 + 1] = height;
                vertices[vertexPointer * 3 + 2] = (float)i / ((float)VERTEX_COUNT - 1) * SIZE;

                Vector3f normal = calculateNormal(j, i, generatedHeight);

                normals[vertexPointer * 3] = normal.x;
                normals[vertexPointer * 3 + 1] = normal.y;
                normals[vertexPointer * 3 + 2] = normal.z;

                textureCoords[vertexPointer * 2] = (float)j / ((float)VERTEX_COUNT - 1);
                textureCoords[vertexPointer * 2 + 1] = (float)i / ((float)VERTEX_COUNT - 1);

                vertexPointer++;
            }
        }

        int pointer = 0;

        for(int gz=0; gz<VERTEX_COUNT - 1; gz++) {
            for(int gx=0; gx<VERTEX_COUNT - 1; gx++) {
                int topLeft = (gz * VERTEX_COUNT) + gx;
                int topRight = topLeft + 1;
                int bottomLeft = ((gz + 1) * VERTEX_COUNT) + gx;
                int bottomRight = bottomLeft + 1;
                indices[pointer++] = topLeft;
                indices[pointer++] = bottomLeft;
                indices[pointer++] = topRight;
                indices[pointer++] = topRight;
                indices[pointer++] = bottomLeft;
                indices[pointer++] = bottomRight;
            }
        }
        return loader.loadToVAO(vertices, textureCoords, normals, indices);
    }

Re: Terrain Generation in Java

Verfasst: 29.03.2023, 09:40
von Schrompf
Du betreibst Deinen HeightsGenerator einmalig am Anfang für ein Vielfaches von SIZE. Das ist jetzt Deine Landschaft. Und jetzt gibst Du bei jedem generateTerrain() die Position des Quadrats mit. Also ein Offset in X und Z, immer ein Vielfaches von SIZE. Dieses Offset benutzt Du bei getHeight(). So bekommst Du Models, die jeweils einen anderen Ausschnitt Deiner Landschaft darstellen.

Re: Terrain Generation in Java

Verfasst: 29.03.2023, 09:56
von focus0941
So sieht es doch schon viel besser aus. Aber was mache ich mit dem Offset?
An den kleinen Hügeln liegt es nicht.

Re: Terrain Generation in Java

Verfasst: 29.03.2023, 10:22
von Schrompf
Ja, ist ein Fortschritt. Aber so schnell, wie das ging, und anhand Deines bisherigen Codes, spekuliere ich mal, dass Du irgendwo noch nen +1 Offset in Deinen Karten-Koordinaten hast. Jedes Terrain-Segment, was Du als Mesh erzeugst, ist SIZE+1 breit und SIZE+1 lang, aber das Nachbar-Terrainsegment startet bei Offset SIZE (nicht +1)! Die Punkte auf der Kante werden von beiden Segmenten gestellt.

Re: Terrain Generation in Java

Verfasst: 29.03.2023, 18:27
von focus0941
Das ist die besagte Methode, wo man dann den Code für das Terrain reinschreibt.
Es scheint zu funktionieren, aber die Normals sind noch fehlerhaft.

Code: Alles auswählen

public static float[][] getHeights(int SIZE, int OCTAVE_COUNT, float PERSISTENCE, long SEED, int chunkX, int chunkZ) {
        float[][] perlinNoise = new float[SIZE+1][SIZE+1];

        for(int x = 0; x < SIZE+1; x++) {
            for(int z = 0; z < SIZE+1; z++) {
                perlinNoise[x][z] = (float)(Math.sin((SIZE*chunkX+x) / 25f) * Math.sin((SIZE*chunkZ+z) / 25f) * 25);
            }
        }

Re: Terrain Generation in Java

Verfasst: 29.03.2023, 18:33
von Schrompf
Ich tippe auf Deine Normalenberechnung. Wenn Du für jeden Chunk die Heights neu berechnest, kennt der an diesen Kanten die Nachbarhöhen nicht mehr, weil die nur noch im nächsten Chunk zu finden sind. Normalen berechnet man an irgendner Stelle durch Betrachtung der Nachbarhöhen, und an der Kante gibt's bei Dir schlicht keine Nachbarhöhe mehr.

Entweder Du berechnest Dein Array perlinNoise mit noch zusätzlich einem weiteren Eintrag links, rechts, vorn, hinten (also SIZE+3). Oder Du machst, was ich vorher schon schrieb, und berechnest ein PerlinNoise-Array für die gesamte Landschaft und liest die Chunks noch aus Ausschnitten davon.

Re: Terrain Generation in Java

Verfasst: 29.03.2023, 19:21
von focus0941
Ich habe es lösen können. Es hat das SIZE in x=SIZE-1 und z=SIZE-1 gefehlt.
Vielen Dank für die Hilfe, war sehr hilfreich.

Code: Alles auswählen

private Vector3f calculateNormal(int x, int z, float[][] generatedHeight) {
        if(x == 0) {
            x = 1; }

        if(z == 0) {
            z = 1; }

        if(x >= SIZE) {
            x = SIZE-1; }

        if(z >= SIZE) {
            z = SIZE-1; }

        float heightL = getHeight(x - 1, z, generatedHeight);
        float heightR = getHeight(x + 1, z, generatedHeight);
        float heightD = getHeight(x,z - 1, generatedHeight);
        float heightU = getHeight(x,z + 1, generatedHeight);

        Vector3f normal = new Vector3f(heightL - heightR,2f,heightD - heightU);
        normal.normalise();

        return normal;
    }