Быстрая аппроксимация инструкции RSQ
Автор: Юрий Степаненко
Ускорения вычисления 1/sqrt(x) аппроксимацией
Для старых видеокарт вычисление 1/sqrt(x) инструкцией RSQ занимает
несколько драгоценных тактов в пиксельном шейдере, так для NV3x время
исполнения одной такой инструкции составлят 3 такта.
Наиболее часто RSQ используется для нормирования векторов H, N, L, и
потому является источником неэффективности шейдера. Для повышения
скорости приходится часть векторов нормировать с помощью кубических
текстур, но при этом напрасно расходуется часть пропускной способности
памяти.
Если векторы были нормированы перед передачей их в пиксельный шейдер, а
количество треугольников в модели велико, то скорее всего длина любого
интерполированного вектора будет в пределах [0.8; 1.0].
Эмпирически была выбрана квадратичная функция, которая двумя командами
MAD весьма точно аппроксимирует 1/sqrt(x) на отрезке [0.8; 1.0]:
1/sqrt(x) = 1.99 + x * (0.5 * x - 1.49);
Пример реализации для GLSL:
vec3 Normalize( vec3 v ) { float r0 = dot( v, v ); float r1 = 0.5 * r0 - 1.49; return (( r1 * r0 + 1.99 ) * v); }
Пример реализации для ARBfp1.0:
DP3 R0.x, vec, vec; MAD R1.x, R0, 0.5, -1.49; MAD R1.x, R0, R1, 1.99; MUL vec, vec, R1.x;
Ну и самое важное: таким образом можно одновременно аппроксимировать
ЧЕТЫРЕ значения, если использовать все четыре компонента переменных
R0 и R1 :-)))) Пример реализации для ARBfp1.0:
DP3 R0.x, vec1, vec1; DP3 R0.y, vec2, vec2; DP3 R0.z, vec3, vec3; DP3 R0.w, vec4, vec4; MAD R1, R0, 0.5, -1.49; MAD R1, R0, R1, 1.99; MUL vec1, vec1, R1.x; MUL vec2, vec2, R1.y; MUL vec3, vec3, R1.z; MUL vec4, vec4, R1.w;
12 октября 2009