WebGL - Shaders

Shaders are the programs that run on GPU. Shaders are written in OpenGL ES Shader Language (known as ES SL). ES SL has variables of its own, data types, qualifiers, built-in inputs and outputs.
The following table lists the basic data types provided by OpenGL ES SL.
void
Represents an empty value.
bool
Accepts true or false.
int
This is a signed integer data type.
float
This is a floating scalar data type.
vec2, vec3, vec4
n-component floating point vector
bvec2, bvec3, bvec4
Boolean vector
ivec2, ivec3, ivec4
signed integer vector
mat2, mat3, mat4
2x2, 3x3, 4x4 float matrix
sampler2D
Access a 2D texture
samplerCube
Access cube mapped texture
There are three main qualifiers in OpenGL ES SL −
attribute
This qualifier acts as a link between a vertex shader and OpenGL ES for per-vertex data. The value of this attribute changes for every execution of the vertex shader.
uniform
This qualifier links shader programs and the WebGL application. Unlike attribute qualifier, the values of uniforms do not change. Uniforms are read-only; you can use them with any basic data types, to declare a variable.
Example − uniform vec4 lightPosition;
varying
This qualifier forms a link between a vertex shader and fragment shader for interpolated data. It can be used with the following data types − float, vec2, vec3, vec4, mat2, mat3, mat4, or arrays.
Example − varying vec3 normal;
Vertex shader is a program code, which is called on every vertex. It transforms (move) the geometry (ex: triangle) from one place to other. It handles the data of each vertex (per-vertex data) such as vertex coordinates, normals, colors, and texture coordinates.
In the ES GL code of vertex shader, programmers have to define attributes to handle data. These attributes point to a Vertex Buffer Object written In JavaScript. The following tasks can be performed using vertex shaders along with vertex transformation −
Vertex transformation
Normal transformation and normalization
Texture coordinate generation
Texture coordinate transformation
Lighting
Color material application
OpenGL ES SL provides the following predefined variables for vertex shader −
highp vec4 gl_Position;
Holds the position of the vertex.
mediump float gl_PointSize;
Holds the transformed point size. The units for this variable are pixels.
Take a look at the following sample code of a vertex shader. It processes the vertices of a triangle.
attribute vec2 coordinates;

void main(void) {
   gl_Position = vec4(coordinates, 0.0, 1.0);
};
If you observe the above code carefully, we have declared an attribute variable with the name coordinates. (This variable will be associated with the Vertex Buffer Object using the method getAttribLocation(). The attribute coordinates is passed as a parameter to this method along with the shader program object.)
In the second step of the given vertex shader program, the gl_position variable is defined.
gl_Position is the predefined variable which is available only in the vertex shader program. It contains the vertex position. In the above code, the coordinates attribute is passed in the form of a vector. As vertex shader is a per-vertex operation, the gl_position value is calculated for each vertex.
Later, the gl_position value is used by primitive assembly, clipping, culling, and other fixed functionality operations that operate on the primitives after the vertex processing is over.
We can write vertex shader programs for all possible operations of vertex shader, which we will discuss individually in this tutorial.
A mesh is formed by multiple triangles, and the surface of the each triangle is known as a fragment. A fragment shader is the code that runs on every pixel on each fragment. This is written to calculate and fill the color on individual pixels. The following tasks can be performed using fragment shaders −
Operations on interpolated values
Texture access
Texture application
Fog
Color sum
OpenGL ES SL provides the following predefined variables for fragment shader −
mediump vec4 gl_FragCoord;
Holds the fragment position within the frame buffer.
bool gl_FrontFacing;
Holds the fragment that belongs to a front-facing primitive.
mediump vec2 gl_PointCoord;
Holds the fragment position within a point (point rasterization only).
mediump vec4 gl_FragColor;
Holds the output fragment color value of the shader
mediump vec4 gl_FragData[n]
Holds the fragment color for color attachment n.
The following sample code of a fragment shader shows how to apply color to every pixel in a triangle.
void main(void) {
   gl_FragColor = vec4(0, 0.8, 0, 1);
}
In the above code, the color value is stored in the variable gl.FragColor. The fragment shader program passes the output to the pipeline using fixed function variables; FragColor is one of them. This variable holds the color value of the pixels of the model.
Since shaders are independent programs, we can write them as a separate script and use in the application. Or, you can store them directly in string format, as shown below.
var vertCode =
   'attribute vec2 coordinates;' +
	
   'void main(void) {' +
      ' gl_Position = vec4(coordinates, 0.0, 1.0);' +
   '}';
Compilation involves following three steps −
Creating the shader object
Attaching the source code to the created shader object
Compiling the program
To create an empty shader, WebGL provides a method called createShader(). It creates and returns the shader object. Its syntax is as follows −
Object createShader (enum type)

As observed in the syntax, this method accepts a predefined enum value as parameter. We have two options for this −
gl.VERTEX_SHADER for creating vertex shader
gl.VERTEX_SHADER for creating vertex shader
gl.FRAGMENT_SHADER for creating fragment shader.
gl.FRAGMENT_SHADER for creating fragment shader.
You can attach the source code to the created shader object using the method shaderSource(). Its syntax is as follows −
void shaderSource(Object shader, string source)

This method accepts two parameters −
shader − You have to pass the created shader object as one parameter.
shader − You have to pass the created shader object as one parameter.
Source − You have to pass the shader program code in string format.
Source − You have to pass the shader program code in string format.
To compile the program, you have to use the method compileShader(). Its syntax is as follow −
compileShader(Object shader)

This method accepts the shader program object as a parameter. After creating a shader program object, attach the source code to it and pass that object to this method.
The following code snippet shows how to create and compile a vertex shader as well as a fragment shader to create a triangle.
// Vertex Shader
var vertCode =
   'attribute vec3 coordinates;' +
	
   'void main(void) {' +
      ' gl_Position = vec4(coordinates, 1.0);' +
   '}';

var vertShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertShader, vertCode);
gl.compileShader(vertShader);
 
// Fragment Shader
var fragCode =
   'void main(void) {' +
      ' gl_FragColor = vec4(0, 0.8, 0, 1);' +
   '}';

var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragShader, fragCode);
gl.compileShader(fragShader);
After creating and compiling both the shader programs, you need to create a combined program containing both the shaders (vertex & fragment). The following steps need to be followed −
Create a program object
Attach both the shaders
Link both the shaders
Use the program
Create a program object by using the method createProgram(). It will return an empty program object. Here is its syntax −
createProgram();

Attach the shaders to the created program object using the method attachShader(). Its syntax is as follows −
attachShader(Object program, Object shader);

This method accepts two parameters −
Program − Pass the created empty program object as one parameter.
Program − Pass the created empty program object as one parameter.
Shader − Pass one of the compiled shaders programs (vertex shader, fragment shader)
Shader − Pass one of the compiled shaders programs (vertex shader, fragment shader)
Note − You need to attach both the shaders using this method.
Link the shaders using the method linkProgram(), by passing the program object to which you have attached the shaders. Its syntax is as follows −
linkProgram(shaderProgram);

WebGL provides a method called useProgram(). You need to pass the linked program to it. Its syntax is as follows −
useProgram(shaderProgram);

The following code snippet shows how to create, link, and use a combined shader program.
var shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertShader);
gl.attachShader(shaderProgram, fragShader);
gl.linkProgram(shaderProgram);
gl.useProgram(shaderProgram); 


    10 Lectures 
     1 hours 

 Frahaan Hussain

    28 Lectures 
     4 hours 

 Frahaan Hussain
 Print
 Add Notes
 Bookmark this page