GLSL-几何着色器详解跟实例(GS:Geometry Shader)[转]

【OpenGL4.0】GLSL-几何着色器详解和实例(GS:Geometry Shader)

一、什么是几何着色器(GS:Geometry Shader)


Input Assembler(IA)从顶点缓冲区上的输入流中接收顶点数据,并且把数据项转换为规范的格式。vertex
shader通常用来把顶点从模型空间变换到平面空间,vertex shader读取一个顶点,输出一个顶点。Pixel
Shader读取单一pixel属性,输出包含颜色和Z信息的的片断。而geometry
shader是DirectX10提出的,把同一区域的所有顶点作为输入,产生新的顶点或者区域。此外数据流输出(steam
output)把geometry shader输出的顶点信息复制为4个连续的输出缓冲子集。理论上来说,steam
output的输出能力和Input Assembler的输入能力相匹配。
Shader就是一段可以改变像素、顶点和几何学特征的小程序。Vertex Shader是专门处理多边形顶点的。那么Geometry
shader就是专门用来处理场景中的几何图形。在过去Vertex
Shader每一次运行只能处理一个顶点的数据,并且每次只能输出一个顶点的结果。在整个游戏场景中,绘制的几何图形的任务量非常庞大,如果仅仅依靠
Vertex Shader单一来完成,效率会极其低下。

现在DX10的设计师们在顶点与像素的处理过程中又加入了(Geometry
shader)几何着色器。它可以根据顶点的信息来批量处理几何图形,对Vertex附近的数据进行函数处理,快速创造出新的多边形。通过stream
out将这些结果传递给其他Shader或buffer,将CPU从复杂庞大的几何运算中解放出来。大爆炸,粒子效果,瀑布流水等复杂又关联的场景都可以
用Geometry shader很逼真的表现出来。

图一是渲染管线示意图。

图一 渲染管线示意图

GS位于VS与PS之间,可以完成许多模型层面上的工作诸如LOD。以往这些工作都是在CPU上完成的,占用了宝贵的CPU循环 —— CPU可是很繁忙的东西,游戏逻辑、音乐、输入接受都是靠它,却无法提高多少性能,CPU的并行计算性能是远远无法和GPU相比的。

二、几何着色器功能简介

GS被设计针对每个图元执行一次。它能够访问图元的所有顶点,以及与其相关的输入变量的值。换句话说,如果前一阶段提供了某一个输出变量,那么GS就可以访问图元中所有顶点的那个变量的值。因此,GS中的输入变量都是数组类型。

需要注意的是,GS所接受的图元和以前的不同,它只接受“可调整的”图元。

可调整的图元(Adjacency Primitive)

在OpenGL中,我们定义了新的图元类型:

GL_LINES_ADJACENCY_EXT 
GL_LINE_STRIP_ADJACENCY_EXT 
GL_TRIANGLES_ADJACENCY_EXT 
GL_TRIANGLE_STRIP_ADJECENCY_EXT

我们可以在glBegin()、glDrawElements()中将他们作为新的参数使用。下面分别说明这4中类型的特点。

(1)Lines with Adjacecy

4*N个顶点被提供,N是要绘制的线段的数目。线段在#1个#2之间绘制,#0和#3提供调整信息。

(2)Line Strip with Adjacency

顶点数目是N+3,N是要绘制的线段的数目。线段在#1、#2、。。。、#N+1之间绘制,#0和#N+2提供调整信息。

(3)Triangles with Adjacency

顶点数目是6*N,组成三角形的是#0、#2、#4.而#1、#3、#5定义了修正三角形。

(4)Triangle Strip with Adjacency

顶点数目是2N+4.#0、#2、。。。定义三角形序列。其他的定义调整三角形。

在着色器链接之前,必须调用glProgramParameter进行相应的设置。

(1)设置GS可以输出的最大顶点数目

glProgramParameteriEXT( progname, GL_GEOMETRY_VERTICES_OUT_EXT, int value )

(2)设置GS接收的图元的类型

glProgramParameteriEXT( progname, GL_GEOMETRY_INPUT_TYPE_EXT, int value )

需要注意的是,GS的输出图元的类型必须和输入图元的类型匹配。

value的可能取值是:

A、GL_POINTS

B、GL_LINES

对应的输入图元类型可以是:GL_LINES、GL_LINE_STRIP、GL_LINE_LOOP

C、GL_LINES_ADJACENCY_EXT

对应的输入图元类型可以是:GL_LINES_ADJACENCY_EXT、GL_LINES_STRIP_ADJACENCY_EXT

D、GL_TRIANGLES

对应的输入图元类型可以是:GL_TRIANGLES、GL_TRIANGLE_STRIP、GL_TRIANGLE_FAN

E、GL_TRIANGLE_ADJACENCY_EXT

对应的输入图元类型可以是:GL_TRIANGLES_ADJACENCY_EXT、GL_TRIANGLE_STRIP_ADJACENCY_EXT

