WebGL - Drawing a Quad

Hello, aspiring web developers! Today, we're going to embark on an exciting journey into the world of WebGL, where we'll learn how to draw a quadrilateral (or "quad" for short). Don't worry if you're new to programming – I'll guide you through each step with the patience of a seasoned teacher who's helped countless students just like you.

WebGL - Drawing a Quad

What is WebGL?

Before we dive into drawing quads, let's take a moment to understand what WebGL is. WebGL (Web Graphics Library) is a powerful JavaScript API that allows us to create stunning 2D and 3D graphics in web browsers. It's like having a magical paintbrush that can bring your imagination to life on a web page!

Steps to Draw a Quadrilateral

Now, let's break down the process of drawing a quad into manageable steps. Think of it as building a house – we'll start with the foundation and work our way up.

Step 1: Set up the HTML Canvas

First, we need a canvas to draw on. In HTML, we use the <canvas> element. It's like setting up an easel for painting.

<canvas id="myCanvas" width="600" height="400">
    Your browser does not support the HTML5 canvas tag.
</canvas>

Step 2: Initialize WebGL Context

Next, we need to get our WebGL context. This is like picking up our magical WebGL paintbrush.

const canvas = document.getElementById('myCanvas');
const gl = canvas.getContext('webgl');

if (!gl) {
    console.log('WebGL not supported, falling back on experimental-webgl');
    gl = canvas.getContext('experimental-webgl');
}

if (!gl) {
    alert('Your browser does not support WebGL');
}

Step 3: Create Vertex Shader

Now, we'll create a vertex shader. This tells WebGL where to draw our quad's corners.

const vertexShaderSource = `
    attribute vec2 a_position;
    void main() {
        gl_Position = vec4(a_position, 0.0, 1.0);
    }
`;

const vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertexShaderSource);
gl.compileShader(vertexShader);

Step 4: Create Fragment Shader

The fragment shader decides what color our quad will be. Let's make it a cheerful blue!

const fragmentShaderSource = `
    precision mediump float;
    void main() {
        gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0);
    }
`;

const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragmentShaderSource);
gl.compileShader(fragmentShader);

Step 5: Create and Link Program

Now, we'll create a program and link our shaders to it. This is like putting our paintbrush and paint together.

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

Step 6: Create Buffer and Load Vertex Data

Time to define our quad's corners!

const positions = [
    -0.7, -0.5,
     0.7, -0.5,
     0.7,  0.5,
    -0.7,  0.5
];

const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);

Step 7: Connect Position Buffer to Attribute

We need to tell WebGL how to read our position data.

const positionAttributeLocation = gl.getAttribLocation(program, "a_position");
gl.enableVertexAttribArray(positionAttributeLocation);
gl.vertexAttribPointer(positionAttributeLocation, 2, gl.FLOAT, false, 0, 0);

Step 8: Draw the Quad

Finally, the moment we've been waiting for – let's draw our quad!

gl.useProgram(program);
gl.drawArrays(gl.TRIANGLE_FAN, 0, 4);

Example – Draw a Quadrilateral

Now, let's put it all together in one complete example:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>WebGL Quad</title>
</head>
<body>
    <canvas id="myCanvas" width="600" height="400">
        Your browser does not support the HTML5 canvas tag.
    </canvas>

    <script>
        const canvas = document.getElementById('myCanvas');
        const gl = canvas.getContext('webgl');

        if (!gl) {
            alert('Your browser does not support WebGL');
        }

        const vertexShaderSource = `
            attribute vec2 a_position;
            void main() {
                gl_Position = vec4(a_position, 0.0, 1.0);
            }
        `;

        const fragmentShaderSource = `
            precision mediump float;
            void main() {
                gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0);
            }
        `;

        const vertexShader = gl.createShader(gl.VERTEX_SHADER);
        gl.shaderSource(vertexShader, vertexShaderSource);
        gl.compileShader(vertexShader);

        const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
        gl.shaderSource(fragmentShader, fragmentShaderSource);
        gl.compileShader(fragmentShader);

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

        const positions = [
            -0.7, -0.5,
             0.7, -0.5,
             0.7,  0.5,
            -0.7,  0.5
        ];

        const positionBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);

        const positionAttributeLocation = gl.getAttribLocation(program, "a_position");
        gl.enableVertexAttribArray(positionAttributeLocation);
        gl.vertexAttribPointer(positionAttributeLocation, 2, gl.FLOAT, false, 0, 0);

        gl.useProgram(program);
        gl.drawArrays(gl.TRIANGLE_FAN, 0, 4);
    </script>
</body>
</html>

And there you have it! Your very own WebGL quad. When you open this HTML file in a browser, you should see a beautiful blue quadrilateral on the canvas.

Conclusion

Congratulations on drawing your first WebGL quad! We've covered a lot of ground today, from setting up the canvas to creating shaders and finally drawing our shape. Remember, learning WebGL is like learning to paint – it takes practice and patience. Don't be discouraged if it doesn't click immediately. Keep experimenting, and soon you'll be creating amazing 3D graphics on the web!

In our next lesson, we'll explore how to add interactivity to our WebGL creations. Until then, happy coding!

Method Description
getContext('webgl') Gets the WebGL rendering context
createShader() Creates a shader object
shaderSource() Sets the source code of a shader
compileShader() Compiles a shader
createProgram() Creates a program object
attachShader() Attaches a shader to a program
linkProgram() Links a program object
createBuffer() Creates a buffer object
bindBuffer() Binds a buffer object to a target
bufferData() Creates and initializes a buffer object's data store
getAttribLocation() Returns the location of an attribute variable
enableVertexAttribArray() Enables a vertex attribute array
vertexAttribPointer() Specifies the layout of vertex attribute data
useProgram() Sets the current program object
drawArrays() Renders primitives from array data

Credits: Image by storyset