OpenGL 编程指南 (8)

1、细分着色器(Tessellation shader)有两个阶段来生成几何图元的模型网格。

 1)在顶点着色阶段,需要设置所有线段、三角形构成处理的网格,使用有序顶点列表生成新的目标图元,。

 2)将新生成的图元顶点放置到指定的位置上后进入下一阶段。

2、tessellation shader 处理一种叫 面片(patch) 的新图元,它是一个保证了期望顺序的顶点列表。面片的的顶点数量需要自行设置,同一个绘制命令处理的面片大小是相同的。

  void glPathcParameteri(GLenum pname, GLint value)//pname必须为GL_PATCH_VERTICES,value的自己需要介于0与GL_MAX_PATCH_VERTICES之间

  面片的顶点数量默认为3,小于这个值那么将忽略处理不产生任何几何图元。如果要设置一个面片,绘制命令的输入类型设置为GL_PATCHES,下面是个例子:

  float vertices[][2] = {{-0.75, 0.25}, {0.5, 0.5}, {0.55, 0.53}, {-0.5, 0.55}};

  glBindVertexArray(VAO);

  glBindBuffer(GL_ARRAY_BUFFER, VBO);

  glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

  glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0 nullptr);

  glEnableVertexAttribArray(0);

  glPatchParameteri(GL_PATCH_VERTICES, 4);

  glDrawArrays(GL_PATCHES, 0, 4);

  tessellation shader中使用gl_in获得顶点数据,gl_PatchVerticesIn可以获得gl_in的长度,gl_PatchVerticesOut是输出面片的顶点数目。

3、细分控制着色器(可选的步骤)

 1)生成细分输出面片的顶点保存在gl_out并传递到细分计算着色器,同时更新所有顶点面片的属性值

 2)设置细分层次因数,以控制生成图元的操作,gl_TessLevelInner 与 gl_TessLevelOuter是隐式声明

4、通过布局限定符设置输出面片顶点的数量,gl_InvocationID表示当前是输出的第几个顶点,也就是gl_out的索引。

  layout (vertices = 4) out;//设置面片输出点顶数目为4同时代表了着色器的执行次数(每输出一个顶点执行一次)

  #version 420 core

  layout (vertices = 4) out;

  void main()

  {

    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[1] = 4.0;

    gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;

    //......

  }

5、细分总量由 内侧(gl_TessLevelInner,2个元素长度的数组,负责控制内部细分方式) 与 外侧(gl_TessLevelOuter,4个元素长度的数组,负责控制细分区域的周长) 共同决定。它们的值可以是在细分控制着色器中写入如上面的例子中也可以在应用程序中写入,当所设置的值小于1或者是NaN的时候,这个面片将会被丢弃不做处理。

  void glPatchParameterfv(GLenum pname, const GLfloat* values)//pname对应为GL_PATCH_DEFAULT_OUTER_LEVEL,GL_PATCH_DEFAULT_INNER_LEVEL,values为对应设置数值的数组

6、三种对线段分段的方式

 1)equal_spacing

OpenGL 编程指南 (8)

 2)fractional_even_spacing

OpenGL 编程指南 (8)

 3)fractional_odd_spacing

OpenGL 编程指南 (8)

7、OpenGL细分支持三种细分域:四边形、三角形、等值线集合。

 1)四边形细分域:使用了gl_TessLevelOuter 与 gl_TessLevelInner 的所有值,面片内的细分坐标使用的是(u, v)2维坐标。根据 4 中参数细分后书中给出的图例是如下:

OpenGL 编程指南 (8)

 但是我自己画出来的是下面这个样子的(上面标注的gl_TessLevelInner[0]与gl_TessLevelInner[1]应该互换位置)

OpenGL 编程指南 (8)

 OpenGL 编程指南 (8)

 2)等值线细分域:使用了gl_TessLevelOuter 前二个值。考虑到两个面片共享一条边的情况,第一条线是不予显示的。

OpenGL 编程指南 (8)

 3)三角形细分域:使用了gl_TessLevelOuter 前三个值 与 gl_TessLevelInner 第一个值。细分坐标系使用的是重心坐标系(x, y, z)表示,各个分量值域为[0.0, 1.0]同时z+y+x = 1.0。

OpenGL 编程指南 (8)

 

8、细分计算着色器:细分生成的顶点都要执行一次细分计算着色器将细分坐标转换为下文能够识别的屏幕坐标。细分计算着色器首先设置图元生成器,通过layout设置细分域、图元类型(quads、triangles、isolines)、图元面朝向(cw、ccw)、生成方式,然后根据前面的参数计算出需要的坐标等信息。

  layout (quads, equal_spacing, ccw, points) out;//这些参数的顺序不是严格的

  #version 420 core

  layout (quads, equal_spacing, ccw) in;

  void main()

  {

    float u = gl_TessCoord.x;

    float v = gl_TessCoord.y;

    float mu = 1.0 - u;

    float mv = 1.0 - v;

    gl_Position = mu*mv*gl_in[0].gl_Position + u*mv*gl_in[1].gl_Position + u*v*gl_in[2].gl_Position + mu*v*gl_in[3].gl_Position;

  }

10、https://www.khronos.org/opengl/wiki/Tessellation

相关推荐