opengles中的Tessellation(曲面细分)

    从opengles3.2开始,支持了一项新的特性,Tessellation Shader,这是一个新的shader,发生在顶点处理阶段,曲面细分可以在显卡上动态生成新的顶点和面,这在支持gles3.2的设备上,可以用来表现模型的lod,我们不用传输大量的顶点数据给显卡,而使显卡能够根据一定规则自动生成细节层次更多的顶点。也有应用结合高度图生成细节更加复杂的模型,因为不用再cpu这边准备高面数的模型,减轻了内存和cpu的负担,使用建模表现高模的一种硬件加速方法。


    因为支持gles3.2的设备还不多,所以还找不到太多应用这个新特性的例子,不过可以先看下3.2新的管线

可以看到早vertex shader后面新加了三道流程,Tessell Control Shader,Tessellation Primitive Generator,Tesselation Evaluation Shader。这三者共同完成曲面细分的硬件处理。

 

   1. 首先是TCS,这是一个可编程管线,但是是可选的,如果没有会使用一个默认的参数。它的输入是patch原语。我们知道原语比较典型的有点 线 三角形 四边形,在tessellation这里多了一种原语patch,一个patch不是一个点也不是一个三角形,而是一个顶点序列,这个顶点序列就是产生细分曲面的基础顶点。在这个过程中一般要定义生成多少个细分曲面,这个要定义两个量,innersize,outsize。这里还可以对patch做一些调整操作,设置每个patch的序列长度,这些量将在下一个过程使用。


   2.然后是TPG,这是一个固定管线,它负责真正的进行曲面细分,它利用上一步进来的patch,以及innersize ,outsize,以及space策略细分曲面,如下图

对外围的三角形进行了曲面细分后,生成了中间更多的顶点。这里面的输出是细分后的每个顶点及其顶点属性,在这里的顶点位置属性是相对的在0-1之间。


 3.最后一步是TES,这是一个编程管线,且必须有,如果没有这个shader,则不发生曲面细分。这个shader将根据上一步进来的每个细分产生的顶点的绝对坐标,生成顶点真实的坐标。



本文不作Tessellation Shader的基本介绍。直接给出细分曲线的”Hellow World“代码。

下面代码将使用Tessellation Shader,传入2个控制点的情况下绘制一条正弦曲线连接这2个控制点。

效果如下图:(细分数目分别为1,8,32)



Vertex Shader:

  1. #version 400
  2. layout (location = 0) in vec3 in_Vertex;
  3. uniform mat4 ModelViewProjectionMatrix;
  4. void main()
  5. {
  6. gl_Position = vec4(in_Vertex, 1);
  7. }
就这么简单。Vertex Shader原封不动的把传入的点传给下一道渲染工序:Tessellation Control Shader。

Tessellation Control Shader(TCS):

  1. #version 400
  2. layout( vertices= 4 ) out;
  3. void main()
  4. {
  5. // Pass along the vertex position unmodified
  6. gl_out[gl_InvocationID].gl_Position = gl_in[gl_InvocationID].gl_Position;
  7. gl_TessLevelOuter[ 0] = float( 1);
  8. gl_TessLevelOuter[ 1] = float( 32);
  9. }
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):

  1. #version 400
  2. layout( isolines ) in;
  3. uniform mat4 ModelViewProjectionMatrix;
  4. void main()
  5. {
  6. float u = gl_TessCoord.x;
  7. vec3 p0 = gl_in[ 0].gl_Position.xyz;
  8. vec3 p1 = gl_in[ 1].gl_Position.xyz;
  9. float leng = length(p1 - p0)/ 2.0;
  10. // Linear interpolation
  11. vec3 p;
  12. p.x = p0.x*u + p1.x*( 1-u);
  13. p.y = p0.y + leng* sin(u* 2* 3.1415);
  14. // Transform to clip coordinates
  15. gl_Position = ModelViewProjectionMatrix * vec4(p, 1);
  16. }

这里就是最关键的细分曲线算法了。

首先看到layout( isolines ) 的申明。这就告诉了TES我们使用的细分类型为曲线。这样,这里的gl_TessCoord.x,对于曲线来说我们只用到x分量就够了,他的取值范围在[0, 1]之间自动插值(根据Tessellation Control Shader中设置的分段数)

对于传入的2个控制点p0和p1,我们计算两点之间的长度,然后使用[0, 2*pi]区间,绘制一条正弦曲线。最后进行MVP坐标转换输出。


 Fragment Shader

  1. #version 400
  2. void main()
  3. {
  4. gl_FragColor = vec4( 1, 0, 0, 1.0);
  5. }
这个不是关键,能多简单我就多简单了。

OpenGL代码:

  1. pShader->sendUniform( string( "ModelViewProjectionMatrix"), value_ptr(matMVP2));
  2. gl::BindVertexArray(_vertexArrayBlock);
  3. gl::EnableVertexAttribArray( 0);
  4. gl::PatchParameteri(GL_PATCH_VERTICES, 2);
  5. gl::DrawArrays(GL_PATCHES, 0, 2);
  6. gl::BindVertexArray( 0);
  7. gl::DisableVertexAttribArray( 0);


这里看到绘制类型一定只能为GL_PATCHES,另外注意设置Patch参数为GL_PATCH_VERTICES。由于只有2个控制点,DrawArrays传递参数2.

【注】2个控制点的VBO或者VAO的设置,以及4个Shader的编译、链接等步骤,这里就省略不写了。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值