GPUImage滤镜中的shader代码分析,及自定义滤镜

from: http://blog.csdn.net/vegerjiangsir/article/details/27172143


GPUImage由于使用GPU,顾其在滤镜染色的时候真正使用的是Open GL的shader语言。下面我们就GPUImagePinchDistortionFilter分析这些shader语言。

GPUImagePinchDistortionFilter是一个实现收缩失真,凹面镜效果滤镜,头文件代码如下:

[objc]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. #import "GPUImageFilter.h"  
  2.   
  3. /** Creates a pinch distortion of the image 
  4.  */  
  5. @interface GPUImagePinchDistortionFilter : GPUImageFilter  
  6. {  
  7.     GLint aspectRatioUniform, radiusUniform, centerUniform, scaleUniform;  
  8. }  
  9.   
  10. /** The center about which to apply the distortion, with a default of (0.5, 0.5) 
  11.  */  
  12. @property(readwritenonatomic) CGPoint center;  
  13. /** The radius of the distortion, ranging from 0.0 to 2.0, with a default of 1.0 
  14.  */  
  15. @property(readwritenonatomic) CGFloat radius;  
  16. /** The amount of distortion to apply, from -2.0 to 2.0, with a default of 0.5 
  17.  */  
  18. @property(readwritenonatomic) CGFloat scale;  
  19.   
  20. @end  

我们来分析一下。

首先,这个类必须继承于GPUImageFilter(这个必须,要不然就没法用)。

其次,这个类有三个参数:center表示效果所在圆的中心点,radius表示所在圆的半径(注意范围是-2.0到2.0),scale表示缩放倍数(当scale小于0的时候,中间缩小,周围放大;当scale大于0的时候,中间放大,周围缩小)。

最后,我们需要关注一个单位(这个很重要,要不然后面的shader代码就很迷茫了)。细心的朋友肯定会发现圆半径的范围是-2.0到2.0。很显然,这不是像素单位,要不然这了滤镜效果范围也太小了,和没有效果一样)。事实上,在shader语言中,半径是真实半径除以图片矩形的宽(横着图片的为高),记realRadio/targetWidth(横着的图片为realRadio/targetHeight);


源文件中,我们重点分析shader语句kGPUImagePinchDistortionFragmentShaderString。在这里,我直接加注释。

[objc]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. NSString *const kGPUImagePinchDistortionFragmentShaderString = SHADER_STRING  
  2. (  
  3.  varying highp vec2 textureCoordinate;/*变形后的图片的坐标*/  
  4.    
  5.  uniform sampler2D inputImageTexture;/*需要变形的图片*/  
  6.    
  7.  uniform highp float aspectRatio;/*坐标变换的系数,在shader坐标系中width永远是1.0,height做相应的等比缩放*/  
  8.  uniform highp vec2 center;/*参数,中心点*/  
  9.  uniform highp float radius;/*参数,圆半径*/  
  10.  uniform highp float scale;/*参数,缩放倍数*/  
  11.    
  12.  void main()  
  13.  {  
  14.      highp vec2 textureCoordinateToUse = vec2(textureCoordinate.x, (textureCoordinate.y * aspectRatio + 0.5 - 0.5 * aspectRatio));/*计算可以用于计算到中心距离的坐标*/  
  15.      highp float dist = distance(center, textureCoordinateToUse);/*计算到中心的距离*/  
  16.      textureCoordinateToUse = textureCoordinate;/*将坐标恢复到shader坐标系*/  
  17.        
  18.      if (dist < radius)/*在圆内*/  
  19.      {  
  20.          textureCoordinateToUse -= center;/*需要相对中心的坐标*/  
  21.          highp float percent = 1.0 + ((0.5 - dist) / 0.5) * scale;/*缩放的程度*/  
  22.          textureCoordinateToUse = textureCoordinateToUse * percent;/*坐标缩放*/  
  23.          textureCoordinateToUse += center;/*需要绝对坐标*/  
  24.            
  25.          gl_FragColor = texture2D(inputImageTexture, textureCoordinateToUse );/*gl_FragColor表示变形后坐标textureCoordinate的颜色*/  
  26. </span>     }  
  27.      else/*不再园内*/  
  28.      {  
  29.          gl_FragColor = texture2D(inputImageTexture, textureCoordinate );/*gl_FragColor表示变形后坐标textureCoordinate的颜色*/  
  30.      }  
  31.  }  
  32. );  

上面我在shader中加了注释,实际的shader代码不要加注释(因为代码长度占GPU内存,且中文可能会出问题)。

从上面我们可以到,我们可以通过修改第三方的库来增加自己的滤镜。事实上,GPUImage已经提供了滤镜扩展的接口,我们不需要修改它的库。类GPUImageFilter有一个初始化函数initWithFragmentShaderFromFile:可以加载自定义以fsh为后缀文件中的shader代码。例如:

[objc]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. GPUImageFilter *filter1 = [[[GPUImageFilter alloc] initWithFragmentShaderFromFile:@"Shader1"] autorelease];  

而Shader.fsh的代码为:

[plain]  view plain copy print ? 在CODE上查看代码片 派生到我的代码片
  1. varying highp vec2 textureCoordinate;  
  2.   
  3. uniform sampler2D inputImageTexture;  
  4.   
  5. void main()  
  6. {  
  7.     lowp vec3 tc = vec3(1.0, 0.0, 0.0);  
  8.   
  9.     lowp vec3 pixcol = texture2D(inputImageTexture, textureCoordinate).rgb;  
  10.     lowp vec3 colors[3];  
  11.     colors[0] = vec3(0.0, 0.0, 1.0);  
  12.     colors[1] = vec3(1.0, 1.0, 0.0);  
  13.     colors[2] = vec3(1.0, 0.0, 0.0);  
  14.     mediump float lum = (pixcol.r + pixcol.g + pixcol.b) / 3.0;  
  15.     int ix = (lum < 0.5)? 0:1;  
  16.     tc = mix(colors[ix], colors[ix + 1], (lum - float(ix) * 0.5) / 0.5);  
  17.   
  18.     gl_FragColor = vec4(tc, 1.0);  
  19. }  





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值