Difference between revisions of "Data Type (GLSL)"

From OpenGL.org
Jump to: navigation, search
(Constructors and initializers)
(Matrices)
(23 intermediate revisions by 3 users not shown)
Line 1: Line 1:
{{missing}}
 
 
 
The [[OpenGL Shading Language]] defines a number of types. It also defines the means by which users can define types.
 
The [[OpenGL Shading Language]] defines a number of types. It also defines the means by which users can define types.
  
 
== Basic types ==
 
== Basic types ==
 +
 +
Basic types in GLSL are the most fundamental types. Non-basic types are aggregates of these fundamental types.
  
 
{{note|This document will mention double-precision types. These are only available on GL 4.0 and above, or with appropriate extension support.}}
 
{{note|This document will mention double-precision types. These are only available on GL 4.0 and above, or with appropriate extension support.}}
Line 11: Line 11:
 
The basic non-vector types are:
 
The basic non-vector types are:
  
* bool: conditional type, values may be either <code>true</code> or <code>false</code>
+
* {{code|bool}}: conditional type, values may be either <code>true</code> or <code>false</code>
* int: a signed integer
+
* {{code|int}}: a signed integer
* uint: an unsigned integer
+
* {{code|uint}}: an unsigned integer
* float: a floating point number
+
* {{code|float}}: a floating point number
* double: a double-precision floating-point number
+
* {{code|double}}: a double-precision floating-point number
  
 
=== Vectors ===
 
=== Vectors ===
Line 21: Line 21:
 
Each of the scalar types, including booleans, have 2, 3, and 4-component vector equivalents. The ''n'' digit below can be 2, 3, or 4:
 
Each of the scalar types, including booleans, have 2, 3, and 4-component vector equivalents. The ''n'' digit below can be 2, 3, or 4:
  
* bvec''n'': a vector of booleans
+
* {{code|bvec''n''}}: a vector of booleans
* ivec''n'': a vector of signed integers
+
* {{code|ivec''n''}}: a vector of signed integers
* uvec''n'': a vector of unsigned integers
+
* {{code|uvec''n''}}: a vector of unsigned integers
* vec''n'': a vector of single-precision floating-point numbers
+
* {{code|vec''n''}}: a vector of single-precision floating-point numbers
* dvec''n'': a vector of double-precision floating-point numbers
+
* {{code|dvec''n''}}: a vector of double-precision floating-point numbers
  
 
Vector values can have the same math operators applied to them that scalar values do. These all perform the component-wise operations on each component. However, in order for these operators to work on vectors, the two vectors must have the same number of components.
 
Vector values can have the same math operators applied to them that scalar values do. These all perform the component-wise operations on each component. However, in order for these operators to work on vectors, the two vectors must have the same number of components.
Line 33: Line 33:
 
You can access the components of vectors using the following syntax:
 
You can access the components of vectors using the following syntax:
  
vec4 someVec;
+
<source lang="glsl">
someVec.x + someVec.y;
+
vec4 someVec;
 +
someVec.x + someVec.y;
 +
</source>
  
 
This is called ''swizzling''. You can use x, y, z, or w, referring to the first, second, third, and fourth components, respectively.
 
This is called ''swizzling''. You can use x, y, z, or w, referring to the first, second, third, and fourth components, respectively.
Line 40: Line 42:
 
The reason it has that name "swizzling" is because the following syntax is entirely valid:
 
The reason it has that name "swizzling" is because the following syntax is entirely valid:
  
vec2 someVec;
+
<source lang="glsl">
vec4 otherVec = someVec.xyxx;
+
vec2 someVec;
vec3 thirdVec = otherVec.zyy;
+
vec4 otherVec = someVec.xyxx;
 +
vec3 thirdVec = otherVec.zyy;
 +
</source>
  
 
You can use any combination of up to 4 of the letters to create a vector (of the same basic type) of that length. So <code>otherVec.zyy</code> is a vec3, which is how we can initialize a vec3 value with it. Any combination of up to 4 letters is acceptable, so long as the source vector actually has those components. Attempting to access the 'w' component of a vec3 for example is a compile-time error.
 
You can use any combination of up to 4 of the letters to create a vector (of the same basic type) of that length. So <code>otherVec.zyy</code> is a vec3, which is how we can initialize a vec3 value with it. Any combination of up to 4 letters is acceptable, so long as the source vector actually has those components. Attempting to access the 'w' component of a vec3 for example is a compile-time error.
  
Additionally, there are 3 sets of swizzle masks. You can use xyzw, rgba (for colors), or stpq (for texture coordinates). These three sets have no actual difference; they're just syntactic sugar.
+
Swizzling also works on l-values:
 +
 
 +
<source lang="glsl">
 +
vec4 someVec;
 +
someVec.wzyx = vec4(1.0, 2.0, 3.0, 4.0); //Reverses the order.
 +
