Tessellation is the process of breaking a high-order primitive (which is known as a patch in OpenGL) into many smaller(Tessellation就是把很多高阶的图元变成很多小图元的过程), simpler primitives such as triangles for rendering(比如说三角形这种简单的图元). OpenGL includes a fixed-function, configurable tessellation engine that is able to break up quadrilaterals, triangles, and lines into a potentially large number of smaller points, lines, or triangles that can be directly consumed by the normal rasterization hardware further down the pipeline(OpenGL的固定功能部分,可以通过配置tessellation引擎,能够将一些四边形、三角形、线变成大量的硬件光栅化时可以支持处理的小的点、线和三角形). Logically, the tessellation phase sits directly after the vertex shading stage in the OpenGL pipeline(逻辑上来说,tessellation阶段是紧接着vertex shader阶段的) and is made up of three parts: the tessellation control shader, the fixed-function tessellation engine, and the tessellation evaluation shader( 并且tessellation阶段由三个部分组成:the tessellation control shader, the fixed-function tessellation engine, and the tessellation evaluation shader)

Tessellation Control Shaders

The first of the three tessellation phases is the tessellation control shader (TCS;sometimes known as simply the control shader). (tessellation shader的第一部分叫tessellation control shader) This shader takes its input from the vertex shader and is primarily responsible for two things(它的输入数据是由vertex shader给的,它主要干两件事): the determination of the level of tessellation that will be sent to the tessellation engine(第一件是确定发送给tessellation引擎的tessellation的级别), and the generation of data that will be sent to the tessellation evaluation shader that is run after tessellation has occurred(以及生成将会被在tessellation发生后,tessellation evaluation shader使用的数据)

Tessellation in OpenGL works by breaking down high-order surfaces known as patches into points, lines, or triangles.(在OpenGL中,Tessellation主要是把高阶的patch图形变成点、线、三角形) Each patch is formed from a number of control points.(每一个patch的数据是从一堆控制点钟获取的) The number of control points per patch is configurable and set by calling glPatchParameteri() with pname set to GL_PATCH_VERTICES and value set to the number of control points that will be used to construct each patch(控制点的数量是可以通过glPatchParameteri来设置的,pname参数传GL_PATCH_VERTICES,value参数设置每个patch的控制点个数). The prototype of glPatchParameteri() is(这个API的定义如下)

void glPatchParameteri(GLenum pname,GLint value);

By default, the number of control points per patch is three(缺省情况下,每个patch的控制点数量是3). Thus, if this is what you want(as in our example application), you don’t need to call it at all(如果你的 patch就是由三个点组成的话,你就不用调用这个API). The maximum number of control points that can be used to form a single patch is implementation defined(每个patch的控制点的上线个数会因为硬件不一样而不一样), but is guaranteed to be at least 32(但至少这个数目会有32个)

When tessellation is active, the vertex shader runs once per control point(当激活tessellation的时候,vertex shader是每个点会执行一次), while the tessellation control shader runs in batches on groups of control points where the size of each batch is the same as the number of vertices per patch(而tessellation control shader是按照patch执行的,每个patch中点数数目是用API去设置好的). That is, vertices are used as control points (也就是说,点是被当做控制点来使用的)and the result of the vertex shader is passed in batches to the tessellation control shader as its input(并且vertex shader的执行结果就是tessellation control shader的输入). The number of control points per patch can be changed such that the number of control points that is output by the tessellation control shader can differ from the number of control points that it consumes(控制点的个数是可以被修改的,意味着输入tessellation control shader的点的个数不一定和该shader的输出点的个数相等). The number of control points produced by the control shader is set using an output layout qualifier in the control shader’s source code(tessellation control shader产生的点的个数是在tessellation control shader里使用output layout修饰符修饰的). Such a layout qualifier looks like this(举个例子):

layout (vertices = N) out;

Here, N is the number of control points per patch(这里的N就是每个patch输出的点的个数). The control shader is responsible for calculating the values of the output control points(control shader需要计算输出的控制点的值) and for setting the tessellation factors for the resulting patch that will be sent to the fixed-function tessellation engine(这些值将会被tessellation引擎使用,并成为最终进行曲面细分时的决定因素). The output tessellation factors are written to the gl_TessLevelInner and gl_TessLevelOuter built-in output variables(曲面细分的影响因素要写在两个内置输出变量上,一个是gl_TessLevelInner一个是gl_TessLevelOuter), whereas any other data that is passed down the pipeline is written to user-defined output variables(这俩变量就跟你自己写的输出变量一样) (those declared using the out keyword, or the special built-in gl_out array) as normal

