Master WebGL & Three.js: From Basics to 3D Rendering in the Browser

This article guides beginners through the fundamentals of computer graphics, explaining OpenGL, WebGL, GLSL, and the rendering pipeline, then demonstrates practical Three.js code for setting up scenes, cameras, lights, materials, and textures to create interactive 3D web experiences.

ELab Team
ELab Team
ELab Team
Master WebGL & Three.js: From Basics to 3D Rendering in the Browser

Learning WebGL and Three.js: Concepts and Practice

This article is contributed by the ByteDance Business Middle‑Platform Frontend team and has been authorized for publication by ELab.

Background

Before preparing this talk, the author searched Zhihu for "How to learn WebGL?" and collected several popular answers, which emphasized a combination of graphics, mathematics, computer architecture, operating systems, software engineering, design patterns, and C++.

Graphics + Mathematics + Architecture + OS + Software Engineering + Design Patterns + Compilers + (C++ skill) ≈ a better 3D software engineer.

The typical learning path suggested by experts includes:

Build a solid foundation in graphics theory and mathematics.

Choose a specific domain such as Web (WebGL, Three.js), 3D engines, or game development (Unity).

Continuously learn and practice until you can build your own tools.

Key Technologies

OpenGL

OpenGL (Open Graphics Library) is a cross‑language, cross‑platform API for rendering 2D and 3D vector graphics. It defines a standard that GPU vendors must implement.

OpenGL ES is a subset of OpenGL designed for embedded systems such as mobile devices.

WebGL

WebGL (Web Graphics Library) is a royalty‑free web standard based on OpenGL ES that exposes a low‑level 3D graphics API to JavaScript via the HTML5 canvas element.

It allows browsers to run GPU‑accelerated graphics directly from JavaScript.

GLSL

GLSL (OpenGL Shading Language) is the C‑like language used to write vertex and fragment shaders that run on the GPU.

Think of the rendering pipeline as a series of stages, each handled by a small program (shader).

Three.js

Three.js is a high‑level JavaScript library that wraps WebGL, providing an easier way to create 3D scenes without writing low‑level shader code, similar to how jQuery simplifies DOM manipulation.

Three.js overview
Three.js overview

Understanding the GPU Design Model

Rendering transforms a 3D scene into a 2D pixel image. The GPU is specialized hardware that performs the same operation on many pixels in parallel, relieving the CPU of heavy per‑pixel calculations.

GPU vs CPU
GPU vs CPU

The graphics rendering pipeline consists of several stages:

Vertex Shader – transforms vertex positions and attributes.

Primitive Assembly – builds geometric primitives.

Geometry Shader – optional processing of primitives.

Rasterization – converts primitives to fragments (potential pixels).

Fragment Shader – computes final color of each fragment.

Depth & Blending – handles occlusion and transparency.

Rendering pipeline
Rendering pipeline

Coordinate Spaces

3D objects are defined in several coordinate systems:

Local Space – object‑centric coordinates.

World Space – shared scene coordinates.

View (Camera) Space – coordinates relative to the camera.

Clip Space – normalized coordinates after projection.

Screen Space – final 2D pixel positions.

Transformations between these spaces rely heavily on linear algebra (matrix multiplication, translation, scaling, rotation).

Coordinate spaces
Coordinate spaces

Practical Three.js Walkthrough

Step 1 – Create Scene and Camera

import * as THREE from 'three';
class ThreeDemo {
  constructor() {
    this.width = window.innerWidth;
    this.height = window.innerHeight;
    this.aspectRatio = this.width / this.height;
    this.scene = null;
    this.camera = null;
    this.light = null;
    this.renderer = null;
  }
  init() {
    this.createScene();
    this.createRenderer();
    document.body.appendChild(this.renderer.domElement);
    const render = () => {
      this.renderer.render(this.scene, this.camera);
      requestAnimationFrame(render);
    };
    render();
    this.axesHelper();
  }
  createScene() {
    this.scene = new THREE.Scene();
    this.scene.fog = new THREE.Fog(0x090918, 1, 600);
    this.camera = new THREE.PerspectiveCamera(75, this.aspectRatio, 0.1, 2000);
    this.camera.position.set(10, 10, 10);
    this.camera.updateProjectionMatrix();
    this.scene.add(this.camera);
  }
  createRenderer() {
    this.renderer = new THREE.WebGLRenderer({ antialias: true });
    this.renderer.setSize(this.width, this.height);
    this.renderer.setClearColor(this.scene.fog.color);
    window.addEventListener('resize', () => {
      this.camera.aspect = window.innerWidth / window.innerHeight;
      this.camera.updateProjectionMatrix();
      this.renderer.setSize(window.innerWidth, window.innerHeight);
    });
  }
  axesHelper() {
    const axesHelper = new THREE.AxesHelper(5);
    this.scene.add(axesHelper);
  }
}
const instance = new ThreeDemo();
instance.init();

Step 2 – Add Lights and Geometry

// Ambient light
this.light = new THREE.AmbientLight(0x404040);
this.scene.add(this.light);
// Add a cube
const geometry = new THREE.BoxGeometry(2, 2, 2);
const material = new THREE.MeshStandardMaterial({ color: 0xaafabb });
this.scene.add(new THREE.Mesh(geometry, material));
Cube with ambient light
Cube with ambient light

Step 3 – Add Directional Light

createLight() {
  this.light = new THREE.AmbientLight(0x404040);
  this.scene.add(this.light);
  this.directionalLight = new THREE.DirectionalLight(0xffffff, 0.6);
  this.directionalLight.position.set(0, 5, 5);
  this.scene.add(this.directionalLight);
}
Cube with directional light
Cube with directional light

Step 4 – Apply Materials and Textures

const geometry = new THREE.BoxGeometry(2, 2, 2);
const material = new THREE.MeshStandardMaterial({
  map: textureLoader.load('.../RoofTilesTerracotta004_COL_1K.jpg'),
  aoMap: textureLoader.load('.../RoofTilesTerracotta004_AO_1K.jpg'),
  normalMap: textureLoader.load('.../RoofTilesTerracotta004_NRM_1K.png'),
  transparent: true,
  roughness: 0,
});
const model = new THREE.Mesh(geometry, material);
this.scene.add(model);
Textured cube
Textured cube

Summary of Steps

Initialize Scene, Light, and Camera, then render them with a Renderer.

Load a Model, apply Material and Texture, position it, and add it to the Scene to obtain a visible 3D object.

Final Thoughts

If you have never systematically studied computer graphics, starting with Three.js is a practical way to grasp core concepts such as scenes, lights, cameras, shaders, and the rendering pipeline. Mastery of linear algebra and the GPU pipeline will later enable deeper exploration of WebGL and GLSL.

frontendGraphicsGPU3D renderingThree.jsWebGLShader
ELab Team
Written by

ELab Team

Sharing fresh technical insights

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.