winziger Diamantquadrat-Algorithmus


12

Der Diamantquadrat-Algorithmus ist ein Algorithmus zur Erzeugung von fraktalem Terrain (Heightmap). Eine schöne Beschreibung, wie es funktioniert, finden Sie hier:

http://www.gameprogrammer.com/fractal.html (Wird als Referenz verwendet.)

http://www.playfuljs.com/realistic-terrain-in-130-lines/ (Großartige JS-Implementierung, vielleicht möchten Sie seinen Renderer stehlen. Schauen Sie sich hier an, was dieser Algorithmus für http: // Demos kann. playfuljs.com/terrain/ .)

Die allgemeine Idee ist, dass Sie 4 Ecken als Startwerte haben (a) und die Höhe des Mittelpunkts berechnen, indem Sie diese vier Ecken mitteln und einen zufälligen Wert hinzufügen, z. B. zwischen -0,5 und 0,5 (b). Wenn Sie dies auf das Raster anwenden, erhalten Sie erneut ein Raster aus Diamanten (Quadrate um 45 ° gedreht) und wiederholen dasselbe (c, d), aber der zufällige Bereich wird kleiner, z. B. -0,125 bis 0,125 usw. Bildbeschreibung hier eingeben

Ihr Programm muss eine Reihe von Eingaben akzeptieren:

  • Eine Ganzzahl l=1,2,3,..., die die Größe des quadratischen Rasters mit der Seitenlänge bestimmt 2^l+1. Bei l=10Ihnen müssen etwa eine Million Nummern gespeichert werden.
  • Vier Samen (Fließkomma) für jede Ecke
  • Ein Parameter 0<h<1, der die Rauheit ( Him Link) bestimmt, die angibt , wie groß der zufällige Bereich anfangs ist
  • Parameter a,b, die anfängliche Unter- und Obergrenzen für den Zufallsbereich darstellen und hbei jedem Verfeinerungsschritt mit multipliziert werden . (Die Zufallszahl wird einheitlich zwischen aund gewählt b.

Die Ausgabe muss aus dem fertigen 2D-Raster bestehen.

Der grobe Algorithmus würde also so aussehen:

Create a square grid with sidelength 2^l+1
Place seed values in the corners
Repeat:
  |  Perform square steps
  |  Refine Range: a = a*h; b=b*h;
  |  Perform diamond steps
  |  Refine Range

Es gibt ein Detail, das Sie beachten sollten: An der Grenze des Rasters haben Sie nur drei Scheitelpunkte des Diamanten , daher sollten Sie auch nur den Durchschnitt dieser drei Punkte berechnen.

Eine Visualisierung einiger Beispiele (bitte geben Sie uns an, welche Parameter Sie verwendet haben) ist optional, wird jedoch geschätzt und trägt natürlich nicht zur Byte-Anzahl bei.

Eine leicht abgewandelte Implementierung dieses Algorithmus finden Sie hier: Parallel projizierter Voxel-Terrain-Generator

Ich habe eine kleine Zeichnungsfunktion in Javascript erstellt, um Höhenkarten in 2d als Graustufenbild zu verschieben. http://jsfiddle.net/flawr/oy9kxpsx/

Wenn jemand von Ihnen Lust auf 3D hat und ein Skript zum Anzeigen von Karten in 3D erstellen kann, lassen Sie es mich wissen! =)

Antworten:


8

Java, 1017 Bytes

Eingabe eine durch Leerzeichen getrennte Liste wie folgt: l s1 s2 s3 s4 h a b.

Die Ausgabe ist ein 2D-Array, das die Zahlen enthält.

Programm:

import java.util.*;import static java.lang.Math.*;class C{public static void main(String[]a){int b=a.length,d=0;float[]c=new float[b];for(;d<b;){c[d]=Float.parseFloat(a[d++]);}e=(int)(pow(2,c[0])+1);f=new float[e][e];f[0][0]=c[1];f[0][e-1]=c[2];f[e-1][0]=c[3];f[e-1][e-1]=c[4];g=c[5];float h=c[6],i=c[7];s(0,0,e-1,e-1,h,i);System.out.print(Arrays.deepToString(f));}static int e;static float[][]f;static float g;static void s(int q,int r,int s,int t,float h,float i){if(s-q<2|t-r<2|q<0|r<0|s>=e|t>=e)return;float o,p;int m=(q+s)/2,n=(r+t)/2;f[m][n]=(float)(a(q,r,s,r,q,t,s,t)+random()*(i-h)-h);d(m,r,m-q,o=h*g,p=i*g);d(q,n,m-q,o,p);d(m,t,m-q,o,p);d(s,n,m-q,o,p);}static void d(int x,int y,int e,float h,float i){float o,p;f[x][y]=(float)(a(x,y-e,x+e,y,x,y+e,x-e,y)+random()*(i-h)-h);s(x-e,y-e,x,y,o=h*g,p=i*g);s(x,y-e,x+e,y,o,p);s(x-e,y,x,y+e,o,p);s(x,y,x+e,y+e,o,p);}static float a(int...j){float k=0,l=0;for(int d=0;d<j.length;d+=2){if(j[d]<0|j[d+1]<0|j[d]>=e|j[d+1]>=e)continue;l++;k+=f[j[d]][j[d+1]];}return k/l;}}

Programm, das eingerückt ist und die Karte anzeigt:

