OpenGL Cheatsheet
Depth and Blending
Use this OpenGL reference while you build software engineering projects, review code, or refresh the syntax you reach for most.
Depth Test
Controls which fragment wins when multiple primitives cover the same pixel.
glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); // default: pass if fragment depth < stored depth glDepthMask(GL_TRUE); // GL_FALSE = read-only depth (no writes) glClearDepth(1.0); // value written by glClear (default 1.0)
Depth functions
| Function | Passes when |
|---|---|
GL_LESS | fragment.depth < stored.depth (default) |
GL_LEQUAL | fragment.depth <= stored.depth |
GL_GREATER | fragment.depth > stored.depth |
GL_GEQUAL | fragment.depth >= stored.depth |
GL_EQUAL | fragment.depth == stored.depth |
GL_NOTEQUAL | fragment.depth != stored.depth |
GL_ALWAYS | Always passes |
GL_NEVER | Always fails |
Depth precision and Z-fighting
// Reverse-Z (more uniform precision distribution) glClipControl(GL_LOWER_LEFT, GL_ZERO_TO_ONE); // GL 4.5+ — use [0,1] range glDepthRange(1.0, 0.0); // flip depth range glDepthFunc(GL_GREATER); // reverse comparison glClearDepth(0.0); // clear to zero (near)
Gotcha: Z-fighting occurs between coplanar or near-coplanar polygons. Fix with
glPolygonOffset, reverse-Z, or simply increase the near plane distance.
// Polygon offset (for decals / shadows) glEnable(GL_POLYGON_OFFSET_FILL); // or _LINE, _POINT glPolygonOffset(factor, units); // Effective offset = factor × maxSlope + units × minResolution // Common shadow map values: glPolygonOffset(1.0f, 4.0f)
Early Depth Testing
The GPU may test depth before running the fragment shader (early-Z) to avoid wasted work. Writing gl_FragDepth in the shader disables early-Z.
// Force early depth test even when writing gl_FragDepth (GL 4.2+) layout(early_fragment_tests) in;
Stencil Test
A per-pixel integer buffer (typically 8 bits) used for masking, outlining, portals, shadows.
glEnable(GL_STENCIL_TEST); glClearStencil(0); glClear(GL_STENCIL_BUFFER_BIT); // Configure stencil test glStencilFunc(func, ref, mask); // Pass when (stencil & mask) {func} (ref & mask) // Configure stencil write operations glStencilOp(sfail, dpfail, dppass); // sfail = stencil test failed // dpfail = stencil passed, depth failed // dppass = both passed
glStencilFunc functions
func | Passes when |
|---|---|
GL_NEVER | Never |
GL_ALWAYS | Always |
GL_LESS | ref < stencil |
GL_LEQUAL | ref <= stencil |
GL_GREATER | ref > stencil |
GL_GEQUAL | ref >= stencil |
GL_EQUAL | ref == stencil |
GL_NOTEQUAL | ref != stencil |
glStencilOp operations
| Operation | Effect |
|---|---|
GL_KEEP | Keep current stencil value |
GL_ZERO | Set to 0 |
GL_REPLACE | Set to ref from glStencilFunc |
GL_INCR | Increment (clamps at max) |
GL_INCR_WRAP | Increment with wrap-around |
GL_DECR | Decrement (clamps at 0) |
GL_DECR_WRAP | Decrement with wrap-around |
GL_INVERT | Bitwise invert |
// Separate front/back face stencil ops glStencilFuncSeparate(GL_FRONT, GL_ALWAYS, 1, 0xFF); glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, GL_REPLACE); glStencilFuncSeparate(GL_BACK, GL_ALWAYS, 1, 0xFF); glStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_REPLACE); // Control which bits are written glStencilMask(0xFF); // all bits writable (default) glStencilMask(0x00); // read-only stencil
Object outline recipe
// Pass 1: draw object, write stencil = 1, depth writes on glStencilFunc(GL_ALWAYS, 1, 0xFF); glStencilMask(0xFF); glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); drawObject(); // Pass 2: draw scaled-up object, stencil = 0, depth writes off glStencilFunc(GL_NOTEQUAL, 1, 0xFF); glStencilMask(0x00); glDepthMask(GL_FALSE); drawObjectScaled(1.05f); // uniform scaled outline glDepthMask(GL_TRUE); glStencilMask(0xFF); glStencilFunc(GL_ALWAYS, 0, 0xFF);
Blending
Combines the output of the fragment shader (source) with what is already in the framebuffer (destination).
glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // standard alpha blend glBlendEquation(GL_FUNC_ADD); // default
glBlendFunc factor tokens
| Token | Value |
|---|---|
GL_ZERO | 0 |
GL_ONE | 1 |
GL_SRC_COLOR | Source color |
GL_ONE_MINUS_SRC_COLOR | 1 − source color |
GL_DST_COLOR | Destination color |
GL_ONE_MINUS_DST_COLOR | 1 − destination color |
GL_SRC_ALPHA | Source alpha |
GL_ONE_MINUS_SRC_ALPHA | 1 − source alpha |
GL_DST_ALPHA | Destination alpha |
GL_ONE_MINUS_DST_ALPHA | 1 − destination alpha |
GL_CONSTANT_COLOR | Constant set by glBlendColor |
GL_ONE_MINUS_CONSTANT_COLOR | 1 − constant |
GL_CONSTANT_ALPHA | Constant alpha |
GL_ONE_MINUS_CONSTANT_ALPHA | 1 − constant alpha |
GL_SRC_ALPHA_SATURATE | min(src.a, 1 − dst.a) |
GL_SRC1_COLOR / GL_ONE_MINUS_SRC1_COLOR | Dual-source blend |
// Separate RGB and alpha blend functions glBlendFuncSeparate(srcRGB, dstRGB, srcAlpha, dstAlpha); // Per-draw-buffer blend functions (MRT, GL 4.0+) glBlendFunci(bufIndex, srcFactor, dstFactor); glBlendFuncSeparatei(bufIndex, srcRGB, dstRGB, srcA, dstA);
Blend equations
| Equation | Formula |
|---|---|
GL_FUNC_ADD | src × srcFactor + dst × dstFactor (default) |
GL_FUNC_SUBTRACT | src × srcFactor − dst × dstFactor |
GL_FUNC_REVERSE_SUBTRACT | dst × dstFactor − src × srcFactor |
GL_MIN | min(src, dst) (factors ignored) |
GL_MAX | max(src, dst) (factors ignored) |
glBlendEquation(GL_FUNC_ADD); glBlendEquationSeparate(modeRGB, modeAlpha); glBlendEquationi(bufIndex, mode); // Constant blend color (used with GL_CONSTANT_COLOR etc.) glBlendColor(r, g, b, a);
Common blend presets
| Effect | glBlendFunc call |
|---|---|
| Alpha (standard) | (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) |
| Premultiplied alpha | (GL_ONE, GL_ONE_MINUS_SRC_ALPHA) |
| Additive | (GL_SRC_ALPHA, GL_ONE) |
| Additive (premul) | (GL_ONE, GL_ONE) |
| Multiplicative | (GL_DST_COLOR, GL_ZERO) |
| Screen | (GL_ONE, GL_ONE_MINUS_SRC_COLOR) |
Gotcha: With standard alpha blend, draw transparent objects back-to-front (painter's algorithm) or depth writes produce incorrect occlusion. Disable
glDepthMask(GL_FALSE)while drawing transparent geometry if exact order is impossible.
Color Masking
Prevent writes to specific color channels or the depth/stencil buffer.
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); // default — all channels glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); // no color writes glColorMaski(bufIndex, r, g, b, a); // per-buffer mask (GL 4.0+) glDepthMask(GL_FALSE); // disable depth writes glDepthMask(GL_TRUE); // re-enable glStencilMask(0x00); // disable stencil writes
Order-Independent Transparency (OIT)
Eliminates the need to sort transparent geometry.
Alpha-to-coverage (MSAA-only)
glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE); // use alpha as coverage mask glEnable(GL_SAMPLE_ALPHA_TO_ONE); // optional: snap coverage to 1 // Works transparently with MSAA — no sorting needed for foliage/fences
Weighted Blended OIT (McGuire & Bavoil, 2013)
// Accumulation pass — additive blend to two MRT targets layout(location = 0) out vec4 accumColor; // premul color × weight layout(location = 1) out float accumAlpha; // alpha × weight float weight = clamp(pow(min(1.0, alpha * 10.0) + 0.01, 3.0) * 1e8 * pow(1.0 - gl_FragCoord.z * 0.9, 3.0), 1e-2, 3e3); accumColor = vec4(color * alpha, alpha) * weight; accumAlpha = alpha * weight;
// Composite pass vec4 accum = texture(uAccumTex, uv); float alpha = texture(uAlphaTex, uv).r; vec3 color = accum.rgb / clamp(accum.a, 1e-4, 5e4); float blend = 1.0 - alpha / clamp(alpha + 0.00001, 0.0, 1.0); FragColor = vec4(color * blend, blend);
Multisample Anti-Aliasing (MSAA)
glfwWindowHint(GLFW_SAMPLES, 4); // request 4× MSAA from windowing system glEnable(GL_MULTISAMPLE); // usually enabled by default // Query actual sample count GLint samples; glGetIntegerv(GL_SAMPLES, &samples); // Sample positions glGetMultisamplefv(GL_SAMPLE_POSITION, i, pos); // [0,1]² for sample i
// Access individual samples in a shader (fragment) uniform sampler2DMS uMSTex; vec4 s = texelFetch(uMSTex, ivec2(gl_FragCoord.xy), gl_SampleID);
Resolve MSAA FBO to single-sample
glBindFramebuffer(GL_READ_FRAMEBUFFER, msFBO); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, resolveFBO); glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST);
Depth Clamp
Prevents near/far clipping of geometry (useful for shadow volumes).
glEnable(GL_DEPTH_CLAMP); // Fragments outside [near, far] are clamped to the boundary instead of clipped
Clip Planes (User-Defined)
glEnable(GL_CLIP_DISTANCE0); // up to GL_CLIP_DISTANCE7
// Vertex shader uniform vec4 uClipPlane; // (A, B, C, D) of plane equation Ax+By+Cz+D=0 out float gl_ClipDistance[1]; void main() { gl_ClipDistance[0] = dot(vec4(worldPos, 1.0), uClipPlane); }