By
OpenGL Shading Language
Course
Chapter 2 – GLSL Basics
Jacobo Rodriguez Villar
jacobo.Rodriguez@typhoonlabs.com
TyphoonLabs’ GLSL Course 1/1
Chapter 2: GLSL Basics
INDEX
Introduction
GLSL Language
Mechanisms Borrowed from C++
Character Set
Pre-processor Keywords
Comments
Variables and Types
Type Descriptions
Type Qualifiers
Operators and Preference
Subroutines
Flow Control
Built-in Variables
Built-in Constants
Built-in Attributes
General Built-in Uniform States
Varying Variables
Built-in Functions
2
2
2
2
3
3
4
4
9
10
10
11
11
14
14
15
18
19
TyphoonLabs’ GLSL Course 2/2
Introduction
This chapter will attempt to summarize the entire GLSL 1.10.59 specification.
GLSL itself is a C-like language, which borrows features from C++. Knowledge of C is
assumed, so the fundamentals and basics of that language will not be explained further
(with exception to the parts that differ between C and C++).
GLSL Language
Mechanisms Borrowed from C++:
• Function overloading based on argument types.
• Declaration of variables where they are required, instead of at the beginning of each
block.
Character Set
The character set used for GLSL is a subset of ASCII, and includes the following
characters:
1º The letters a-z, A-Z, and the underscore ( _ ).
2º The numbers 0-9.
3º The symbols period (.), plus (+), dash (-), slash (/), asterisk (*), percent (%), angled
brackets (< and >), square brackets ( [ and ] ), parentheses ( ( and ) ), braces ( { and }
), caret (^), vertical bar ( | ), ampersand (&), tilde (~), equals (=), exclamation point (!),
colon (:), semicolon (;), comma (,), and question mark (?).
4º The number sign (#) for pre-processor use.
5º White space: the space character, horizontal tab, vertical tab, form feed, carriage-
return, and linefeed.
The character set is case-sensitive, and there are no characters or string data types, so no
quotation characters are included.
Also, the language does not allow any pointer types or any kind of pointer arithmetic.
TyphoonLabs’ GLSL Course 3/3
Pre-processor Keywords
#
#define
#undef
#if
#ifdef
#ifndef
#else
#elif
#endif
Operates as is standard for C++ pre-processors.
Operates as is standard for C++ pre-processors.
Operates as is standard for C++ pre-processors.
Operates as is standard for C++ pre-processors (only for integer and #defined types).
Operates as is standard for C++ pre-processors.
Operates as is standard for C++ pre-processors.
Operates as is standard for C++ pre-processors.
Operates as is standard for C++ pre-processors (only for integer and #defined types).
Operates as is standard for C++ pre-processors.
error will cause the implementation to put a diagnostic message in the shader’s
information log. The message will be the tokens following the #error directive, up to the
first new line. The implementation must then consider the shader to be ill-formed.
#pragma allows implementation-dependent compiler control. Tokens following #pragma
are not subject to pre-processor macro expansion.
The following pragmas are defined as part of the language:
#pragma optimize(on)
#pragma optimize(off)
#pragma debug(on)
#pragma debug(off)
For default, any extension to the language must be enabled using this keyword:
#extension extension_name : behaviour
#extension all : behaviour
[Frame1] The initial state of the compiler is as if the directive
#extension all : disable
was issued, telling the compiler that all error and warning reporting must be done
according to this specification, ignoring any extensions.
Macro expansion is not done on lines containing #extension directive.
Used to declare the GLSL version against the shader. Written (#version number), where
number must be 110 for this specification’s version of the language (following the same
convention as __VERSION__ above), in which case the directive will be accepted with
no errors or warnings. Any number less than 110 will cause an error to be generated.
Macro expansion is not done on lines containing #version directive.
#line must have, after macro substitution, one of the following two forms:
#line line or #line line source-string-number
where line and source-string-number are constant integer expressions. After processing
this directive (including its new-line), the implementation will behave as if it is compiling at
line number line+1 and source string number source-string-number. Subsequent source
strings will be numbered sequentially, until another #line directive overrides that
numbering.
The defined operator can be used in either of the following ways:
defined identifier or
defined ( identifier )
__LINE__ will substitute a decimal integer constant that is one more than the number of
preceding newlines in the current source string.
__FILE__ will substitute a decimal integer constant that says which source string number
is currently being processed.
__VERSION__ will substitute a decimal integer reflecting the version number of the
OpenGL shading language. The version of the shading language described in this
document will have __VERSION__ substitute the decimal integer 110.
#error
#pragma
#extension
#version
#line
defined
__LINE__
__FILE__
__VERSION__
Comments
Comments are delimited by /* and */, or by // and a new-line. The begin comment
delimiters (/* or //) are not recognized as delimiters when inside a comment, meaning
nesting does not exist.
Variables and types
These are the basic GLSL types:
TyphoonLabs’ GLSL Course 4/4
C data type
Description
int
int
float
float [2]
float [3]
float [4]
int [2]
int [3]
int [4]
int [2]
int [3]
int [4]
float [4]
float [9]
float [16]
int
int
int
int
int
int
A conditional type, taking on values of true or false.
Signed integer.
Single floating-point scalar.
Two component floating-point vector.
Three component floating-point vector.
Four component floating-point vector.
Two component Boolean vector.
Three component Boolean vector.
Four component Boolean vector.
Two component signed integer vector.
Three component signed integer vector.
Four component signed integer vector.
2×2 floating-point matrix.
3×3 floating-point matrix.
4×4 floating-point matrix.
Handle for accessing a 1D texture.
Handle for accessing a 2D texture.
Handle for accessing a 3D texture.
Handle for accessing a cubemap texture.
A handle for accessing a 1D depth texture with comparison.
A handle for accessing a 2D depth texture with comparison.
GLSL data type
bool
int
float
vec2
vect3
vec4
bvec2
bvec3
bvec4
ivec2
ivec3
ivec4
mat2
mat3
mat4
sampler1D
sampler2D
sampler3D
samplerCube
sampler1DShadow
Sampler2DShadow
Type Descriptions
Booleans
To make conditional execution of code easier to express, the type bool is supported.
There is no expectation that hardware directly supports variables of this type. It is a
genuine Boolean type, holding only one of two values (either true or false). Two keywords,
true and false, can be used as Boolean constants.
Integers
Integers are mainly supported as a programming aid. At the hardware level, real integers
would aid in the efficient implementation of loops and array indices, and in referencing
texture units. However, there is no requirement that integers used within the language can
map to integer types used within hardware. It is not expected that underlying hardware has
full support for a wide range of integer operations. Because of their intended (limited)
purpose, integers are limited to 16 bits of precision, plus a sign representation in both the
vertex and fragment languages. There is no automatic promotion from int to float (so
int a=1.0; would cause an error, for example).
Floats
Floats are available for use within a variety of scalar calculations. Floating-point variables
are defined as follows: float a = 1.8;
Vector types
GLSL includes data types for generic 2, 3, and 4 component vectors of floating-point
values, integers, or booleans. Defining vectors as part of the shading language allows for
direct mapping of vector operations on graphics hardware that is capable of doing vector
processing. In general, applications will be able to take better advantage of the parallelism
in graphics hardware by doing computations on vectors rather than on scalar values.
TyphoonLabs’ GLSL Course 5/5
Vector elements can be accessed in several ways:
For example, using vec4 myVector; we can access myVector’s elements in the usual
way:
myVector[1] = 6.4;
Another way of accessing the elements is to use the struct subscript:
myVector.y = 6.4 or myVector.s = 6.4;
When using a struct subscript, we have the following access names for the indices (they
are synonyms):
[0] [1]
x
y
t
s
r
g
[2]
z w Useful when accessing vectors that represent points.
p
b
q Useful when accessing vectors that texture coordinates.
a Useful when accessing vectors that represent colors.
[3] Useful when element looping is required.
vec2 pos;
pos.x // is legal
pos.z // is illegal
Accessing components beyond those declared for the vector type is an error, meaning:
The component selection syntax allows multiple components to be selected by appending
their names (from the same name set) after the period character ( . ):
The order of the components can be changed or replicated via sizzling:
vec4 v4;
v4.rgba; // is a vec4 and the same as just using v4
v4.rgb; // is a vec3
v4.b; // is a float
v4.xy; // is a vec2
v4.xgba; // is illegal - the component names do not come from the same set
vec4 pos = vec4(1.0, 2.0, 3.0, 4.0);
vec4 swiz = pos.wzyx; // swiz = (4.0, 3.0, 2.0, 1.0)
vec4 dup = pos.xxyy; // dup = (1.0, 1.0, 2.0, 2.0)
TyphoonLabs’ GLSL Course 6/6
vec4 pos = vec4(1.0, 2.0, 3.0, 4.0);
pos.xw = vec2(5.0, 6.0); // pos = (5.0, 2.0, 3.0, 6.0)
pos.wx = vec2(7.0, 8.0); // pos = (8.0, 2.0, 3.0, 7.0)
pos.xx = vec2(3.0, 4.0); // illegal - 'x' used twice
pos.xy = vec3(1.0, 2.0, 3.0); // illegal - mismatch between vec2 and vec3
vec3 (float) // initializes each component of a vec3 with the float
vec4 (ivec4) // makes a vec4 from an ivec4, with component-wise conversion
vec2 (float, float) // initializes a vec2 with 2 floats
ivec3 (int, int, int) // initializes an ivec3 with 3 ints
bvec4 (int, int, float, float) // initializes with 4 Boolean conversions
vec2 (vec3) // drops the third component of a vec3
vec3 (vec4) // drops the fourth component of a vec4
vec3 (vec2, float) // vec3.x = vec2.x, vec3.y = vec2.y, vec3.z = float
vec3 (float, vec2) // vec3.x = float, vec3.y = vec2.x, vec3.z = vec2.y
vec4 (vec3, float)
vec4 (float, vec3)
vec4 (vec2, vec2)
Component group notation can occur on the left-hand side of an expression:
Some examples of vector type construction:
Examples:
Matrices
GLSL supports 2×2, 3×3, and 4×4 matrices of floating-point numbers. Matrices are read-
from and written-to the column in major order.
Example matrix declarations:
Matrices are based on vectors, so syntax like optMatrix[2]=vec3(1.0,1.0,1.0); is
allowed.
For example, initializing the diagonal of a matrix with all other elements set to zero:
vec4 color = vec4(0.0, 1.0, 0.0, 1.0);
vec4 rgba = vec4(1.0); // sets each component to 1.0
mat2 mat2D;
mat3 optMatrix;
mat4 view, projection;
mat2(float)
mat3(float)
mat4(float)
TyphoonLabs’ GLSL Course 7/7
mat2(vec2, vec2);
mat3(vec3, vec3, vec3);
mat4(vec4, vec4, vec4, vec4);
mat2(float, float,
float, float);
mat3(float, float, float,
float, float, float,
float, float, float);
mat4(float, float, float, float,
float, float, float, float,
float, float, float, float,
float, float, float, float);
Initializing a matrix can be achieved by specifying vectors, or specifying all 4, 9, or 16
floats for mat2, mat3, and mat4 respectively. The floats are then assigned to elements in
column major order.
There are many possibilities here, as long as enough components are present to initialize
the matrix. However, construction of a matrix from other matrices is currently reserved for
future use.
Samplers
Sampler types (like sampler2D) are effectively opaque handles to textures. They are
used with the built-in texture functions to access textures, and can only be declared as
function parameters or uniforms. Samplers are not allowed to be used as operands within
expressions, nor can they be assigned within. As uniforms, they are initialized through the
OpenGL API using int type.
Note:
Samplers represent texture units, not texture objects. In order to use a texture within a
shader, it must first be bound to a texture unit, and then the tex unit number must be
passed to the shader. Some cards only have few texture units (for example, the GeForce
FX5200 hardware only has four). If we only have access to GL_MAX_TEXTURE_UNITS
textures within the shader this will not be an ideal situation.
However, this perceived limitation is not entirely correct:
A texture unit is composed of an image, a matrix, an interpolator, and a coordinate
generation processor. Though we are limited by the number of texture images available,
we are not limited by the number of texture units. This number can be obtained by
querying GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS_ARB (with a FX5200 this
number is 16). Graphics cards usually have more texture images than texture units.
TyphoonLabs’ GLSL Course 8/8