本文不作Tessellation Shader的基本介绍。直接给出细分曲线的”Hellow World“代码。
下面代码将使用Tessellation Shader,传入2个控制点的情况下绘制一条正弦曲线连接这2个控制点。
效果如下图:(细分数目分别为1,8,32)
Vertex Shader:
#version 400 layout (location = 0) in vec3 in_Vertex; uniform mat4 ModelViewProjectionMatrix; void main() { gl_Position = vec4(in_Vertex, 1); }就这么简单。Vertex Shader原封不动的把传入的点传给下一道渲染工序:Tessellation Control Shader。
Tessellation Control Shader(TCS):
#version 400 layout( vertices=4 ) out; void main() { // Pass along the vertex position unmodified gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position; gl_TessLevelOuter[0] = float(1); gl_TessLevelOuter[1] = float(32); }Tessellation Control Shader干了两件事情。
第一:把输入的控制点的坐标信息(gl_in[gl_InvocationID].gl_Position)原封不动的输出。
第二:设置了细分控制参数。对于不同的细分类型(这里是曲线细分,会在下一个shader中看到细分类型的选择),这2个参数意义不一样。
gl_TessLevelOuter[0]表示要生成几条曲线。这里我们选择1条。
gl_TessLevelOuter[1] 表示将曲线细分成几段。这个很是决定细分程度的关键参数。我们分别使用1、8、32测试。
【注意】gl_TessLevelOuter[0]与gl_TessLevelOuter[1]的意义,在ATI显卡和NV显卡中是相反的!我这里以NV的卡为例。
Tessellation Evaluation Shader(TES):
#version 400 layout( isolines ) in; uniform mat4 ModelViewProjectionMatrix; void main() { float u = gl_TessCoord.x; vec3 p0 = gl_in[0].gl_Position.xyz; vec3 p1 = gl_in[1].gl_Position.xyz; float leng = length(p1 - p0)/2.0; // Linear interpolation vec3 p; p.x = p0.x*u + p1.x*(1-u); p.y = p0.y + leng*sin(u*2*3.1415); // Transform to clip coordinates gl_Position = ModelViewProjectionMatrix * vec4(p, 1); }
这里就是最关键的细分曲线算法了。
首先看到layout( isolines ) 的申明。这就告诉了TES我们使用的细分类型为曲线。这样,这里的gl_TessCoord.x,对于曲线来说我们只用到x分量就够了,他的取值范围在[0, 1]之间自动插值(根据Tessellation Control Shader中设置的分段数)
对于传入的2个控制点p0和p1,我们计算两点之间的长度,然后使用[0, 2*pi]区间,绘制一条正弦曲线。最后进行MVP坐标转换输出。
Fragment Shader
#version 400 void main() { gl_FragColor = vec4(1, 0, 0, 1.0); }这个不是关键,能多简单我就多简单了。
pShader->sendUniform(string("ModelViewProjectionMatrix"), value_ptr(matMVP2)); gl::BindVertexArray(_vertexArrayBlock); gl::EnableVertexAttribArray(0); gl::PatchParameteri(GL_PATCH_VERTICES, 2); gl::DrawArrays(GL_PATCHES, 0, 2); gl::BindVertexArray(0); gl::DisableVertexAttribArray(0);
这里看到绘制类型一定只能为GL_PATCHES,另外注意设置Patch参数为GL_PATCH_VERTICES。由于只有2个控制点,DrawArrays传递参数2.
【注】2个控制点的VBO或者VAO的设置,以及4个Shader的编译、链接等步骤,这里就省略不写了。