Geometry Shader Tutorials
2013-03-05 14:22 三戒1993 阅读(257) 评论(0) 编辑 收藏 举报Geometry Shader Tutorials
by Xie Yongming
15/11 2006
Introduction
Nvidia opened the geometry shader at November 13, 2006 , A geometry shader begins with a single primitive (point, line, triangle). It can read the attributes of any of the vertices in the primitive and use them to generate new primitives. A geometry shader has a fixed output primitive type (point, line strip, or triangle strip) and emits vertices to define a new primitive. A geometry shader can emit multiple disconnected primitives. The primitives emitted by the geometry shader are clipped and then processed like an equivalent OpenGL primitive specified by the application.
Thanks for Nvidia's developer great work!
Geometry shader fit into Opengl pipeline
First, vertex attributes are specified via immediate-mode commands or through vertex arrays. They can be conventional attributes (e.g., glVertex, glColor, glTexCoord) or generic (numbered) attributes. Vertices are then transformed, either using a vertex shader or fixed-function vertex processing. Fixed-function vertex processing includes position transformation (modelview and projection matrices), lighting, texture coordinate generation, and other calculations. The results of either method are a "transformed vertex", which has a position (in clip coordinates), front and back colors, texture coordinates, generic attributes (vertex shader only), and so on. Note that on many current GL implementations, vertex processing is performed by executing a "fixed function vertex shader" generated by the driver. After vertex transformation, vertices are assembled into primitives, according to the topology (e.g., TRIANGLES, QUAD_STRIP) provided by the call to glBegin(). Primitives are points, lines, triangles, quads, or polygons, but instead decompose them into triangles as permitted by the spec.
After initial primitive assembly, a geometry shader is executed on eachindividual point, line, or triangle primitive, if one is active. It can read the attributes of each transformed vertex, perform arbitrary computations, and emit new transformed vertices. These emitted vertices are themselves assembled into primitives according to the output primitive type of the geometry shader.
Then, the colors of the vertices of each primitive are clamped to [0,1](if color clamping is enabled), and flat shading may be performed by taking the color from the provoking vertex of the primitive. Each primitive is clipped to the view volume, and to any enabled user-defined clip planes. Color, texture coordinate, and other attribute values are computed for each new vertex introduced by clipping. After clipping, the position of each vertex (in clip coordinates) is converted to normalized device coordinates in the perspective division (divide by w) step, and to window coordinates in the viewport transformation step. At the same time, color values may be converted to normalized fixed-point values according to the "Final Color Processing" portion of the specification. After the vertices of the primitive are transformed to window coordinate, the GL determines if the primitive is front- or back-facing. That information is used for two-sided color selection, where a single set of colors is selected from either the front or back colors associated with each transformed vertex. When all this is done, the final transformed position, colors (primary and secondary), and other attributes are used for rasterization (Chapter 3 in the OpenGL 2.0 Specification). When the raster position is specified (via glRasterPos), it goes through the entire vertex processing pipeline as though it were a point. However, geometry shaders are never run on the raster position.
Geometry shader setup for GLSL
Nvidia's NVemulate allows you to emulate the functionality of various GPUs (very slowly) in software. In addition, you can use it to control GLSL Support. New in this version of NVemulate:
- Support for GeForce 8 Series
- Include support enable for EXT_gpu_shader4, EXT_geometry_shader4, and EXT_bindable_uniform
GLSL support is enabled by default in Nvidia's Release 95 drivers, but you can enable/disable the enhanced GLSL support as well as manipulate software emulation of GPU feature sets and control the dumping of GLSL source and assembly text for debugging, The NVemulate control panel looks like this:
![nevemulate.png](http://appsrv.cse.cuhk.edu.hk/~ymxie/Geometry_Shader/nevemulate.png)
To enable the enhanced GLSL functionality, select the “G80(GeForce 8800 GTS, Quadro FX)” option from the GLSL compiler device support drop box and press the “Apply” button. No changes to NVemulate settings take effect until the “Apply” button is pressed.
Pressing the “Restore” button reverts the display settings to the driver’s current applied state. With the G80 functionality enabled, the driver will export an additional set of extension strings exposing the enhanced capabilities. The extensions string will
now include GL_EXT_gpu_shader4, GL_EXT_geometry_shader4, and GL_EXT_bindable_uniform. Additionally, the GLSL parts of the GL_NV_transform_feedback extension are now also enabled. Furthermore, all GLSL shaders not using these capabilities will now be compiled
to the more capable G80 target. This enables better dynamic flow control and array indexing, among other benefits. As noted earlier, some graphics cards are not capable of GLSL or enhanced GLSL in hardware, so this may require enabling a higher hardware emulation
level. (A minimum of NV30 for GLSL and a minimum of G80 for the enhancements)
here three extensions are required:
- GL_ARB_fragment_shader
- GL_ARB_vertex_shader
- GL_EXT_geometry_shader4
#include <GL/glew.h>
#include <GL/glut.h>void main(int argc, char **argv)
{glutInit(&argc, argv);
...
glewInit();
if (GL_ARB_vertex_shader && GL_ARB_fragment_shader&&GL_EXT_geometry_shader4)
printf("Ready for GLSL/n");
else {
printf("Not totally ready :( /n");
exit(1);
}setShaders();
glutMainLoop();
}
#include <GL/glew.h>
#include <GL/glut.h>void main(int argc, char **argv)
{glutInit(&argc, argv);
...
glewInit();
if (glewIsSupported("GL_VERSION_2_1"))
printf("Ready for OpenGL 2.0/n");
else {
printf("OpenGL 2.1 not supported/n");
exit(1);
}setShaders();
glutMainLoop();
}
Creating a Program
The figure bellow shows the necessary steps (in OpenGL 2.0 syntax) to create the geometry shader, the functions used will be detailed in latter sections.
The first step is creating an object which will act as a program container. The function available for this purpose returns a handle for the container.
The syntax for this function, in OpenGL 2.0 syntax is as follows:
GLhandleARB glCreateProgramObjectARB(void);
void glProgramParameteriEXT(GLhandleARB program, enum pname, int value);
Geometry shader Input Primitives
glProgramParameteriEXT with <pname> set to GEOMETRY_INPUT_TYPE_EXT and <value> set to one of POINTS, LINES,
LINES_ADJACENCY_EXT, TRIANGLES or TRIANGLES_ADJACENCY_EXT.
glProgramParameteriEXT(GLhandleARB program,GL_GEOMETRY_INPUT_TYPE_EXT ,GL_LINES_ADJACENCY_EXT);
Geometry Shader Output Primitives
The output primitive type is a parameter of the program object, and can be set by calling glProgramParameteriEXT with <pname> set to GL_GEOMETRY_OUTPUT_TYPE_EXT and <value> set to one of GL_POINTS, GL_LINE_STRIP or GL_TRIANGLE_STRIP.
glProgramParameteriEXT(GLhandleARB program,GL_GEOMETRY_OUTPUT_TYPE_EXT ,GL_LINE_STRIP);
Geometry Shader outputs
A geometry shader is limited in the number of vertices it may emit per invocation. The maximum number of vertices a geometry shader can possibly emit needs to be set as a parameter of the program object that contains the geometry shader. call ProgramParameteriEXT
with <pname> set to GEOMETRY_VERTICES_OUT_EXT and <value> set to the maximum number of vertices the geometry shader will emit in one invocation. This setting will not be guaranteed to be in effect until the next time LinkProgram has been called successfully.
If a geometry shader, in one invocation, emits more vertices than the value GEOMETRY_VERTICES_OUT_EXT, these emits may have no effect.
glGetIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT,&temp);
glProgramParameteriEXT(GLhandleARB program,GL_GEOMETRY_VERTICES_OUT_EXT,<temp)
To attach a shader to a program use the OpenGL 2.0 function:
void glAttachObjectARB(GLhandleARB program, GLhandleARB shader);
Parameters:
- program - the handler to the program.
- shader - the handler to the shader you want to attach.
The syntax for the link function, in OpenGL 2.0, is as follows:
void glLinkProgramARB(GLhandleARB program);
Parameters:
- program - the handler to the program.
After the link operation the shader's source can be modified, and the shaders recompiled without affecting the program.
As shown in the figure above, after linking the program, there is a function to actually load and use the program, (ARB extension) glUseProgramObjectARB, or (OpenGL 2.0) glUseProgram. Each program is assigned an handler, and you can have as many programs linked and ready to use as you want (and your hardware allows).
The syntax for this function is as follows (OpenGL 2.0 notation):
void glUseProgramObjectARB(GLhandleARB prog);
Parameters:
- prog - the handler to the program you want to use, or zero to return to fixed functionality
Creating a shader
The first step is creating an object which will act as a shader container. The function available for this purpose returns a handle for the container.
The OpenGL 2.0 syntax for this function is as follows:
GLhandleARB glCreateShaderObjectARB(GLenum shaderType);
Parameter:
- shaderType - GL_GEOMETRY_SHADER_EXT.
You can create as many shaders as you want to add to a program, but remember that there can only be amain function for the set of vertex shaders and one main function for the set of fragment shaders in each single program.
The following step is to add some source code. The source code for a shader is a string array.
void glShaderSourceARB(GLhandleARB shader, int numOfStrings, const char **strings, int *lenOfStrings);
Parameters:
- shader - the handler to the shader.
- numOfStrings - the number of strings in the array.
- strings - the array of strings.
- lenOfStrings - an array with the length of each string, or NULL, meaning that the strings are NULL terminated.
Finally, the shader must be compiled. The function to achieve this using OpenGL 2.0 is:
void glCompileShaderARB(GLhandleARB shader);
Parameters:
- shader - the handler to the shader.
Creating a geometry shader
#version 120
where number must be a version of the language, following the same convention as __VERSION__ above. The directive “#version 120” is required in any shader that uses version 1.20 of the language.
#extension GL_EXT_geometry_shader4 : enable
where extension_name is the name of an extension. Extension names are not documented in this specification.
Geometry language built-in outputs: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;
Geometry language input varying variables:
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];
Geometry Shader Function
This section contains functions that are geometry language specific.Syntax:
void EmitVertex();
void EndPrimitive();
Description:
The function EmitVertex() specifies that a vertex is completed. A vertex is added to the current output primitive using the current values of the varying output variables and the current values of the special built-in output variables gl_PointSize, gl_ClipVertex,
gl_Layer, gl_Position and gl_PrimitiveID. The values of any unwritten output variables are undefined. The values of all varying output variables and the special built-in output variables are undefined after a call to EmitVertex(). If a geometry shader, in
one invocation, emits more vertices than the valueGEOMETRY_VERTICES_OUT_EXT, these emits may have no effect.
The function EndPrimitive() specifies that the current output primitive is completed and a new output primitive (of the same type) should be started. This function does not emit a vertex. The effect of EndPrimitive() is roughly equivalent to calling End followed by a new Begin, where the primitive mode is taken from the program object parameter GEOMETRY_OUTPUT_TYPE_EXT. If the output primitive type is POINTS, calling EndPrimitive() is optional.
#version 120
#extension GL_EXT_geometry_shader4 : enablevoid main(void)
{
mat4x4 bezierBasis=mat4x4( 1, -3, 3, -1, 0, 3, -6, 3 , 0, 0, 3, -3 , 0, 0, 0, 1);
for(int i=0; i<64; i++)
{
float t = i / (64.0-1.0);
vec4 tvec= vec4(1, t, t*t, t*t*t);
vec4 b =tvec*bezierBasis;
vec4 p = gl_PositionIn[0]*b.x+ gl_PositionIn[1]*b.y+ gl_PositionIn[2]*b.z+ gl_PositionIn[3]*b.w;
gl_Position =p;
EmitVertex();
}
EndPrimitive();
}
Demo&source code.
Demo :
Download Demo: Demo.zip for windows XP.
source code: EMAIL to ymxie@cse.cuhk.edu.hk
References