Fori trasparenti curiosi rendono artefatto


8

Quindi sto cercando di implementare un terreno "liscio" nel mio motore a blocchi dando ad ogni blocco di superficie una mappa di altezza.

Fondamentalmente, ciò che faccio per generare queste "mappe altimetriche" per ciascun blocco è generare le altezze a intervalli di 0,25 lungo il bordo del blocco. Quindi, per costruire i vertici del blocco, giro attraverso le altezze e creo triangoli da un'altezza all'altra e metto rettangoli sotto i triangoli per creare qualcosa del genere: inserisci qui la descrizione dell'immagine

Ad esempio, per costruire il lato X positivo di un blocco, faccio:

                    Vector2[] uv = BlockUtil.UVMappings[(byte)side]; // uv[0] = top left

                    float height;
                    float nextHeight;
                    float min;

                    float tex_len = 1f / EngineGlobals.TEXTURE_ATLAS_SIDE;

                    for (int i = 0; i < 4; i++)
                    {
                        height = (float)b.Heights[4, i] / 255f;

                        nextHeight = (float)b.Heights[4, i + 1] / 255f;

                        min = Math.Min(height, nextHeight);

                        //create the triangles at the top
                        if (nextHeight > height)
                        {
                            int offset = ch.vertexMap.Count;

                            AddVertex(ch, 0, 0, uv[0] + new Vector2(tex_len * (i / 4f), (1-height)*tex_len), blockPos, new Vector3(1f, height, i / 4f), tr, isliquid);
                            AddVertex(ch, 0, 0, uv[0] + new Vector2(tex_len * ((i + 1) / 4f), 0), blockPos, new Vector3(1f, height, (i + 1) / 4f), tr, isliquid);
                            AddVertex(ch, 0, 0, uv[0] + new Vector2(tex_len * ((i + 1) / 4f), 0), blockPos, new Vector3(1f, nextHeight, (i + 1) / 4f), tr, isliquid);

                            AddTriIndices(offset, 0, 1, 2);
                        }
                        else if (nextHeight < height)
                        {
                            int offset = ch.vertexMap.Count;

                            AddVertex(ch, 0, 0, uv[0] + new Vector2(tex_len * (i / 4f), (1-height)*tex_len), blockPos, new Vector3(1f, height, i / 4f), tr, isliquid);
                            AddVertex(ch, 0, 0, uv[0] + new Vector2(tex_len * (i / 4f), (1-nextHeight)*tex_len), blockPos, new Vector3(1f, nextHeight, i / 4f), tr, isliquid);
                            AddVertex(ch, 0, 0, uv[0] + new Vector2(tex_len * ((i + 1) / 4f), (1 - nextHeight) * tex_len), blockPos, new Vector3(1f, nextHeight, (i + 1) / 4f), tr, isliquid);

                            AddTriIndices(offset, 0, 1, 2);
                        }
                        // else: heights are equal; ignore

                        // create the base rectangle
                        AddVertex(ch, 0, 0, uv[0] + new Vector2(tex_len * (float)i / 4f + tex_len / 4f, (1 - min) * tex_len), blockPos, new Vector3(1, min, (float)(i + 1) / 4f), tr, isliquid);
                        AddVertex(ch, 0, 1, uv[0] + new Vector2(tex_len * (float)i/4f, (1 - min) * tex_len), blockPos, new Vector3(1, min, (float)i / 4f), tr, isliquid);
                        AddVertex(ch, 0, 2, uv[0] + new Vector2(tex_len * (float)i / 4f + tex_len / 4f, tex_len), blockPos, new Vector3(1, 0, (float)(i + 1) / 4f), tr, isliquid);
                        AddVertex(ch, 0, 3, uv[0] + new Vector2(tex_len * (float)i / 4f, tex_len), blockPos, new Vector3(1, 0, (float)i / 4f), tr, isliquid);

                        AddIndices(ch, 0, 1, 2, 2, 1, 3, isliquid);
                    }

Non sono sicuro che si tratti di un errore di precisione in virgola mobile, ma quando lo rendering, ottengo questi curiosi fori sui bordi dei rettangoli di base (so che sono buchi perché i loro colori corrispondono al colore dietro di loro)

Quello che mi butta davvero fuori è che piuttosto che un'intera linea, sono solo punti apparentemente casuali.

inserisci qui la descrizione dell'immagine

Una visione del mondo wireframe non ha rivelato alcuna discrepanza. (tutto ciò che ha fatto è stato ritardare il gioco) inserisci qui la descrizione dell'immagine

Un piccolo trucco che ho fatto è stato quello di estendere (i + 1) / 4 nel codice a (i + 1.01f) / 4, ma preferirei ottenere una soluzione concreta piuttosto che qualcosa del genere.

Forse è qualcosa nel mio shader? Il mio campionatore di texture è:

Texture TextureAtlas;
sampler TextureSampler = sampler_state
{
        texture = <TextureAtlas>;
    magfilter = POINT;
    minfilter = POINT;
    mipfilter = POINT;
    AddressU = WRAP;
    AddressV = WRAP;
};

Grazie in anticipo!

Risposte:


15

Dal tuo diagramma, sembra che la geometria che stai costruendo contenga giunzioni a T - luoghi in cui un vertice di un triangolo dovrebbe trovarsi esattamente sul bordo di un altro triangolo (risultando in un bordo che incontra un altro a forma di "T"). A causa dei limiti dell'aritmetica a precisione finita, di solito non è possibile garantire che il vertice soddisfi perfettamente il bordo e ci sono incrinature microscopiche tra loro, che spesso si presentano come anomalie a pixel singolo perché un singolo pixel può capitare di atterrare nella crepa mentre i suoi vicini no.

Per risolverlo, devi costruire la tua geometria in modo tale che non ci siano giunzioni a T, suddividendo ciascun bordo dove un vertice dovrebbe incontrarlo. Questo diagramma mostra un esempio:

inserisci qui la descrizione dell'immagine

EDIT: quanto sopra si applica alle giunzioni a T in generale. Per il tuo caso specifico, come ha sottolineato Ilmari Karonen nei commenti, puoi costruire la geometria ancora meglio in questo modo:

inserisci qui la descrizione dell'immagine

che evita anche le giunzioni a T e ha un numero complessivo inferiore di triangoli.


6
Un modo migliore per evitare le giunzioni a T sarebbe fare la triangolazione in questo modo . In questo modo, sono necessari solo due triangoli per segmento e nessun nuovo vertice interno. (Potresti farlo con ancora meno triangoli, se lo desideri; il minimo è uno più il numero di segmenti.)
Ilmari Karonen

@IlmariKaronen Grazie, mi sono preso la libertà di aggiungere il tuo diagramma alla risposta. :)
Nathan Reed,
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.