Я пытаюсь сделать raytrace на сетке в фрагментарный шейдер. Я написал шейдер ниже, чтобы сделать это (вершинный шейдер просто рисует экранное изображение).Почему этот шейдер 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;
}
Пока я смотрю на близких элементов сетки, в закодированных те, фреймрейт выглядит приемлемым (400 + кадров в секунду на Geforce 680M) (хотя и ниже, чем я ожидал бы по сравнению с другими шейдерами я написал так далеко), но когда я смотрю на пустоту (так что цикл доходит до 64), частота кадров ужасная (40 кадров в секунду). Я получаю около 1200 кадров в секунду, когда смотрю так близко к сетке, что каждый пиксель попадает в один и тот же элемент сетки.
Хотя я понимаю, что выполнение этой петли для каждого пикселя - это какая-то работа, это все еще простая математическая математика, особенно теперь, когда я удалил поиск текстуры и просто использовал простой тест, поэтому я не понимаю почему это так сильно тормозит. Мой GPU имеет 16 ядер и работает на скорости 700 + МГц. Я рендеринга на 960x540, 518400 пикселей. Он должен уметь обрабатывать гораздо больше, чем я думал.
Если я удаляю часть сглаживания вышеуказанного (часть кода, где я буду проверять некоторые дополнительные смежные точки на основе значения возрастания), она немного лучше (100 кадров в секунду), но при этом, используя эти вычисления, это не должно иметь большого значения! Если я разделяю код так, чтобы приращение не использовалось, но приведенный ниже код выполняется для каждой другой части, частота кадров остается прежней. Если я изменю некоторые ints на float, ничего не изменится.
Я делал гораздо более интенсивные и/или сложные шейдеры раньше, так почему же это так ужасно медленно? Может ли кто-нибудь сказать, какой расчет я делаю, делает это так медленно?
Я не устанавливаю униформы, которые не используются, или что-то в этом роде, C-код также делает не что иное, как просто рендеринг. Это код, который я использовал успешно 100 раз.
Кто-нибудь?
Conditionals хуже маты: они останавливают трубопровод. – Luca
Я вижу. Я попытаюсь придумать лучший метод. Но почему? Почему условности останавливают трубопровод? Я не понимаю, почему что-либо вне шейдера должно ждать его выполнения? – scippie
Другие шейдерные потоки, которые взяли кратчайший путь. – Luca