奇妙な透明な穴がアーティファクトをレンダリングする


8

したがって、各サーフェスブロックにハイトマップを与えることにより、ブロックエンジンに「滑らかな」地形を実装しようとしています。

基本的に、各ブロックのこれらの「高さマップ」を生成するために私が行うことは、ブロックの端に沿って0.25の間隔で高さを生成することです。次に、ブロックの頂点を構築するために、高さをループして高さから高さに三角形を作成し、三角形の下に長方形を配置して次のようなものを作成します。 ここに画像の説明を入力してください

たとえば、ブロックのXの正側を作成するには、次のようにします。

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

これが浮動小数点の精度エラーかどうかはわかりませんが、レンダリングすると、基本の長方形の境界にこれらの奇妙な穴ができます(それらの色が背後の色と一致しているため、穴であることがわかります)

本当に私を驚かせているのは、行全体ではなく、一見ランダムなドットにすぎないということです。

ここに画像の説明を入力してください

世界をワイヤーフレームで表示しても差異はありませんでした。(それがしたすべてはゲームの遅れを作ることでした) ここに画像の説明を入力してください

コードで(i + 1)/ 4を(i + 1.01f)/ 4に拡張するのが簡単な小さなハックでしたが、私はそのようなものより具体的な解決策を得たいと思います。

多分それは私のシェーダーの何かですか?私のテクスチャサンプラーは:

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

前もって感謝します!

回答:


15

ダイアグラムから、作成しているジオメトリにはTジャンクションが含まれているように見えます。これは、1つの三角形の頂点が別の三角形のエッジに正確に位置するはずの場所です(その結果、1つのエッジが別の三角形の「T」字形に出会います)。有限精度演算の制限により、頂点は通常、エッジに完全に一致することが保証されず、それらの間に微視的な亀裂が見つかります。これは、個々のピクセルが亀裂に着地することがあるので、しばしば単一ピクセルのグリッチとして表示されます。その隣人はしませんが。

これを修正するには、頂点が交わるはずの各エッジを分割することにより、T字接合がないようにジオメトリを構築する必要があります。この図は例を示しています:

ここに画像の説明を入力してください

編集:上記は、T字型ジャンクション一般に適用されます。特定のケースでは、Ilmari Karonenがコメントで指摘しているように、次のようにジオメトリをさらによく構築できます。

ここに画像の説明を入力してください

Tジャンクションも回避され、全体的に三角形が少なくなります。


6
T字接続を回避するより良い方法は、このような三角形分割を行うことです。この方法では、セグメントごとに2つの三角形が必要で、新しい内部頂点は必要ありません。(必要に応じて、さらに少ない三角形でそれを行うこともできます。最小値は、セグメントの数に1を加えたものです。)
Ilmari Karonen 2013年

@IlmariKaronenおかげで、私はあなたの図を答えに自由に追加できました。:)
Nathan Reed
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.