Buffers in WebGL are important for storing and managing vertex and index data used in rendering. They allow for efficient transfer of data from JavaScript to the GPU, enabling smooth and flexible graphics rendering.
By creating and binding buffers, you can manage vertex attributes and indices for various geometric shapes, optimizing performance and resource utilization in WebGL applications.
These are the following approaches to create and use Buffers in WebGL:
Table of Content
1. Using Vertex Buffer
In this approach, we are using a WebGL vertex buffer to draw a simple triangle. We first define the vertex positions and store them in a buffer. The buffer is then bound and used to specify vertex attributes for rendering. The triangle is drawn using the gl.drawArrays method, with vertices defined by the buffer.
Syntax:
// Create a buffer
const vertexBuffer = gl.createBuffer();
// Bind the buffer to the ARRAY_BUFFER target
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
// Provide data to the buffer
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
// Get the attribute location
const positionLocation = gl.getAttribLocation(program, 'a_position');
// Enable the attribute
gl.enableVertexAttribArray(positionLocation);
// Specify how to pull data from the buffer
gl.vertexAttribPointer(positionLocation, 3, gl.FLOAT, false, 0, 0);
Example: The below example uses Vertex Buffer to draw Triangle.
<!DOCTYPE html>
<html>
<head>
<title>WebGL Buffer Example 1</title>
<style>
body {
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
background-color: #f0f0f0;
}
canvas {
border: 1px solid black;
}
h1 {
color: green;
margin-bottom: 10px;
}
h3 {
margin-top: 0;
margin-bottom: 20px;
}
</style>
</head>
<body>
<h1>GeeksforGeeks</h1>
<h3>Approach 1: Using Vertex Buffer</h3>
<canvas id="glCanvas" width="300" height="300"></canvas>
<script>
const canvas = document.getElementById('glCanvas');
const gl = canvas.getContext('webgl');
if (!gl) {
console.error('WebGL not supported');
}
const vertexShaderSource = `
attribute vec4 a_position;
void main() {
gl_Position = a_position;
}
`;
const fragmentShaderSource = `
precision mediump float;
void main() {
gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); // Red color
}
`;
function createShader(gl, sourceCode, type) {
const shader = gl.createShader(type);
gl.shaderSource(shader, sourceCode);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
console.error(gl.getShaderInfoLog(shader));
gl.deleteShader(shader);
return null;
}
return shader;
}
function createProgram(gl, vertexShader, fragmentShader) {
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
console.error(gl.getProgramInfoLog(program));
gl.deleteProgram(program);
return null;
}
return program;
}
const vertexShader = createShader(gl, vertexShaderSource, gl.VERTEX_SHADER);
const fragmentShader = createShader(gl, fragmentShaderSource, gl.FRAGMENT_SHADER);
const program = createProgram(gl, vertexShader, fragmentShader);
gl.useProgram(program);
const vertices = new Float32Array([
0.0, 0.5, 0.0,
-0.5, -0.5, 0.0,
0.5, -0.5, 0.0
]);
const vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
const positionLocation = gl.getAttribLocation(program, 'a_position');
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation, 3, gl.FLOAT, false, 0, 0);
gl.clearColor(0.9, 0.9, 0.9, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, 3);
</script>
</body>
</html>
Output

2. Using Index Buffer
In this approach, we are using an index buffer to render a rectangle. We define the vertex positions and their corresponding indices. The index buffer specifies the order in which vertices are used to draw the shape. We use gl.drawElements to render the shape based on these indices, which allows for efficient reuse of vertex data.
Syntax
// Create a buffer
const indexBuffer = gl.createBuffer();
// Bind the buffer to the ELEMENT_ARRAY_BUFFER target
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
// Provide data to the buffer
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
// Draw using the index buffer
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT, 0);
Example: The below example uses Index Buffer to draw a rectangle.
<!DOCTYPE html>
<html>
<head>
<title>WebGL Buffer Example 2</title>
<style>
body {
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
background-color: #f0f0f0;
}
canvas {
border: 1px solid black;
}
h1 {
color: green;
margin-bottom: 10px;
}
h3 {
margin-top: 0;
margin-bottom: 20px;
}
</style>
</head>
<body>
<h1>GeeksforGeeks</h1>
<h3>Approach 2: Using Index Buffer</h3>
<canvas id="glCanvas" width="300" height="300"></canvas>
<script>
const canvas = document.getElementById('glCanvas');
const gl = canvas.getContext('webgl');
if (!gl) {
console.error('WebGL not supported');
}
const vertexShaderSource = `
attribute vec4 a_position;
void main() {
gl_Position = a_position;
}
`;
const fragmentShaderSource = `
precision mediump float;
void main() {
gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0); // Blue color
}
`;
function createShader(gl, sourceCode, type) {
const shader = gl.createShader(type);
gl.shaderSource(shader, sourceCode);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
console.error(gl.getShaderInfoLog(shader));
gl.deleteShader(shader);
return null;
}
return shader;
}
function createProgram(gl, vertexShader, fragmentShader) {
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
console.error(gl.getProgramInfoLog(program));
gl.deleteProgram(program);
return null;
}
return program;
}
const vertexShader = createShader(gl, vertexShaderSource, gl.VERTEX_SHADER);
const fragmentShader = createShader(gl, fragmentShaderSource, gl.FRAGMENT_SHADER);
const program = createProgram(gl, vertexShader, fragmentShader);
gl.useProgram(program);
const vertices = new Float32Array([
-0.5, 0.5, 0.0,
-0.5, -0.5, 0.0,
0.5, -0.5, 0.0,
0.5, 0.5, 0.0
]);
const indices = new Uint16Array([
0, 1, 2,
0, 2, 3
]);
const vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
const indexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
const positionLocation = gl.getAttribLocation(program, 'a_position');
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation, 3, gl.FLOAT, false, 0, 0);
gl.clearColor(0.9, 0.9, 0.9, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT, 0);
</script>
</body>
</html>
Output
