Master WebGL: From Basics to Shaders and Texture Mapping

This article provides a comprehensive overview of WebGL, explaining its relationship to OpenGL ES, the structure of WebGL programs, shader programming (vertex and fragment shaders), storage qualifiers, a step‑by‑step colored‑triangle example, the rendering pipeline, and practical texture‑mapping techniques with code samples.

ELab Team
ELab Team
ELab Team
Master WebGL: From Basics to Shaders and Texture Mapping

WebGL Overview

WebGL is a technology that combines HTML5 and JavaScript to draw and render complex 3D graphics on web pages. It operates through a JavaScript API that mirrors OpenGL ES, allowing 3D scenes to be displayed on a 2‑D canvas.

WebGL and OpenGL

OpenGL is a specification, not an API, that standardizes graphics operations across GPU vendors. WebGL inherits from OpenGL ES 2.0, which introduced programmable shaders that let developers control pixel positions and colors via GLSL.

Structure of a WebGL Program

WebGL browsers implement the OpenGL/OpenGL ES standards and support the GLSL ES shading language, which is supplied as strings in JavaScript and compiled at runtime.

Shaders

Shaders are GPU programs that perform rendering. WebGL uses a pair of shaders: a vertex shader and a fragment (pixel) shader.

Vertex Shader

The vertex shader computes vertex positions and passes data to the rasterizer. By default, colors are linearly interpolated across vertices.

Example vertex shader code:

attribute vec4 a_Position;
attribute float a_PointSize;
attribute vec4 a_Color;
varying vec4 v_Color;
void main() {
  gl_Position = a_Position;
  gl_PointSize = a_PointSize;
  v_Color = a_Color;
}

Built‑in variables such as gl_Position and gl_PointSize represent the vertex position and size. Custom variables must not start with webgl_ or _webgl.

Fragment Shader

The fragment shader computes the color of each pixel. It receives interpolated values from the vertex shader via varying variables and writes the final color to gl_FragColor.

Example fragment shader code:

precision mediump float;
varying vec4 v_Color;
void main() {
  gl_FragColor = v_Color;
}

Storage Qualifiers

GLSL uses storage qualifiers to indicate how variables are used. Common qualifiers include attribute (for vertex inputs), uniform (constant across a draw call), and varying (interpolated between vertex and fragment shaders).

Attribute

Attributes are only available in vertex shaders and describe per‑vertex data such as position, texture coordinates, and color. They are supplied via buffer objects.

Using Buffers to Set Vertex Data

Creating a buffer:

// create buffer object
const vertexBuffer = gl.createBuffer();

Writing data to the buffer:

const vertices = new Float32Array([
  -0.5, 0.5, 10.0, 1.0, 0.0, 0.0, 1.0,
  -0.5, -0.5, 20.0, 0.0, 1.0, 0.0, 1.0,
   0.5, 0.5, 30.0, 0.0, 0.0, 1.0, 1.0
]);
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);

Setting attribute pointers and enabling them:

gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, SIZE * 7, 0);
gl.vertexAttribPointer(a_PointSize, 1, gl.FLOAT, false, SIZE * 7, SIZE * 2);
gl.vertexAttribPointer(a_Color, 4, gl.FLOAT, false, SIZE * 7, SIZE * 3);
gl.enableVertexAttribArray(a_Position);
gl.enableVertexAttribArray(a_PointSize);
gl.enableVertexAttribArray(a_Color);

Uniform Global Variables

Uniforms are constant for all vertices or fragments during a draw call and can be shared between vertex and fragment shaders.

Varying Variables

Varyings pass interpolated data from the vertex shader to the fragment shader.

A Simple Example: Colored Triangle

The following code draws a triangle with vertices colored red, green, and blue. The colors are interpolated across the surface.

// vertex shader
const vs_source = `
  attribute vec4 a_Position;
  attribute float a_PointSize;
  attribute vec4 a_Color;
  varying vec4 v_Color;
  void main() {
    gl_Position = a_Position;
    gl_PointSize = a_PointSize;
    v_Color = a_Color;
  }
`;

// fragment shader
const fs_source = `
  precision mediump float;
  varying vec4 v_Color;
  void main() {
    gl_FragColor = v_Color;
  }
`;

const canvas = document.getElementById('app');
const gl = canvas.getContext('webgl');
// ... shader compilation and linking ...
gl.drawArrays(gl.TRIANGLES, 0, 3);

Interpolation of v_Color causes the triangle to appear with a smooth gradient.

WebGL Rendering Pipeline

For each vertex, the vertex shader runs, storing results in the assembly area. The chosen primitive type (e.g., gl.TRIANGLES) assembles vertices into geometry, which is then rasterized into fragments. The fragment shader runs for each fragment, writing colors to the framebuffer.

Image Rendering (Texture Mapping)

To render images, textures are mapped onto geometry. Since WebGL can only draw points, lines, and triangles, a rectangle is formed from two triangles and the image is applied as a texture.

Texture Mapping Steps

Prepare a power‑of‑two texture image.

Define vertex positions and corresponding texture coordinates.

Load the image, flip the Y axis, activate a texture unit, bind the texture, and set filtering parameters.

Pass the texture unit to the sampler uniform.

In the fragment shader, sample the texture and assign the result to gl_FragColor.

Example shader code for texture mapping:

// vertex shader
const vs_source = `
  attribute vec4 a_Position;
  attribute vec2 a_TexCoord;
  varying vec2 v_TexCoord;
  void main() {
    gl_Position = a_Position;
    v_TexCoord = a_TexCoord;
  }
`;

// fragment shader
const fs_source = `
  precision mediump float;
  uniform sampler2D u_Sampler;
  varying vec2 v_TexCoord;
  void main() {
    gl_FragColor = texture2D(u_Sampler, v_TexCoord);
  }
`;

Loading the texture in JavaScript:

const texture = gl.createTexture();
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, img);
gl.uniform1i(u_Sampler, 0);
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

glslWebGLgraphics programmingtexture mappingShaders
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.