Help end child hunger

GLSL Tutorial – Fragment Shader

 
Prev: Rasterization and Interpolation Next: OpenGL Setup
 

A fragment shader processes…fragments. A fragment is basically a position on the window (X,Y), a depth value (Z), plus all the interpolated data from previous stages.

The fragments that were found in the rasterization process, and whose attributes were computed in the interpolation phase, are now fed, one by one, to the fragment shader. This shader is not optional, unless transform feedback is being used.

Fragment shaders can access the fragment position, and all the interpolated data computed in the rasterization process. The shader performs computations based on these attributes and the pixels position. The pixel’s X,Y position is fixed, i.e. a fragment shader can not choose to write the attributes of other pixel. However, it can change the pixel’s depth (the Z value).

The fragment shader does not have access to the framebuffer, neither at the current pixel’s position, nor at any other pixel position. The fragment shader, similarly to the vertex shader, only has access to the current pixel and its associated data.

As in the previous stages the fragment shader has access to all uniforms made available in the application.

Some built-in variables available in a fragment shader are (for a complete list see the GLSL spec section on Built-in Variables):

    • gl_FragCoord: contains the fragments coordinate (xf, yf, zf, wf), where (xf, yf) is the pixels position on the window, zf is the depth, and wf is 1/wc, where wc is the component of the fragments clip space position
    • gl_FrontFacing: tells the orientation of the primitive that originated the pixel. Note that if face culling is enabled then this value will be the same for all pixels.
    • gl_PrimitiveID: This variable is an output of the geometry shader. If no geometry shader is present, the value reflects the index of the primitive in the OpenGL draw command.

Note: gl_PrimitiveID is only available in version 4.1.

Regarding outputs, these can range, in number, from 1 to GL_MAX_DRAW_BUFFERS. By default an application has a single color output, and its type is a vec4. An application should bind user-defined variables to color outputs. There may be more than one color output if using framebuffer objects.

The shader below is probably the simplest fragment shader we can write. Not very interesting though, it just paints everything red!

#version 150

out vec4 colorOut;

void main()
{
	colorOut = vec4(1.0, 0.0, 0.0, 1.0);
}

As with uniform variables and vertex attributes, the output variables of the fragment shader also have a location. In the shader above, the variable colorOut is bound to location 0 (zero) by default. In the application we should bind the variable colorOut to output location zero, the default location when not using framebuffer objects, using the following function:

[stextbox]
void glBindFragDataLocation(GLuint program, GLuint colorNumber, const char *name);

Params:

  • program: the program object handle
  • colorNumber: the output location to bind the variable to
  • name: the name of the shader output variable

[/stextbox]

So, considering the shader above, and assuming p as a handle to our program, we could write in our application the following OpenGL instruction:

glBindFragDataLocation(p, 0, "colorOut");

Note that the binding does not take effect until the program is next linked. The location can also be queried by the application for previously linked programs with the function:

[stextbox]
GLint gGetFragDataLocation(GLuint program, const char *name);

Params:

  • program: the program object handle
  • name: the name of the shader output variable

[/stextbox]

If name does not refer to an active user defined output variable, the result is -1. Otherwise the location of the variable is returned.

Locations for the output variables can also be hard-coded in the shader itself using layout qualifiers. The declaration of the colorOut variable can include a layout qualifier that establishes its location, as in the following example:

layout(location = 0) out vec4 colorOut;

When using the layout qualifier in the shader, the location it refers to overrides the settings from instruction glBindFragDataLocation.

When using framebuffer objects, each output will have a location to match its render target (or texture) output, otherwise, when using the default framebuffer, the only location that matters is location zero.

 

Prev: Rasterization and Interpolation Next: OpenGL Setup
 

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: