GLSL Tessellation Shader的编程入门介绍
2015-05-13 10:11
267 查看
Tessellation Shader是OpenGL4.0引入的新特性,由Tessellation
Control Shader和Tessellation
Evaluation Shader两部分构成,在管线中位于Vertex Shader和Geometry Shader中间。引入了这两个Shader之后的OpenGL管线如下图所示
这两个Shader正如其名,是为了做曲面细分而存在的。他们的输入叫Patch,是由多个顶点组成的一个结构;输出是图元(Primitive),也就是Geometry Shader输入输出的那个。
OpenGL中添加这两个Shader和添加其他Shader的过程类似,先create,链上代码,编译,最后连接到Shader程序。也就是调用glCreateShader,glShaderSource,glCompileShader,glAttachShader这几个函数。只提一下glCreateShader,建立Tessellation Control Shader用GL_TESS_CONTROL_SHADER,建立Tessellation
Evaluation Shader用GL_TESS_EVALUATION_SHADER。如下:
前面提到Tessellation Shader的输入是由多个顶点组成的Patch,这个Patch的顶点数是在OpenGL中调用glPatchParameteri指定的。
OpenGL中的绘制函数也需要据此作出调整,例如使用VBO绘制时调用的glDrawArrays函数,第一个参数将不再是以往的GL_TRIANGLES之类的而将改为GL_PATCHES,后面的几个参数也应与你的Patch大小一致。以我的代码为例:
接下来真正开始讲Tessellation Shader的编程部分。Tessellation实质上是由3部分组成,首先进入Tessellation Control Shader,然后进入Tessellation Primitive Generation,最后是Tessellation Evaluation Shader。其中中间的Tessellation Primitive Generation部分是不可编程的。
Tessellation Control Shader的作用是指定细分的等级。首先要决定其输出Patch的size,通过:
The TCS can change the size of a patch, adding more vertices per-patch or providing fewer. However, a TCS cannot discard
a patch (directly; it can do so indirectly), nor can it write multiple patches.
其输入常用的如下两个:
gl_InvocationID是Patch中顶点的索引数;
gl_in中是每个顶点的信息,包括位置、大小和裁剪距离(这个gl_ClipDistance没用过,不清楚它的值具体是什么含义)。
输出常用的有:
这两个TessLevel下面再提,gl_out和上面的gl_in相同,一般都是简单的pass through,如
gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
这行代码的意思是将index为gl_InvocationID的顶点的输入坐标直接作为输出坐标,该操作会对Patch中所有的顶点进行。
Tessellation Control Shader的核心就是gl_TessLevelOuter和gl_TessLevelInner,前者决定外围的细分等级,后者决定内部的细分等级。其数值代表将该段分为几部分,即如果值为2,那么就是在中间插入1个点分为两段。为了便于理解我给个小例子:
对一个四边形做双线性插值,其细分等级如下:
Outer分别对应了四边形的外面四条边,按右上左下的顺序。Inner对应了四边形内部的左右和上下。
需要注意的是这两个Level的类型都是float。
接下来的Tessellation Primitive Generation部分会被Tessellation Evaluation Shader中的一些设置影响所以就先说Tessellation Evaluation Shader。
Tessellation Evaluation Shader首先是决定数据类型,如:
layout( quads, equal_spacing, cw ) in;
其输入控制有三部分,分别为:
Abstract patch tpye:
isolines,输入为一系列平行线,输出为一系列的线;
triangles,输入为一个三角形,输出为一系列三角形;
quads,输入为一个四边形,输出为一系列三角形。
Spacing:
equal_spacing,插值点之间均匀;
fractional_even_spacing,分段数量为偶数;
fractional_odd_spacing,分段数量为奇数。
Primitive odering:
cw,顺时针;
ccw,逆时针。
其中Spacing中的两个不太好理解,在上例基础上做些更改,
fractional_even_spacing:
fractional_odd_spacing:
也就是说,fractional_even_spacing先将非偶数的分割段变成偶数分割,然后保证偶数分割段长度相等,fractional_odd_spacing类比。(不知道有没有讲清楚,这个比较蛋疼)
最后再提一点,Tessellation一般都是在局部坐标系下进行,因此vertex shader往往是pass through,因而需要在Tessellation Shader中进行model view projection,但Tessellation是OpenGL4.0的特性,已经取消了ftransform()等,所以需要自己传矩阵,如:
在OpenGL中传入这两个矩阵
Control Shader和Tessellation
Evaluation Shader两部分构成,在管线中位于Vertex Shader和Geometry Shader中间。引入了这两个Shader之后的OpenGL管线如下图所示
这两个Shader正如其名,是为了做曲面细分而存在的。他们的输入叫Patch,是由多个顶点组成的一个结构;输出是图元(Primitive),也就是Geometry Shader输入输出的那个。
OpenGL中添加这两个Shader和添加其他Shader的过程类似,先create,链上代码,编译,最后连接到Shader程序。也就是调用glCreateShader,glShaderSource,glCompileShader,glAttachShader这几个函数。只提一下glCreateShader,建立Tessellation Control Shader用GL_TESS_CONTROL_SHADER,建立Tessellation
Evaluation Shader用GL_TESS_EVALUATION_SHADER。如下:
tcs_shader = glCreateShader(GL_TESS_CONTROL_SHADER); tes_shader = glCreateShader(GL_TESS_EVALUATION_SHADER);
前面提到Tessellation Shader的输入是由多个顶点组成的Patch,这个Patch的顶点数是在OpenGL中调用glPatchParameteri指定的。
void glPatchParameteri(GLenum pname, GLint value)pname为GL_PATCH_VERTICES,value为每个Patch的顶点数。例如当你想让每个Patch由4个点组成时调用如下:
glPatchParameteri(GL_PATCH_VERTICES, 4);在Tessellation Shader中每个Patch都是独立的,不存在Patch Strip之类的东西,需要与Geometry Shader中带邻接信息图元的概念区分开。如果你需要用到邻接信息,那么你只能让这个Patch包含所有你需要用到的顶点。例如你需要做一个参数曲面需要用到16个点而每个图元是一个三角形,那么你的Patch应该是由16个点而不是3个点组成。
OpenGL中的绘制函数也需要据此作出调整,例如使用VBO绘制时调用的glDrawArrays函数,第一个参数将不再是以往的GL_TRIANGLES之类的而将改为GL_PATCHES,后面的几个参数也应与你的Patch大小一致。以我的代码为例:
glPatchParameteri(GL_PATCH_VERTICES, 4); glDrawElements(GL_PATCHES, MESH_RECTANGLE_NUM * 4, GL_UNSIGNED_INT, 0);这里我Buffer了顶点坐标和索引数组,由于是索引绘制所以使用了glDrawElements,可以看到我每个Patch由4个顶点组成。在调用glDrawElements绘制时第一个参数为GL_PATCHES,第二个参数为顶点总数(四边形数量*4)。这里的索引数组与以往的三角形索引数组不同,因为每个patch是四边形所以应该是四边形的索引数组。
接下来真正开始讲Tessellation Shader的编程部分。Tessellation实质上是由3部分组成,首先进入Tessellation Control Shader,然后进入Tessellation Primitive Generation,最后是Tessellation Evaluation Shader。其中中间的Tessellation Primitive Generation部分是不可编程的。
Tessellation Control Shader的作用是指定细分的等级。首先要决定其输出Patch的size,通过:
layout(vertices = patch_size) out;一般这个patch_size与OpenGL中指定的相同。但官方文档中提到TCS可以用于改变patch的size,应该就是在这里改,不过我还没遇到过这种情况。官方的原文如下:
The TCS can change the size of a patch, adding more vertices per-patch or providing fewer. However, a TCS cannot discard
a patch (directly; it can do so indirectly), nor can it write multiple patches.
其输入常用的如下两个:
in int gl_InvocationID;
in gl_PerVertex { vec4 gl_Position; float gl_PointSize; float gl_ClipDistance[]; }gl_in[gl_MaxPatchVertices];
gl_InvocationID是Patch中顶点的索引数;
gl_in中是每个顶点的信息,包括位置、大小和裁剪距离(这个gl_ClipDistance没用过,不清楚它的值具体是什么含义)。
输出常用的有:
patch out float gl_TessLevelOuter[4]; patch out float gl_TessLevelInner[2];
out gl_PerVertex { vec4 gl_Position; float gl_PointSize; float gl_ClipDistance[]; } gl_out[];
这两个TessLevel下面再提,gl_out和上面的gl_in相同,一般都是简单的pass through,如
gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
这行代码的意思是将index为gl_InvocationID的顶点的输入坐标直接作为输出坐标,该操作会对Patch中所有的顶点进行。
Tessellation Control Shader的核心就是gl_TessLevelOuter和gl_TessLevelInner,前者决定外围的细分等级,后者决定内部的细分等级。其数值代表将该段分为几部分,即如果值为2,那么就是在中间插入1个点分为两段。为了便于理解我给个小例子:
对一个四边形做双线性插值,其细分等级如下:
gl_TessLevelOuter[0] = float(2); gl_TessLevelOuter[1] = float(3); gl_TessLevelOuter[2] = float(4); gl_TessLevelOuter[3] = float(5); gl_TessLevelInner[0] = float(2); gl_TessLevelInner[1] = float(3);结果如下图:
Outer分别对应了四边形的外面四条边,按右上左下的顺序。Inner对应了四边形内部的左右和上下。
需要注意的是这两个Level的类型都是float。
接下来的Tessellation Primitive Generation部分会被Tessellation Evaluation Shader中的一些设置影响所以就先说Tessellation Evaluation Shader。
Tessellation Evaluation Shader首先是决定数据类型,如:
layout( quads, equal_spacing, cw ) in;
其输入控制有三部分,分别为:
Abstract patch tpye:
isolines,输入为一系列平行线,输出为一系列的线;
triangles,输入为一个三角形,输出为一系列三角形;
quads,输入为一个四边形,输出为一系列三角形。
Spacing:
equal_spacing,插值点之间均匀;
fractional_even_spacing,分段数量为偶数;
fractional_odd_spacing,分段数量为奇数。
Primitive odering:
cw,顺时针;
ccw,逆时针。
其中Spacing中的两个不太好理解,在上例基础上做些更改,
fractional_even_spacing:
fractional_odd_spacing:
也就是说,fractional_even_spacing先将非偶数的分割段变成偶数分割,然后保证偶数分割段长度相等,fractional_odd_spacing类比。(不知道有没有讲清楚,这个比较蛋疼)
最后再提一点,Tessellation一般都是在局部坐标系下进行,因此vertex shader往往是pass through,因而需要在Tessellation Shader中进行model view projection,但Tessellation是OpenGL4.0的特性,已经取消了ftransform()等,所以需要自己传矩阵,如:
uniform mat4 ModelViewMatrix; uniform mat4 ProjectionMatrix;
在OpenGL中传入这两个矩阵
glGetFloatv(GL_MODELVIEW_MATRIX, model_view_matrix); glGetFloatv(GL_PROJECTION_MATRIX, projection_matrix); glUniformMatrix4fv(glGetUniformLocation(shader_program, "ModelViewMatrix"), 1, GL_FALSE, model_view_matrix); glUniformMatrix4fv(glGetUniformLocation(shader_program, "ProjectionMatrix"), 1, GL_FALSE, projection_matrix); //model view projecction 矩阵
相关文章推荐
- Tessellation Shader的GLSL入门实现: 平面
- Tessellation Shader的GLSL入门实现: 曲线
- ABAP--关于SAP Control Framework(入门GUI编程的不错的基础介绍)
- .NET 4 并行(多核)编程系列之一入门介绍
- ABAP--关于SAP Control Framework(入门GUI编程的不错的基础介绍)
- 在 App 中加入 AdMob 广告 - 入门介绍与编程技巧
- ABAP--关于SAP Control Framework(入门GUI编程的不错的基础介绍)
- Shell编程入门进阶之bash配置文件介绍
- .NET 4 并行(多核)编程系列之一入门介绍
- Android开发入门——Socket编程简单介绍
- GPU(CUDA)学习日记(三)------ CUDA基本架构介绍以及编程入门!
- .NET 4 并行(多核)编程系列之一入门介绍
- VS2010/MFC编程入门之十二(对话框:属性页对话框及相关类的介绍)
- 【Linux环境编程入门】二、Linux常用命令以及vim的介绍
- Python Tkinter GUI编程入门介绍
- [置顶] 【Aladdin Unity3D Shader编程】之一 基本入门
- Shader编程笔记(二)<新手入门> 固定管线Shader
- GPU(CUDA)学习日记(三)------ CUDA基本架构介绍以及编程入门!~~
- 【转】详细介绍java的annotation入门编程
- ABAP--关于SAP Control Framework(入门GUI编程的不错的基础介绍)