什么是面片
是一个传递给OpenGL的顶点列表
使用面片绘制的区别:
如果我们不使用面片绘制图形 我们就是使用默认的图元类型 这些类型都是已知图元类型和顶点数量的对应关系 例如三个顶点对应于一个三角形 或者两个顶点对应于一条线
但是如果使用面片 我们无法知道一个面片包含了多少个顶点 所以就要使用glPatchParameteri()
细分控制
细分控制着色器负责控制要渲染的输出面片类型 也就是细分发生的区域
OpenGL有三种细分域:四边形 三角形 等值线集合
内侧细分层级
设置的是细分区域的内部划分方式 保存在gl_TessLevelInner中
内测细分层级的值设置了区域内水平和垂直方向上各自有多少“区域”
外侧细分层级
负责控制细分区域的周长 保存在gl_TessLevelOuter数组中
外侧细分层级的值于周长上每条边的段数是对应的
细分计算
每个通过图元生成的细分坐标都需要执行一次细分计算着色器
细分计算着色器的输入变量
变量声明 | 描述 |
---|---|
gl_PrimitiveID | 当前输入面片的图元索引 |
gl_PatchVerticesIn | 输入面片的顶点数,也就是gl_in的大小 |
gl_TessLevelOuter[4] | 外侧细分层级的值 |
gl_TessLevelInner[2] | 内测细分层级的值 |
gl_TessCoord | 细分坐标 还未进入细分计算着色器中面片域空间的顶点坐标值 |
细分计算着色器中输出的顶点数据被存储在如下的接口块中
out gl_PerVertex
{
vec4 gl_Positionl;
float gl_PointSize;
float gl_ClipDistance[];
float gl_CullDistance[];
}
设置图元生成域
图元类型 | 描述 | 域坐标 |
---|---|---|
quads | 单位块上的一个四边形域 | (u,v)对的形式 u,v范围0-1 |
triangles | 使用重心坐标的三角形 | (a,b,c)坐标形式,范围均为0-1 且a+b+c = 1 |
isolines | 一系列穿过单位块的线段集合 | (u,v)对的形式 u的范围0-1,v的范围0到接近1 |
设置生成图元的面朝向
cw表示顶点按照顺时针排列 ccw相反
设置细分坐标的间隔
选项 | |
---|---|
equal_spacing | 细分层将被截断在[1,max]范围内 然后取整到下一个整数值 |
frational_even_spacing | 数值将被截断在[2,max] 范围内 然后取整到下一个偶数整数值n 然后将边界划分为n-2个等长的部分 以及2个位于两端的部分 |
fractional_odd_spacing | 数值将被截断在[1,max] 范围内 然后取整到下一个奇数整数值n 然后将边界划分为n-2个等长的部分 以及2个位于两端的部分 |
max表示OpenGL中能支持的最大细层级值
输出点集
如果想输出点集而不是等值线或者填充区域 我们可用使用point_mode选项 他会为细分计算着色器处理的每个顶点渲染一个单独的点
例子
gl_TessLevelOuter[0] =2.0;
gl_TessLevelOuter[1] =3.0;
gl_TessLevelOuter[2] =2.0;
gl_TessLevelOuter[3] =5.0;
gl_TessLevelInner[0] =3.0;
gl_TessLevelInner[0] =4.0;
上图是对区域三角化的结果
gl_TessLevelOuter[0] =6.0;
gl_TessLevelOuter[1] =8.0;
最上面有一条虚线是因为等值线的结果并不包含边长上的等值数据
如果两个面片共享一条边 则边长上不会发生交叠情况
gl_TessLevelOuter[0] =6.0;
gl_TessLevelOuter[1] =5.0;
gl_TessLevelOuter[2] =8.0;
gl_TessLevelInner[0] =5.0;
如果用t表示内侧细分层级 则偶数在中心点和周长之间生成(t/2)-1个同心三角形
奇数则到周长为止生成 (t/2)-1个同心三角形
左边为gl_TessLevelInner[0] = 奇数时 右边为gl_TessLevelInner[0] = 偶数时
细分着色器有两个着色阶段 细分控制着色器,细分计算着色器
1.首先要指定面片 也就是顶点的有序列表
2.渲染面片时 将首先执行细分控制着色器,处理面片顶点,并设置面片中要生成多少集合数据
3.细分控制着色器结束后 细分计算着色器将负责把生成网格的顶点放置到细分坐标指定的位置 并将他们发送到光栅化阶段 或发给几何着色器
所有管线中的着色器都能处理片元这个图元类型
gl_in的结构体
in gl_PerVertex
{
vec4 gl_Positionl;
float gl_PointSize;
float gl_ClipDistance[];
float gl_CullDistance[];
}gl_in[gl_PatchVerticesIn];
函数
(设置面片顶点数)glPatchParameteri(GLenum paname,GLint value)
设置一个面片中的顶点数为vlaue panme必须设置为GL_PATCH_VERTICES
一个面片默认值是3 如果面片的顶点数量小于这个值 那么将忽略这个面片 不会产生几何体
(设置内测和外侧细分层级因数)glPatchParameterfv(GLenum panme, const GLfloat* values)
如果没有绑定细分控制着色器 则用这个函数来设置内测和外侧细分层级因数
pname必须时GL_PATCH_DEFAULT_OUTER_LEVEL或者GL_PATCH_DEPCH_INNER_LEVEL
内置变量
(获取gl_in的元素个数)gl_PatchVerticesIn
(当前细分着色器在控制的顶点索引)gl_InvocationID
(gl_in的大小 输入面片的顶点数量)gl_PatchVerticesIn
(gl_out的大小 输出面片的顶点数量)gl_PatchVerticesOut
(细分坐标)gl_TessCoord(不知道干嘛的)
(细分控制着色器的输出顶点)gl_out[i].gl_Position
这是细分计算着色器中调用gl_out[i].gl_Position可以获取从细分控制着色器输进来的顶点坐标
例子
#version 430 core
layout (vertices = 4) out;
void main()
{
gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
}