cocos2dx shader系列一——基本篇
這裏介紹幾種最基本也較常用的shader特效,當然序列幀動畫也可以做這些特效,但遠沒有shader做的高效完美,而且省去不必要的內存消耗和cpu消耗,畢竟現在手機的gpu遠遠沒有發揮它的作用,今天我們就讓它發揮它該有的作爲,讓cpu歇一歇,不讓你的手機燙壞你的手。。。。
以下shader均在cocos2dx引擎下測試過。
一、灰度圖
這是最基本的shader,也是常用的效果,比如一個按鈕會有三個狀態,可點擊、點擊中、不可點擊,第三種狀態正是用灰度圖表示的。灰度圖也叫黑白圖,即使用算法將每個像素RGB值轉換爲一種“灰色”顏色。
#ifdef GL_ES
precision lowp float;
#endif
uniform sampler2D u_texture;
// pass from vs
varying vec4 v_fragmentColor;
varying vec2 v_texCoord;
void main()
{
vec4 texColor = texture2D(u_texture, v_texCoord);
float gray = dot(texColor.rgb, vec3(0.299, 0.587, 0.114));
gl_FragColor = v_fragmentColor * vec4(gray, gray, gray, texColor.a);
}
二、流光
流光的特效也常用,當然閃光的特效也類似,主要是給像素的RGB乘個因子,比如閃光是所有像素變亮或變暗
vec4 texColor = texture2D(u_texture, v_texCoord);
texColor[0] = texColor[0] * factor;
texColor[1] = texColor[1] * factor;
texColor[2] = texColor[2] * factor;
gl_FragColor = v_fragmentColor * texColor;
factor=1時就是正常的顯示,大於1的話,會發亮,小與1會變暗。
做流光的話,就不能這麼簡單的處理了。因爲是要用到2張texture的混合。這裏我們用shader生成一個有顏色的線條,選擇一個x+y-c=0這條斜線爲高亮部分。c從0到
#ifdef GL_ES
precision lowp float;
#endif
varying vec4 v_fragmentColor;
varying vec2 v_texCoord;
uniform sampler2D u_texture;
uniform float factor;
uniform float width;
uniform float offset;
uniform vec3 color;
void main()
{
vec4 texColor = texture2D(u_texture, v_texCoord);
// line (x+y-offset=0) offset:[0, 2] (2->0)
// |y
// |
// ____|0__ 1__2____x
// | |
// |_______|
float distance = abs(v_texCoord[0]+v_texCoord[1]/1.414;
// linear gradient (base on distance)
// (1/width)x + y = 1
distance = 1.0-(1.0/width)*distance;
distance = max(distance, 0.0);
vec4 sample = vec4(0.0,0.0,0.0,0.0);
sample[0] = color[0] * distance;
sample[1] = color[1] * distance;
sample[2] = color[2] * distance;
sample[3] = distance;
gl_FragColor = v_fragmentColor * sample;
}
生成的效果,width是線條的寬度,offset是線條的偏移(控制線條的移動),color是線條的顏色,
然後,我們用這條有顏色的線條來混合我們真實的貼圖,起到高亮明顯的效果。
void main()
{
vec4 texColor = texture2D(u_texture, v_texCoord);
// line (x+y-offset=0) offset:[0, 2] (2->0)
// |y
// |
// ____|0__ 1__2____x
// | |
// |_______|*
float distance = abs(v_texCoord[0]+v_texCoord[1]-offset)/1.414;
// linear gradient
// (1/width)x + y = 1
distance = 1.0-(1.0/width)*distance;
distance = max(distance, 0.0);
vec4 sample = vec4(0.0,0.0,0.0,0.0);
sample[0] = color[0] * distance;
sample[1] = color[1] * distance;
sample[2] = color[2] * distance;
sample[3] = distance;
// blend additive
float alpha = sample[3]*texColor[3];
texColor[0] = texColor[0] + sample[0]*alpha*factor;
texColor[1] = texColor[1] + sample[1]*alpha*factor;
texColor[2] = texColor[2] + sample[2]*alpha*factor;
gl_FragColor = v_fragmentColor * texColor;
}
效果如下:
factor來控制凸顯部分的亮度(如圖爲正常亮度,即factor=1)
ps:如果覺得麻煩,可以另外傳一張貼圖來代替第一步生成的線條,這樣可以省去動態生成有顏色的線條。
三、百葉窗
這是關於texture切換的效果,需要傳遞2張texture,這裏我們就可以控制那張texture顯示,那張不顯示。shader如下:
#ifdef GL_ES
precision lowp float;
#endif
uniform sampler2D texture0;
uniform sampler2D texture1;
uniform float flag;
uniform float lineWidth;
uniform float offset;
varying vec4 v_fragmentColor;
varying vec2 v_texCoord;
void main()
{
float modPart = mod(v_texCoord[0], lineWidth);
float solidPart = (1.0-offset) * lineWidth;
// reduce tex-switch times
// (0, 1) (2, 1) (2, 3) (0, 3)
//modPart = modPart * flag;
//solidPart = solidPart * flag;
if (modPart > solidPart)
{
gl_FragColor = v_fragmentColor * texture2D(texture1, v_texCoord);
}
else
{
gl_FragColor = v_fragmentColor * texture2D(texture0, v_texCoord);
}
}
我們通過linewidth變量來控制百葉窗分成幾塊,每一塊區間[0,1],然後通過offset變量來控制[0, offset]部分顯示tex0, [offset,1]部分顯示tex1。效果如下:
ps:當有多張貼圖時,就要改變texture0和texture1,之前擔心切換texture的開銷,所以加了個flag變量來較少切換的個數,不過在手機上試下,切換時不會卡頓。在不加flag變量的情況下需要切換2張texture,加了flag變量每次就只要切換一張texture。
例如 0, 1,2 三張texture,
不加flag: (0, 1) - > (1, 2) -> (2, 0) - > (0, 1)
加flag:(0, 1) -> (2, 1) - > (2, 0) - > (1, 0)
Repository:代碼