Shader使用GPU来运算的,判断语句会使GPU中的硬件单元不能单纯的做计算,还需要去做逻辑判断,导致不能大规模数据通过相同的逻辑结构来做并行计算。
GPU不得不根据判断语句构建多个流水线阶段,在流水线之间根据临时计算的值来做跳转。
简单的if可以使用step这种函数来替换掉。
例子1
例如:
float offset(float x){
if(x < 0.1) return 0.0;
else if(x < 0.2) return x-0.1;
else if(x < 0.7) return 0.1;
else if(x <= 1.0) return (1.0-x)/3.0;
}
使用step替换之后:
float offset(float x){
float x_1 = step(x,0.1);//x < 0.1 return 1 else return 0
float x_2 = step(x,0.2);//x < 0.2 return 1 else return 0
float x_3 = step(x,0.7);//x < 0.7 return 1 else return 0
float x_4 = step(x,1.0);//x < 1.0 return 1 else return 0
return x_1*0.0 + (1-x_1)*x_2*(x-0.1) + (1-x_1)*(1-x_2)*x_3*0.1 + (1-x_1)*(1-x_2)*(1-x_3)*x_4*(1.0-x)/3.0;
}
例子2
想使用shader来写一个四方格往四周扩散的效果:
若使用if语句:
void main() {
float pts_1 = sin(pts/600);
vec2 newCoord = texcoord;
if(texcoord.x < 0.5 && texcoord.y < 0.5){
newCoord = (texcoord - vec2(0.0,0.0) )*2;
newCoord = newCoord + vec2(abs(pts_1),abs(pts_1));
}
else if(texcoord.x > 0.5 && texcoord.y < 0.5){
newCoord = (texcoord - vec2(0.5,0.0) )*2;
newCoord = newCoord + vec2(-abs(pts_1),abs(pts_1));
}
else if(texcoord.x < 0.5 && texcoord.y > 0.5){
newCoord = (texcoord - vec2(0.0,0.5) )*2;
newCoord = newCoord + vec2(abs(pts_1),-abs(pts_1));
}
else if(texcoord.x > 0.5 && texcoord.y > 0.5){
newCoord = (texcoord - vec2(0.5,0.5) )*2;
newCoord = newCoord + vec2(-abs(pts_1),-abs(pts_1));
}
if(newCoord.x < 0.01 || newCoord.x > 0.99 ) newCoord = texcoord;
if(newCoord.y < 0.01 || newCoord.y > 0.99 ) newCoord = texcoord;
gl_FragColor = vec4(texture2D(texture, newCoord.xy).rgb, 1.0);
}
优化之后:
void main() {
float pts_1 = sin(pts/600);
vec2 newCoord = texcoord;
float x_1 = step(texcoord.x,0.5);//x < 0.5 return 1 else return 0
float y_1 = step(texcoord.y,0.5);//y < 0.5 return 1 else return 0
newCoord = (newCoord - vec2((1.0-x_1)*0.5,(1.0-y_1)*0.5) )*2;//分为四个方格
newCoord = newCoord + vec2(2.0*(x_1-0.5)*abs(pts_1),2.0*(y_1-0.5)*abs(pts_1));//随着时间往四周移动
if(newCoord.x < 0.01 || newCoord.x > 0.99 ) newCoord = texcoord;
if(newCoord.y < 0.01 || newCoord.y > 0.99 ) newCoord = texcoord;
gl_FragColor = vec4(texture2D(texture, newCoord.xy).rgb, 1.0);
}
主要就可以构建大量逻辑相同的并行运算单元,将数据并行的投入其中。