someVec.zx = vec2(3.0, 5.0); //Sets the 3rd component of someVec to 3.0 and the 1st component to 5.0
 +
</source>
 +
 
 +
However, when you use a swizzle as a way of setting a value, you ''cannot'' use the same swizzle component twice. So {{code|someVec.xx {{=}} vec2(4.0, 4.0);}} is not allowed.
 +
 
 +
Additionally, there are 3 sets of swizzle masks. You can use xyzw, rgba (for colors), or stpq (for texture coordinates). These three sets have no actual difference; they're just syntactic sugar. You cannot combine names from different sets in a single swizzle operation. So ".xrs" is not a valid swizzle mask.
 +
 
 +
In GLSL 420/{{extref|shading_language_420pack}}, scalars can be swizzled as well. They obviously only have one source component, but it is legal to do this:
 +
 
 +
<source lang="glsl">
 +
float aFloat;
 +
vec4 someVec = aFloat.xxxx;
 +
</source>
  
 
=== Matrices ===
 
=== Matrices ===
Line 52: Line 73:
 
In addition to vectors, there are also matrix types. All matrix types are floating-point, either single-precision or double-precision. Matrix types are as follows, where ''n'' and ''m'' can be the numbers 2, 3, or 4:
 
In addition to vectors, there are also matrix types. All matrix types are floating-point, either single-precision or double-precision. Matrix types are as follows, where ''n'' and ''m'' can be the numbers 2, 3, or 4:
  
* <code>mat''n''x''m''</code>: A matrix with ''n'' columns and ''m'' rows. OpenGL uses column-major matrices, which is standard for mathematics users. Example: <code>mat3x4</code>.
+
* {{code|mat''n''x''m''}}: A matrix with ''n'' columns and ''m'' rows. OpenGL uses column-major matrices, which is standard for mathematics users. Example: {{code|mat3x4}}.
* <code>mat''n''</code>: A symmetric matrix with ''n'' columns and rows. This type is equivalent to <code>mat''n''x''n''</code>.
+
* {{code|mat''n''}}: A matrix with ''n'' columns and ''n'' rows. Shorthand for {{code|mat''n''x''n''}}
  
Double-precision matrices (GL 4.0 and above) can be declared with a <code>''dmat''</code> instead of <code>mat</code>
+
Double-precision matrices (GL 4.0 and above) can be declared with a {{code|''dmat''}} instead of {{code|mat}}
  
 
Swizzling does not work with matrices. You can instead access a matrix's fields with array syntax:
 
Swizzling does not work with matrices. You can instead access a matrix's fields with array syntax:
  
mat3 theMatrix;
+
<source lang="glsl">
theMatrix[1] = vec3(3.0, 3.0, 3.0); //Sets the second column to all 3.0s
+
mat3 theMatrix;
theMatrix[2][0] = 16.0; //Sets the first entry of the third column to 16.0.
+
theMatrix[1] = vec3(3.0, 3.0, 3.0); //Sets the second column to all 3.0s
 +
theMatrix[2][0] = 16.0; //Sets the first entry of the third column to 16.0.
 +
</source>
  
=== Samplers ===
+
However, the result of the first array accessor is a vector, so you ''can'' swizzle that:
{{main|GLSL Sampler}}
+
 
 +
<source lang="glsl">
 +
mat3 theMatrix;
 +
theMatrix[1].yzx = vec3(3.0, 1.0, 2.0);
 +
</source>
 +
 
 +
=== Opaque types ===
 +
 
 +
Opaque types represent some external object which the shader references in some fashion. Opaque variables do not have "values" in the same way as regular types; they are markers that reference the real data. As such, they can only be used as parameters to functions. These functions return/modify the actual referenced data.
 +
 
 +
