OpenGL Cheatsheet
Textures
Use this OpenGL reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.
Creating and Binding Textures
GLuint tex; glGenTextures(1, &tex); glBindTexture(GL_TEXTURE_2D, tex); // Upload image data glTexImage2D(GL_TEXTURE_2D, /*mip=*/0, GL_RGBA8, width, height, /*border=*/0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); glGenerateMipmap(GL_TEXTURE_2D); // auto-generate all mip levels
DSA (GL 4.5+) — preferred
GLuint tex; glCreateTextures(GL_TEXTURE_2D, 1, &tex); // Immutable storage — format and dimensions fixed (recommended) glTextureStorage2D(tex, mipLevels, GL_RGBA8, width, height); glTextureSubImage2D(tex, /*mip=*/0, /*x=*/0, /*y=*/0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); glGenerateTextureMipmap(tex);
Texture Targets
| Target | Description |
|---|---|
GL_TEXTURE_1D | 1D texture |
GL_TEXTURE_2D | 2D texture |
GL_TEXTURE_3D | 3D / volume texture |
GL_TEXTURE_1D_ARRAY | Array of 1D textures |
GL_TEXTURE_2D_ARRAY | Array of 2D textures |
GL_TEXTURE_CUBE_MAP | 6-face cube map |
GL_TEXTURE_CUBE_MAP_ARRAY | Array of cube maps (GL 4.0+) |
GL_TEXTURE_2D_MULTISAMPLE | MSAA texture |
GL_TEXTURE_2D_MULTISAMPLE_ARRAY | MSAA texture array |
GL_TEXTURE_RECTANGLE | Non-power-of-2 (integer UV, no mips) |
GL_TEXTURE_BUFFER | 1D view into a buffer object |
Internal Formats
Sized color formats
| Format | Channels | Bit depth | Notes |
|---|---|---|---|
GL_R8 | R | 8 unorm | — |
GL_RG8 | RG | 8+8 unorm | — |
GL_RGB8 | RGB | 8+8+8 unorm | No alpha |
GL_RGBA8 | RGBA | 8×4 unorm | Most common |
GL_SRGB8 | RGB | 8×3 sRGB | Auto linearize on sample |
GL_SRGB8_ALPHA8 | RGBA | sRGB+linear A | — |
GL_R16F | R | 16-bit float | HDR single channel |
GL_RGB16F | RGB | 16-bit float | HDR color |
GL_RGBA16F | RGBA | 16-bit float | Most common HDR |
GL_R32F | R | 32-bit float | Full precision |
GL_RGBA32F | RGBA | 32-bit float | — |
GL_R8I / GL_R8UI | R | 8-bit int/uint | Integer texture |
GL_RGBA8I / GL_RGBA8UI | RGBA | 8-bit int/uint | — |
GL_R11F_G11F_B10F | RGB | 11+11+10 float | Compact HDR, no alpha |
GL_RGB9_E5 | RGB | Shared exponent | — |
GL_RGB10_A2 | RGBA | 10+10+10+2 | — |
Depth / stencil formats
| Format | Description |
|---|---|
GL_DEPTH_COMPONENT16 | 16-bit depth |
GL_DEPTH_COMPONENT24 | 24-bit depth |
GL_DEPTH_COMPONENT32F | 32-bit float depth |
GL_DEPTH24_STENCIL8 | Packed depth+stencil |
GL_DEPTH32F_STENCIL8 | Float depth + stencil |
GL_STENCIL_INDEX8 | Stencil only |
Compressed formats
| Format | Notes |
|---|---|
GL_COMPRESSED_RGB_S3TC_DXT1_EXT | BC1 (EXT_texture_compression_s3tc) |
GL_COMPRESSED_RGBA_S3TC_DXT5_EXT | BC3 |
GL_COMPRESSED_RED_RGTC1 | BC4 |
GL_COMPRESSED_RG_RGTC2 | BC5 |
GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT | BC6H |
GL_COMPRESSED_RGBA_BPTC_UNORM | BC7 |
// Upload pre-compressed data glCompressedTexImage2D(GL_TEXTURE_2D, mip, internalFormat, width, height, 0, imageSize, data);
Texture Parameters
// Wrapping glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // DSA: glTextureParameteri(tex, GL_TEXTURE_WRAP_S, GL_REPEAT); // Filtering glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // Border color (used with GL_CLAMP_TO_BORDER) float border[] = { 0.0f, 0.0f, 0.0f, 1.0f }; glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border); // Anisotropic filtering (widely supported, core in GL 4.6) float maxAniso; glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY, &maxAniso); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY, maxAniso); // LOD clamp glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, 0.0f); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 1000.0f); // default glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -0.5f); // sharper // Swizzle (remap channels) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_RED); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_GREEN); // or all at once GLint swiz[] = { GL_RED, GL_RED, GL_RED, GL_ONE }; // R as grayscale glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swiz); // Mip range glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 8);
Wrap modes
| Value | Behavior |
|---|---|
GL_REPEAT | Tile (default) |
GL_MIRRORED_REPEAT | Tile with mirror on each repeat |
GL_CLAMP_TO_EDGE | Clamp to edge texel |
GL_CLAMP_TO_BORDER | Clamp; outside uses GL_TEXTURE_BORDER_COLOR |
GL_MIRROR_CLAMP_TO_EDGE | Mirror once, then clamp |
Filter modes
| Min filter | Description |
|---|---|
GL_NEAREST | Nearest texel |
GL_LINEAR | Bilinear |
GL_NEAREST_MIPMAP_NEAREST | Nearest mip, nearest texel |
GL_LINEAR_MIPMAP_NEAREST | Nearest mip, bilinear |
GL_NEAREST_MIPMAP_LINEAR | Trilinear, nearest texel |
GL_LINEAR_MIPMAP_LINEAR | Trilinear (best, default recommended) |
| Mag filter | Description |
|---|---|
GL_NEAREST | Nearest texel |
GL_LINEAR | Bilinear |
Gotcha: mag filter cannot be a mipmap filter — only
GL_NEARESTorGL_LINEAR.
Binding to Texture Units
// Activate unit and bind glActiveTexture(GL_TEXTURE0 + unit); // unit = 0..GL_MAX_TEXTURE_IMAGE_UNITS-1 glBindTexture(GL_TEXTURE_2D, tex); // Set sampler uniform to the unit index glUniform1i(glGetUniformLocation(prog, "uAlbedo"), unit); // DSA binding (GL 4.5+) glBindTextureUnit(unit, tex); // no glActiveTexture needed
Samplers
A sampler object decouples filter/wrap state from the texture object.
GLuint sampler; glGenSamplers(1, &sampler); glSamplerParameteri(sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glSamplerParameteri(sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glSamplerParameteri(sampler, GL_TEXTURE_WRAP_S, GL_REPEAT); glSamplerParameterf(sampler, GL_TEXTURE_MAX_ANISOTROPY, 16.0f); glBindSampler(unit, sampler); // sampler overrides texture's own params glDeleteSamplers(1, &sampler);
Shadow / Depth Texture Comparison
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LESS); // Returns 0.0 or 1.0 (or filtered PCF result) from sampler2DShadow
uniform sampler2DShadow uShadowMap; float shadow = texture(uShadowMap, vec3(uv, compareDepth));
Cube Maps
glCreateTextures(GL_TEXTURE_CUBE_MAP, 1, &tex); glTextureStorage2D(tex, mips, GL_RGB8, width, height); // Upload each face GLenum faces[] = { GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z }; for (int i = 0; i < 6; i++) { // Can use glTextureSubImage3D with zoffset=i for cube maps glTextureSubImage3D(tex, 0, 0, 0, i, width, height, 1, GL_RGB, GL_UNSIGNED_BYTE, faceData[i]); } glTextureParameteri(tex, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTextureParameteri(tex, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTextureParameteri(tex, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
uniform samplerCube uCubemap;
vec3 color = texture(uCubemap, direction).rgb;Texture Arrays
glCreateTextures(GL_TEXTURE_2D_ARRAY, 1, &tex); glTextureStorage3D(tex, mips, GL_RGBA8, width, height, layerCount); glTextureSubImage3D(tex, 0, 0, 0, layer, width, height, 1, GL_RGBA, GL_UNSIGNED_BYTE, data);
uniform sampler2DArray uAtlas; vec4 color = texture(uAtlas, vec3(uv, float(tileIndex)));
Image Units (for Compute / Load-Store)
// Bind a texture level to an image unit for shader read/write glBindImageTexture( /*unit=*/0, tex, /*level=*/0, /*layered=*/GL_FALSE, /*layer=*/0, GL_READ_WRITE, // GL_READ_ONLY, GL_WRITE_ONLY, GL_READ_WRITE GL_RGBA32F // must match texture internal format );
layout(rgba32f, binding = 0) uniform image2D uImage; vec4 v = imageLoad(uImage, ivec2(gl_GlobalInvocationID.xy)); imageStore(uImage, ivec2(gl_GlobalInvocationID.xy), v * 2.0);
GLSL Sampler Types
| Type | Texture |
|---|---|
sampler1D / sampler2D / sampler3D | 1D/2D/3D |
samplerCube | Cube map |
sampler1DArray / sampler2DArray | 1D/2D array |
samplerCubeArray | Cube map array |
sampler2DRect | Rectangle texture |
sampler2DMS / sampler2DMSArray | MSAA |
samplerBuffer | Buffer texture |
sampler1DShadow / sampler2DShadow | Depth comparison |
samplerCubeShadow | Cube shadow |
sampler2DArrayShadow | Array shadow |
isampler2D / usampler2D | Integer / unsigned samplers |
Pixel Transfer
// Readback (slow — causes pipeline stall) glReadPixels(x, y, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels); // Async readback with PBO glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo); glReadPixels(x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, 0); // 0 = offset into PBO // ... next frame ... void* ptr = glMapBuffer(GL_PIXEL_PACK_BUFFER, GL_READ_ONLY); memcpy(dest, ptr, size); glUnmapBuffer(GL_PIXEL_PACK_BUFFER); // Async upload with PBO glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo); glTextureSubImage2D(tex, 0, 0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, 0); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
Bindless Textures (ARB_bindless_texture)
GLuint64 handle = glGetTextureHandleARB(tex); glMakeTextureHandleResidentARB(handle); // Pass handle to shader via uniform/SSBO glUniformHandleui64ARB(loc, handle);
#extension GL_ARB_bindless_texture : enable layout(location = 0) uniform sampler2D uTex; // handle passed as uvec2 internally
Gotcha: Always call
glMakeTextureHandleNonResidentARBbefore deleting the texture; resident textures cannot be deleted.