import java.util.*;
import java.awt.image.*;
import java.awt.*;
import javax.swing.*;
import static java.lang.Math.*;

class D{

    public static void main(String[]a){
        int b=a.length,d=0;
        float[]c=new float[b];
        for(;d<b;){
            c[d]=Float.parseFloat(a[d++]);
        }
        e=(int)(pow(2,c[0])+1);
        f=new float[e][e];
        f[0][0]=c[1];
        f[0][e-1]=c[2];
        f[e-1][0]=c[3];
        f[e-1][e-1]=c[4];
        g=c[5];
        float h=c[6],i=c[7];
        s(0,0,e-1,e-1,h,i);
        showImage(f);
    }

    static int e;
    static float[][]f;
    static float g;

    static void s(int q,int r,int s,int t,float h,float i){
        if(s-q<2|t-r<2|q<0|r<0|s>=e|t>=e)
            return;
        float o,p;
        int m=(q+s)/2,n=(r+t)/2;
        f[m][n]=(float)(a(q,r,s,r,q,t,s,t)+random()*(i+h)-h);
        d(m,r,m-q,o=h*g,p=i*g);
        d(q,n,m-q,o,p);
        d(m,t,m-q,o,p);
        d(s,n,m-q,o,p);
    }

    static void d(int x,int y,int e,float h,float i){
        float o,p;
        f[x][y]=(float)(a(x,y-e,x+e,y,x,y+e,x-e,y)+random()*(i-h)+h);
        s(x-e,y-e,x,y,o=h*g,p=i*g);
        s(x,y-e,x+e,y,o,p);
        s(x-e,y,x,y+e,o,p);
        s(x,y,x+e,y+e,o,p);
    }

    static float a(int...j){
        float k=0,l=0;
        for(int d=0;d<j.length;d+=2){
            if(j[d]<0|j[d+1]<0|j[d]>=e|j[d+1]>=e)
                continue;
            l++;
            k+=f[j[d]][j[d+1]];
        }
        return k/l;
    }

    public static void showImage(float[][] f){
        float maxHeight = Float.MIN_VALUE;
        float minHeight = Float.MAX_VALUE;
        for (float[] row : f){
            for (float height : row){
                if (height > maxHeight){
                    maxHeight = height;
                }
                if (height < minHeight){
                    minHeight = height;
                }
            }
        }
        int e = f.length;
        BufferedImage image = new BufferedImage(e, e, BufferedImage.TYPE_INT_RGB);
        for (int x = 0; x < e; x++){
            for (int y = 0; y < e; y++){
                Color color = Color.getHSBColor((float)((f[x][y] - minHeight)/(maxHeight - minHeight)), 1, 1);
                image.setRGB(x,y,color.getRGB());
            }
        }
        JFrame frame = new JFrame("Picture");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(new JComponent(){

            @Override
            public void paint(Graphics g){
                g.drawImage(image, 0, 0, getWidth(), getHeight(), null);
            }

        });
        frame.setVisible(true);
        frame.setBounds(0,0,e,e);
    }

}

Hier ist eine Funktion in Java, um eine Karte anzuzeigen:

public static void showImage(float[][] map){
    float maxHeight = Float.MIN_VALUE;
    float minHeight = Float.MAX_VALUE;
    for (float[] row : map){
        for (float height : row){
            if (height > maxHeight){
                maxHeight = height;
            }
            if (height < minHeight){
                minHeight = height;
            }
        }
    }
    int size = map.length;
    BufferedImage image = new BufferedImage(size, size, BufferedImage.TYPE_INT_RGB);
    for (int x = 0; x < size; x++){
        for (int y = 0; y < size; y++){
            Color color = Color.getHSBColor((float)((map[x][y] - minHeight)/(maxHeight - minHeight)), 1, 1);
            image.setRGB(x,y,color.getRGB());
        }
    }
    JFrame frame = new JFrame("Picture");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.add(new JComponent(){

        @Override
        public void paint(Graphics g){
            g.drawImage(image, 0, 0, getWidth(), getHeight(), null);
        }

    });
    frame.setVisible(true);
    frame.setBounds(0,0,size,size);
}

Alle diese Bilder haben eine Größe von 7. Die 4 Samen sind 5, 10, 15, und 20.

aund bsind -10und 10jeweils.

Die Rauheit beginnt bei .1und erhöht sich um .1bis zu 1.

EinsZweiDreiVierFünfSechsSiebenAchtNeunZehn

Geländegenerierungscode kommt bald !!!

Bilder folgen in Kürze !!!


Vielen Dank! Könnten Sie vielleicht eine Klasse dazu mit allen erforderlichen Importen bereitstellen, sodass keine großen Änderungen erforderlich sind? Das wäre super!
Fehler

@flawr Ich arbeite daran.
TheNumberOne

Ich habe es gerade zum Laufen gebracht, wenn Sie wissen, wie es geht, wäre es großartig, wenn Sie das Fenster "unzusammengebrochen" erscheinen lassen könnten. Zumindest auf meinem Computer müssen Sie es jedes Mal öffnen, wenn Sie es starten. Hier ist , wie ich die Klasse beendet: pastebin.com/pRAMst4d
flawr

Das sieht toll aus! Mir gefällt besonders die elegante Art und Weise, wie Sie mit den Grenzen
umgehen, an

@flawr Das Fenster wird nicht minimiert, wenn Sie es jetzt öffnen.
TheNumberOne
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.