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.
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