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万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章