Skip to content

WebGL and Three.js — 3D Graphics in the Browser

DodaTech Updated 2026-06-21 6 min read

In this tutorial, you'll learn about WebGL and Three.js. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.

WebGL is a JavaScript API for rendering 2D and 3D graphics in the browser without plugins, and Three.js is a high-level library that makes WebGL accessible by abstracting shaders, buffers, and pipeline management.

What You'll Learn & Why It Matters

In this tutorial, you will learn how to create 3D scenes in the browser using WebGL directly and through the Three.js library. You will build interactive 3D visualizations that run on any device with a web browser.

Real-world use: Product configurators, data dashboards, architectural walkthroughs, and even antivirus UI dashboards use WebGL. At DodaTech, we use Three.js for real-time security analytics visualizations.

Prerequisites

  • OpenGL Basics (previous)
  • JavaScript fundamentals
  • Basic understanding of 3D math

Learning Path

flowchart LR
  A[OpenGL Basics] --> B[WebGL and Three.js]
  B --> C[Shader Programming]
  B --> D[Texture Mapping]
  B --> E[Post-Processing]
  C --> F[Compute Shaders]
  B:::current

  classDef current fill:#f90,color:#fff,stroke:#333,stroke-width:2px

WebGL vs OpenGL

WebGL 2.0 is based on OpenGL ES 3.0. The concepts are identical: you have a Rendering Pipeline, shaders written in GLSL, vertex buffers, and framebuffers. The main difference is the host language (JavaScript) and the absence of a native windowing system.

<canvas id="glCanvas" width="800" height="600"></canvas>
<script>
const canvas = document.getElementById('glCanvas');
const gl = canvas.getContext('webgl2');

if (!gl)
{
    console.error('WebGL 2.0 not supported');
}

gl.clearColor(0.1, 0.1, 0.2, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
</script>

Three.js Fundamentals

Three.js wraps raw WebGL and provides a clean object-oriented API. The three core objects are the scene, camera, and renderer.

import * as THREE from 'three';

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, 800 / 600, 0.1, 1000);
const renderer = new THREE.WebGLRenderer();
renderer.setSize(800, 600);
document.body.appendChild(renderer.domElement);

const geometry = new THREE.BoxGeometry(1, 1, 1);
const material = new THREE.MeshPhongMaterial({ color: 0x44aa88 });
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);

const light = new THREE.DirectionalLight(0xffffff, 1);
light.position.set(5, 5, 5);
scene.add(light);

camera.position.z = 5;

The Animation Loop

function animate()
{
    requestAnimationFrame(animate);
    cube.rotation.x += 0.01;
    cube.rotation.y += 0.01;
    renderer.render(scene, camera);
}
animate();

Expected output: A rotating turquoise cube with directional lighting on a dark background.

flowchart TD
  A[Scene] --> B[Mesh]
  B --> C[Geometry + Material]
  A --> D[Light]
  A --> E[Camera]
  F[Renderer] --> G[Render Scene with Camera]
  G --> H[Animate Frame]
  H --> F

Working with Geometry

Three.js provides geometry primitives and supports custom geometry:

// Custom triangle geometry
const geometry = new THREE.BufferGeometry();
const vertices = new Float32Array([
    -1.0, -1.0, 0.0,
     1.0, -1.0, 0.0,
     0.0,  1.0, 0.0
]);
geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));

const material = new THREE.MeshBasicMaterial({ color: 0xff6600, side: THREE.DoubleSide });
const triangle = new THREE.Mesh(geometry, material);
scene.add(triangle);

Textures and Materials

const textureLoader = new THREE.TextureLoader();
const texture = textureLoader.load('brick.jpg');

const material = new THREE.MeshStandardMaterial({
    map: texture,
    roughness: 0.7,
    metalness: 0.2
});

MeshStandardMaterial uses physically-based rendering (PBR), which responds realistically to lights. Properties like roughness and metalness control how light interacts with the surface.

OrbitControls for Interaction

import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;

function animate()
{
    requestAnimationFrame(animate);
    controls.update();
    renderer.render(scene, camera);
}

Writing Raw WebGL Shaders

