Shader class

general

A shader in this context is a small program (also called kernel) that defines the calculation necessary to compute the resulting color for a certain pixel in one render step. further reading
In the general purpose GPU computing this may be for example the values contained in a cell (in an Eulerian framework) or the position of a particle (in a Lagrangian framework).
The shader class is a c++ class, that provides methods to load shaders from a text file, bind it into the render pipeline, connect input and output textures to the corresponding texture devices and perform a render step.

constructor

The constructor for a shader object takes two parameters, a header name and the source file. The header is just another textfile that is set at the beginning of the shader, so many shaders can share some parts of the code like domain size definitions and other often used functions and variables. The method adds the extension “.fsd” to the shader file name automatically. For every shader two files are necessary. The fragment shader file (.fsd), where the per pixel operations are defined, and a vector shader where texture coordinates and the resulting position of the pixel is calculated (.vsd). There is also a shader version without the header feature. If you are unsure check shader.h for parameters.
To construct a shader object, the code looks like:

shader s_euler(“shader/header”,”shader/euler”);
therefore we need a file called “euler.vsd” in the shader directory containing a simple vertex shader

void main ()
{
vec4 v = vec4(gl_Vertex);
gl_Position=gl_ModelViewProjectionMatrix*v;
gl_TexCoord[0]=gl_MultiTexCoord0;
}

and a file called “euler.fsd” containing the fragment shader, with the calculations we actually want to perform (e.g. a simple euler step)

uniform sampler2D t0; // incoming datafield, old state
uniform sampler2D t1; // incoming datafield, rhs
void main ()
{
vec4 z,k;
float dt=0.1; // timestep
z=texture2D(t0, vec2(gl_TexCoord[0])); // get old state in actual cell
k=texture2D(t1, vec2(gl_TexCoord[0])); // get rhs for actual cell

gl_FragData[0] = z+k*dt; // perform euler step and write it to gl_FragData[0]
}

gl_FragData[0] is the variable containing the color for the resulting pixel. It’s an array because it is possible to render to multiple render targets/textures in one step.

bind to textures

The datafields the calculations are performed on, are so called textures. Different GPU’s can handle different count of textures in one step for input and output. To define which texture is input and output, the shader class contains an array of pointers that have to be set to the corresponding texture object. The method bind() then binds the textures to the texture devices and set the texture variables in the shader to the correct devices.
In the code this looks like

s_euler->t[0]=z; // texture t0 in shader is bound to texture z in c++ code
s_euler->t[1]=rhs; // texture t1 in shader is bound to texture rhs in c++ code
s_euler->tout[0]=zneu; // gl_FragData[0] is written to texture zneu
s_euler->bind(); // bind shader to render pipeline, textures to texture devices and set uniform variables
s_euler->step(); // perform calculation step

This code together with the shaders defined in the upper part, perform one euler step on the state z using rhs. The result is saved in zneu.