フラグメント シェーダーのグリッドでレイトレースを実行しようとしています。これを行うために、以下のシェーダーを作成しました (頂点シェーダーはスクリーンクワッドを描画するだけです)。
#version 150
uniform mat4 mInvProj, mInvRot;
uniform vec4 vCamPos;
varying vec4 vPosition;
int test(vec3 p)
{
if (p.x > -4.0 && p.x < 4.0
&& p.y > -4.0 && p.y < 4.0
&& ((p.z < -4.0 && p.z > -8.0) || (p.z > 4.0 && p.z < 8.0)))
return 1;
return 0;
}
void main(void) {
vec4 cOut = vec4(0, 0, 0, 0);
vec4 vWorldSpace = mInvRot * mInvProj * vPosition;
vec3 vRayOrg = vCamPos.xyz;
vec3 vRayDir = normalize(vWorldSpace.xyz);
// http://en.wikipedia.org/wiki/Xiaolin_Wu%27s_line_algorithm
vec3 adelta = abs(vRayDir);
int increaser;
vec3 gradient, sgradient;
if (adelta.x > adelta.y && adelta.x > adelta.z)
{
increaser = 0;
gradient = vec3(vRayDir.x > 0.0? 1.0: -1.0, vRayDir.y / vRayDir.x, vRayDir.z / vRayDir.x);
sgradient = vec3(0.0, gradient.y > 0.0? 1.0: -1.0, gradient.z > 0.0? 1.0: -1.0);
}
else if (adelta.y > adelta.x && adelta.y > adelta.z)
{
increaser = 1;
gradient = vec3(vRayDir.x / vRayDir.y, vRayDir.y > 0.0? 1.0: -1.0, vRayDir.z / vRayDir.y);
sgradient = vec3(gradient.x > 0.0? 1.0: -1.0, 0.0, gradient.z > 0.0? 1.0: -1.0);
}
else
{
increaser = 2;
gradient = vec3(vRayDir.x / vRayDir.z, vRayDir.y / vRayDir.z, vRayDir.z > 0.0? 1.0: -1.0);
sgradient = vec3(gradient.x > 0.0? 1.0: -1.0, gradient.y > 0.0? 1.0: -1.0, 0.0);
}
vec3 walk = vRayOrg;
for (int i = 0; i < 64; ++i)
{
vec3 fwalk = floor(walk);
if (test(fwalk) > 0)
{
vec3 c = abs(fwalk) / 4.0;
cOut = vec4(c, 1.0);
break;
}
vec3 nextwalk = walk + gradient;
vec3 fnextwalk = floor(nextwalk);
bool xChanged = fnextwalk.x != fwalk.x;
bool yChanged = fnextwalk.y != fwalk.y;
bool zChanged = fnextwalk.z != fwalk.z;
if (increaser == 0)
{
if ((yChanged && test(fwalk + vec3(0.0, sgradient.y, 0.0)) > 0)
|| (zChanged && test(fwalk + vec3(0.0, 0.0, sgradient.z)) > 0)
|| (yChanged && zChanged && test(fwalk + vec3(0.0, sgradient.y, sgradient.z)) > 0))
{
vec3 c = abs(fwalk) / 4.0;
cOut = vec4(c, 1.0);
break;
}
}
else if (increaser == 1)
{
if ((xChanged && test(fwalk + vec3(sgradient.x, 0.0, 0.0)) > 0)
|| (zChanged && test(fwalk + vec3(0.0, 0.0, sgradient.z)) > 0)
|| (xChanged && zChanged && test(fwalk + vec3(sgradient.x, 0.0, sgradient.z)) > 0))
{
vec3 c = abs(fwalk) / 4.0;
cOut = vec4(c, 1.0);
break;
}
}
else
{
if ((xChanged && test(fwalk + vec3(sgradient.x, 0.0, 0.0)) > 0)
|| (yChanged && test(fwalk + vec3(0.0, sgradient.y, 0.0)) > 0)
|| (xChanged && yChanged && test(fwalk + vec3(sgradient.x, sgradient.y, 0.0)) > 0))
{
vec3 c = abs(fwalk) / 4.0;
cOut = vec4(c, 1.0);
break;
}
}
walk = nextwalk;
}
gl_FragColor = cOut;
}
ハードコーディングされた近いグリッド アイテムを見ている限り、フレームレートは許容できるように見えます (Geforce 680M で 400+fps) (これまでに書いた他のシェーダーと比較すると予想よりも低いですが)。空の場合 (ループは 64 まで続く)、フレームレートはひどいものです (40fps)。グリッドを非常に近くで見ると、すべてのピクセルが同じ閉じたグリッド アイテムになってしまうため、約 1200 fps になります。
すべてのピクセルに対してこのループを実行するのはある程度の作業であることは理解していますが、特にテクスチャルックアップを削除して簡単なテストを使用しただけなので、簡単な基本的な計算であるため、なぜこれが必要なのかわかりませんすべてを非常に遅くします。私の GPU には 16 コアがあり、700+Mhz で動作します。960x540、518400 ピクセルでレンダリングしています。これは、私が考えるよりもはるかに多くを処理できるはずです。
上記のアンチエイリアシング部分 (増加値に基づいていくつかの余分な隣接ポイントをテストするコードの部分) を削除すると、少し良くなります (100fps) が、これらの計算ではそうではありません。大きな違いを生む!コードを分割して増量剤を使用しないようにしますが、以下のコードを異なる部分ごとに実行すると、フレームレートは変わりません。一部の int を float に変更しても、何も変わりません。
以前にもっと集中的で複雑なシェーダーを行ったことがありますが、なぜこれは非常に遅いのですか? 私が行う計算が非常に遅くなる理由を誰か教えてもらえますか?
使用されていないユニフォームなどを設定しているわけではありません。C コードもレンダリング以外のことは何もしていません。これは、私が何百回も前に使用したコードです。
誰?