我想在片段着色器的网格上做光线跟踪。我已经写了下面的着色器来做到这一点(顶点着色器只是画一个screenquad)。这个GLSL着色器为什么这么慢?
#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),但是通过这些计算,它应该没有太大的区别! 如果我分裂,使增速不使用,但下面的代码为每个不同的部分进行编码,帧率保持不变。 如果我改变一些整数浮动,没有什么变化。
我以前做过更密集和/或复杂的着色器,所以这是为什么一个如此可怕慢?任何人都可以告诉我做了什么计算让它变得如此缓慢?
我没有设置未使用或类似的东西,在C-代码也什么都不做的不仅仅是呈现更多的制服。这是我以前成功使用过的代码。
有人吗?
条件语句是有过之而无不及垫子操作:他们拖延管道。 – Luca 2013-05-02 13:11:10
我明白了。我会试着想一个更好的方法。但是,为什么呢?条件为什么拖延管道?我不明白为什么着色器之外的任何东西需要等待其执行? – scippie 2013-05-02 13:44:53
采用了最短路径的其他着色器线程。 – Luca 2013-05-02 13:56:49