本日はコンピュートシェーダー枠です。
コンピュートシェーダーに関しては苦手意識があったため一つ一つ学んでいます。
現在はコンピュートシェーダーの概要を学びながらある条件の頂点座標数を抽出する処理を実装しています。
〇環境
・Windows11PC
・Unity6000.0.2f1
〇コンピュートシェーダーの処理
前回はコンピュートシェーダーの構造やカーネルについてみていきました。
今回は実際の処理の中身を追っていきます。
[numthreads(1, 1, 1)]
void CSMain(uint3 id : SV_DispatchThreadID)
{
// 面のインデックスを3つずつ取得
int index0 = indexBuffer[id.x * 3 + 0];
int index1 = indexBuffer[id.x * 3 + 1];
int index2 = indexBuffer[id.x * 3 + 2];
float3 v0 = vertexBuffer[index0].position;
float3 v1 = vertexBuffer[index1].position;
float3 v2 = vertexBuffer[index2].position;
// ローカル座標をワールド座標に変換
v0 = mul(localToWorldMatrix, float4(v0, 1.0)).xyz;
v1 = mul(localToWorldMatrix, float4(v1, 1.0)).xyz;
v2 = mul(localToWorldMatrix, float4(v2, 1.0)).xyz;
// Y座標が0以下の頂点が含まれるかチェック
if (v0.y <= 0 || v1.y <= 0 || v2.y <= 0)
{
// 面のカウンタをインクリメント
InterlockedAdd(countBuffer[0], 1);
}
}
コンピュートシェーダー内ではHLSLで記述されています。
3Dモデルの頂点はStructuredBuffer<int>を使用します。
3Dモデルの頂点と面(トライアングル)の情報は、コンピュートシェーダーに転送され、シェーダーで計算が行えるようにするために、ComputeBufferというデータ構造を使っています
これは構造を定義しC#を使用して実際のデータを受け渡しています。
// 面のインデックスを3つずつ取得
int index0 = indexBuffer[id.x * 3 + 0];
int index1 = indexBuffer[id.x * 3 + 1];
int index2 = indexBuffer[id.x * 3 + 2];
float3 v0 = vertexBuffer[index0].position;
float3 v1 = vertexBuffer[index1].position;
float3 v2 = vertexBuffer[index2].position;
上記では頂点を取得して座標を求めています。
次に座標返還を粉う必要があります。
これにはUnity側で提供されるlocalToWorldMatrixと頂点座標との計算によって行えます。
最後に座標を求めインクリメントしています。
// ローカル座標をワールド座標に変換
v0 = mul(localToWorldMatrix, float4(v0, 1.0)).xyz;
v1 = mul(localToWorldMatrix, float4(v1, 1.0)).xyz;
v2 = mul(localToWorldMatrix, float4(v2, 1.0)).xyz;
// Y座標が0以下の頂点が含まれるかチェック
if (v0.y <= 0 || v1.y <= 0 || v2.y <= 0)
{
// 面のカウンタをインクリメント
InterlockedAdd(countBuffer[0], 1);
}
本日は以上です。
次回C#の処理を実装していきます。