(3)设置输出图元类型

glProgramParameteriEXT( progname, GL_GEOMETRY_OUTPUT_TYPE_EXT, int value )

value的可能取值是:

GL_POINTS

GL_LINE_STRIP

GL_TRIANGLE_STRIP

GS可以输出0个、1个或者多个图元。这些图元的类型和它从前一阶段接收到的图元的类型不一定相同。然而,GS不能输出多种类型的图元。比如,GS可以接收三角形,输出多个线段序列,或者是输出0个或多个三角形序列。

这就是的GS有多种用途。下面是几个典型例子。一个GS可以依据某些准则比如可见性来移除一些图元。GS也可以产生额外的图元扩大所渲染的对象的形状。GS也可以计算图元的额外信息,而把图元原封不动的输出。GS也可以输出和输入图元完全不同的图元。

GLSL中GS与VS的交互

在GS中,绿色正方形所表示的是由变量gl_VerticesIn所指定的,即最大维数。

GS内置输出变量:
varying out vec4 gl_FrontColor;
varying out vec4 gl_BackColor;
varying out vec4 gl_FrontSecondaryColor;
varying out vec4 gl_BackSecondaryColor;
varying out vec4 gl_TexCoord[]; // at most gl_MaxTextureCoords
varying out float gl_FogFragCoord;

GS内置输入变量:
varying in vec4 gl_FrontColorIn[gl_VerticesIn];
varying in vec4 gl_BackColorIn[gl_VerticesIn];
varying in vec4 gl_FrontSecondaryColorIn[gl_VerticesIn];
varying in vec4 gl_BackSecondaryColorIn[gl_VerticesIn];
varying in vec4 gl_TexCoordIn[gl_VerticesIn][]; // at most will be// gl_MaxTextureCoords
varying in float gl_FogFragCoordIn[gl_VerticesIn];
varying in vec4 gl_PositionIn[gl_VerticesIn];
varying in float gl_PointSizeIn[gl_VerticesIn];
varying in vec4 gl_ClipVertexIn[gl_VerticesIn];

GS的功能实现基于两个很重要的内置函数:EmitVertex和EndPrimitive.这两个函数使得GS能够传送多个顶点或者图元到管线的
下一阶段。GS为一个顶点定义输出变量,然后调用EmitVertex。之后,GS就能够接着定义下一个顶点的相关输出变量,再次调用
EmitVertex。在对图元的所有顶点完成相同的操作之后,GS调用EndPrimitive让OpenGL知道图元的所有顶点都传送完毕。如果没有
显式调用EndPrimitive,系统会隐式调用。不过显式调用是一个好的习惯,建议这么做。如果GS没有调用EmitVertex,那么输入的图元就
不会被渲染。

需要注意的是,GS保证输出由输入图元产生的结果的顺序和输入图元的顺序是相同的。这会造成性能上的影响。比如,多个着色器单元并行运算,结果必须
被保存然后进行排序。为了在兼容性和效率之间平衡,Shader  Model4.0做了一个限制:每一次执行最多只能产生1024个32位的值。

三、几何着色器运用实例

下面介绍一个实例:用GS实现一个粒子系统,绘制了很多上面贴了纹理的小正方形。

效果如下:

顶点着色器:

#version 400

layout (location = 0) in vec3 VertexPosition;

uniform mat4 ModelViewMatrix;
uniform mat3 NormalMatrix;
uniform mat4 ProjectionMatrix;

void main()
{
    gl_Position = ModelViewMatrix * vec4(VertexPosition,1.0);
}

几何着色器:

#version 400

layout( points ) in;
layout( triangle_strip, max_vertices = 4 ) out;

uniform float Size2;   // Half the width of the quad

uniform mat4 ProjectionMatrix;

out vec2 TexCoord;

void main()
{
    mat4 m = ProjectionMatrix;

    gl_Position = m * (vec4(-Size2,-Size2,0.0,0.0) + gl_in[0].gl_Position);
    TexCoord = vec2(0.0,0.0);
    EmitVertex();

    gl_Position = m * (vec4(Size2,-Size2,0.0,0.0) + gl_in[0].gl_Position);
    TexCoord = vec2(1.0,0.0);
    EmitVertex();

    gl_Position = m * (vec4(-Size2,Size2,0.0,0.0) + gl_in[0].gl_Position);
    TexCoord = vec2(0.0,1.0);
    EmitVertex();

    gl_Position = m * (vec4(Size2,Size2,0.0,0.0) + gl_in[0].gl_Position);
    TexCoord = vec2(1.0,1.0);
    EmitVertex();

    EndPrimitive();
}

片断着色器:

#version 400

in vec2 TexCoord;

uniform sampler2D SpriteTex;

layout( location = 0 ) out vec4 FragColor;

void main()
{
    FragColor = texture(SpriteTex, TexCoord);
}

GLSL-几何着色器详解跟实例(GS:Geometry Shader)[转]

