piccolo algoritmo quadrato diamantato


12

L'algoritmo del diamante quadrato è un algoritmo di generazione del terreno frattale (heightmap). Puoi trovare una bella descrizione di come funziona qui:

http://www.gameprogrammer.com/fractal.html (utilizzato come riferimento.)

http://www.playfuljs.com/realistic-terrain-in-130-lines/ (Grande implementazione di JS, forse potresti voler rubare il suo renderer. Dai un'occhiata qui di cosa è capace questo algoritmo di http: // demos. playfuljs.com/terrain/ .)

L'idea generale è che hai 4 angoli come semi (a) e calcoli l'altezza del punto centrale facendo la media di quei quattro angoli e aggiungendo un valore casuale, ad esempio tra -0,5 e 0,5 (b). Se lo applichi alla griglia ottieni di nuovo una griglia di diamanti (quadrati turend 45 °) e ripeti lo stesso (c, d), ma l'intervallo casuale si riduce, ad esempio da -0,125 a 0,125 ecc. inserisci qui la descrizione dell'immagine

Il tuo programma deve accettare un numero di input:

  • Un numero intero l=1,2,3,...che determina la dimensione della griglia quadrata con la lunghezza laterale 2^l+1. Dovrai l=10archiviare circa un milione di numeri.
  • Quattro semi (virgola mobile) per ogni angolo
  • Un parametro 0<h<1che determina la rugosità ( Hnel collegamento) che indica quanto è grande l'intervallo casuale inizialmente
  • Parametri a,bche rappresentano i limiti iniziale inferiore e superiore per l'intervallo casuale e vengono moltiplicati per hogni fase di perfezionamento. (Il numero casuale viene scelto in modo uniforme tra ae b.

L'output deve essere costituito dalla griglia 2d finita.

Quindi l'algoritmo approssimativo sarebbe simile al seguente:

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

C'è un dettaglio di cui dovresti essere a conoscenza: al limite della griglia, avrai solo tre vertici del diamante , quindi dovresti anche calcolare solo la media di quei tre punti.

Una visualizzazione di alcuni esempi (per favore dicci quali parametri hai usato) è facoltativa ma apprezzata, e ovviamente non si aggiunge al conteggio dei byte.

Una leggera implementazione variegata di questo algoritmo può essere trovata qui: generatore di terreno voxel proiettato in parallelo

Ho creato una piccola funzione di disegno in JavaScript per eliminare le mappe di altezza in 2d come immagine in scala di grigi. http://jsfiddle.net/flawr/oy9kxpsx/

Se qualcuno di voi è appassionato di 3d e può creare uno script per visualizzare le mappe in 3d, fammi sapere! =)

Risposte:


8

Java, 1017 byte

Input è una lista separata da spazi in questo modo: l s1 s2 s3 s4 h a b.

L'output è un array 2d contenente i numeri.

Programma:

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

Programma indentato e visualizza la mappa:

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

}

Ecco una funzione in Java per mostrare una mappa:

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

Tutte queste immagini hanno una dimensione di 7. I 4 semi sono 5, 10, 15, e 20.

ae bsono -10e 10rispettivamente.

La rugosità inizia da .1e aumenta .1fino a 1.

UnoDueTrequattroCinqueSeiSetteOttoNoveDieci

Codice di generazione del terreno in arrivo !!!

Immagini in arrivo !!!


Grazie mille! Potresti forse fornire una classe attorno a quella con tutte le importazioni necessarie, quindi non sono necessarie grandi modifiche? Sarebbe fantastico!
flawr,

@flawr ci sto lavorando.
TheNumberOne il

Ho appena funzionato, se sai come farlo, sarebbe bello se si potesse far apparire la finestra "non intrappolata". Almeno sulla mia macchina devi aprirlo ogni volta che lo avvii. Ecco come ho completato la lezione: pastebin.com/pRAMst4d
flawr il

Sembra fantastico! Mi piace soprattutto il modo elegante in cui hai a che fare con i confini in cui manca un vertice =)
flawr

@flawr La finestra non verrà chiusa quando la apri ora.
TheNumberOne
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.