Terreno Voxel liscio


13

Come progetto personale, sto cercando di creare un generatore di terreno che crei un terreno che assomigli al terreno liscio di Castle Story.

Se non l'hai mai visto prima, qui: inserisci qui la descrizione dell'immagine

Come puoi vedere, è una combinazione di blocchi e blocchi "lisci".

Quello che ho provato a fare per emulare questo aspetto è quello di dare ad ogni blocco di superficie una mini altezza. In genere funziona, ma ci sono alcuni problemi, che danno un terreno come questo:

inserisci qui la descrizione dell'immagine

Il problema è che ogni blocco è 1x1x1, ma a volte l'altezza in una determinata posizione è negativa o> 1. In tal caso, lo aggancio e imposto l'altezza su 0 o 1.

Per illustrare meglio cosa intendo, ecco un diagramma: inserisci qui la descrizione dell'immagine

Per generare l'altezza, fondamentalmente faccio:

genColumn(int x, int z)
{
    int highestBlockY = (int)noise2d(x, z);

    bool is_surface = true;

    for(int y = max_height - 1; y >= 0; y--)
    {
        Block b;

        if(is_surface)
        {
            b = Block.Grass;
            b.HasHeightMap = true;

            // generate heightmap
            for(int ix = 0; ix < 5; ix++)
            {
                for(int iz = 0; iz < 5; iz++)
                {
                    float heightHere = noise2d(x + ix / 4, z + iz / 4) - y;

                    // clip heights
                    if(heightHere > 1)
                        heightHere = 1;

                    if(heightHere < 0)
                        heightHere = 0;

                    b.HeightMap[ix][iz] = heightHere;
                }
            }

            is_surface = false;
        }
        else
        {
            b = Block.Dirt;
        }

        setBlock(x, y, z, b);
    }
}

Forse mi sto avvicinando a questo in modo errato utilizzando il "vero" valore del rumore perlin?

Qualsiasi aiuto sarebbe molto apprezzato!

Risposte:


11

Castle Story si presenta così a causa di vincoli tecnici: dovevano esserci una mappa di altezza per ogni voxel nell'intero volume, piuttosto che solo una mappa di altezza per ciascuno voxel di superficie , il costo di archiviazione sarebbe notevolmente maggiore, nell'ordine di O (n ^ 3 ) che può essere proibitivo, al contrario di una O più favorevole (n ^ 2), dove n è la lunghezza laterale di uno spazio cubico in voxel che rappresenta il tuo mondo. Tieni presente che le informazioni sulla mappa di altezza per i voxel sotterranei sono implicite nella struttura della griglia, quindi le informazioni sulla mappa di altezza devono essere archiviate esplicitamente solo per quei voxel che si trovano in superficie. Quindi i ragazzi di Castle Story hanno fatto scattare vertici su interstizi in griglia per risparmiare sui costi di archiviazione e sulla complessità della costruzione di mesh ... continua a leggere.

Prima di tutto, diamo un'occhiata alle tue opzioni:

inserisci qui la descrizione dell'immagine

