Я использую бикубическую фильтрацию для сглаживания карты высот, я реализовал ее на GLSL:
Бикубическая интерполяция: (см. функцию interpolate()
ниже)
float interpolateBicubic(sampler2D tex, vec2 t)
{
vec2 offBot = vec2(0,-1);
vec2 offTop = vec2(0,1);
vec2 offRight = vec2(1,0);
vec2 offLeft = vec2(-1,0);
vec2 f = fract(t.xy * 1025);
vec2 bot0 = (floor(t.xy * 1025)+offBot+offLeft)/1025;
vec2 bot1 = (floor(t.xy * 1025)+offBot)/1025;
vec2 bot2 = (floor(t.xy * 1025)+offBot+offRight)/1025;
vec2 bot3 = (floor(t.xy * 1025)+offBot+2*offRight)/1025;
vec2 mbot0 = (floor(t.xy * 1025)+offLeft)/1025;
vec2 mbot1 = (floor(t.xy * 1025))/1025;
vec2 mbot2 = (floor(t.xy * 1025)+offRight)/1025;
vec2 mbot3 = (floor(t.xy * 1025)+2*offRight)/1025;
vec2 mtop0 = (floor(t.xy * 1025)+offTop+offLeft)/1025;
vec2 mtop1 = (floor(t.xy * 1025)+offTop)/1025;
vec2 mtop2 = (floor(t.xy * 1025)+offTop+offRight)/1025;
vec2 mtop3 = (floor(t.xy * 1025)+offTop+2*offRight)/1025;
vec2 top0 = (floor(t.xy * 1025)+2*offTop+offLeft)/1025;
vec2 top1 = (floor(t.xy * 1025)+2*offTop)/1025;
vec2 top2 = (floor(t.xy * 1025)+2*offTop+offRight)/1025;
vec2 top3 = (floor(t.xy * 1025)+2*offTop+2*offRight)/1025;
float h[16];
h[0] = texture(tex,bot0).r;
h[1] = texture(tex,bot1).r;
h[2] = texture(tex,bot2).r;
h[3] = texture(tex,bot3).r;
h[4] = texture(tex,mbot0).r;
h[5] = texture(tex,mbot1).r;
h[6] = texture(tex,mbot2).r;
h[7] = texture(tex,mbot3).r;
h[8] = texture(tex,mtop0).r;
h[9] = texture(tex,mtop1).r;
h[10] = texture(tex,mtop2).r;
h[11] = texture(tex,mtop3).r;
h[12] = texture(tex,top0).r;
h[13] = texture(tex,top1).r;
h[14] = texture(tex,top2).r;
h[15] = texture(tex,top3).r;
float H_ix[4];
H_ix[0] = interpolate(f.x,h[0],h[1],h[2],h[3]);
H_ix[1] = interpolate(f.x,h[4],h[5],h[6],h[7]);
H_ix[2] = interpolate(f.x,h[8],h[9],h[10],h[11]);
H_ix[3] = interpolate(f.x,h[12],h[13],h[14],h[15]);
float H_iy = interpolate(f.y,H_ix[0],H_ix[1],H_ix[2],H_ix[3]);
return H_iy;
}
Это моя версия, размер текстуры (1025) все еще жестко задан. Использование этого в вершинном шейдере и/или в шейдере оценки тесселяции очень сильно влияет на производительность (20-30 кадров в секунду). Но когда я изменяю последнюю строку этой функции на:
return 0;
производительность увеличивается так же, как если бы я использовал билинейную или ближайшую/без фильтрации.
То же самое происходит с: (я имею в виду, что производительность остается хорошей)
return h[...]; //...
return f.x; //...
return H_ix[...]; //...
Функция интерполяции:
float interpolate(float x, float v0, float v1, float v2,float v3)
{
double c1,c2,c3,c4; //changed to float, see EDITs
c1 = spline_matrix[0][1]*v1;
c2 = spline_matrix[1][0]*v0 + spline_matrix[1][2]*v2;
c3 = spline_matrix[2][0]*v0 + spline_matrix[2][1]*v1 + spline_matrix[2][2]*v2 + spline_matrix[2][3]*v3;
c4 = spline_matrix[3][0]*v0 + spline_matrix[3][1]*v1 + spline_matrix[3][2]*v2 + spline_matrix[3][3]*v3;
return(c4*x*x*x + c3*x*x +c2*x + c1);
};
Fps уменьшается только тогда, когда я возвращаю окончательное значение H_iy
. Как возвращаемое значение влияет на производительность?
EDIT Я только что понял, что использовал double
в функции interpolate()
для объявления c1
, c2
... и т. д. Я изменил его на float
, и теперь производительность остается хорошей с правильным возвращаемым значением. Поэтому вопрос немного меняется:
Как переменная точности double
влияет на производительность оборудования и почему другая функция интерполяции не вызвала эту потерю производительности, а только последнюю, поскольку массив H_ix[]
тоже был float
, как и H_iy
? эм>
a
иb
, и вы возвращаете толькоa
,b
не нужно вычислять, и все вместе оптимизируется. На графических процессорах меньше поддержки двойной точности (карты, ориентированные на вычисления, имеют больше, но все же меньше, чем число с плавающей запятой), поэтому по сравнению с производительностью с плавающей запятой это довольно плохо, не говоря уже о том, что двойная точность удваивает обрабатываемые данные, и, кроме того, больше нужно сделать округление. Наткнулся на это на днях, похоже, это связано... /GPUGems2/gpugems2_chapter20.html - person jozxyqk   schedule 18.11.2013