Skip to main content
GameDev.net gamedev.net

Texture Sampling Lab

by GameDev.net · GLSL ES 3.00 (WebGL2) · 25 Aug 2026

Use in your engine

Run the shader to adjust these controls.

What it demonstrates

Sampling a texture is one function call. Everything that makes it look right or wrong happens to the coordinate before that call, and to the channel settings around it. This lab puts a diagnostic chart on a channel and exposes scale, offset and rotation, so aspect errors, wrap behaviour, filtering and alpha are all things you can see rather than things you remember.

Source Revision 1

Author notes are linked to specific lines.

Shader inputs

void mainImage(out vec4 fragColor, in vec2 fragCoord)

Called once per pixel. Write the colour to fragColor.

iResolution vec3
Viewport size in pixels (z is the pixel aspect ratio).
iTime float
Seconds since the shader started.
iTimeDelta float
Seconds since the previous frame.
iFrameRate float
Frames per second, smoothed.
iFrame int
Frames rendered since the start.
iMouse vec4
Mouse position: xy while held, zw of the last click.
iDate vec4
Year, month, day, and seconds within the day.
iChannel0 sampler2D
Texture bound to channel 0.
iChannel1 sampler2D
Texture bound to channel 1.
iChannel2 sampler2D
Texture bound to channel 2.
iChannel3 sampler2D
Texture bound to channel 3.
iChannelResolution vec3[4]
Pixel size of each bound channel texture.
iChannelTime float[4]
Playback time of each channel, in seconds.
iSampleRate float
Audio sample rate, always 44100.
Main Image5
1 uniform float uScale; // @param 0.25..4.0 = 1.0 "UV scale"
2 uniform vec2 uOffset; // @param -1.0..1.0 = 0.0, 0.0 "UV offset"
3 uniform float uRotation; // @param -3.15..3.15 = 0.0 "Rotation"
4 uniform bool uMarkOutside; // @param = 1 "Mark outside 0-1"
5
6 void mainImage(out vec4 fragColor, in vec2 fragCoord) {
7 vec2 centered = (fragCoord - 0.5 * iResolution.xy) / iResolution.y;
8 float c = cos(uRotation);
9 float s = sin(uRotation);
10 vec2 rotated = vec2(centered.x * c - centered.y * s,
11 centered.x * s + centered.y * c);
12 vec2 uv = rotated * uScale + 0.5 + uOffset;
13
14 vec4 texel = texture(iChannel0, uv);
15
16 float checker = mod(floor(fragCoord.x / 16.0) + floor(fragCoord.y / 16.0), 2.0);
17 vec3 backdrop = mix(vec3(0.09, 0.10, 0.12), vec3(0.15, 0.16, 0.19), checker);
18 vec3 color = mix(backdrop, texel.rgb, texel.a);
19
20 if (uMarkOutside) {
21 vec2 outside = max(vec2(0.0) - uv, uv - vec2(1.0));
22 if (max(outside.x, outside.y) > 0.0) {
23 color = mix(color, vec3(0.95, 0.25, 0.40), 0.22);
24 }
25 }
26 fragColor = vec4(color, 1.0);
27 }
28

Inputs for this pass

  • iChannel0 textures/uv-test-v1.png
  • iChannel1 Empty
  • iChannel2 Empty
  • iChannel3 Empty

Learn from this shader

How it works

The fragment coordinate is centred and divided by height, which keeps the square chart square whatever shape the canvas is. That coordinate is rotated, scaled and shifted back to the middle before sampling. The chart is built to make mistakes obvious: four differently coloured corners and a single diagonal so a flip is unmistakable, concentric rings that turn into ellipses under an aspect error, a fine checkerboard that reveals filtering and minification, and a band along one edge whose alpha ramps to zero. Because the channel is set to repeat, scaling past one tiles the chart rather than smearing its edge pixels, and the tint marks every fragment whose coordinate left the zero to one range.

Try changing

Raise UV scale past one and watch the tiles appear, then imagine the same shader with the channel set to clamp instead. Rotate and note the rings stay circular. Drag UV offset and see the alpha band cross the frame. Turn the outside marker off to see how convincingly a repeat wrap hides itself.

Using it in a game

This is the coordinate maths behind every sprite atlas, scrolling background, decal and detail map. The two settings that are not code — filter and wrap — belong to the sampler in every engine, and choosing clamp instead of repeat is what stops a scrolled texture bleeding its opposite edge into frame.

Explore the techniques

Continue with curated explanations and progressively related examples.

LicenseMIT
Views0
Forks0

Discussion

Loading comments...