【发布时间】:2013-04-26 14:33:15
【问题描述】:
我正在尝试在片段着色器中的网格上进行光线追踪。我已经编写了下面的着色器来执行此操作(顶点着色器只绘制一个屏幕四边形)。
#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 代码也只是渲染而已。这是我之前成功使用过 100 次的代码。
有人吗?
【问题讨论】:
-
条件比 mat 操作更糟糕:它们使管道停滞。
-
我明白了。我会试着想一个更好的方法。但是,这是为什么呢?为什么条件会停止管道?我不明白为什么着色器之外的任何东西都需要等待它的执行?
-
走最短路径的其他着色器线程。
-
是的,我刚刚阅读了这个主题:stackoverflow.com/questions/4176247/shader-branching-question,它准确地解释了你所说的。谢谢。树枝必须走! :)
-
所以如果我理解正确的话,这个从 0 到 64 的循环也可能会使其他只循环到 2 的线程也停止?神圣.......我不知道,我写了很多很棒的着色器。
标签: performance glsl shader raytracing