(1) renderà le cose difficili per te, poiché in una singola colonna voxel vuoi solo informazioni mini-heightmap per il voxel più in alto - fai riferimento al primo paragrafo per i motivi. Guardando (1), la colonna a destra contiene informazioni sull'altezza sia per il più in alto che per il secondo dall'alto (e questo potrebbe applicarsi al terzo dall'alto e così via, se la pendenza fosse abbastanza estrema). Questo non va bene.

(2) Probabilmente è un'opzione migliore allora; vale a dire, assicurare che i vertici degli angoli si aggancino agli interstizi della griglia voxel. Ma come affrontare il problema delle pendenze estreme? Bene, dobbiamo scegliere un certo gradiente in cui semplicemente agganciamo a una colonna verticale e quindi assicuriamo di non avere gradienti che possano attraversare n i voxel più in alto. Un gradiente di 45 gradi è il naturale limite per le ragioni che spiegherò di seguito. Quindi invece di (3), avremmo (4):

inserisci qui la descrizione dell'immagine

(4) Far scattare il vertice d'angolo del voxel all'interstizio di griglia più vicino è la soluzione. L'effetto visivo - alias diagonale - può essere visto nello screenshot di Castle Story. La pendenza di taglio per i voxel è un gradiente 1: 1 o 45 gradi (visto ortogonalmente). Lavorando all'indietro dalla soluzione, esaminiamo i motivi:

  • L'unico modo in cui potremmo avere una pendenza estrema, ininterrotta, è se un voxel fosse allungato verticalmente ...
  • .... Ma nessuna mesh di voxel può superare la sua area di delimitazione, indipendentemente dalla sua reale forma levigata; un voxel deve stare in uno spazio definito in una griglia 3D che tiene conto, se non per la sua forma esatta, almeno per il suo riquadro di delimitazione allineato agli assi.

Un altro motivo per affrontarlo in questo modo è che, come hai già scoperto, non usare lo snap (discretizzazione) porta a una serie di scenari di levigatura della superficie geometricamente complessi, che è meglio evitare del tutto ... giochi di questo tipo generalmente non richiedono il grado di accuratezza che fornirebbe un algoritmo CSG adeguato, che è la ragione principale per cui stiamo usando voxel in primo luogo: i Voxels rendono molto più facile lavorare in modo incrementale con i volumi, rispetto agli algoritmi di intersezione poligonale / continua in virgola mobile (continua) .


Ho appena provato a implementarlo, e ho incontrato un po 'di confusione: cosa intendi con "interstizi?" Intendi le coordinate della griglia integrale?
senza titolo

@ThomasBradworth. "Uno spazio che interviene tra le cose." Per 2D, se hai una griglia di celle anxn, avrai (n + 1) x (n + 1) interstizi. Questo si estende direttamente al 3D. Sono i "vertici" che legano ogni cella, che sono per lo più condivisi tra più celle / voxel. Se la riduci a 1D (una linea), se entrambe le celle e gli interstizi sono rappresentati come array, la cella 0 è delimitata dall'interstizio 0 e dall'interstizio 1, mentre la cella 1 è delimitata dall'interstizio 1 e dall'interstizio 2 ... ecc.
Ingegnere,

Grazie per la risposta! Ho provato a fare esattamente questo, ma ho ottenuto alcuni risultati sfavorevoli. All'inizio, ho provato semplicemente ad arrotondare i valori di altezza ai bordi (quando x è 0 o 4 o z è 0 o 4), ma questo mi ha procurato: i.imgur.com/eQW7Y.png ( pastebin.com/Lr8vyyHB ) Successivamente, ho provato a appianare i punti nel mezzo, quindi ho aggiunto una "funzione di correzione delle altezze": pastebin.com/AazQ07Xm che, tuttavia, mi ha dato anche un risultato più angolare, ma anche negativo: i.imgur.com/q1JVP .png Forse qualcosa non va nella mia funzione di rumore?
senza titolo,

@ThomasBradsworth Purtroppo, ho sentito che hai letto solo a metà / capito la risposta che ho impiegato più di un'ora per scrivere e modificare. Dimentica il rumore; inoltre, se non capisci la funzione del rumore, rimuovila dall'equazione per ora. Il tuo problema risiede nel modo in cui sono costruiti i singoli dati della mesh voxel e il rumore non ha nulla a che fare con questo, perché puoi creare una mappa di altezza in assenza di rumore. Lavora con il caso di test più semplice, ovvero hardcode l'array di altezza. Quindi visualizza i risultati e modifica l'algoritmo di generazione della mesh. Ripeti fino a quando non fa ciò che è previsto. Quindi reinserire il rumore e rivedere.
Ingegnere,

Stai dicendo che dovrei semplicemente memorizzare i valori di altezza per gli angoli e non memorizzare i valori di altezza dei punti "intermedi"?
senza titolo
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.