Listing 3.7 shows a simple tessellation control shader(Listing3.7显示了一个简单的tessellation control shader). It sets the number of output control points to three (它使用layout (vertices = 3) out设置了输出的数据个数是3)(the same as the default number of input control points(就跟缺省的control shader的输入数据个数一样)) using the layout (vertices = 3) out; layout qualifier, copies its input to its output (using the built-in variables gl_in and gl_out) (layout修饰符会使用内置的gl_in和gl_out,拷贝它的输入到它的输出里去), and sets the inner and outer tessellation level to 5(并且设置inner和outer的tessellation级别为5). Higher numbers would produce a more densely tessellated output(细分级别越高,产生的曲面的小面片就越多), and lower numbers would yield a more coarsely tessellated output(细分级别越小,产生的结果的面片数就越少). Setting the tessellation factor to 0 will cause the whole patch to be thrown away(设置tessellation因子为0将会使得整个patch被丢弃)

The built-in input variable gl_InvocationID is used as an index into the gl_in and gl_out arrays. This variable contains the zero-based index of the control point within the patch being processed by the current invocation of the tessellation control shader

#version 450 core
layout (vertices = 3) out;
void main(void)
{
// Only if I am invocation 0 ...
if (gl_InvocationID == 0)
{
gl_TessLevelInner[0] = 5.0;
gl_TessLevelOuter[0] = 5.0;
gl_TessLevelOuter[1] = 5.0;
gl_TessLevelOuter[2] = 5.0;
}/
/ Everybody copies their input to their output
gl_out[gl_InvocationID].gl_Position =
gl_in[gl_InvocationID].gl_Position;
}
Listing 3.7: Our first tessellation control shader

By using the shader of Listing 2.8, we can assign a different position to each of the vertices based on its value of gl_VertexID(我们可以根据gl_VertexID给每个顶点赋值一个位置). The points in the array vertices form a triangle(那些点是以三角形的方式进行组织的), and if we modify our rendering function to pass GL_TRIANGLES to glDrawArrays() instead of GL_POINTS(并且我们修改glDrawArrays的参数,从GL_POINTS变成GL_TRIANGLES,如Listing2.9所示), as shown in Listing 2.9, then we obtain the image shown in Figure 2.4(这样一来,我们应该会得到如图2.4的运行结果).

// Our rendering function
void render(double currentTime)
{
const GLfloat color[] = { 0.0f, 0.2f, 0.0f, 1.0f };glClearBufferfv(GL_COLOR, 0, color);
// Use the program object we created earlier for rendering
glUseProgram(rendering_program);
// Draw one triangle
glDrawArrays(GL_TRIANGLES, 0, 3);
}
Listing 2.9: Rendering a single triangle

The Tessellation Engine

The tessellation engine is a fixed-function part of the OpenGL pipeline that takes highorder surfaces represented as patches and breaks them down into simpler primitives such as points, lines, or triangles(Tessellation引擎是OpenGL固定功能的一部分,它会把高阶的patch打碎成点、线、三角形). Before the tessellation engine receives a patch, the tessellation control shader processes the incoming control points and sets tessellation factors that are used to break down the patch(在tessellation引擎收到patch之前,tessellation control shader会处理输入的控制点,并且设置一些用于打碎patch的一些参数). After the tessellation engine produces the output primitives, the vertices representing them are picked up by the tessellation evaluation shader(当tessellation引擎输出了图元之后,这些点会被tessellation evaluation shader处理). The tessellation engine is responsible for producing the parameters that are fed to the invocations of the tessellation evaluation shader (tessellation引擎负责设置在调用tessellation evaluation shader时需要的参数), which it then uses to transform the resulting primitives and get them ready for rasterization(evaluation shader处理完毕之后,得到的结果就可以被用于进行光栅化处理了)

Tessellation Evaluation Shaders

