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);
}
主要就可以構建大量邏輯相同的並行運算單元,將數據並行的投入其中。