cocos2dx shader -- Vol.1(灰度、流光、百葉窗)

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:代碼

發佈了28 篇原創文章 · 獲贊 3 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章