Terrain Generation in Java

Einstiegsfragen, Mathematik, Physik, künstliche Intelligenz, Engine Design
Antworten
focus0941
Beiträge: 39
Registriert: 27.03.2023, 18:28
Benutzertext: hatte mit 3 einen Bart
Echter Name: Vladimir Ilyushko

Terrain Generation in Java

Beitrag 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.
Benutzeravatar
Schrompf
Moderator
Beiträge: 4838
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: Terrain Generation in Java

Beitrag 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.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
Benutzeravatar
Jonathan
Establishment
Beiträge: 2352
Registriert: 04.08.2004, 20:06
Kontaktdaten:

Re: Terrain Generation in Java

Beitrag 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...
Lieber dumm fragen, als dumm bleiben!
https://jonathank.de/games/
focus0941
Beiträge: 39
Registriert: 27.03.2023, 18:28
Benutzertext: hatte mit 3 einen Bart
Echter Name: Vladimir Ilyushko

Re: Terrain Generation in Java

Beitrag 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.
Dateianhänge
So sieht es aus
So sieht es aus
Benutzeravatar
Schrompf
Moderator
Beiträge: 4838
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: Terrain Generation in Java

Beitrag 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.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
focus0941
Beiträge: 39
Registriert: 27.03.2023, 18:28
Benutzertext: hatte mit 3 einen Bart
Echter Name: Vladimir Ilyushko

Re: Terrain Generation in Java

Beitrag 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);
    }
Zuletzt geändert von focus0941 am 29.03.2023, 09:43, insgesamt 1-mal geändert.
Benutzeravatar
Schrompf
Moderator
Beiträge: 4838
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: Terrain Generation in Java

Beitrag 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.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
focus0941
Beiträge: 39
Registriert: 27.03.2023, 18:28
Benutzertext: hatte mit 3 einen Bart
Echter Name: Vladimir Ilyushko

Re: Terrain Generation in Java

Beitrag 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.
Dateianhänge
Es gibt immer noch einen kleinen Offset
Es gibt immer noch einen kleinen Offset
Benutzeravatar
Schrompf
Moderator
Beiträge: 4838
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: Terrain Generation in Java

Beitrag 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.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
focus0941
Beiträge: 39
Registriert: 27.03.2023, 18:28
Benutzertext: hatte mit 3 einen Bart
Echter Name: Vladimir Ilyushko

Re: Terrain Generation in Java

Beitrag 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);
            }
        }
Dateianhänge
Am Rand jeden Chunks ist eine helle / dunkle Linie
Am Rand jeden Chunks ist eine helle / dunkle Linie
Benutzeravatar
Schrompf
Moderator
Beiträge: 4838
Registriert: 25.02.2009, 23:44
Benutzertext: Lernt nur selten dazu
Echter Name: Thomas Ziegenhagen
Wohnort: Dresden
Kontaktdaten:

Re: Terrain Generation in Java

Beitrag 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.
Früher mal Dreamworlds. Früher mal Open Asset Import Library. Heutzutage nur noch so rumwursteln.
focus0941
Beiträge: 39
Registriert: 27.03.2023, 18:28
Benutzertext: hatte mit 3 einen Bart
Echter Name: Vladimir Ilyushko

Re: Terrain Generation in Java

Beitrag 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;
    }
Dateianhänge
ein sauberer Übergang
ein sauberer Übergang
Antworten