Neugierige transparente Löcher machen Artefakt


8

Ich versuche also, "glattes" Gelände in meine Block-Engine zu implementieren, indem ich jedem Oberflächenblock eine Höhenkarte gebe.

Grundsätzlich generiere ich diese "Höhenkarten" für jeden Block, indem ich die Höhen in Intervallen von 0,25 entlang der Blockkante generiere. Um dann die Eckpunkte des Blocks zu bilden, durchlaufe ich die Höhen und erstelle Dreiecke von Höhe zu Höhe und lege Rechtecke unter die Dreiecke, um so etwas zu erstellen: Geben Sie hier die Bildbeschreibung ein

Um beispielsweise die X-positive Seite eines Blocks zu erstellen, gehe ich wie folgt vor:

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

Ich bin nicht sicher, ob dies ein Gleitkommapräzisionsfehler ist, aber wenn ich ihn rendere, erhalte ich diese merkwürdigen Löcher an den Rändern der Basisrechtecke (ich weiß, dass sie Löcher sind, weil ihre Farben mit der Farbe dahinter übereinstimmen).

Was mich wirklich abschreckt, ist, dass es sich nicht um eine ganze Zeile, sondern nur um scheinbar zufällige Punkte handelt.

Geben Sie hier die Bildbeschreibung ein

Eine Drahtgitteransicht der Welt ergab keine Unstimmigkeiten. (Alles was es getan hat war das Spiel zu verzögern) Geben Sie hier die Bildbeschreibung ein

Ein kurzer kleiner Hack, den ich gemacht habe, war, das (i + 1) / 4 im Code auf (i + 1.01f) / 4 zu erweitern, aber ich würde lieber eine konkrete Lösung als so etwas bekommen.

Vielleicht ist es etwas in meinem Shader? Mein Textur-Sampler ist:

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

Danke im Voraus!

Antworten:


15

Aus Ihrem Diagramm geht hervor, dass die von Ihnen konstruierte Geometrie T-Übergänge enthält - Stellen, an denen ein Scheitelpunkt eines Dreiecks genau auf der Kante eines anderen Dreiecks liegen soll (was dazu führt, dass eine Kante in einer "T" -Form auf eine andere trifft). Aufgrund der Einschränkungen der Arithmetik mit endlicher Genauigkeit kann normalerweise nicht garantiert werden, dass der Scheitelpunkt die Kante perfekt trifft, und Sie finden mikroskopische Risse zwischen ihnen, die häufig als Einzelpixelstörungen auftreten, da ein einzelnes Pixel im Riss landen kann während seine Nachbarn nicht.

Um dies zu beheben, müssen Sie Ihre Geometrie so erstellen, dass keine T-Übergänge vorhanden sind, indem Sie jede Kante dort teilen, wo ein Scheitelpunkt darauf treffen soll. Dieses Diagramm zeigt ein Beispiel:

Geben Sie hier die Bildbeschreibung ein

EDIT: Das obige gilt für T-Übergänge im Allgemeinen. Für Ihren speziellen Fall können Sie, wie Ilmari Karonen in den Kommentaren hervorhob, die Geometrie noch besser wie folgt erstellen:

Geben Sie hier die Bildbeschreibung ein

Dies vermeidet auch T-Übergänge und hat insgesamt weniger Dreiecke.


6
Ein besserer Weg, um T-Übergänge zu vermeiden, wäre die Triangulation wie folgt . Auf diese Weise benötigen Sie nur zwei Dreiecke pro Segment und keine neuen inneren Eckpunkte. (Sie könnten es mit noch weniger Dreiecken tun, wenn Sie wollten; das Minimum ist eins plus die Anzahl der Segmente.)
Ilmari Karonen

@IlmariKaronen Danke, ich habe mir erlaubt, Ihr Diagramm zur Antwort hinzuzufügen. :)
Nathan Reed
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.