How WebGL Handles Geometry Outside Canvas Boundaries

When rendering 3D or 2D scenes, WebGL frequently encounters geometry that extends past the edges of the visible rendering area. Rather than throwing errors or rendering off-screen pixels, WebGL relies on an automated hardware pipeline feature known as clipping, paired with viewport mapping and rasterization rules. This article explains how WebGL processes vertices outside the canvas boundaries, how primitive clipping works, and how the viewport transformation dictates the final visible output.

The Clip Space Stage

All rendering in WebGL begins in the vertex shader, which assigns a position to every vertex via the special variable gl_Position. This position is defined in clip space using homogeneous coordinates \((x, y, z, w)\).

In clip space, the visible region—called the viewing frustum—is defined by the range:

\[-w \le x \le w\] \[-w \le y \le w\] \[-w \le z \le w\]

Any vertex whose coordinates fall outside these constraints is positioned outside the viewable volume.

Primitive Clipping and Culling

Before converting coordinates into screen pixels, the graphics hardware performs a fixed-function clipping stage:

  1. Complete Culling: If an entire primitive (such as a triangle, line, or point) lies entirely outside the clip boundaries, the GPU discards it completely. The fragment shader is never executed for this geometry, saving processing power.
  2. Clipping Intersecting Primitives: If a primitive spans both the inside and outside of the boundary, WebGL clips it. For triangles, the hardware computes the exact intersection points with the frustum edge, drops the exterior portion, and generates new vertices to construct one or more smaller sub-triangles that fit perfectly within the boundary.
  3. Perspective Division: Surviving geometry undergoes perspective division (dividing \(x, y,\) and \(z\) by \(w\)), converting coordinates to Normalized Device Coordinates (NDC), which consistently range from \(-1.0\) to \(+1.0\).

Viewport Mapping and Rasterization

Once coordinates are in NDC, WebGL maps them to the actual pixels of the HTML <canvas> element using the dimensions defined by gl.viewport(x, y, width, height).

  • If a geometry's mapped pixel coordinate falls outside the viewport rectangle, it simply produces no fragments during rasterization.
  • By default, the viewport matches the canvas resolution, meaning anything outside the \([-1.0, 1.0]\) NDC range maps to non-existent pixels outside the canvas and is ignored.
  • If the viewport is set smaller than the canvas, geometry outside the viewport bounds will not be drawn, leaving the rest of the canvas untouched unless cleared.

Scissor Testing

WebGL also provides an optional mechanism called the scissor test (gl.scissor), which establishes a sub-rectangle within the canvas. When enabled (gl.enable(gl.SCISSOR_TEST)), any fragments generated outside this specified rectangle are discarded, even if they fall within the normal viewport bounds.

Through automatic clipping at the hardware level and rasterization limits defined by the viewport, WebGL ensures that drawing outside the canvas boundaries is safe, mathematically precise, and optimized to consume minimal GPU resources.