When you need custom effects, you can write GLSL shaders with Three.js:

const vertexShader = `
    varying vec2 vUv;
    void main()
    {
        vUv = uv;
        gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
    }
`;

const fragmentShader = `
    varying vec2 vUv;
    uniform float time;
    void main()
    {
        vec3 color = vec3(
            sin(vUv.x * 10.0 + time) * 0.5 + 0.5,
            cos(vUv.y * 10.0 + time) * 0.5 + 0.5,
            sin((vUv.x + vUv.y) * 10.0 + time) * 0.5 + 0.5
        );
        gl_FragColor = vec4(color, 1.0);
    }
`;

const material = new THREE.ShaderMaterial({
    vertexShader: vertexShader,
    fragmentShader: fragmentShader,
    uniforms: { time: { value: 0 } }
});

Performance Considerations

  • Use BufferGeometry instead of Geometry (deprecated)
  • Reuse materials and geometries across meshes
  • Use mergeBufferGeometries for static objects
  • Limit draw calls by combining meshes
  • Use LOD (level of detail) for distant objects

Common Errors & Mistakes

1. CORS Errors with Textures

Mistake: Loading textures from a file:// URL or a different domain without CORS headers.

Fix: Serve your page via HTTP (localhost or a web server) and ensure textures come from the same origin or have CORS permissions.

2. Not Calling renderer.setSize

Mistake: Using the default renderer size (300x150) and wondering why the output is small.

Fix: Always call renderer.setSize(width, height) matching your canvas or viewport dimensions.

3. Forgetting requestAnimationFrame

Mistake: Calling render() once in a loop without requestAnimationFrame, causing the browser tab to freeze.

Fix: Use requestAnimationFrame for smooth, efficient animation that pauses when the tab is hidden.

4. Not Setting Camera Aspect Ratio

Mistake: Creating a perspective camera with the default aspect ratio that looks stretched.

Fix: Match the camera aspect ratio to the renderer size: new THREE.PerspectiveCamera(75, width / height, 0.1, 1000).

Practice Questions

Question 1

What is the difference between WebGL and Three.js?

Show answer WebGL is a low-level JavaScript API for GPU rendering. Three.js is a high-level library that wraps WebGL, handling buffers, shaders, and pipeline management so you can create 3D scenes with minimal code.

Question 2

Why use OrbitControls in a 3D scene?

Show answer OrbitControls provides mouse-driven camera manipulation (rotate, pan, zoom) which is essential for interactive 3D visualizations. It handles all the math for orbiting around a target point.

Question 3

What is the purpose of the animation loop?

Show answer The animation loop using `requestAnimationFrame` updates scene state and re-renders each frame, creating smooth animation. It pauses when the tab is hidden, saving battery and CPU.

Question 4

How does MeshStandardMaterial differ from MeshBasicMaterial?

Show answer MeshBasicMaterial renders without lighting (flat color/texture). MeshStandardMaterial uses PBR lighting calculations, responding to scene lights with proper reflections, shadows, and material properties.

Challenge

Build a 3D solar system visualization using Three.js with orbital animation, textured planets, a starfield background, and mouse-controlled camera. Use at least four planets with different orbital speeds and sizes.

FAQ

Do I need a server to run WebGL?

WebGL works from file:// URLs for basic content, but textures and some features require an HTTP server due to CORS restrictions. Use npx serve or Python's http.server for local development.

Can WebGL run on mobile devices?

Yes. WebGL 2.0 runs on most modern mobile browsers (Chrome, Safari, Firefox). Performance depends on the device GPU but basic 3D works on mid-range phones.

Is Three.js still maintained?

Yes, Three.js is actively maintained with regular releases. Version r170+ is current in 2026, with ongoing improvements to WebGPU support, shadow rendering, and performance.

What is WebGPU and should I learn it?

WebGPU is the successor to WebGL, offering lower-level GPU access in the browser. It is available in Chrome and Edge. Learn WebGL/Three.js first, then explore WebGPU for advanced use cases.


Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.

Author: DodaTech | Last updated: June 21, 2026

DodaTech tutorials are built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro — security tools used by millions worldwide.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro