opengles shader

来源:互联网 发布:淘宝花呗支付怎么开通 编辑:程序博客网 时间:2024/06/06 08:52

shader对于初学来讲是比较晦涩的,一般分为顶点着色器和片段着色器
顶点着色器只管独立的顶点,顶点之间并不建立联系,用于计算顶点的裁剪坐标、深度缓冲、颜色及纹理坐标等。
片段着色器根据每一个片段和顶点着色器的输出数据,计算每个片段的颜色值。
讲的详细点,完整的流程:
1、顶点数据(CPU输出待渲染的图元,即渲染所需的几何信息,包括点、线、三角面等)
2、顶点着色器:(1)坐标变换:转到齐次裁剪坐标系,归一化,也可通过改变顶点位置产生顶点动画。
(2)逐顶点光照
3、裁剪:在视野外部的顶点需要丢弃或者用新的顶点代替,一般用交点。
4、屏幕映射:归一化坐标转屏幕坐标,屏幕坐标+z值构成窗口坐标
5、三角形设置:计算光栅化一个三角网格所需的信息)
6、三角形遍历(扫描变换):得到一个片段序列,每个包含屏幕坐标、深度信息、顶点法线、纹理坐标等。
7、片段着色器:根据上一步插值后的片段信息,计算该片段的输出颜色。
8、逐片段操作(输出合并):模版测试–>深度测试–>混合–>写入颜色缓冲区。 模版和深度测试都属于可见性测试,混合是指与之前颜色缓冲区像素颜色混合,如果是完全不透明,则覆盖之前颜色。

大体流程:顶点着色器对图元的每个顶点投影变换,再进行时锥体裁剪,被修改过的图元投影到屏幕,通过光栅化将图元转换为多个片段,它生成每个片段的位置,片段着色器负责计算每个片段的颜色值,通常还会要求输入纹理,以对每个片段进行着色贴图。然后片段经历各种测试、混合等,被发送到帧缓冲区,帧缓冲区被交换到屏幕最终显示。

存储限定符:
const:常量,或者只读方法
attribute:每顶点数据,应用程序传输给顶点着色器的。对应的是上面的1(只能用在顶点着色器)。
uniform:由应用程序传递给顶点的,片段着色器的全局变量,在一个图元的绘制期间其值保持不变(片段着色器使用)。
varying:由顶点着色器传递给片段着色器的,经过插值的易变变量。

一个简单的顶点着色器:

attribute vec4 a_position;attribute vec2 a_texCoord;attribute vec4 a_color;varying vec4 v_fragmentColor;varying vec2 v_texCoord;void main(){    gl_Position = CC_PMatrix * a_position;    v_fragmentColor = a_color;    v_texCoord = a_texCoord;}

逐行分析,前面几个attribute对应的是顶点位置、顶点纹理、顶点颜色。可以看下cocos里面,用V3F_C4B_T2F描述Sprite的一个顶点属性结构:

struct V3F_C4B_T2F{    Vertex3F vertices;   //顶点位置      Color4B  colors;     //顶点颜色    Tex2F    texCoords;  //顶点纹理(uv)}

v_fragmentColor就是要传递给片段着色器的片段颜色
v_texCoord是要传递给片段着色器的纹理坐标

CC_PMatrix这个是什么?这是个变换矩阵。先科普下,OpenGL里面介绍:
3D物体从建模到最终显示到屏幕上面要经历以下几个阶段:

1、模型空间(Model Space)
2、世界空间(World Space)(只在我本身的对象空间看到的我的位置可能是(0,0,0),你以你的坐标系看我可能在(1000,0,1000),不到世界空间不行,坐标不统一)
3、视点空间(View Space)(视点为原点,以视线的方向为Z轴正方向的坐标系中。OpenGL管道会将世界坐标先变换到眼坐标,然后进行裁剪,只有在视线范围(视锥体)之内的场景才会进入下一阶段的计算)
4、裁剪空间(Clipping Space)(或者叫投影空间,相机空间经过投影变换,和裁剪到达的空间)
5、视口空间(Viewport)(窗口坐标)

对象空间到世界空间:Model-To-World,世界空间到相机空间:World-To-View,这两个阶段一般cocos并称CC_MVMatrix,视点到投影空间View-To-Projection,cocos称作CC_PMatrix,CC_PMatrix*CC_MVMatrix即得到常见的CC_MVPMatrix。可以看情况使用,或者统一用CC_MVPMatrix,像例子里二维的又没什么变换的直接用CC_PMatrix。

一个简单的片段着色器:

#ifdef GL_ESprecision mediump float;#endifvarying vec2 v_texCoord;varying vec4 v_fragmentColor;void main(){    vec4 texColor = texture2D(CC_Texture0, v_texCoord);    gl_FragColor = v_fragmentColor * texColor;}

vec4 texture2D(Sampler2D sampler, vec2 coord);
该方法用于纹理查找,用来查找纹理上某个纹理坐标的颜色值。
可设置不同的sampler,多纹理的时候该参数的作用会体现。
v_fragmentColor * texColor代表颜色相乘,有个术语叫正片叠底 ,其实就是把两种颜色混合,比如:
白色(1,1,1,1)
灰色(0.5,0.5,0.5,1)
两个相乘就是 (0.5,0.5,0.5,1) 还是灰色
灰色(0.5,0.5,0.5,1)
浅灰色(0.4,0.4,0.4,1)
两个相乘就是(0.2,0.2,0.2,1) 深灰色

举两个例子,
1、实现马赛克效果

#ifdef GL_ESprecision mediump float;#endifvarying vec4 v_fragmentColor;varying vec2 v_texCoord;uniform vec2 u_textureSize;uniform vec2 u_mosaicSize;void main(){    vec2 uv = v_texCoord * u_textureSize;    uv = floor(uv / u_mosaicSize) * u_mosaicSize;     uv = uv / u_textureSize;      gl_FragColor = texture2D(CC_Texture0, uv) * v_fragmentColor;}

u_textureSize代表纹理尺寸,u_mosaicSize假设为5,假如一张200*100的纹理,某个点坐标为(40,50),则归一化坐标为(0.25,0.5),这里要注意是归一化坐标,
uv = (40,50)*5
而对于(44,54)得到的uv是同一个值,再把uv归一化,马赛克效果就实现了。

2、类似裁剪节点clippnode的效果

#ifdef GL_ESprecision mediump float;#endifvarying vec2 v_texCoord;varying vec4 v_fragmentColor;uniform sampler2D u_maskTexture;void main(){    vec4 texColor   = texture2D(CC_Texture0, v_texCoord);    vec4 maskColor  = texture2D(u_maskTexture, v_texCoord);    gl_FragColor = v_fragmentColor * texColor * maskColor.a;}

一旦u_maskTexture对应的纹理颜色透明度为0,片段颜色值也全为0。比如u_maskTexture代表200*200的矩形纹理,而其中有颜色的部分(透明度不为0)为一个半径100的内接圆,则由于圆周围透明度为0,得出的gl_FragColor也为0,就实现了被裁剪掉了的效果。
clippnode还有一种方法setInverted(is_inverted),设置是否裁掉有颜色区域而留下外面区域,只要写成:
gl_FragColor = v_fragmentColor * texColor * (1.0 - maskColor.a);
即可。

0 0
原创粉丝点击