Fragment Shader

Revision as of 19:09, 3 October 2012 by Alfonse (talk | contribs) (Outputs)

Jump to: navigation, search

A Fragment Shader is a user-supplied program that, when executed, will process a Fragment from the rasterization process into a set of colors and a single depth value.


The fragment shader is the OpenGL pipeline stage after a primitive is rasterized. For each sample of the pixels covered by a primitive, a "fragment" is generated. Each fragment has a Window Space position, a few other values, and it contains all of the interpolated per-vertex output values from the last Vertex Processing stage.

The output of a fragment shader is a depth value, a possible stencil value (unmodified by the fragment shader), and zero or more color values to be potentially written to the buffers in the current framebuffers.


The inputs to the fragment shader are either generated by the system or passed from prior fixed-function operations and potentially interpolated across the surface of the primitive.

The user-defined outputs from the last Vertex Processing stage will be interpolated according to their assigned interpolation qualifiers. The fragment shader must define its user-defined inputs exactly as they were defined in the last Vertex Processing stage (with the exception of the centroid​ qualifier).

System inputs

Fragment shaders have a lot of input variables who's values are generated primarily by the rendering system.

in vec4 gl_FragCoord;
in bool gl_FrontFacing;
in vec2 gl_PointCoord;
The location of the fragment in window space. The X, Y and Z components are the window-space position of the fragment. The Z value will be written to the depth buffer if gl_FragDepth​ is not written to by this shader stage. The W component of gl_FragCoord​ is 1/Wclip, where Wclip is the interpolated W component of the clip-space vertex position output to gl_Position​ from the last Vertex Processing stage.
The space of gl_FragCoord​ can be modified by redeclaring gl_FragCoord​ with special input layout qualifiers:
layout(origin_upper_left) in vec4 gl_FragCoord;
This means that the origin for gl_FragCoord​'s window-space will be the upper-left of the screen, rather than the usual lower-left.
layout(pixel_center_integer) in vec4 gl_FragCoord;
OpenGL window space is defined such that pixel centers are on half-integer boundaries. So the center of the lower-left pixel is (0.5, 0.5). Using pixel_center_integer​​ adjust {{code|gl_FragCoord)) such that whole integer values represent pixel centers.
Both of these exist to be compatible with D3D's window space. Unless you need your shaders to have this compatibility, you are advised not to use these features.
This is true if this fragment was generated by the front-face of the primitive; it is false if it was generated by the back-face.
The location within a point primitive that defines the position of the fragment relative to the side of the point. Points are effectively rasterized as window-space squares of a certain pixel size. Since points are defined by a single vertex, the only way to tell where in that square a particular fragment is is with gl_PointCoord​.
The values of gl_PointCoord​'s coordinates range from [0, 1]. Standard OpenGL convention uses a upper-left origin for point-coordinates, so (0, 0) is the bottom left. However, the origin can be switched to a bottom-left origin by calling glPointParameteri(GL_POINT_SPRITE_COORD_ORIGIN, GL_LOWER_LEFT);

OpenGL 4.0 and above define additional system-generated input values:

in int gl_SampleID;
in vec2 gl_SamplePosition;
in int gl_SampleMaskIn[];
This is an integer identifier for the current sample that this fragment is rasterized for.
Warning: Any use of this variable at all will force this shader to be evaluated per-sample. Since much of the point of multisampling is to avoid that, you should use it only when you must.
This is the location of the current sample for the fragment within the pixel's area, with values on the range [0, 1]. The origin is the bottom-left of the pixel area.
Warning: Any use of this variable at all will force this shader to be evaluated per-sample. Since much of the point of multisampling is to avoid that, you should use it only when you must.
When using multisampling, this variable contains a bitfield for the sample mask of the fragment being generated. The array is as long as needed to fill in the number of samples supported by the GL implementation.

User overridden inputs

Some built-in inputs will take values specified by OpenGL, but these values can be overridden by user control.

in float gl_ClipDistance[];
in int gl_PrimitiveID;
This array contains the interpolated clipping plane half-spaces, as output for vertices from the last Vertex Processing stage.
This value is the index of the current primitive being rendered by this rendering command. However, if a Geometry Shader is active, then the gl_PrimitiveID​ is what the GS provided as output. If the GS did not output a value, then the fragment shader gets an undefined value.

GL 4.3 provides the following additional inputs:

in int gl_Layer;
in int gl_ViewportIndex;
This is either 0 or the layer number for this primitive output by the Geometry Shader.
This is either 0 or the viewport index for this primitive output by the Geometry Shader.


User-defined output values from the fragment are written to one or more color buffers in the current framebuffer.

There are some built-in output values with special meaning:

out float gl_FragDepth;
This output is the fragment's depth. If the shader does not statically write this value, then it will take the value of gl_FragCoord.z​.
To "statically write" to a variable means that you write to it anywhere in the program. Even if the writing code is technically unreachable for some reason, if there is a {{{1}}}​ expression anywhere in the shader, then it is statically written.
Warning: If the fragment shader statically writes to gl_FragDepth​, then it is the responsibility of the shader to statically write to the value in all circumstances. No matter what branches may or may not be taken, the shader must ensure that the value is written. So, if you conditionally write to it in one place, you should at least make sure that there is a single non-conditional write sometime before that.