GLSL OpenGL Shading Language - Fish-In-A-Suit/Conquest GitHub Wiki

Using layout qualifers

We can avoid the need to call glBindAttribLocation within the OpenGL program by using layout qualifers to define the attribute index within the shader itself. For example, we could remove the two calls to glBindAttribLocation, and change the input variable declarations in our vertex shader to:

layout (location = 0) in vec3 VertexPosition;
layout (location = 1) in vec3 VertexColor;

This would indicate to the linker that VertexPosition should correspond to generic attribute index 0 and VertexColor to index 1.

We can use a layout qualifer to define the color number for our fragment output variables as well:

layout (location = 0) out vec4 FragColor;

This would tell the linker to bind the output variable FragColor to color number 0, avoiding the need to call glBindFragDataLocation within our OpenGL program.

Built in variables

https://www.khronos.org/opengl/wiki/Built-in_Variable_(GLSL)

Vertex shader inputs

Vertex shaders have the following built-in input variables.

in int gl_VertexID;
in int gl_InstanceID;
in int gl_DrawID; // Requires GLSL 4.60 or ARB_shader_draw_parameters
in int gl_BaseVertex; // Requires GLSL 4.60 or ARB_shader_draw_parameters
in int gl_BaseInstance; // Requires GLSL 4.60 or ARB_shader_draw_parameters
  • gl_VertexID: the index of the vertex currently being processed. When using non-indexed rendering, it is the effective index of the current vertex (the number of vertices processed + the first​ value). For indexed rendering, it is the index used to fetch this vertex from the buffer

  • gl_InstanceID: the index of the current instance when doing some form of instanced rendering. The instance count always starts at 0, even when using base instance calls. When not using instanced rendering, this value will be 0. Warning: This value does not follow the baseInstance​ provided by some instanced rendering functions. gl_InstanceID always falls on the half-open range [0, instancecount​). If you have GLSL 4.60, you may use gl_BaseInstance to compute the proper instance index

  • gl_DrawID: the index of the drawing command within multi-draw rendering commands (including indirect multi-draw commands). The first draw command has an ID of 0, increasing by one as the renderer passes through drawing commands. This value will always be a Dynamically Uniform Expression

  • gl_BaseVertex: the value of the baseVertex​ parameter of the rendering command. If the rendering command did not include that parameter, the value of this input will be 0.

  • gl_BaseInstance: the value of the baseInstance​ parameter of the instanced rendering command. If the rendering command did not include this parameter, the value of this input will be 0

Vertex shader outputs

Vertex shaders have the following predefined outputs:

out gl_PerVertex
{
  vec4 gl_Position;
  float gl_PointSize;
  float gl_ClipDistance[];
};

gl_PerVertex defines an interface block for outputs. The block is defined without an instance name, so that prefixing the names is not required. These variables only take on the meanings below if this shader is the last active Vertex Processing stage.

  • gl_Position: the clip-space output position of the current vertex

  • gl_PointSize: the pixel width/height of the point being rasterized. It only has a meaning when rendering point primitives. It will be clamped to the GL_POINT_SIZE_RANGE

  • gl_ClipDistance: allows the shader to set the distance from the vertex to each user-defined clipping half-space. A non-negative distance means that the vertex is inside/behind the clip plane, and a negative distance means it is outside/in front of the clip plane. Each element in the array is one clip plane. In order to use this variable, the user must manually redeclare it with an explicit size

Code explanation

Simple pass-through vertex and fragment shader

#version 400

layout (location = 0) in vec3 VertexPosition;
layout (location = 1) in vec3 VertexColour;

out vec3 vOutputColour;

void main() {
    gl_Position = vec4(VertexPosition, 1);
    vOutputColour = VertexColour;
}

This is the most simplest of vertex shaders. First it maps the inputs VertexPosition and VertexColour to corresponding attribute list indexes (0 for positions, 1 for colours; supposed the vao is already populated with vbos that store this data). It outputs the colour of the vertex - vOutputColour. It just extends the position of each vertex by 1 (making it homogenous coordinates). vOutputColour is just assigned the input colour without any changes - it's a pass-through shader.

#version 400

in vOutputColour;

layout (location = 0) out FragColour;

void main() {
    FragColour = vec4(vOutputColour, 1);
}

Pay attention to the fact that the output of the vertex shader and the input of the fragment shader match. Case sensitive! The output of the fragment shader is then written to the back buffer ("the 0 buffer") and swapped with the front one with a call to glSwapBuffers(windowHandle). That's why it's important to clear the buffers with glClear(). As the buffers are swapped, the front buffer becomes the back buffer, but it still has the previous image. Wasn't that buffer cleared, it's immage would be overwritten with a new image --> odd results. The output of this vertex shader is colour with 4 components, rgba.