Introduction to GLSL Syntax
- Variable
- Statement
- Qualifier
- Preprocessor macro definition
Scalar
The way to construct a scalar is the same as the C language:
Vector
The rules for constructing a vector are as follows:
- If a scalar is provided to the vector constructor, all values of the vector are set to the scalar value.
- If multiple scalar values or vectors are provided, the provided values are assigned from left to right, provided that the sum of the number of scalars or vectors is equal to the number of vector constructors.
vec2 myVec2 = vec2(0.5, 0.5); // myVec2 = {0.5, 0.5}
vec4 newVec4 = vec4(1.0, 1.0, myVec2);// newVec4 = {1.0, 1.0, 0.5, 0.5}
Vectors can be accessed via r, g, b, a
or x, y, z, w
, and multiple indices can be accessed simultaneously:
vec4 myVec4_0 = vec4(1.0); // myVec4_0 = { 1.0, 1.0, 1.0, 1.0 }
vec4 myVec4 = vec4(1.0, 2.0, 3.0, 4.0); // myVec4 = { 1.0, 2.0, 3.0, 4.0 }
float x = myVec4.x; // x = 1.0;
vec3 myVec3_0 = myVec4.xyz; // myVec3_0 = { 1.0, 2.0, 3.0 }
vec3 myVec3_1 = myVec4.rgb; // myVec3_1 = { 1.0, 2.0, 3.0 }
vec3 myVec3_2 = myVec4.zyx; // myVec3_2 = { 3.0, 2.0, 1.0 }
vec3 myVec3_3 = myVec4.xxx; // myVec3_3 = { 1.0, 1.0, 1.0 }
In GLSL, mat[2..4] can be constructed to represent matrices of order 2 to 4.
The matrix construction has the following rules:
- Matrices can be constructed from multiple vectors
- Matrices can be constructed from a single scalar from left to right
mat4 marixt4x4 = mat4(1.0); // marixt4x4 = { 1.0, 0.0, 0.0, 0.0,
// 0.0, 1.0, 0.0, 0.0
// 0.0, 0.0, 1.0, 0.0
// 0.0, 0.0, 0.0, 1.0 }
vec2 col1 = vec2(1.0, 0.0);
vec2 col2 = vec2(1.0, 0.0);
mat2 matrix2x2 = mat2(coll1, col2);
// GLSL is a column-matrix store, so when constructed, the constructor fills in column order
mat3 matrix3x3 = mat3(0.0, 0.0, 0.0, // Column 0
0.0, 0.0, 0.0, // Column 1
0.0, 0.0, 0.0); // Column 2
Access to the matrix
Matrix can access different columns by index:
mat2 matrix2x2 = mat2(0.0, 0.0, 0.0, 0.0);
vec4 myVec4 = vec4(matrix2x2[0], matrix2x2[1]);
vec2 myVec2 = matrix2x2[0];
// Access the first element of the first column
matrix2x2[1][1] = 2.0;
Structure
The formation of structure is similar to that of C language, and it can be aggregated from different data types:
An example of code to construct a structure is as follows:
myStruct structVar = myStruct(vec4(0.0, 0.0,0.0,0.0), vec4(1.0, 1.0, 1.0, 1.0), vec2(0.5, 0.5));
Structs support assignment (=) and comparison (==, !=) operators, but require that both structs have the same type and must be the same component-wise.
Array
- Arrays must have a declared length
- Array cannot be initialized at the same time as declaration
- Arrays must be initialized by constant expressions
- Arrays cannot be decorated with
const
- Multidimensional arrays are not supported
An example of code for array declaration and initialization is as follows:
float array[4];
for(int i =0; i < 4; i ++)
{
array[i] = 0.0;
GLSL supports standard C/C++ control flow, including:
if-esle
/switch-case
for
/while
/do-while
break
/continue
/return
- There is no
goto
, usediscard
to jump out. This statement is only valid under the fragment shader. It should be noted that using this statement will cause the pipeline to discard the current fragment and will not write to the frame buffer.
The usage of if-else
is consistent with the C language, the code example is as follows:
if(v_uvMode >= 3.0) {
i.uv = v_uv0 * v_uvSizeOffset.xy + v_uvSizeOffset.zw;
} else if (v_uvMode >= 2.0) {
i.uv = fract(v_uv0) * v_uvSizeOffset.xy + v_uvSizeOffset.zw;
} else if (v_uvMode >= 1.0) {
i.uv = evalSlicedUV(v_uv0) * v_uvSizeOffset.xy + v_uvSizeOffset.zw;
} else {
i.uv = v_uv0;
}
In GLSL, loop must be constant or known at compile time. The code example is as follows:
const float value = 10.;
for(float i = 0.0; i < value; i ++){
...
Error example:
Function
A GLSL function consists of return value, function name and parameter, where the return value and function name are required. If there is no return value, you need to use void
instead.
The code example is as follows:
void scaleMatrix (inout mat4 m, float s){
m[0].xyz *= s;
m[1].xyz *= s;
m[2].xyz *= s;
}
Storage qualifier
Storage qualifiers are used to describe the role of variables in the pipeline.
Uniform
Uniform
declared within a render pass cannot be repeated. For example, if the variable variableA
is defined in the vertex shader, variableA
will also exist in the fragment shader with the same value, then variableA
cannot be defined again in the fragment shader.
Varying
varying
is the variable output by the vertex shader and passed to the fragment shader. Under the action of the pipeline, the variable value will not be consistent with the output of the vertex shader, but will be interpolated by the pipeline, which may cause the normal of the vertex output to not be normalized. At this point, manual normalization is required. The code example is as follows:
// normalized the normal from vertex shader
vec3 normal = normalize(v_normal);
Parameter qualifiers for functions in GLSL include the following:
Precision qualifier
GLSL introduces precision qualifiers for specifying the precision of integer or floating point variables. Precision qualifiers allow shader writers to explicitly define the precision with which shader variables are computed.
The precision declared in the Shader header applies to the entire Shader, and is the default precision for all floating-point-based variables, and it is also possible to define the precision of a single variable. If no default precision is specified in Shader, all integer and floating point variables are calculated with high precision.
The precision qualifiers supported by GLSL include the following:
The code example is as follows:
highp mat4 cc_matWorld;
mediump vec2 dir;
lowp vec4 cc_shadowColor;
GLSL allows the definition of macros similar to the C language.
Preprocessing macro definitions allow shaders to define a variety of dynamic branches that determine the final rendering effect.
An example of code defined using preprocessor macros in GLSL is as follows:
#define
#undef
#if
#ifdef
#ifndef
#else
#endif
The following code example declares a four-dimensional vector named v_color
only if the USE_VERTEX_COLOR
condition is true: