なつねこメモ

主にプログラミング関連のメモ帳 ♪(✿╹ヮ╹)ノ 書いてあるコードは自己責任でご自由にどうぞ。記事本文の無断転載は禁止です。

ドメインシェーダーで一意な ID を頂点に割り振りたい

そんなことをする必要があるかどうかはさておき、やりたくなったのでメモしておきます。


前提環境は以下の通り :

  • Unity 2018.4.20f1 Personal
  • DirectX 11+
  • 板ポリ (Quad) を分割する

Vertex Shader は頂点をそのまま渡すだけのものを、 Hull Shader は下のような感じ。

// #define TESSELLATION 16

h2d_const hs_const()
{
    h2d_const o = (h2d_const) 0;
    const float tess = TESSELLATION;
    o.edges[0]  = tess;
    o.edges[1]  = tess;
    o.edges[2]  = tess;
    o.edges[3]  = tess;
    o.inside[0] = tess;
    o.inside[1] = tess;

    return o;
}

[domain("quad")]
[partitioning("pow2")]
[outputtopology("point")]
[outputcontrolpoints(4)]
[patchconstantfunc("hs_const")]
h2d hs(const InputPatch<v2h, 4> input, const uint id : SV_OUTPUTCONTROLPOINTID)
{
    h2d o = (h2d) 0;
    o.position = input[id].position.xyz;

    return o;
}

この状態で、 Domain Shader で一意な ID を割り振っていきたい。
ただ、参考にした Qiita 記事の割り振り方だと、 ID の重複がいくつか見られました。

f:id:MikazukiFuyuno:20200523180704p:plain:w350

ID: 15 までの描画

f:id:MikazukiFuyuno:20200523180732p:plain:w350

ID: 16 までの描画、見ての通り若干描画されている数が多い

そこで、改良したのがこちらです。

[domain("quad")]
d2g ds(const h2d_const data, const OutputPatch<h2d, 4> i, const float2 uv : SV_DOMAINLOCATION)
{
    d2g o = (d2g) 0;

    // position 計算はなくても良いよ!
    const float3 x = lerp(i[0].position, i[1].position, uv.x);
    const float3 y = lerp(i[3].position, i[2].position, uv.x);
    const float3 z = lerp(x, y, uv.y);

    o.position = float4(z, 1.0f);
    o.id = (uint) (uv.x * TESSELLATION) + ((uint) ((uv.y * TESSELLATION) * TESSELLATION)) + (uint) (uv.y * TESSELLATION);

    return o;
}

全ての値を Geometry Shader から出力して、 Analyzer でダンプした感じだと、
ID: 0 から連番で出力されていました。

ということで、 ID の生成方法でした。