Primitives are ways that OpenGL interprets vertex streams, converting them from vertices into triangles, lines, points, and so forth.
A vertex stream is an ordered list of vertices sent by an OpenGL drawing command. These get processed by a vertex shader into post-transform vertices.
Primitives define how OpenGL interprets a vertex stream. OpenGL can draw a vertex stream as points, lines or triangles. The primitive used to interpret a stream is given by the command used to render that stream.
There is only one kind of point primitive: GL_POINTS. This will cause OpenGL to interpret each individual vertex in the stream as a point.
Points are squares or circles of a given size. The size can be given in two methods: by the program or by the context's state. To switch between them, use
glEnable/glDisable(GL_PROGRAM_POINT_SIZE). If GL_PROGRAM_POINT_SIZE is enabled, then the point size comes from a built-in variable:
float gl_PointSize. If it is disabled, the point size is constant for all points in a primitive, and is set by the
Regardless of how the point size is defined, it must be greater than 0, or else undefined behavior results. There is an implementation-defined range for point sizes, and the size given by either method is clamped to that range. You can query the range with GL_POINT_SIZE_RANGE (returns 2 floats). There is also a point granularity that you can query with GL_POINT_SIZE_GRANULARITY; the implementation will clamp sizes to its granularity as needed.
Point Fragment Inputs
Because a single point can generate multiple fragments, it is useful to know exactly where on the point a particular fragment is. A fragment shader gets the same input values for all user-defined inputs (
gl_FragCoord will change, per the fragment's lcoation); therefore, the fragment shader must do its own interpolation.
To assist in this, the fragment shader can use the built-in input
vec2 gl_PointCoord. This gives coordinates on the range [0, 1]. The location of (0, 0) depends on the point parameter setting for GL_POINT_SPRITE_COORD_ORIGIN: if it is set to GL_LOWER_LEFT, then (0, 0) is the bottom-left coordinate. While if it is GL_UPPER_LEFT, then (0, 0) is the top-left coordinate.
There are 3 kinds of line primitives, based on different interpretations of a vertex stream.
- GL_LINES: Vertices 0 and 1 are considered a line. Vertices 2 and 3 are considered a line. And so on. The user must specify an even number of vertices in the stream to use this.
- GL_LINE_STRIP: The adjacent vertices are considered lines. Thus, if you pass n vertices, you will get n-1 lines.
- GL_LINE_LOOP: As line strips, except that the first and last vertices are also used as a line. Thus, you get n lines for n input vertices.
There are 3 kinds of triangle primitives, based again on different interpretations of the vertex stream:
- GL_TRIANGLES: Vertices 0, 1, and 2 form a triangle. Vertices 3, 4, and 5 form a triangle. And so on. The vertex stream must be a number of vertices divisible by 3 to work.
- GL_TRIANGLE_STRIP: Every group of 3 adjacent vertices forms a triangle. The face direction of triangles started on odd-numbered vertices are effectively reversed, due to different winding orders. A vertex stream of n length will generate n-2 triangles.
- GL_TRIANGLE_FAN: The first vertex is always held fixed. From there on, every group of 2 adjacent vertices form a triangle with the first. So with a vertex stream, you get a list of triangles like so: (0, 1, 2) (0, 2, 3), (0, 3, 4), etc. A vertex stream of n length will generate n-2 triangles.
These are special primitives that are expected to be used specifically with Geometry Shaders (GS). These primitives give the geometry shader more vertices to work with for each input primitive. Normally, when using any of the above primitives, the GS gets merely one of the base type. If you use a GS with a GL_TRIANGLE_STRIP, each execution of the GS will only see the 3 vertices of one particular triangle. These special primitive modes allow the GS to access vertex data for adjacent triangles.
Setting a primitive restart index will cause the interpretation of the primitive to be reset when that index is reached in the vertex stream. The vertex data at that index will not be processed, nor will a vertex be inserted into the vertex stream for that index value.