Scissor Test

How to 3D

Chapter 5: Graphics Pipeline

Scissor Test

Perhaps you've played a game with a split-screen or a mini-map. Or perhaps you recently explored orthographic projections with this renderer:

There's a picture-in-picture display in the bottom-left corner.

Split-screens, mini-maps, and picture-in-picture displays are all achieved by rendering to multiple viewports. Each display's viewport is defined with a call to gl.viewport. For example, to set up a horizontal split-screen effect, which you might see in a two-player racing game, you might write this code:

const halfHeight = canvas.height / 2;

// gl.viewport's parameters are (x, y, width, height)
gl.viewport(0, 0, canvas.width, halfHeight);
// draw bottom racer

gl.viewport(0, halfHeight, canvas.width, halfHeight);
// draw top racer
const halfHeight = canvas.height / 2;

// gl.viewport's parameters are (x, y, width, height)
gl.viewport(0, 0, canvas.width, halfHeight);
// draw bottom racer

gl.viewport(0, halfHeight, canvas.width, halfHeight);
// draw top racer

Setting the viewport is usually not enough. If any geometry falls outside the viewport, it will bleed into neighboring viewports. You must perform two additional steps to staunch this bleeding:

Applying these steps results in this code:

gl.enable(gl.SCISSOR_TEST);

gl.viewport(0, 0, canvas.width, halfHeight);
gl.scissor(0, 0, canvas.width, halfHeight);
// draw bottom racer

gl.viewport(0, halfHeight, canvas.width, halfHeight);
gl.scissor(0, halfHeight, canvas.width, halfHeight);
// draw top racer
gl.enable(gl.SCISSOR_TEST);

gl.viewport(0, 0, canvas.width, halfHeight);
gl.scissor(0, 0, canvas.width, halfHeight);
// draw bottom racer

gl.viewport(0, halfHeight, canvas.width, halfHeight);
gl.scissor(0, halfHeight, canvas.width, halfHeight);
// draw top racer

The gl.viewport and gl.scissor calls use the same parameters, but both are needed because the viewport merely defines the transformation that converts normalized space coordinates into pixel coordinates. It doesn't stop fragments outside the viewport from being written to the framebuffer. The scissor test discards those fragments.

← Depth SortingBlending →