Unity ComputeShaderでSV_GroupIndexを利用したい(ができない)
解決したいこと
Unityで独自データに対するレイチェックを実装しています。コンピュートシェーダーでDispatch(カーネル,1,1,1)の1グループだけで動作するコードが期待通り動いたので、複数グループを想定した実装を始めたのですが、SV_GroupIndexを使ってインデックスを作成するとコンパイルエラーになります。どうか解決策を教えてください。
実現したい内容
- 独自データの四角形の配列全てに対し、16*16でテッセレーションをして格子点の配列を作る
- 1で作成された(四角形の数)*256 の格子点配列をシェーダーに渡す(tessedPos)
- Dispatch(四角形の数,1,1)で四角形の数だけグループを作成し、(グループインデックス)*256をオフセットとして使用し四角形のレイチェックをする
発生している問題・エラー
コメントアウトされている一文以外は、1グループだけで動作する実装の状態です。
この一文を追加しても、1グループだけで実行すれば増分は0であるはずなので、問題は起こらないと思います。
しかしコメントアウトを解除すると、コンパイルエラーが発生します。エラーメッセージはコンパイルが途中で停止したこと、エラーをUnityに報告しろということが書いてあるだけでした。(report済み)
#pragma kernel TessedQuadRayLength
#include "MollerTrumboreRayCheck.hlsl"
float3 rayOrigin;
float3 rayDirection;
RWStructuredBuffer<float> IntersectLength;
half3 tessedPos[64000];
[numthreads(15, 15, 1)]
void TessedQuadRayLength(uint3 threadID : SV_GroupThreadID, uint3 quadID : SV_GroupID)
{
uint tessid = threadID.x + 16 * threadID.y;
//tessid += quadID.x * 256;
float3 LD = tessedPos[tessid];
float3 LU = tessedPos[tessid + 16];
float3 RD = tessedPos[tessid + 1];
float3 RU = tessedPos[tessid + 17];
uint resultIndex = threadID.x + threadID.y * 15;
IntersectLength[resultIndex] = 9999;
float lengthA = IntersectRayLengthFB(rayOrigin, rayDirection, RD, LD, LU);
if (0 < lengthA)
{
IntersectLength[resultIndex] = lengthA;
return;
}
float lengthB = IntersectRayLengthFB(rayOrigin, rayDirection, LU, RU, RD);
if (0 < lengthB)
{
IntersectLength[resultIndex] = lengthB;
}
}
再現方法
空プロジェクト(Unity2022.3.2f1) でも、関係する2ファイルをアセットに入れてから、プレイボタンを押すなどしてシェーダーコンパイルを走らせるとエラーが発生しました。
RayCheckTessedQuad.compute
#pragma kernel TessedQuadRayLength
#include "MollerTrumboreRayCheck.hlsl"
float3 rayOrigin;
float3 rayDirection;
RWStructuredBuffer<float> IntersectLength;
half3 tessedPos[64000];
[numthreads(15, 15, 1)]
void TessedQuadRayLength(uint3 threadID : SV_GroupThreadID, uint3 quadID : SV_GroupID)
{
uint tessid = threadID.x + 16 * threadID.y;
//tessid += quadID.x * 256;
float3 LD = tessedPos[tessid];
float3 LU = tessedPos[tessid + 16];
float3 RD = tessedPos[tessid + 1];
float3 RU = tessedPos[tessid + 17];
uint resultIndex = threadID.x + threadID.y * 15;
IntersectLength[resultIndex] = 9999;
float lengthA = IntersectRayLengthFB(rayOrigin, rayDirection, RD, LD, LU);
if (0 < lengthA)
{
IntersectLength[resultIndex] = lengthA;
return;
}
float lengthB = IntersectRayLengthFB(rayOrigin, rayDirection, LU, RU, RD);
if (0 < lengthB)
{
IntersectLength[resultIndex] = lengthB;
}
}
MollerTrumboreRayCheck.hlsl
#define RayCheckEPSILON 0.0001
#define BaseProcess \
half3 edge1, edge2, h, s, q;\
half a, f, u, v;\
half resultFlag = 1.0;\
edge1 = vertex1 - vertex0;\
edge2 = vertex2 - vertex0;\
h = cross(rayDirection, edge2);\
a = dot(edge1, h);\
if(-RayCheckEPSILON < a && a < RayCheckEPSILON)return 0;\
f = 1.0 / a; \
s = rayOrigin - vertex0;\
u = f * dot(s, h); \
resultFlag *= (u < 0.0 || 1.0 < u) ? 0.0 : 1.0; \
q = cross(s, edge1); \
v = f * dot(rayDirection, q); \
resultFlag *= (v < 0.0 || 1.0 < u + v) ? 0.0 : 1.0; \
half length = f * dot(edge2, q) * resultFlag;
half IntersectRayLengthFB(half3 rayOrigin, half3 rayDirection, half3 vertex0, half3 vertex1, half3 vertex2)
{
BaseProcess
return length;
}
half IntersectRayLengthF(half3 rayOrigin, half3 rayDirection, half3 vertex0, half3 vertex1, half3 vertex2)
{
BaseProcess
half frontFlag = step(-RayCheckEPSILON, a);
return length * frontFlag;
}
half IntersectRayLengthB(half3 rayOrigin, half3 rayDirection, half3 vertex0, half3 vertex1, half3 vertex2)
{
BaseProcess
half backFlag = step(a, RayCheckEPSILON);
return length * backFlag;
}
0