Open In App

How to Animate Objects with WebGL?

Last Updated : 14 Aug, 2024
Comments
Improve
Suggest changes
Like Article
Like
Report

WebGL is the JavaScript API that allows the rendering 2D and 3D graphics directly within web browsers without the need for plugins. It provides low-level access to the GPU, enabling high-performance graphics and animations. By using WebGL, developers can create sophisticated animations and interactive visual effects that enhance user experiences on the web.

Below are the approaches to Animate Objects with WebGL:

Using the WebGL Built-in Animation Loop

In this approach, we are using the WebGL built-in animation loop to create a simple animation of a rectangle that moves horizontally across the canvas. The animation is achieved by updating the translation uniform in the vertex shader and reversing the direction when the rectangle reaches the canvas edges.

Syntax:

function render() {
// Rendering code here
requestAnimationFrame(render); // Schedule the next frame
}

render(); // Start the animation loop

Example: The below example uses WebGL Built-in Animation Loop.

HTML
<!DOCTYPE html>
<html lang="en">

<head>
    <title>Using the WebGL Built-in Animation Loop</title>
    <style>
        body {
            margin: 0;
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            height: 100vh;
            background-color: #000;
            overflow: hidden;
        }

        canvas {
            border: 1px solid #fff;
            margin-top: 20px;
        }

        h1 {
            color: green;
            text-align: center;
            font-size: 2em;
            margin: 0;
        }

        h3 {
            color: #fff;
            text-align: center;
            font-size: 1.2em;
            margin: 0;
            padding: 10px 20px;
            background-color: rgba(0, 0, 0, 0.5);
            border-radius: 5px;
            position: relative;
            top: 10px;
        }
    </style>
</head>

<body>
    <h1>GeeksforGeeks</h1>
    <h3>Using the WebGL Built-in Animation Loop</h3>
    <canvas id="webglCanvas"></canvas>
    <script src="script.js"></script>
</body>

</html>
JavaScript
const canvas = document.getElementById('webglCanvas');
const gl = canvas.getContext('webgl');
const canvasWidth = 600;
const canvasHeight = 400;
canvas.width = canvasWidth;
canvas.height = canvasHeight;
const vsSource = `
    attribute vec4 a_position;
    uniform vec2 u_translation;
    void main() {
        gl_Position = a_position + vec4(u_translation, 0.0, 0.0);
    }
`;
const fsSource = `
    void main() {
        gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); 
    }
`;
const vs = gl.createShader(gl.VERTEX_SHADER);
const fs = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(vs, vsSource);
gl.shaderSource(fs, fsSource);
gl.compileShader(vs);
gl.compileShader(fs);
const program = gl.createProgram();
gl.attachShader(program, vs);
gl.attachShader(program, fs);
gl.linkProgram(program);
gl.useProgram(program);
const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
const positions = new Float32Array([
    -0.5, -0.5,
    0.5, -0.5,
    -0.5, 0.5,
    0.5, 0.5
]);
gl.bufferData(gl.ARRAY_BUFFER, positions,
gl.STATIC_DRAW);
const positionLocation = gl.getAttribLocation(program, 
'a_position');
const translationLocation = gl.getUniformLocation(program,
'u_translation');
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
let translation = [0, 0];
let speed = 0.01;
function render() {
    gl.clear(gl.COLOR_BUFFER_BIT);
    translation[0] += speed;
    if (translation[0] > 1 || translation[0] < -1) {
        speed = -speed;
    }
    gl.uniform2fv(translationLocation, translation);
    gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
    requestAnimationFrame(render);
}
gl.viewport(0, 0, canvasWidth, canvasHeight);
gl.clearColor(0.0, 0.0, 0.0, 1.0);
render();

Output:

1
Output

Using Three.js for Advanced WebGL Animation

In this approach, we are using Three.js to create a more advanced WebGL animation featuring a rotating and scaling cube. The animation includes dynamic color changes, camera movement, and scaling effects, which are handled by a custom animation loop and various Three.js components like MeshStandardMaterial and PointLight.

Example: The below example uses Three.js for Advanced WebGL Animation.

HTML
<!DOCTYPE html>
<html lang="en">

<head>
    <title>Animated objects</title>
    <style>
        body {
            margin: 0;
            overflow: hidden;
        }

        canvas {
            display: block;
        }

        h1 {
            color: green;
            text-align: center;
            position: absolute;
            top: 20px;
            width: 100%;
            font-size: 2em;
            margin: 0;
        }

        h3 {
            color: #fff;
            text-align: center;
            font-size: 1.2em;
            position: absolute;
            top: 80px;
            width: 100%;
            margin: 0;
            background-color: rgba(0, 0, 0, 0.5);
            padding: 10px;
            border-radius: 5px;
        }
    </style>
</head>

<body>
    <h1>GeeksforGeeks</h1>
    <h3>Using Three.js for Advanced WebGL Animation</h3>
    <script src=
"https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
    <script src="script.js"></script>
</body>

</html>
JavaScript
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75,
    window.innerWidth / window.innerHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
const geometry = new THREE.BoxGeometry();
const material = new THREE.MeshStandardMaterial({ color: 0xff0000 });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
const light = new THREE.PointLight(0xffffff, 1, 100);
light.position.set(10, 10, 10);
scene.add(light);
camera.position.z = 10;
let scaleDirection = 1;
const scaleSpeed = 0.01;
const colorChangeSpeed = 0.005;
function animate() {
    requestAnimationFrame(animate);
    cube.rotation.x += 0.01;
    cube.rotation.y += 0.01;
    cube.scale.x += scaleDirection * scaleSpeed;
    cube.scale.y += scaleDirection * scaleSpeed;
    cube.scale.z += scaleDirection * scaleSpeed;
    if (cube.scale.x > 2 || cube.scale.x < 0.5) {
        scaleDirection *= -1;
    }
    const time = Date.now() * colorChangeSpeed;
    const r = Math.sin(time) * 0.5 + 0.5;
    const g = Math.sin(time + Math.PI / 2) * 0.5 + 0.5;
    const b = Math.sin(time + Math.PI) * 0.5 + 0.5;
    material.color.setRGB(r, g, b);
    camera.position.x = 10 * Math.sin(Date.now() * 0.001);
    camera.position.z = 10 * Math.cos(Date.now() * 0.001);
    camera.lookAt(scene.position);
    renderer.render(scene, camera);
}
window.addEventListener('resize', () => {
    renderer.setSize(window.innerWidth, window.innerHeight);
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
});
animate();

Output:

2
Output

Next Article

Similar Reads