GLSL 高级教程 – Geometry Shader

来源:互联网 发布:淘宝收藏夹分类没有了 编辑:程序博客网 时间:2024/06/10 11:13

The geometry shader is part of the specification since OpenGL 3.2.

This stage is optional. When present, a geometry shader receives as input the primitives assembled in the previous stage. A geometry shader does not receive strips, fans, or loops. The geometry shader receives the assembled primitives. So if the draw command specifies triangle strips, the geometry shader actually receives triangles.

The geometry shader, as opposed to the vertex shader, has full knowledge of the primitive it is working on. For each input primitive, the geometry shader has access to all the vertices that make up the primitive, including adjacency information, if specified.

The available geometry shader input primitives are:

  • points (1)
  • lines (2)
  • lines_adjacency (4)
  • triangles (3)
  • triangles_adjacency (6)

In parenthesis, it is represented the number of vertices per primitive.

Note that the inputs of the geometry shader must match the primitive of the OpenGL draw instruction as described in the primitive assembly section.  When receiving primitives with adjacency information, lines_adjacency ortriangles_adjacency, the order of the vertices are as presented in the figure below:



The output primitive types available are:

  • points
  • line_strip
  • triangle_strip

A match between the input and output is not required. For instance, a geometry shader can receivetriangles and outputpoints or a line_strip.

The output of a geometry shader can be zero or more primitives. For instance, if outputting triangle strips, a geometry shader can output three strips, with two triangles each. The input primitive is always discarded after the shader execution.

This means that the geometry shader, if it choses not to produce any output primitives for a particular input primitive, is in effect providing some sort of culling.

It also means that the geometry shader can output multiple primitives per input primitive. Note however, that the geometry shader is not designed to provide mass amplification of geometry, for instance, it is not adequate for tesselation purposes.

Both the input and output primitive types must be declared in the shader using thelayout qualifier. Assuming that the input primitive type istriangles and that the output primitive type isline_strip, our shader’s code could begin as follows:

1
2
3
4
5
6
// geometry shaders require at least version 1.5
#version 150
 
layout (triangles) in;
layout (line_strip, max_vertices = 4) out;
...

The max_vertices limits the number of vertices that the geometry shader will output. This is for real! If we try to output more vertices than stated, the exceeding vertices will not be sent to the remaining of the pipeline.

As of OpenGL 4.0, a geometry shader can be invoked more than once for each input primitive. The number of invocations is determined by the input layout qualifier. For instance to state that the geometry shader should run twice for each input primitive we write:

1
2
3
4
5
#version 400
 
layout (triangles, invocations = 2) in;
layout (line_strip, max_vertices = 4) out;
...

If the invocations is absent in the layout, then the shader will run once for each input primitive.

Besides user defined vertex attributes, defined as outputs in the vertex shader, geometry shaders can access uniform variables and textures.

The following built-in variables are available:

in gl_PerVertex {    vec4  gl_Position;    float gl_PointSize;    float gl_ClipDistance[];} gl_in[];in int gl_PrimitiveIDIn;// only for OpenGL 4.0+in int gl_InvocationID;

Note that the inputs of the geometry shader in struct gl_PerVertex match the outputs of the homonimous output struct in the vertex shader, but this time are in array format. Thegl_PrimitiveID variable stores the index of the primitive generated by the Draw* family of OpenGL commands.

Although the geometry shader conceptually outputs primitives, in practice it is as if it outputs vertices. So, if the output primitive is a triangle, the geometry shader should write the attributes of three vertices. Vertices are then assembled into primitives according to the output layout. For each vertex the following built-in variables may be used:

out gl_PerVertex {    vec4  gl_Position;    float gl_PointSize;    float gl_ClipDistance[];};out int gl_PrimitiveID;out int gl_Layer;// only for OpenGL 4.1+out int gl_ViewportIndex;

As in the vertex shader, gl_Position is optional, but the following stages may rely on it for interpolation purposes.gl_PrimitiveID should be written at least for theprovoking vertex. As forgl_Layer and gl_ViewportIndex, if specified, all vertices of a primitive must write the same value. If not specified, i.e. if the geometry shader does not write togl_ViewportIndex orgl_Layer, then theirs values will be zero.

The geometry shader can specify, per primitive, a layer for drawing. This allows the geometry shader to specify multiple primitives, and direct them to different layers. Layered rendering implies the usage of framebuffers, otherwise the gl_Layer value is ignored. An example of layered rendering usage is for rendering, in a single pass, the six faces of a cube map.

As of OpenGL 4.1, a geometry shader can also select a viewport to output to. Multiple views can be rendered simultaneously with this feature.

Besides the built-in variables, the geometry shader may declare, and write to, user-defined variables. As in the previous shaders, the output of a geometry shader can be redirected to a buffer (or set of buffers) using transform feedback.


原创粉丝点击