Wrapping Coordinates

How to 3D

Chapter 9: Textures

Wrapping Coordinates

Texture coordinates are proportions rather than absolute column and row indices. Proportions are usually in [0, 1]. What happens if we let the coordinates wander outside this range? This square's texture coordinates span [-1, -1] at the bottom-left to [1.5, 1.5] at the top right:

By default, out-of-bounds texture coordinates cause the texture to repeat. This effect is often used to make a single image tile across a floor or wall. The graphics card maps the coordinate back into the [0, 1] range by effectively subtracting away the floor of the coordinate:

$$c' = c - \lfloor c \rfloor$$

For example, 1.6 maps to 0.6 because \(1.6 - 1 = 0.6\). -2.3 becomes 0.7 because \(-2.3 - -3 = 0.7\). Probably the graphics card implements this not with subtraction, but with some fast hardware instructions.

We can make this default behavior explicit by setting the texture's wrapping parameters to gl.REPEAT:

gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);

Physical space is often described as having x-, y-, and z-axes. To distinguish texture space from this physical space, some graphics developers say the texture's horizontal axis is the s-axis and the vertical axis is the t-axis. Thus the parameters are named gl.TEXTURE_WRAP_S and gl.TEXTURE_WRAP_T. The horizontal and vertical wrapping are independent, which is why two calls are needed.

We should only repeat a texture if it was designed to repeat seamlessly. Otherwise we will see jarring discontinuities between the repetitions. If changing the texture is too much work, we can switch to mirrored repetition:

gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.MIRRORED_REPEAT);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.MIRRORED_REPEAT);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.MIRRORED_REPEAT);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.MIRRORED_REPEAT);

See this in action by switching the renderer above to use mirrored repetition.

Sometimes we don't want any kind of repetition. Rather we want to clamp the coordinates to [0, 1], with any smaller coordinate forced to 0 and any larger coordinate forced to 1. If we had to implement this clamping in software, we might write this statement:

$$c' = \min(1, \max(0, c))$$

The graphics card will perform the clamping in hardware if we set the wrapping parameters to gl.CLAMP_TO_EDGE:

gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);

See this in action by switching the renderer above to use clamping.

← Looking Up TexelsPowers of Two →