彩色图转灰度图

  上一节课讲解了纹理贴图的知识点,本节课通过一个把彩色图处理为灰度图的案例进一步认识可编程片元着色器和逐片元的概念。

WebGL彩色图       WebGL灰度图

  纹理贴图可以经过渲染管线处理后映射到三维空间中顶点坐标定义的位置,在这个过程中,执行方法texture2D()提取的像素值直接赋值给片元,存入帧缓存的颜色缓冲区中, 显示系统扫描颜色缓冲区中的像素值显示在屏幕上。渲染过线的片元着色器是可编程的,可以执行着色器语言编写的程序,也就是说可以对图片的纹素进行后期处理, 就像生活中你利用PS等软件去处理你拍的照片风格化,它的本质都是按照一定的算法处理图片,更改像素RGBA值。

亮度

  灰度图颜色只有黑白两色,或者说灰度图颜色分量只有光亮度这一个分量,黑色相当于没有光照,白色相当于最大光照强度。那么光的亮度和RGB颜色模型的三原色有什么样的数学关系, 简单的理解,RGB分量越大,灰度图就越接近于白色,具体的计算公式如下,RGB的系数之和为1,这样可以保证计算的结果不会超出WebGL颜色分量默认的最大值1。

亮度 = 0.299 x R + 0.587 x G + 0.114 x B

代码解析

源码下载

  纹理的加载处理处理过程和上一节课的一样,这里只列出片元着色器要执行的程序,片元着色器的计算语句要写在主函数main()里面。

25   'void main(){' +
26   //采集纹素
27   'vec4 texture = texture2D(u_Sampler,v_TexCoord);' +
28   //计算RGB三个分量光能量之和,也就是亮度
29   'float luminance = 0.299*texture.r+0.587*texture.g+0.114*texture.b;' +
30   //逐片元赋值,RGB相同均为亮度值,用黑白两色表达图片的明暗变化
31   'gl_FragColor = vec4(luminance,luminance,luminance,5);' +
32   '}';

  执行第27行代码texture2D()方法,片元着色器会从纹理缓冲区的纹理单元中获取像素值RGB,返回vec4类型向量数据,vec4的三个分量分别是RGB和A,jpg格式图片没有透明度分量, 程序默认补1表示不透明,通过运算符点(.)可以访问RGBA分量,第29行代码执行的是彩色图转灰度图的公式:亮度 = 0.299 x R + 0.587 x G + 0.114 x B, 通过第31行代码把计算结果赋值给片元,片元的RGB分量相同都是亮度值,显示效果只有黑白两色。

其它后期处理

更改透明度

  在实际的工程中,对像素值进行后期处理是很常见的操作,通常都是通过片元着色器程序控制片元着色器处理像素值的分量,你可以把第31行的代码vec4构造函数的最后一个分量1更改为0.5, 你会发现熊猫图片的颜色会与canvas画布的背景颜色进行融合,熊猫图片呈现出半透明状态。

拉深图片

  图片颜色值可以更改,显示尺寸也可以实现拉伸,本案例程序中图片的尺寸宽高比例是1,顶点坐标矩形区域宽高比也是1,显示效果正常。你可以把顶点数据的y值正值变大,负值变小, 刷新浏览器查看效果你会发现熊猫图片纵向拉伸。

43   /**
44    * 四个顶点坐标数据data,z轴为零
45    * 定义纹理贴图在WebGL坐标系中位置
46    **/
47   var data=new Float32Array([
48       -0.5, 0.5,//左上角——v0
49       -0.5,-0.5,//左下角——v1
50       0.5,  0.5,//右上角——v2
51       0.5, -0.5 //右下角——v3
52   ]);
43   /**
44    * 四个顶点坐标数据data,z轴为零
45    * 定义纹理贴图在WebGL坐标系中位置
46    **/
47   var data=new Float32Array([
48       -0.5, 0.7,//左上角——v0
49       -0.5,-0.7,//左下角——v1
50       0.5,  0.7,//右上角——v2
51       0.5, -0.7 //右下角——v3
52   ]);