WebGL - Shaders: A Beginner's Guide

Hello, aspiring programmers! Today, we're going to embark on an exciting journey into the world of WebGL Shaders. Don't worry if you've never written a line of code before – I'll be your friendly guide through this colorful landscape of computer graphics.

WebGL - Shaders

What are Shaders?

Before we dive in, let's understand what shaders are. Imagine you're painting a picture. The canvas is your computer screen, and shaders are like magical paintbrushes that tell the computer exactly how to color each pixel. Cool, right?

Data Types

In the shader world, we have some special data types to work with. Let's look at them:

Data Type Description Example
float A single precision floating point number 3.14
vec2 A 2D vector vec2(1.0, 2.0)
vec3 A 3D vector vec3(1.0, 2.0, 3.0)
vec4 A 4D vector vec4(1.0, 2.0, 3.0, 4.0)
mat2 A 2x2 matrix mat2(1.0, 2.0, 3.0, 4.0)
mat3 A 3x3 matrix mat3(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0)
mat4 A 4x4 matrix mat4(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0)

Don't worry if these seem overwhelming – we'll use them step by step!

Qualifiers

Qualifiers are like special labels we put on our variables. They tell the shader how to treat these variables. Here are the main ones:

Qualifier Description
attribute Input values that change per vertex
uniform Input values that stay constant for all vertices
varying Values passed from vertex shader to fragment shader

Vertex Shader

The vertex shader is like the skeleton of our 3D model. It calculates where each point (vertex) of our model should be on the screen. Here's a simple vertex shader:

attribute vec3 aVertexPosition;
uniform mat4 uModelViewMatrix;
uniform mat4 uProjectionMatrix;

void main(void) {
    gl_Position = uProjectionMatrix * uModelViewMatrix * vec4(aVertexPosition, 1.0);
}

Let's break this down:

  1. We declare an attribute called aVertexPosition - this is the position of our vertex.
  2. We have two uniform matrices - these help us position and project our 3D model onto a 2D screen.
  3. In the main function, we calculate the final position of our vertex.

Fragment Shader

If the vertex shader is the skeleton, the fragment shader is the skin. It decides the color of each pixel. Here's a simple fragment shader:

precision mediump float;

void main(void) {
    gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
}

This shader is painting everything red! The vec4(1.0, 0.0, 0.0, 1.0) represents full red, no green, no blue, and full opacity.

Storing and Compiling the Shader Programs

Now that we've written our shaders, we need to tell WebGL about them. Here's how we do it in JavaScript:

function getShader(gl, id) {
    const shaderScript = document.getElementById(id);
    if (!shaderScript) return null;

    const str = shaderScript.text;
    let shader;

    if (shaderScript.type === "x-shader/x-fragment") {
        shader = gl.createShader(gl.FRAGMENT_SHADER);
    } else if (shaderScript.type === "x-shader/x-vertex") {
        shader = gl.createShader(gl.VERTEX_SHADER);
    } else {
        return null;
    }

    gl.shaderSource(shader, str);
    gl.compileShader(shader);

    if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
        alert(gl.getShaderInfoLog(shader));
        return null;
    }

    return shader;
}

This function does a few things:

  1. It finds our shader code in the HTML document.
  2. It creates a shader of the right type (vertex or fragment).
  3. It compiles the shader and checks for errors.

Combined Program

Finally, we need to combine our vertex and fragment shaders into a program:

const shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);

if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
    alert("Could not initialize shaders");
}

gl.useProgram(shaderProgram);

This code creates a program, attaches our shaders, links the program, and tells WebGL to use it.

And there you have it! You've just taken your first steps into the world of WebGL shaders. Remember, like learning any new language, it takes practice. Don't be discouraged if it doesn't click right away – keep experimenting and soon you'll be creating amazing 3D graphics in your web browser!

In my years of teaching, I've seen countless students go from complete beginners to shader wizards. One of my students even used these skills to create a virtual art gallery for her final project – imagine walking through a 3D museum right in your web browser!

So, what will you create with your new shader skills? The only limit is your imagination! Happy coding, future graphics gurus!

Credits: Image by storyset