夜風のMixedReality

xRと出会って変わった人生と出会った技術を書き残すためのGeekなHoloRangerの居場所

MRTK HandTrianglesShaderの中身を読み解く その⑬ ジオメトリシェーダーの書き出し

本日も土曜日なので毎週時間をかけて一つ一つ読み解いているMRTK HandTrianglesShaderのジオメトリーシェーダーの中身を読み解いています。

〇ジオメトリシェーダーの終わり、出力

  int vxix=0;
        int strip=0;
        [unroll]
        while (strip<stripCount) {
            int i=0;
            [unroll]
            while (i<stripVxCount[strip]) {
                //UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(vxOut[vxix]);
                UNITY_TRANSFER_VERTEX_OUTPUT_STEREO(vxIn[0],vxOut[vxix]);

                triStream.Append(vxOut[vxix]);
                i+=1; vxix+=1;
            }
            triStream.RestartStrip();
            strip+=1;
        }

ここではwhile文で繰り返し処理されています。While文はif文同様()の中が真であれば実行されます。処理の終わりでまた()ないが評価され真であれば繰り返し処理が行われます。

ここではstripは0が代入されているのでstripcountが0より小さい場合ループが終了します。

〇unroll

unrollアトリビュートは条件式に基づき一連の宣言を反復的に実行する場合の属性です。これはプログラムを高速化する技法のひとつで単純な処理を繰り返し展開(アンロール)して行うことでループ処理の回数を減らしています。(要は高速化)

docs.microsoft.com

 while (i<stripVxCount[strip]) {
                //UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(vxOut[vxix]);
                UNITY_TRANSFER_VERTEX_OUTPUT_STEREO(vxIn[0],vxOut[vxix]);

                triStream.Append(vxOut[vxix]);
                i+=1; vxix+=1;
            }

iは最初のループでは0が代入されます。

このループは一回処理されるごとにi、vxixにそれぞれ1が加算されStripVxCount[strip]以上になった時ループが終了します。

ジオメトリシェーダーは頂点シェーダーからいくつかの頂点を受け取り、メッシュとして扱います。

ここではメッシュに変換する処理を行っています。

//UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(vxOut[vxix]);
UNITY_TRANSFER_VERTEX_OUTPUT_STEREO(vxIn[0],vxOut[vxix]);

HoloLensでの描画のインスタンス ID と右、左の両目のインデックスをフラグメントシェーダに渡します。

これにより、フラグメントシェーダ内のインスタンスプロパティにアクセスできるだけでなく、必要に応じて右目、左目ごとに独自の作業を行うことができます。

                triStream.Append(vxOut[vxix]);
                i+=1; vxix+=1;

triStream.Append(vxOut[vxix])はvxOut[vxix]の変数を基にメッシュを作成する関数です。

triStreamは処理したものをフラグメントシェーダーに渡すときに用いるものです。triStream.Appendで引数として指定した値を出力します。

ここでvxixははじめ0をとります。つまりはじめ配列0番目のvxOutがtriStreamに出力されます。

iとvxixにそれぞれ1が加算され次は配列1番目のvxOutがtriStreamに出力されます。これがiがStripVxCount[strip]以上になるまで繰り返し処理されます。

616行目で

 stripVxCount[0]=0;

と配列0番目(最初)のstripVxCountは0が代入されるので最初の処理は一度目で(i<stripVxCount)を満たし終了します。

 triStream.RestartStrip();
strip+=1;

triStream.TestartStrip()はtriStream.append()で出力される要素を区切るために使用される処理です。

例えば

triStream.Append(a);
triStream.Append(b);
triStream.Append(c);
triStream.TestartStrip();

triStream.Append(d);
triStream.Append(e);
triStream.Append(f);
triStream.TestartStrip();

という例では6つの頂点から2つのポリゴンとして出力されます。

triStream.TestartStrip();

によって区切ってstrip+=1;でstripに1を加算しています。

615行目で

        stripCount=0;

stripCountは0が代入されていますがその後に処理されるEmit_Triangle_B177関数の248行目で

       stripCount+=1;

stripCountに1が加算されています。

strip<stripCountの条件が満たされるまで同じ処理が行われます。

こうしてtriStream.Append()で出力されtriStream.append()で区切られたデータがフラグメントシェーダーで扱われます。

以上がジオメトリシェーダーの処理になります。