Variables of opaque types can only be declared in one of two ways. They can be declared at global scope, as a {{code|uniform}} variables. They can be aggregated into arrays of their opaque type, but they cannot be part of a [[GLSL Interface Blocks#Buffer backed |buffer-backed interface block]] or a struct definition. They can also be declared locally, but only as {{code|in}}-qualified function parameters.
 +
 
 +
Opaque types cannot be l-values. The only expressions that they can be a part of are array-indexing, structure field selection, and the parenthesis operator.
 +
 
 +
==== Samplers ====
 +
{{main|Sampler (GLSL)}}
  
 
[[Texture|Texture access]] is not as simple as reading a value from a memory address. Filtering and other processes are applied to textures, and how texture coordinates are interpreted can be part of the texture access operation. For these reason, texture access is somewhat complicated.
 
[[Texture|Texture access]] is not as simple as reading a value from a memory address. Filtering and other processes are applied to textures, and how texture coordinates are interpreted can be part of the texture access operation. For these reason, texture access is somewhat complicated.
  
It starts with ''samplers'', a special type that GLSL defines. Each sampler variable represents a texture that is attached to the context. Samplers have a type that defines what kind of texture can be attached to them.
+
The sampler type is an opaque GLSL type that represents a texture bound to the OpenGL context. There are many sampler types, one for each type of texture (2D, 2D_ARRAY, etc). Samplers can only access textures of the proper type.
 +
 
 +
==== Images ====
 +
{{main|Image Load Store}}
 +
 
 +
Image variables refer to an image, of a particular type, stored within a texture. These are used for arbitrary loading/storing of values within shaders.
 +
 
 +
==== Atomic counters ====
 +
{{main|Atomic Counter}}
  
Sampler types cannot be initialized to a value. They cannot have any operations executed on them. They can only be passed as parameters to functions, and variables of sampler types can only be global [[GLSL Uniform|uniforms]] (declared outside of [[GLSL Interface Blocks|interface blocks]] or as input parameters to functions.
+
Atomic variables represent a memory location within a [[Buffer Object]] upon which atomic operations can take place.
  
 
=== Implicit conversion ===
 
=== Implicit conversion ===
Line 82: Line 128:
 
== Arrays ==
 
== Arrays ==
  
Basic types can be grouped into sequences of those elements, called arrays. This generally works like in C/C++, but there are some limitations.
+
Basic types can be grouped into sequences of those elements, called arrays. This generally works like in C/C++, but there are some limitations. First and foremost is that arrays cannot be multidimensional (unless you have GL 4.3/{{extref|arrays_of_arrays}}; [[#Arrays of arrays|see below]]}}.
  
Arrays usually must be declared with a size. Input arrays to geometry shaders do not need a size. Global variables can be declared without a size, but only if they are later redeclared with a size.
+
Arrays usually must be declared with a size. Input arrays to geometry shaders do not need a size. Global variables can be declared without a size, but only if they are later redeclared with a size. An array in a [[Shader Storage Buffer Object|buffer variable or shader storage interface block]] may be declared without a size, but only if it is the last variable in the block.
  
 
The array size must be a compile-time integral constant expression.
 
The array size must be a compile-time integral constant expression.
Line 90: Line 136:
 
With a few exceptions, arrays can be used for all of the storage qualifiers: inputs, outputs, uniforms, constants, etc. Outputs from the fragment shader cannot be arrays.
 
With a few exceptions, arrays can be used for all of the storage qualifiers: inputs, outputs, uniforms, constants, etc. Outputs from the fragment shader cannot be arrays.
  
The length of an array variable can be computed with the <code>.length()</code> function. For example:
+
The length of an array variable can be computed with the {{code|.length()}} function. For example:
  
<source lang="cpp">
+
<source lang="glsl">
 
uniform float myValues[12];
 
uniform float myValues[12];
  
Line 100: Line 146:
 
</source>
 
</source>
  
Arrays can be accessed with arbitrary numeric expressions. They do not have to be compile-time constants (though there are a few exceptions to this rule).
+
Arrays can be accessed with arbitrary numeric expressions. They do not have to be compile-time constants (though there are a few exceptions to this rule; for example, the very next section).
  
=== Sampler arrays ===
+
=== Opaque arrays ===
  
Arrays of sampler types are special. Under GLSL version 3.30, sampler arrays can be declared, but they can only be accessed by compile-time integral constant expressions. So you cannot loop over an array of samplers.
+
Arrays of [[#Opaque types|opaque types]] are special. Under GLSL version 3.30, sampler arrays (the only opaque type 3.30 provides) can be declared, but they can only be accessed by compile-time integral constant expressions. So you cannot loop over an array of samplers.
  
Under GLSL 4.00 and above, sampler arrays can be accessed by non-compile-time constants, but there are still limitations. The value must be "dynamically uniform." This means that the value used to access sampler arrays must be the same, in the same execution order, regardless of any non-uniform parameter values. So the index must be either a compile-time constant, a uniform variable, or an expression composed of only compile-time constants and uniform variables.
+
Under GLSL 4.00 and above, arrays of opaque can be accessed by non-compile-time constants, but there are still limitations. The expression used to access the array must be a [[Dynamically Uniform Expression]]. This means that the value used to access opaque arrays must be the same, in the same execution order, regardless of any non-uniform parameter values..
  
 
For example, in 4.00, it is legal to loop over an array of samplers, so long as the loop index is based on constants and uniforms. So this is legal:
 
For example, in 4.00, it is legal to loop over an array of samplers, so long as the loop index is based on constants and uniforms. So this is legal:
  
<source lang="cpp">
+
<source lang="glsl">
 
uniform sampler images[10];
 
uniform sampler images[10];
 
uniform int imageCount;
 
uniform int imageCount;
Line 125: Line 171:
  
 
This would add up all of the values in the textures, up to ''imageCount'' in size. Note that this is not legal in GLSL 3.30.
 
This would add up all of the values in the textures, up to ''imageCount'' in size. Note that this is not legal in GLSL 3.30.
 +
 +
=== Arrays of arrays ===
 +
{{infobox feature
 +
| name = Arrays of arrays
 +
| core = 4.3
 +
| core_extension = {{extref|arrays_of_arrays}}
 +
}}
 +
 +
Given the presence of this feature, arrays can be declared multidimensionally in GLSL:
 +
{{clear float}}
 +
<source lang="glsl">
 +
uniform vec3 multidim[5][2];
 +
</source>
 +
 +
{{code|multidim}} is an array of 5 elements, where each element is an array of 2 {{code|vec2}} elements.
 +
 +
Such arrays can also be declared like this:
 +
 +
<source lang="glsl">
 +
uniform vec3[5][2] multidim;
 +
</source>
 +
 +
This may make things more clear.
 +
 +
If an array can be specified without a size (such as in buffer variables), only the first array index can be unsized.
 +
 +
<source lang="glsl">
 +
buffer vec3[][2] multidim; //legal
 +
buffer vec3[5][] multidim; //not legal
 +
</source>
  
 
== Structs ==
 
== Structs ==
Line 130: Line 206:
 
Structs are defined much like C++ (note: the common ''typedef struct *{}'' syntax from standard C is ''not'' supported). GLSL does not support anonymous structures (ie: structs without a type name), and structs must have at least one member declaration. Structs cannot be defined within another struct.
 
Structs are defined much like C++ (note: the common ''typedef struct *{}'' syntax from standard C is ''not'' supported). GLSL does not support anonymous structures (ie: structs without a type name), and structs must have at least one member declaration. Structs cannot be defined within another struct.
  
<source lang="cpp">
+
<source lang="glsl">
 
struct Light
 
struct Light
 
{
 
{
Line 152: Line 228:
 
== Constructors and initializers ==
 
== Constructors and initializers ==
  
Variables of almost types can be initialized with an initial value. The exceptions are:
+
Variables of almost any type can be initialized with an initial value. The exceptions are:
  
 
* Input or output qualified variables.
 
* Input or output qualified variables.
* Any variable of a [[GLSL Sampler|sampler]] type.
+
* Any variable of a [[#Opaque_types|opaque type]] type.
* Uniform variables declared in a [[Uniform Buffer Object|uniform block]].
+
* Variables declared in an [[Interface Block]].
 
+
those that use input or output qualifiers and all variables of [[GLSL Sampler|sampler]] types.
+
  
 
For basic types, the variable can be initialized by setting it equal to a literal value:
 
For basic types, the variable can be initialized by setting it equal to a literal value:
Line 170: Line 244:
 
A literal is a value written into the shader. Literals are always basic types, and they can be used to initialize the value of a basic type. They can also be used wherever a constant basic value is needed.
 
A literal is a value written into the shader. Literals are always basic types, and they can be used to initialize the value of a basic type. They can also be used wherever a constant basic value is needed.
  
Literals are typed. There are two literals of ''bool'' type: <code>true</code> and <code>false</code>.
+
Literals are typed. There are two literals of {{code|bool}} type: {{code|true}} and <code>false</code>.
  
Any integer value is by default of type ''int'' (a signed integer). To create an integer literal of unsigned type, use the suffix <code>u</code> or <code>U</code>.
+
Any integer value is by default of type {{code|int}} (a signed integer). To create an integer literal of unsigned type, use the suffix {{code|u}} or {{code|U}}.
  
 
Integer literals can be defined in base 8 or base 16 using the standard C/C++ conventions (prefix with 0 for base 8 or 0x for base 16).
 
Integer literals can be defined in base 8 or base 16 using the standard C/C++ conventions (prefix with 0 for base 8 or 0x for base 16).
  
A numeric literal that uses a decimal is by default of type ''float''. To create a float literal from an integer value, use the suffix <code>f</code> or <code>F</code> as in C/C++.
+
A numeric literal that uses a decimal is by default of type {{code|float}}. To create a float literal from an integer value, use the suffix {{code|f}} or {{code|F}} as in C/C++.
  
Floats can also be defined using exponential notation, using the <code>e</code> or <code>E</code> to separate the base from the exponent. The exponent is always base-10.
+
Floats can also be defined using exponential notation, using the {{code|e}} or {{code|E}} to separate the base from the exponent. The exponent is always base-10.
  
In GLSL 4.00 and above, double-precision floats are available. By default, all floating-point literals are of type ''float''. To create a double-precision float, use the <code>lf</code> or <code>LF</code> suffixes. This will force it to the ''double'' type.
+
In GLSL 4.00 and above, double-precision floats are available. By default, all floating-point literals are of type ''float''. To create a double-precision float, use the {{code|lf}} or {{code|LF}} suffixes. This will force it to the ''double'' type.
  
 
=== Constructors ===
 
=== Constructors ===
Line 186: Line 260:
 
Types more complex than the base types are initialized with constructors. All constructors take the form:
 
Types more complex than the base types are initialized with constructors. All constructors take the form:
  
   ''typename''(''value1'', ''value2'', ...)
+
   {{param|typename}}({{param|value1}}, {{param|value2}}, ...)
  
The ''typename'' is the name of the type to construct. The values can be literals, previously-defined variables, and other constructors.
+
The {{param|typename}} is the name of the type to construct. The values can be literals, previously-defined variables, and other constructors.
  
 
Some constructors have special syntax.
 
Some constructors have special syntax.
Line 196: Line 270:
 
Vector constructors take the number of values that they store. So a ''vec3'' takes 3 values. However, all vectors can be constructed from a single value; this results in a vector where all of the values are the value given to the constructor. So:
 
Vector constructors take the number of values that they store. So a ''vec3'' takes 3 values. However, all vectors can be constructed from a single value; this results in a vector where all of the values are the value given to the constructor. So:
  
  vec3(1.0) == vec3(1.0, 1.0, 1.0);
+
vec3(1.0) == vec3(1.0, 1.0, 1.0);
  
 
Vectors can also be constructed from other vectors, or a combination of vectors and scalars. The values in the output vector are filled in, right to left, by the values in the input scalars and vectors. There must be enough values, counting scalars and vectors, to fill in all of the elements of the output vector. Here are some examples:
 
Vectors can also be constructed from other vectors, or a combination of vectors and scalars. The values in the output vector are filled in, right to left, by the values in the input scalars and vectors. There must be enough values, counting scalars and vectors, to fill in all of the elements of the output vector. Here are some examples:
  
  vec4(vec2(10.0, 11.0), 1.0, 3.5) == vec4(10.0, vec2(11.0, 1.0), 3.5);
+
<source lang="glsl">
  vec3(vec4(1.0, 2.0, 3.0, 4.0) == vec3(1.0, 2.0, 3.0);
+
vec4(vec2(10.0, 11.0), 1.0, 3.5) == vec4(10.0, vec2(11.0, 1.0), 3.5);
  vec4(vec3(1.0, 2.0, 3.0)); //error. Not enough components.
+
vec3(vec4(1.0, 2.0, 3.0, 4.0) == vec3(1.0, 2.0, 3.0);
  vec2(vec3(1.0, 2.0, 3.0)); //error. Too many components.
+
vec4(vec3(1.0, 2.0, 3.0)); //error. Not enough components.
 +
vec2(vec3(1.0, 2.0, 3.0)); //error. Too many components.
 +
</source>
  
 
=== Matrix constructors ===
 
=== Matrix constructors ===
Line 209: Line 285:
 
For matrices, construction is rather more complicated.
 
For matrices, construction is rather more complicated.
  
If a matrix is constructed with a single scalar value, then that value is used to initialize all the values along the ''diagonal'' of the matrix; the rest are given zeros. Therefore, <code>mat4(1.0)</code> is a 4x4 identity matrix.
+
If a matrix is constructed with a single scalar value, then that value is used to initialize all the values along the ''diagonal'' of the matrix; the rest are given zeros. Therefore, {{code|mat4(1.0)}} is a 4x4 identity matrix.
  
 
For more values, matrices are filled in in column-major order. That is, the first X values are the first column, the second X values are the next column, and so forth. Examples:
 
For more values, matrices are filled in in column-major order. That is, the first X values are the first column, the second X values are the next column, and so forth. Examples:
  
<source lang="cpp">
+
<source lang="glsl">
 
mat2(
 
mat2(
 
   float, float,  //first column
 
   float, float,  //first column
Line 229: Line 305:
 
   vec2, float);  //third column
 
   vec2, float);  //third column
 
</source>
 
</source>
 
  
 
Matrices can be constructed from other matrices as well. A matrix can only be constructed from a single other matrix. The column and row values from the input matrix are copied to their corresponding values in the output; any values of the output not filled in are filled with the identity matrix.
 
Matrices can be constructed from other matrices as well. A matrix can only be constructed from a single other matrix. The column and row values from the input matrix are copied to their corresponding values in the output; any values of the output not filled in are filled with the identity matrix.
Line 244: Line 319:
 
=== Array constructors ===
 
=== Array constructors ===
  
 +
Arrays can be constructed using array constructor syntax. In this case, the type also contains the [] array notation:
  
 +
  const float array[3] = float[3](2.5, 7.0, 1.5);
 +
 +
The size is not necessary for array constructors, as the size is implicitly specified by the number of arguments to the constructor.
  
 
=== Struct constructors ===
 
=== Struct constructors ===
  
{{stub}}
+
Structs are constructed by filling in their values in the order in which they are defined. For example:
 +
 
 +
<source lang="glsl">
 +
struct Data
 +
{
 +
  float first;
 +
  vec2 second;
 +
};
 +
 
 +
Data dataValue = Data(1.4, vec2(16.0, 22.5));
 +
</source>
 +
 
 +
Notice the vector constructor in the middle of the struct constructor. Constructors can be nested. So if you have an array of structs of the above type, you can construct it as follows:
 +
 
 +
<source lang="glsl">
 +
Data dataArray[3] = Data[3](
 +
  Data(1.0, vec2(-19.0, 4.5)),
 +
  Data(-3.0, vec2(2.718, 2.0)),
 +
  Data(29.5, vec2(3.142, 3.333)));
 +
</source>
 +
 
 +
== Interface blocks ==
 +
{{main|GLSL Interface Blocks}}
 +
 
 +
Groups of variables that use the input, output, or uniform [[GLSL Type Qualifiers|type qualifiers]] can be grouped into named blocks. These have special syntax, and appear similar to a struct definition. However, they are not equivalent to structs.
 +
 
 +
== See also ==
 +
 
 +
* [[GLSL Type Qualifier]]
 +
* [[GLSL Predefined Variable]]
  
 
[[Category:OpenGL Shading Language]]
 
[[Category:OpenGL Shading Language]]

Revision as of 15:05, 2 November 2012

The OpenGL Shading Language defines a number of types. It also defines the means by which users can define types.

Basic types

Basic types in GLSL are the most fundamental types. Non-basic types are aggregates of these fundamental types.

Note: This document will mention double-precision types. These are only available on GL 4.0 and above, or with appropriate extension support.

Scalars

The basic non-vector types are:

  • bool​: conditional type, values may be either true or false
  • int​: a signed integer
  • uint​: an unsigned integer
  • float​: a floating point number
  • double​: a double-precision floating-point number

Vectors

Each of the scalar types, including booleans, have 2, 3, and 4-component vector equivalents. The n digit below can be 2, 3, or 4:

  • bvecn: a vector of booleans
  • ivecn: a vector of signed integers
  • uvecn: a vector of unsigned integers
  • vecn: a vector of single-precision floating-point numbers
  • dvecn: a vector of double-precision floating-point numbers

Vector values can have the same math operators applied to them that scalar values do. These all perform the component-wise operations on each component. However, in order for these operators to work on vectors, the two vectors must have the same number of components.

Swizzling

You can access the components of vectors using the following syntax:

vec4 someVec;
someVec.x + someVec.y;

This is called swizzling. You can use x, y, z, or w, referring to the first, second, third, and fourth components, respectively.

The reason it has that name "swizzling" is because the following syntax is entirely valid:

vec2 someVec;
vec4 otherVec = someVec.xyxx;
vec3 thirdVec = otherVec.zyy;

You can use any combination of up to 4 of the letters to create a vector (of the same basic type) of that length. So otherVec.zyy is a vec3, which is how we can initialize a vec3 value with it. Any combination of up to 4 letters is acceptable, so long as the source vector actually has those components. Attempting to access the 'w' component of a vec3 for example is a compile-time error.

Swizzling also works on l-values:

vec4 someVec;
someVec.wzyx = vec4(1.0, 2.0, 3.0, 4.0); //Reverses the order.
someVec.zx = vec2(3.0, 5.0); //Sets the 3rd component of someVec to 3.0 and the 1st component to 5.0

However, when you use a swizzle as a way of setting a value, you cannot use the same swizzle component twice. So someVec.xx = vec2(4.0, 4.0);​ is not allowed.

Additionally, there are 3 sets of swizzle masks. You can use xyzw, rgba (for colors), or stpq (for texture coordinates). These three sets have no actual difference; they're just syntactic sugar. You cannot combine names from different sets in a single swizzle operation. So ".xrs" is not a valid swizzle mask.

In GLSL 420/ARB_shading_language_420pack, scalars can be swizzled as well. They obviously only have one source component, but it is legal to do this:

float aFloat;
vec4 someVec = aFloat.xxxx;

Matrices

In addition to vectors, there are also matrix types. All matrix types are floating-point, either single-precision or double-precision. Matrix types are as follows, where n and m can be the numbers 2, 3, or 4:

  • matnxm: A matrix with n columns and m rows. OpenGL uses column-major matrices, which is standard for mathematics users. Example: mat3x4​.
  • matn: A matrix with n columns and n rows. Shorthand for matnxn

Double-precision matrices (GL 4.0 and above) can be declared with a dmat instead of mat​

Swizzling does not work with matrices. You can instead access a matrix's fields with array syntax:

mat3 theMatrix;
theMatrix[1] = vec3(3.0, 3.0, 3.0); //Sets the second column to all 3.0s
theMatrix[2][0] = 16.0; //Sets the first entry of the third column to 16.0.

However, the result of the first array accessor is a vector, so you can swizzle that:

mat3 theMatrix;
theMatrix[1].yzx = vec3(3.0, 1.0, 2.0);

Opaque types

Opaque types represent some external object which the shader references in some fashion. Opaque variables do not have "values" in the same way as regular types; they are markers that reference the real data. As such, they can only be used as parameters to functions. These functions return/modify the actual referenced data.

Variables of opaque types can only be declared in one of two ways. They can be declared at global scope, as a uniform​ variables. They can be aggregated into arrays of their opaque type, but they cannot be part of a buffer-backed interface block or a struct definition. They can also be declared locally, but only as in​-qualified function parameters.

Opaque types cannot be l-values. The only expressions that they can be a part of are array-indexing, structure field selection, and the parenthesis operator.

Samplers

Texture access is not as simple as reading a value from a memory address. Filtering and other processes are applied to textures, and how texture coordinates are interpreted can be part of the texture access operation. For these reason, texture access is somewhat complicated.

The sampler type is an opaque GLSL type that represents a texture bound to the OpenGL context. There are many sampler types, one for each type of texture (2D, 2D_ARRAY, etc). Samplers can only access textures of the proper type.

Images

Image variables refer to an image, of a particular type, stored within a texture. These are used for arbitrary loading/storing of values within shaders.

Atomic counters

Atomic variables represent a memory location within a Buffer Object upon which atomic operations can take place.

Implicit conversion

Certain values can be implicitly converted to certain types. This means that an explicit construction operation is not necessary.

Signed integers can be implicitly converted to unsigned integers, but the reverse is not true. Either integer type can be converted into floats, and integers and floats can be converted into doubles.

Vector and matrix values are implicitly converted if the basic type they contain is implicitly convertible.

Arrays

Basic types can be grouped into sequences of those elements, called arrays. This generally works like in C/C++, but there are some limitations. First and foremost is that arrays cannot be multidimensional (unless you have GL 4.3/ARB_arrays_of_arrays; see below}}.

Arrays usually must be declared with a size. Input arrays to geometry shaders do not need a size. Global variables can be declared without a size, but only if they are later redeclared with a size. An array in a buffer variable or shader storage interface block may be declared without a size, but only if it is the last variable in the block.

The array size must be a compile-time integral constant expression.

With a few exceptions, arrays can be used for all of the storage qualifiers: inputs, outputs, uniforms, constants, etc. Outputs from the fragment shader cannot be arrays.

The length of an array variable can be computed with the .length()​ function. For example:

uniform float myValues[12];
 
...
 
myValues.length();    //Returns 12.

Arrays can be accessed with arbitrary numeric expressions. They do not have to be compile-time constants (though there are a few exceptions to this rule; for example, the very next section).

Opaque arrays

Arrays of opaque types are special. Under GLSL version 3.30, sampler arrays (the only opaque type 3.30 provides) can be declared, but they can only be accessed by compile-time integral constant expressions. So you cannot loop over an array of samplers.

Under GLSL 4.00 and above, arrays of opaque can be accessed by non-compile-time constants, but there are still limitations. The expression used to access the array must be a Dynamically Uniform Expression. This means that the value used to access opaque arrays must be the same, in the same execution order, regardless of any non-uniform parameter values..

For example, in 4.00, it is legal to loop over an array of samplers, so long as the loop index is based on constants and uniforms. So this is legal:

uniform sampler images[10];
uniform int imageCount;
 
void main()
{
  vec4 accum = vec4(0.0);
  for(int i = 0; i < imageCount; i++)
  {
    accum += texture(images[i], ...);
  }
}

This would add up all of the values in the textures, up to imageCount in size. Note that this is not legal in GLSL 3.30.

Arrays of arrays

Arrays of arrays
Core in version 4.5
Core since version 4.3
Core ARB extension ARB_arrays_of_arrays

Given the presence of this feature, arrays can be declared multidimensionally in GLSL:

uniform vec3 multidim[5][2];

multidim​ is an array of 5 elements, where each element is an array of 2 vec2​ elements.

Such arrays can also be declared like this:

uniform vec3[5][2] multidim;

This may make things more clear.

If an array can be specified without a size (such as in buffer variables), only the first array index can be unsized.

buffer vec3[][2] multidim; //legal
buffer vec3[5][] multidim; //not legal

Structs

Structs are defined much like C++ (note: the common typedef struct *{} syntax from standard C is not supported). GLSL does not support anonymous structures (ie: structs without a type name), and structs must have at least one member declaration. Structs cannot be defined within another struct.

struct Light
{
  vec3 eyePosOrDir;
  bool isDirectional;
  vec3 intensity;
  float attenuation;
} variableName;

The above definition not only defines a struct type Light, it also creates a variable of that type called variableName. As in C/C++, the variable name can be omitted.

Structs cannot contain variables of sampler types. They can contain variables of other struct types.

Structs define a named type. But there are limits on the type qualifiers that can be used with struct types. Uniforms can use struct types, as well as regular globals, locals, and constant variables. Structs cannot be used with any other storage qualifiers.

Struct fields are accessed using the standard "." syntax from C/C++.

Structs can be passed as function parameters.

Constructors and initializers

Variables of almost any type can be initialized with an initial value. The exceptions are:

For basic types, the variable can be initialized by setting it equal to a literal value:

 uniform int aValue = 5;

Note that initializing a uniform only sets that variable at the moment that the program object is successfully compiled and linked. The user can override this value by manually setting that uniform value.

Literals

A literal is a value written into the shader. Literals are always basic types, and they can be used to initialize the value of a basic type. They can also be used wherever a constant basic value is needed.

Literals are typed. There are two literals of bool​ type: true​ and false.

Any integer value is by default of type int​ (a signed integer). To create an integer literal of unsigned type, use the suffix u​ or U​.

Integer literals can be defined in base 8 or base 16 using the standard C/C++ conventions (prefix with 0 for base 8 or 0x for base 16).

A numeric literal that uses a decimal is by default of type float​. To create a float literal from an integer value, use the suffix f​ or F​ as in C/C++.

Floats can also be defined using exponential notation, using the e​ or E​ to separate the base from the exponent. The exponent is always base-10.

In GLSL 4.00 and above, double-precision floats are available. By default, all floating-point literals are of type float. To create a double-precision float, use the lf​ or LF​ suffixes. This will force it to the double type.

Constructors

Types more complex than the base types are initialized with constructors. All constructors take the form:

 typename​(value1​, value2​, ...)

The typename​ is the name of the type to construct. The values can be literals, previously-defined variables, and other constructors.

Some constructors have special syntax.

Vector constructors

Vector constructors take the number of values that they store. So a vec3 takes 3 values. However, all vectors can be constructed from a single value; this results in a vector where all of the values are the value given to the constructor. So:

vec3(1.0) == vec3(1.0, 1.0, 1.0);

Vectors can also be constructed from other vectors, or a combination of vectors and scalars. The values in the output vector are filled in, right to left, by the values in the input scalars and vectors. There must be enough values, counting scalars and vectors, to fill in all of the elements of the output vector. Here are some examples:

vec4(vec2(10.0, 11.0), 1.0, 3.5) == vec4(10.0, vec2(11.0, 1.0), 3.5);
vec3(vec4(1.0, 2.0, 3.0, 4.0) == vec3(1.0, 2.0, 3.0);
vec4(vec3(1.0, 2.0, 3.0)); //error. Not enough components.
vec2(vec3(1.0, 2.0, 3.0)); //error. Too many components.

Matrix constructors

For matrices, construction is rather more complicated.

If a matrix is constructed with a single scalar value, then that value is used to initialize all the values along the diagonal of the matrix; the rest are given zeros. Therefore, mat4(1.0)​ is a 4x4 identity matrix.

For more values, matrices are filled in in column-major order. That is, the first X values are the first column, the second X values are the next column, and so forth. Examples:

mat2(
  float, float,   //first column
  float, float);  //second column
 
mat4(
  vec4,           //first column
  vec4,           //second column
  vec4,           //third column
  vec4);          //fourth column
 
mat3(
  vec2, float,    //first column
  vec2, float,    //second column
  vec2, float);   //third column

Matrices can be constructed from other matrices as well. A matrix can only be constructed from a single other matrix. The column and row values from the input matrix are copied to their corresponding values in the output; any values of the output not filled in are filled with the identity matrix.

Therefore:

 mat3 diagMatrix = mat3(5.0);  //Diagonal matrix with 5.0 on the diagonal.
 mat4 otherMatrix = mat4(diagMatrix);

The otherMatrix is a diagonal matrix, where the first 3 values are 5.0, and the last diagonal value is 1.0.

There are no restrictions on size when doing matrix construction from another matrix. So you can construct a 4x2 matrix from a 2x4 matrix; only the corresponding elements are copied.

Array constructors

Arrays can be constructed using array constructor syntax. In this case, the type also contains the [] array notation:

 const float array[3] = float[3](2.5, 7.0, 1.5);

The size is not necessary for array constructors, as the size is implicitly specified by the number of arguments to the constructor.

Struct constructors

Structs are constructed by filling in their values in the order in which they are defined. For example:

struct Data
{
  float first;
  vec2 second;
};
 
Data dataValue = Data(1.4, vec2(16.0, 22.5));

Notice the vector constructor in the middle of the struct constructor. Constructors can be nested. So if you have an array of structs of the above type, you can construct it as follows:

Data dataArray[3] = Data[3](
  Data(1.0, vec2(-19.0, 4.5)),
  Data(-3.0, vec2(2.718, 2.0)),
  Data(29.5, vec2(3.142, 3.333)));

Interface blocks

Groups of variables that use the input, output, or uniform type qualifiers can be grouped into named blocks. These have special syntax, and appear similar to a struct definition. However, they are not equivalent to structs.

See also