GLSL Language
GLSL is strictly typed programming language which means you can't combine different datatypes.
int myvar = 1.0*3;
is not possible because you can't combine float
with int
datatype.
You can combine these with type declaration
int myvar = int(1.0)*3;
Datatypes
Common datatypes in GLSL are bool
,int
andfloat
.
with v.x v.y v.z
we can access the components of the vectors. We also can use the arrayformat v[0]
.
vec4 vector;
vector[0] = vector.r = vector.x = vector.s;
vector[1] = vector.g = vector.y = vector.t;
vector[2] = vector.b = vector.z = vector.p;
vector[3] = vector.a = vector.w = vector.q;
GLSL also has constants const
. The difference is that these must be initialised and they can't be changed in the code.
Varying
A varying is a variable that gets passed from the vertex shader to the frament shader.
In the vertex shader varyings get defined with out
and in the fragment shader they get definied with in
If
Other way to write an if condition
float func(... bool soften){
float edge = (soften) ? radius * 0.05 : 0.0;
// (soften) ? if soften
// 0.05 - true condition
// 0.0 - false condition
}
For-Loop
Functions
If you have functions that have the same name but they have differnt input parameters the get considered as different functions.
bool inRect(vec2 pt, vec4 rect){
bool result = false;
//calculate
return bool;
}
bool inRect(float x, float y, vec4 rect){
bool result = false;
//calculate
return bool;
}
The fragment and the vertex shader have a void main()
function that automatically gets called.
Swizzling
Swizzling in GLSL is the possibility to reorder values from a vector.
Swizzling also allows to write shorter versions of the variables
fragCoord.xy <=> vec2(fragCoord.x,fragCoord.y);
When the vectors have the same length writing the calculations between the vectors can be shortened
vec2(v1.x/v2.x,v1.y/v2.y) <=> v1/v2
Preprocessor Macros
With preprocessor macros you can define values like constants for example.
They get evaluated in the first step before the compiling of the shader.
#define float TWO_PI = 3.1415926535
You also can define conditional definitions with
Float defintion
In shader float values and their accuracy play a big role. If the accuracy the values are less acurate but the shader is faster.
We define the accuracy of these in a preprocessor macro
Uniforms
The GPU of a computer is executing a big amount of parallel tasks - called threads. Every thread calculates the color value for one pixel.
GLSL uses uniform
to pass Data from the control framework like P5.js, TouchDesigner, Three.js, etc. into the shader and the single threads so the data is available and can be processed by the shader.
uniform
is the same for all threads and can just be read by the shader -> so the shader can't change the value of the uniform.
Uniforms can have all possible GLSL datatypes.
So uniforms save values from outside the shader so they can used in the shader
There are some standard uniforms:
- u_mouse
Coordinates of the mouse on the screen
- u_time
passed time in seconds since the program start
- u_resolution
size of canvas/window in pixels
We define uniforms like uniform datatype name
.
Debugging
In shader there aren't many possibilities to debug. One option is to assign the currently calculated pixel extreme color values.