Curious Transparent Holes Render Artifact


8

J'essaie donc d'implémenter un terrain "lisse" dans mon moteur de blocs en donnant à chaque bloc de surface une hauteur.

Fondamentalement, ce que je fais pour générer ces "cartes de hauteur" pour chaque bloc, c'est que je génère les hauteurs à des intervalles de 0,25 le long du bord du bloc. Ensuite, pour construire les sommets du bloc, je boucle à travers les hauteurs et crée des triangles de hauteur en hauteur et place des rectangles sous les triangles pour créer quelque chose comme ceci: entrez la description de l'image ici

Par exemple, pour construire le côté positif X d'un bloc, je fais:

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

Je ne sais pas s'il s'agit d'une erreur de précision en virgule flottante, mais lorsque je la rends, j'obtiens ces curieux trous sur les bordures des rectangles de base (je sais que ce sont des trous parce que leurs couleurs correspondent à la couleur derrière elles)

Ce qui me dérange vraiment, c'est que plutôt que d'une ligne entière, ce sont juste des points apparemment aléatoires.

entrez la description de l'image ici

Une vision filaire du monde n'a révélé aucun écart. (il n'a fait que retarder le jeu) entrez la description de l'image ici

Un petit hack rapide que j'ai fait a été d'étendre le (i + 1) / 4 dans le code à (i + 1.01f) / 4, mais je préfère obtenir une solution concrète que quelque chose comme ça.

C'est peut-être quelque chose dans mon shader? Mon échantillonneur de texture est:

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

Merci d'avance!

Réponses:


15

D'après votre diagramme, il semble que la géométrie que vous construisez contient des jonctions en T - des endroits où un sommet d'un triangle est censé se trouver exactement sur le bord d'un autre triangle (ce qui fait qu'un bord rencontre un autre en forme de «T»). En raison des limites de l'arithmétique de précision finie, le sommet ne peut généralement pas être garanti de rencontrer le bord parfaitement et vous trouverez des fissures microscopiques entre eux, qui apparaissent souvent comme des défauts d'un pixel car un pixel individuel peut arriver à atterrir dans la fissure tandis que ses voisins ne le font pas.

Pour le réparer, vous devez construire votre géométrie de manière à ce qu'il n'y ait pas de jonctions en T, en divisant chaque arête où un sommet est censé le rencontrer. Ce diagramme montre un exemple:

entrez la description de l'image ici

EDIT: Ce qui précède s'applique aux jonctions en T en général. Pour votre cas spécifique, comme Ilmari Karonen l'a souligné dans les commentaires, vous pouvez encore mieux construire la géométrie comme ceci:

entrez la description de l'image ici

ce qui évite également les jonctions en T et a moins de triangles dans l'ensemble.


6
Une meilleure façon d'éviter les jonctions en T serait de faire la triangulation comme ceci . De cette façon, vous n'avez besoin que de deux triangles par segment et pas de nouveaux sommets intérieurs. (Vous pouvez le faire avec encore moins de triangles, si vous le souhaitez; le minimum est un plus le nombre de segments.)
Ilmari Karonen

@IlmariKaronen Merci, j'ai pris la liberté d'ajouter votre diagramme à la réponse. :)
Nathan Reed
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.