1

詳細:

私は手続き型惑星生成の過程にいます。これまで動的LOD作業を行ってきましたが、現在のソフトウェアアルゴリズムは非常に低速です。代わりに、DX11の新しいテッセレーション機能を使用してそれを行うことにしました。現在、私の球は細分化された二十面体です。(20辺すべての正三角形)

ソフトウェアアルゴリズムを使用して細分化していたとき、1つの三角形が親の中点で4つの子に分割され、毎回Hyruleシンボルを形成していました...次のようになります:http://puu.sh/1xFIx

ご覧のとおり、細分化された各三角形は、ますます多くの正三角形を作成しました。つまり、それぞれがまったく同じ形状でした。

しかし、GPUを使用してHLSLでテッセレーションを行っているので、結果は間違いなく私が探しているものではありません:http: //puu.sh/1xFx7

質問:

ハルシェーダーとドメインシェーダーで、最初の画像のように正三角形のセットに分割されるようにテッセレーションを変更するためにできることはありますか?

このようなものにジオメトリシェーダーを使用する必要がありますか?もしそうなら、それはテッセレータよりも遅いでしょうか?

4

1 に答える 1

0

テッセレーションシェーダーを使用してみましたが、問題が発生しました。頂点のドメイン位置が0.3、0.3、0.3(中心頂点)の場合、ドメインシェーダーはUV座標(SV_DomainLocation)と頂点を配置するための入力パッチのみを渡します。ドメインシェーダーステージによって提供されない他の頂点または反復のインデックス(x、y)に関する情報が必要なため、正しい位置を知るため。

この問題はジオメトリシェーダーでコードを記述しているため、出力ストリームのサイズを1024バイトより大きくすることはできないため(シェーダーモデル5.0)、このシェーダーはテッセレーションに対して非常に制限されています。uv(SV_DomainLocationなど)を使用して頂点位置の計算を実装しましたが、これは三角形をテッセレーションするだけです。正確な最終結果を作成するには、コードの一部を使用して三角形の中心に追加された位置を計算する必要があります。

これは、正三角形のテッセレーションのコードです。

// required for array
#define MAX_ITERATIONS 5

void DrawTriangle(float4 p0, float4 p1, float4 p2, inout TriangleStream<VS_OUT> stream)
{
    VS_OUT v0;
    v0.pos = p0;
    stream.Append(v0);

    VS_OUT v1;
    v1.pos = p1;
    stream.Append(v1);

    VS_OUT v2;
    v2.pos = p2;
    stream.Append(v2);

    stream.RestartStrip();
}

[maxvertexcount(128)] // directx rule: maxvertexcount * sizeof(VS_OUT) <= 1024
void gs(triangle VS_OUT input[3], inout TriangleStream<VS_OUT> stream)
{
    int itc = min(tess, MAX_ITERATIONS);
    float fitc = itc;
    float4 past_pos[MAX_ITERATIONS];
    float4 array_pass[MAX_ITERATIONS];
    for (int pi = 0; pi < MAX_ITERATIONS; pi++)
    {
        past_pos[pi] = float4(0, 0, 0, 0);
        array_pass[pi] = float4(0, 0, 0, 0);
    }
    // -------------------------------------
    // Tessellation kernel for the control points
    for (int x = 0; x <= itc; x++)
    {
        float4 last;
        for (int y = 0; y <= x; y++)
        {
            float2 seg = float2(x / fitc, y / fitc);
            float3 uv;
            uv.x = 1 - seg.x;
            uv.z = seg.y;
            uv.y = 1 - (uv.x + uv.z);

            // ---------------------------------------
            // Domain Stage
            // uv           Domain Location
            // x,y          IterationIndex

            float4 fpos = input[0].pos * uv.x;
            fpos += input[1].pos * uv.y;
            fpos += input[2].pos * uv.z;

            if (x > 0 && y > 0)
            {
                DrawTriangle(past_pos[y - 1], last, fpos, stream);
                if (y < x)
                {
                    // add adjacent triangle
                    DrawTriangle(past_pos[y - 1], fpos, past_pos[y], stream);
                }
            }
            array_pass[y] = fpos;
            last = fpos;
        }
        for (int i = 0; i < MAX_ITERATIONS; i++)
        {
            past_pos[i] = array_pass[i];
        }
    }
}
于 2013-01-05T00:38:24.133 に答える