DEV Community

Cover image for Creating Simple Shaders in WebGL: A Step-by-Step Guide
Haider Aftab
Haider Aftab

Posted on

Creating Simple Shaders in WebGL: A Step-by-Step Guide

WebGL (Web Graphics Library) is a powerful JavaScript API for rendering 2D and 3D graphics in a web browser. One of the fundamental skills in WebGL programming is creating and using shaders. Shaders are small programs that run on the GPU to control the rendering process. This guide will walk you through the steps to create basic shaders using WebGL.

Getting Started

Before diving into shader programming, you need a basic HTML structure to set up a WebGL context. Here’s a simple HTML template to get started:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>WebGL Shaders</title>
    <style>
        body { margin: 0; }
        canvas { display: block; }
    </style>
</head>
<body>
    <canvas id="glCanvas"></canvas>
    <script src="shader.js"></script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

Setting Up WebGL

Next, create a JavaScript file (shader.js) to initialize WebGL and compile the shaders.

Initializing WebGL

function initWebGL() {
    const canvas = document.getElementById('glCanvas');
    const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');

    if (!gl) {
        alert('Unable to initialize WebGL. Your browser may not support it.');
        return;
    }

    return gl;
}

const gl = initWebGL();
if (gl) {
    gl.clearColor(0.0, 0.0, 0.0, 1.0);  // Clear to black, fully opaque
    gl.clear(gl.COLOR_BUFFER_BIT);      // Clear the color buffer
}
Enter fullscreen mode Exit fullscreen mode

Creating Shaders

Shaders in WebGL are written in GLSL (OpenGL Shading Language). You need two types of shaders: a vertex shader and a fragment shader.

Vertex Shader

The vertex shader processes each vertex's position.

const vsSource = `
    attribute vec4 aVertexPosition;

    void main(void) {
        gl_Position = aVertexPosition;
    }
`;
Enter fullscreen mode Exit fullscreen mode

Fragment Shader

The fragment shader processes each pixel's color.

Copy code
const fsSource = `
    void main(void) {
        gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);  // Red color
    }
`;
Enter fullscreen mode Exit fullscreen mode

Compiling Shaders

To use the shaders, you need to compile and link them into a shader program.

function loadShader(gl, type, source) {
    const shader = gl.createShader(type);

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

    if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
        console.error('An error occurred compiling the shaders:', gl.getShaderInfoLog(shader));
        gl.deleteShader(shader);
        return null;
    }

    return shader;
}

const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource);
const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);

function initShaderProgram(gl, vs, fs) {
    const shaderProgram = gl.createProgram();
    gl.attachShader(shaderProgram, vs);
    gl.attachShader(shaderProgram, fs);
    gl.linkProgram(shaderProgram);

    if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
        console.error('Unable to initialize the shader program:', gl.getProgramInfoLog(shaderProgram));
        return null;
    }

    return shaderProgram;
}

const shaderProgram = initShaderProgram(gl, vertexShader, fragmentShader);
Enter fullscreen mode Exit fullscreen mode

Using the Shader Program

Now, set up the vertex buffer and draw the scene using the shader program.

Setting Up the Vertex Buffer

function initBuffers(gl) {
    const vertices = new Float32Array([
        -0.5, -0.5,
         0.5, -0.5,
         0.0,  0.5,
    ]);

    const vertexBuffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
    gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);

    return vertexBuffer;
}

const vertexBuffer = initBuffers(gl);
Drawing the Scene
javascript
Copy code
function drawScene(gl, shaderProgram, vertexBuffer) {
    gl.clear(gl.COLOR_BUFFER_BIT);

    const vertexPosition = gl.getAttribLocation(shaderProgram, 'aVertexPosition');
    gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
    gl.vertexAttribPointer(vertexPosition, 2, gl.FLOAT, false, 0, 0);
    gl.enableVertexAttribArray(vertexPosition);

    gl.useProgram(shaderProgram);

    gl.drawArrays(gl.TRIANGLES, 0, 3);
}

drawScene(gl, shaderProgram, vertexBuffer);
Enter fullscreen mode Exit fullscreen mode

Conclusion

This guide covered the basics of setting up a WebGL context, creating and compiling shaders, and rendering a simple triangle using a basic vertex and fragment shader. With this foundation, you can start exploring more advanced shader techniques and create complex visual effects for your WebGL applications.

Stay Connected:

Twitter: @HaiderAftab007
Instagram: @HaiderAftab007
LinkedIn: Haider Aftab
Website: GLSL
BuyMeCoffe: HaiderAftab

Top comments (0)