Once the fixed-function tessellation engine has run(当tessellation引擎运行之后,它会产生很多输出的点), it produces a number of output vertices representing the primitives it has generated. These are passed to the tessellation evaluation shader(这些点会被传递给tessellation evaluation shader). The tessellation evaluation shader (TES; also called simply the evaluation shader) runs an invocation for each vertex produced by the tessellator (tessellation evaluation shader会每个点运行一次). When the tessellation levels are high, the tessellation evaluation shader could run an extremely large number of times(当细分的数目很多时,TES会运行很多次). For this reason, you should be careful with complex evaluation shaders and high tessellation levels(因此,你需要小心的处理那些细分很多,而TES很复杂的情况)

Listing 3.8 shows a tessellation evaluation shader that accepts input vertices produced by the tessellator as a result of running the control shader shown in Listing 3.7. (Listing3.8显示了接收来自Listing3.7的TCS所产生的点的TES代码) At the beginning of the shader is a layout qualifier that sets the tessellation mode(在一开始的时候设置tessellation的模式). In this case,we selected the mode to be triangles(这里我们设置成了三角形). Other qualifiers, equal_spacing and cw,(其他的一些设置,比如equal_spacing,cw) indicate that new vertices should be generated equally spaced along the tessellated polygon edges and that a clockwise vertex winding order should be used for the generated triangles(这些参数的意思是,在细分曲面的时候,在边线上的分界点之间的间隔要相等,然后再产生图元的时候,需要用顺时针方向去组织三角形). We will cover the other possible choices in the “Tessellation” section in Chapter 8(我们将在第8章的时候,来讲解其他的关于Tessellation的一些内容).

The remainder of the shader assigns a value to gl_Position just like a vertex shader does(剩余的代码也就是给gl_Position赋值,就如同vertex shader). It calculates this using the contents of two more built-in variables(同时它使用到了另外的两个内置变量). The first is gl_TessCoord, which is the barycentric coordinate of the vertex generated by the tessellator(其中一个是gl_TessCoord,它是由tessellator产生的重心坐标). The second is the gl_Position member of the gl_in[] array of structures(第二个是gl_in数组,里面放着的是一堆gl_Position). This matches the gl_out structure written to in the tessellation control shader given in Listing 3.7(对应的gl_out的结构体和Listing3.7中的对应). This shader essentially implements pass-through tessellation(这个shader就是一个基本的简单的传输数据的tessellation). That is, the tessellated output patch is exactly the same shape as the original, incoming triangular patch(也就是最终输出的图形跟原来的patch代表的图元一模一样,没什么改变)

#version 450 core
layout (triangles, equal_spacing, cw) in;
void main(void)
{
gl_Position = (gl_TessCoord.x gl_in[0].gl_Position +
gl_TessCoord.y
gl_in[1].gl_Position +
gl_TessCoord.z * gl_in[2].gl_Position);
}
Listing 3.8: Our first tessellation evaluation shader

To see the results of the tessellator, we need to tell OpenGL to draw only the outlines of the resulting triangles(为了显示tessellation的结果,我们需要告诉OpenGL采用线框模式去绘制). To do this, we call glPolygonMode(), whose prototype is(这时候,我们需要使用glPolygonMode函数,它的定义如下:)

void glPolygonMode(GLenum face, GLenum mode);

The face parameter specifies which type of polygons we want to affect(face参数需要设置我们希望哪个面被影响). Because we want to affect everything, we set it to GL_FRONT_AND_BACK(因为我们希望影响到所有东西,所以我们设置成GL_FRONT_AND_BACK). The other modes will be explained shortly(其他的模式稍后再解释). mode says how we want our polygons to be rendered(模式设置的是你希望你的多边形如何被渲染). As we want to render in wireframe mode (i.e., lines)(由于我们希望它被渲染成线框模式,我们设置这个参数为GL_LINE), we set this to GL_LINE. The result of rendering our one triangle example with tessellation enabled and the two shaders of Listing 3.7 and Listing 3.8 is shown in Figure 3.1(完事之后,刚才的Listing3.7和Listing3.8的代码所渲染出来的结果就如同图3.1所示)

Tessellation(细分曲面)_第1张图片

本日的翻译就到这里,明天见,拜拜~~

第一时间获取最新桥段,请关注东汉书院以及图形之心公众号

东汉书院,等你来玩哦