Geometry shader总结

摘要:
什么是GeometryShaderGS?它存在于vertex着色器和固定函数vertex st processingstage之间。它是可选的,但不是必需的。然而,Geometry有一个关键的内置输出变量:outouttgl_Layer,它正好是可以绘制的层数。三角形有三个顶点。这组三个顶点将同时进入几何体,因此您可以在几何体中获得gl_[]中的内置数组。绘制时,此数组的大小应与一组顶点的数量一致。三角形为3。calls=n表示Geometry对每组顶点执行n个操作,使用gl_InvocationID标记每个操作的序列号。接下来,只需在Fragment_Layer中获取此gl,即可根据需要逐层处理。

什么是Geometry Shader

GS存在于vertext shader和固定功能vertex post-processing stage之间,它是可选的不是必要的。
GS的输入是单个primitive,输出可能是0个或多个primitive. 

Geometry shader总结第1张

GS的作用

GS的主要作用就是从已有的primitive中生成新的primitive,它可以“无中生有”的生成新的顶点

OpenGL官网上提到两种用法:

  Layered rendering: 对一个primitive,不改变rendertarget渲染出多个图片
  Transform Feedback: 用来执行GPU的计算任务(pre-compute shader)

Real-time rendering书中提到了几种效果可以用GS来实现:

  creating various sized particles from point data

      extruding fins along silhouettes for fur rendering

      finding object edges for shadow algorithms

下图是个例子,给GS输入一个三角形,GS输出4个三角形

Geometry shader总结第2张

Layered Rendering

上面说到了,GS的一大用处体现在layerd rendering,即多层渲染。

试想一下,对于多层纹理而言,每一层的纹理坐标实际上是相同的。层号如何指定呢?固然可以在建立VBO时给纹理坐标第三个维度值,但是这并不会让OpenGL画到你想画的层上:Fragment的过程就是将顶点像素化的过程,而这个过程是二维的……最后拿到的二维图像必然没有深度,层数无从谈起。

但是Geometry却有个关键的内建输出变量:out int gl_Layer,正是它能够指定绘制的层数。我们不妨先将我写出来的geometry shader的内容贴出来,注意显卡至少要支持到OpenGL 4.0,#version这句至少是400:

 1 #version 450
 2 layout (triangles, invocations = 2) in; //输入三角形,2次调用
 3 layout (triangle_strip, max_vertices = 3) out;  //输出三角形
 4 in vec2 gTexCoord[];    //从Vertex传过来的纹理坐标
 5 out vec2 fTexCoord;     //传到Fragment去的纹理坐标
 6 out int gl_Layer;   //层数的标记
 7 void main()
 8 {
 9     for(int k=0; k<gl_in.length(); k++)   //针对三角形每个顶点
10     {
11         gl_Layer = gl_InvocationID;    //用调用编号标记层号
12         fTexCoord = gTexCoord[k];    //纹理坐标传递
13         gl_Position = gl_in[k].gl_Position;    //顶点坐标传递
14         EmitVertex();    //开始传递顶点信息,对每个顶点调用一次
15     }
16     EndPrimitive();    //结束一个primitive,一个primitive调用一次
17 }

 需要注意的是,triangles意味着你在OpenGL的绘制指令必须是GL_TRIANGLEGL_TRIANGLE_STRIP或者GL_TRIANGLE_FAN。其他的对应关系可以在Wiki查到。三角形有3个顶点,这一组3个顶点将同时进入Geometry中,因此在Geometry中能拿到一个gl_in[]的内建数组,这个数组的大小应该跟绘制时一组顶点的数量一致,三角形就是3。而在这里我不需要增加顶点,因此输出也还是3个顶点。同时纹理坐标也理所当然地变成了数组。因此需要一个循环来对三角形的每个顶点进行操作。