时间: 2024-10-09 12:54:45

GLSL-几何着色器详解跟实例(GS:Geometry Shader)[转]的相关文章

顶点着色器详解 (Vertex Shaders)

学习了顶点处理,你就知道固定功能流水线怎么将顶点从模型空间坐标系统转化到屏幕空间坐标系统.虽然固定功能流水线也可以通过设置渲染状态和参数来改变最终输出的结果,但是它的整体功能还是受限.当我们想实现一个外来的光照模型,外来的Fog或者点大小计算方式,等等,我们可能就放弃使用固定功能流水线,转而使用CPU来实现这些计算. 使用vertex shaders,它用一段小程序替换固定功能处理.这段小程序的输入是模型空间的顶点,输出齐次剪裁空间的顶点,并且还携带一些信息,如:per-vertex diffu

Java---JUnita、注解与类加载器详解以及实例

JUnit软件测试技术(工具) 在项目中建立专门用户测试的包结构. 在Junit中,通过@Test注解,可以运行一个方法. ★ Junit注解说明 使用了@Test注解应该满足以下条件: 1) 必须是无参数的非静态方法. 2) 添加@Test注解的类,必须拥有一个无参数的公开构造 ★ JUnit测试示例演示 1.运行完成后,可以在Junit的窗口上看到运行所用的时间和结果信息. 2.被测试程序的运行结果出现在控制台(Console)上. "项目"代码: package cn.hncu.

python--装饰器详解

Python---装饰器详解 定义: 本质上是一个函数.作用是用来装饰另一个函数(即被装饰函数),给被装饰函数添加功能.前提是不能改变被装饰函数的源代码和调用方式.这样的一个函数称之为装饰器. 解析: 下面我们话不多说,直接用代码说明.下面是一个函数. 1 def add(): 2 b=1+2 3 print(b45 add() 程序输出: -------- 3 -------- 现在我要给这个函数增加一个解释性的句子,如下,我们可以编写一个装饰器: 1 #原函数 2 def add(): 3

Java学习-007-Log4J 日志记录配置文件详解及实例源代码

此文主要讲述在初学 Java 时,常用的 Log4J 日志记录配置文件详解及实例源代码整理.希望能对初学 Java 编程的亲们有所帮助.若有不足之处,敬请大神指正,不胜感激!源代码测试通过日期为:2015-1-30 13:54:02,请知悉. 所需的 jar 包下载链接为:http://yunpan.cn/cKE56sxqtQCfP  访问密码 63d8 有关 Log4J 日志文件中日志级别及文件配置的详细情况,在 Log4J 的配置文件(xml.properties)中有详细的介绍,敬请参阅!

Rxjava2 Observable的辅助操作详解及实例(二)

目录 8. TimeInterval 9. Timeout 9.1 timeout(timeout, timeUnit) 9.2 timeout(timeout, timeUnit, scheduler, other) 9.3 timeout(Function itemTimeoutIndicator, ObservableSource other) 10. Timestamp 11. Using 12. To 小结 接续上篇: Rxjava2 Observable的辅助操作详解及实例(一) 8

Rxjava2 Observable的辅助操作详解及实例(一)

目录 简要: 1. Delay 2. Do 3. SubscribeOn 4. ObserverOn 5. Serialize 6. Materialize 7. Dematerialize 接续: 简要: 需求了解: Rxjava中有一些方便的辅助操作符,来更方便我们的函数式的编程.比如延迟.定时.指定操作的监听.数据类型转换等一系列的操作. 下面列出了一些用于Observable的辅助操作符: Delay:延时发射Observable的结果. Do:注册一个动作作为原始Observable生

Rxjava2 Observable的数据过滤详解及实例(一)

目录 简要: 1. Debounce 1.1 debounce(timeout, unit) 1.2 debounce(debounceSelector) 2. Throttle 2.1 throttleFirst(windowDuration, unit) 2.2 throttleLast(intervalDuration, unit) 2.3 throttleWithTimeout(timeout, unit) 3. Sample 3.1 sample(period, unit) 3.2 s

Rxjava2 Observable的数据变换详解及实例(二)

目录 1. Window 1.1 window(closingSelector) 1.2 window(openingIndicator, closingIndicator) 1.3 window(count) 1.4 window(count, skip) 1.5 window(timespan, TimeUnit) 1.6 window(timespan, TimeUnit, count) 1.7 window(timespan, timeskip, TimeUnit) 2. GroupBy

Rxjava2 Observable的数据变换详解及实例(一)

目录 简要: 1.1 buffer(count) 1.2 buffer(boundary) 1.3 buffer(count, skip) 1.4 buffer(timespan, TimeUnit) 1.5 buffer(timespan, TimeUnit, count) 1.6 buffer(timespan, timeskip, TimeUnit) 1.7 buffer(bufferClosingSelector) 2. Map 3. FlatMap 3.1 flatMap(mapper