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.
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);Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