这里顶点坐标和纹理坐标都不必改,因此直接传递过去了。重点在于gl_Layer这一句。gl_Layer这个内建变量用于指示当前绘制的层号,这个值将影响像素化后像素绘制到哪一层上。OpenGL要求一组顶点(这里是一个三角形)内部的gl_Layer必须一致。这里赋值之后顺便把它传到Fragment里作为标志。
关键的一步在于第二行的invocations = 2gl_InvocationID这个内建变量。invocations=n指示Geometry对每组顶点做n次运算,用gl_InvocationID来标记每次运算的序号。我们可以将这个序号送到gl_Layer来作为层号的值!这样geometry就会将这一组顶点重复发送两次,而这两次是发送到不同层上的,从而实现不同层的绘制!

接下来只要在Fragment里拿到这个gl_Layer,根据需要分层作处理就可以了。

用Transform feedback创建粒子系统

粒子系统是为了模仿一些自然现象(比如烟,灰尘,烟火,雨等)所使用的技术的一个通用名字。在这些现象中,共同的地方就是它们是由大量的小粒子所组成,这些小的粒子以某种方式在一起移动,这样就构成了一种自然现象。

DirectX10 介绍了一个新的特性叫 Stream Output,这个对于粒子系统的实现是非常有用的。OpenGL 在 3.0
版本之后也加入了这个特性——Transform Feedback,其实现思路是在 GS(如果没有使用 GS 则是
VS)处理之后,我们可以将变换之后的图元存放到一个特殊的缓存——Transform Feedback Buffer
中。此外,我们可以决定图元是否将继续按照以前的流程进行光栅化。在下一帧渲染的时候,上一帧中输出的顶点信息可以在这一帧中作为顶点缓存使用,在这样的一个循环过程中,我们可以不借助于应用程序来实现对粒子信息的更新。下面这幅图片介绍了 Transform Feedback Buffer 在管线中所处的位置。

 Geometry shader总结第3张

免责声明:文章转载自《Geometry shader总结》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Centos7离线部署redis集群React Native环境搭建下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

RenderSettings 渲染设置

在Edit->RenderSettings里设置 Fog: 激活或不激活 Fog Color:雾的颜色,仅RGB起作用。 Fog Mode:显示方式 Linear线性 Exp指数 Exp2 指数2 Fog Density:雾化的强度 Linear Fog Start:开始距离 Linear Fog End:结束距离 Ambien...

fragment 中利用spinner实现省市联动

(1)布局文件就不在说明了,主要说代码的实现,先把代码贴上! package com.example.cl; import android.annotation.SuppressLint; import android.app.Fragment; import android.os.Bundle; import android.view.Layo...

使用FragmentTabHost+TabLayout+ViewPager实现双层嵌套Tab

大多数应用程序都会在底部使用3~5个Tab对应用程序的主要功能进行划分,对于一些信息量非常大的应用程序,还需要在每个Tab下继续划分子Tab对信息进行分类显示. 本文实现采用FragmentTabHost+TabLayout+ViewPager实现双层嵌套Tab,实现原理如下: 第一层Tab:FragmentTabHost + Fragment; 第二层T...

box2d HelloWorld

源地址:http://www.cocoachina.com/blog/blog.php?do=showone&uid=4039&type=blog&cid=&itemid=927 一、 HelloWorld开始之前,我假想你已经看过了HelloWorld的源代码,并看了用户手册中关于HelloWorld的相关说明,而且已经大...

Unity Shader之模板测试

Unity Shader之模板测试一沙一世界,一花一天堂 一、Stencil testing   渲染管线     当片段着色器处理完一个片段之后,模板测试(Stencil Test)会开始执行,和深度测试一样,它也可能会丢弃片段。接下来,被保留的片段会进入深度测试,它可能会丢弃更多的片段。模板测试是根据又一个缓冲来进行的,它叫做模板缓...

Android FragmentActivity onActivityResult冲突问题

场景:假设fragment的填充数据是ListView,ListView中的每一项都有button,点击每一项的button跳转到B界面。在B界面处理完业务需返回fragment中更新数据。 解决方式:1.在FragmentActivity中重写: @Overridepublic void onActivityResult(int requestCod...