OpenGL 各个shader的作用和区别

OpenGL4.0发布了Tessellation shader(Control + Evaluation shader)。到OpenGL4.* 为止,现在OpenGL已经支持了5种不同类型的shader。

1.Vertex Shader,简称VS

2.TESS  Control  Shader (D3D11 叫Hull shader),简称TCS

3.TESS Evaluation Shader (D3D叫Domain shader),简称TES

4.Geometry Shader ,简称GS

5.Fragment Shader(D3D叫Pixel Shader),简称PS


我将根据他们的“主要”输入与输出,以及其基本功能进行对比。这样我们就可以很好的了解他们在OpenGL Pipeline里面的作用和区别。

以下顺序是他们在OpenGL Pipeline里面的执行顺序。


1.Vertex Shader

输入:顶点坐标(Position),该坐标值是由glVertex* 或者是glDraw*传入的。

输出:顶点坐标,这个是经过几何变换后的坐标。

功能简单的说就是把输入的顶点坐标乘以(一系列)几何变换矩阵。每输入一个顶点(也就是glVertex*每调用一次),Vertex shader都会被调用一次。Vertex Shader只知道处理顶点,它不知道这些顶点是做什么用的,也就是不知道这些顶点将来会被装配成什么图元。(因为Vertex shader后面才会有图元装配的过程)

当然,VS还可以接收颜色,纹理坐标,雾坐标等属性,并在内部对他们做一点点变化,然后再输出。


2.TESS Control Shader

输入:Patch,一个Patch可以看成是多个顶点的集合。它包括每个顶点的属性(坐标,颜色,纹理坐标等等)。用户可以指定一个patch里面要包含几个顶点。同时,一个patch还可以用自己的属性,该属性被它内部的所有顶点共有,即这些顶点只有一套patch属性,而不是每个顶点拥有一个自己的patch属性。(懂了吗?)

输出:Patch , gl_TessLevelOuter , gl_TessLevelInner。

功能:TCS会根据需求把Patch自己的属性以及它内部的顶点属性做一些修改。然后输出Patch。当然,它也可以不做任何修改,直接传给后面的shader。我们知道Tessellation的作用就是把一个图元分割成很多图元,比如把一个三角形分割成很多更小的三角形。因此,在分割的时候我们得要知道这个三角形的每个边要被分割成多少段,然后在三角形内部,我们还要怎么继续分割,这两个紫色的内容就是存储在 gl_TessLevelOuter 和gl_TessLevelInner。TCS可以根据需要设置这两个值。

所以,TCS的主要作用是设置Patch以及它内部顶点的属性。同时也是最重要的,设置图元接下来被细分的。(TCS不做分割动作)

下面贴了个三角形分割的图片。

OpenGL 各个shader的作用和区别_第1张图片

注意:用TCS的话,glBegin函数的参数必须是GL_PATCHES,而不是以前那种传统的图元(点,线,三角形等)。 glPatchParameteri可以指定每个Patch包含几个顶点。在VS与TCS直接有个图元装配的过程,它就是把VS输出的顶点封装一个Patch,然后传给TCS。


3.TESS Evaluation Shader

输入:一系列顶点。这些顶点是三角形被分割后产生的顶点。下面是每个TES程序都必须有的一段代码:

layout( triangles, fractional_odd_spacing, ccw ) in;

它表示TES的输入是三角形(当然你也可以写成其他类型的图元),至于 fractional_odd_spacing,和ccw是什么意思,大家看spec吧,很简单,我怕我解释不清楚而误解大家。最后的那个“in”进一步说明了这是TES的输入。

输出:也是一系列顶点。

功能:其实在TCS与TES之间有个过程叫Tessellation Primitive Generator(简称TGP),它首先会去查看TES的输入是什么,哦,它要三角形。那么,TGP就会把TCS传入的Patch内部的顶点看成是若干个三角形(注意Patch内部的顶点不一定只有三个)。然后,TGP每次从当前Patch里面取出三个顶点做一个三角形的分割,直到Patch里面的顶点全部被取出。

每个三角形具体怎么被分割呢?

其实,gl_TessLevelOuter 和gl_TessLevelInner会被传入给TGP。它们的作用就被体现出来。这就是为什么我前面说的TCS不做分割,只计算分割的度。(注意TGP不是shader,它只是pipeline里面的一个状态而已)

现在开始讲TES的功能吧。其实TGP传入的顶点的坐标值并不是世界坐标值,而是一个三角形内部的坐标表示形式,大家看到上面的图了吧,三角形顶点上有坐标的,TGP然后根据这个坐标去计算内部新成立的顶点在该局部坐标系内部的坐标。因此,TES就是要把每个顶点的局部坐标变换成世界坐标,以及把顶点相应属性(颜色,纹理坐标等)转换成真正且有效的属性值。每处理一个顶点就输出一个顶点。

注意:TES并不知道这些顶点会被组成什么图元,它只要求TGP把patch内部的顶点当成什么图元去分割。TES和VS一样,输入是顶点,输出也是顶点。在TES后面有个图元装配的过程,它会根据TES的输入(看上面的那行代码),转换成相应的图元。这里图元装配器会把TES输出的顶点装配成一个一个的三角形。


4.Geometry Shader

输入:一个图元

输出:一个或者多个图元

功能:无论是否有VS,TCS或者TES,在GS前面都会有一个图元装配的过程,也就是说,传给GS的是图元,而不是顶点。

GS可以做什么呢?

根据新图元生成新一个或者多个图元。下面两会代码也是每个GS都必须有的:

layout( triangles ) in;
layout( triangle_strip, max_vertices = 3 ) out;

它表示GS输入的图元是三角形。如果当前图元不是三角形,该GS将不会被调用。该GS的输出是三角形带,每个三角形带最多包括三个顶点。其实这个GS的输入和输出可以看成是一样,没做太多的事情。呵呵。如果最大顶点数超过3,那么GS实际上是把多个三角形拼成了一个三角形带。具体怎么,根据需要自己去写程序吧。

具体GS能够做什么呢?

举个简单的例子吧。我们可以用GS画Bezier曲线。Bezier曲线是有几个控制点生成的,我们可以把这些控制点假装当成图元(点,线,线带)传个GS。然后GS在内部通过Bezier曲线算法算出跟多的Bezier曲线上面的顶点。算出来的点当成线带输出,这样就由控制点计算出了新图元(Bezier曲线)。懂了吗?

这里有很多GS的例子:http://blog.csdn.net/jackers679/article/details/7472317


下班了,下次写FS。

你可能感兴趣的:(layout,domain,generator,patch,shader,Primitive)