ジオメトリシェーダでライン描画

DirectXには一応、線を描画する機能がある。
プリミティブ型にラインリストやラインストリップを指定すれば、頂点バッファの頂点を線として描画してくれる。

ただし、その線には太さという概念がない。線を描くならできればそれなりの太さが欲しい。

太さのもった線を描画するのには、やはり三角形を使って描画するしかないのだが、ここでジオメトリシェーダが役に立つ。

グラフィックパイプラインにおけるジオメトリステージとは、頂点シェーダのあと、ピクセルシェーダの前に走るシェーダステージのことだ。

頂点シェーダが頂点ごと、ピクセルシェーダがラスタライズ後のピクセルごとに処理が走るのに対し、ジオメトリシェーダは「プリミティブ単位」で処理が走る。つまり、プリミティブ型に三角形を指定していれば、ジオメトリシェーダの入力は3頂点というわけだ。そして、ジオメトリシェーダは複数のプリミティブを出力することができる。

このジオメトリシェーダは今回のようなケースで非常に役に立つ。
「ラインリスト」のプリミティブを受け取り、「三角形リスト」を出力する、という処理を書くことができる。線を受け取り、それを三角形二つで構成された四角形を出力するジオメトリシェーダを作れば、太さのある線を描くことができる。

struct VSOutput
{
    float4 pos : SV_POSITION;
    float4 col : COLOR;
    float thickness : THICKNESS;
};

struct GSOutput
{
	float4 pos : SV_POSITION;
    float4 col : COLOR;
};

[maxvertexcount(6)]
void main(
	line VSOutput input[2],
	inout TriangleStream< GSOutput > output
)
{
	for (int i = 0; i < 2; i++)
	{
        float offset = input[i].thickness / 2.0f;

        {
            GSOutput element;
            element.pos = input[i].pos + float4(offset, 0.0f, 0.0f, 0.0f);
            element.col = input[i].col;
            output.Append(element);
        }
        {
            GSOutput element;
            element.pos = input[i].pos + float4(-offset, 0.0f, 0.0f, 0.0f);
            element.col = input[i].col;
            output.Append(element);
        }
        {
            GSOutput element;
            element.pos = input[(i + 1) % 2].pos + float4(offset * sign(i - 1), 0.0f, 0.0f, 0.0f);

            element.col = input[(i + 1) % 2].col;
            output.Append(element);
        }

        output.RestartStrip();
	}
}


今回は頂点情報に線の太さ情報を追加した。これはコンスタントバッファーで与えてもいいだろう。

さて、これを使って現在はレイトレース及びそのビジュアライザを実装している。
レイの挙動を視覚的に確認することができるので、デバッグに大いに役立っている。


f:id:riyaaaaasan:20180406235024p:plain



近いウチにレイトレースのブログ記事も投稿する予定だ。