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

FunctionPasses when
GL_LESSfragment.depth < stored.depth (default)
GL_LEQUALfragment.depth <= stored.depth
GL_GREATERfragment.depth > stored.depth
GL_GEQUALfragment.depth >= stored.depth
GL_EQUALfragment.depth == stored.depth
GL_NOTEQUALfragment.depth != stored.depth
GL_ALWAYSAlways passes
GL_NEVERAlways 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

funcPasses when
GL_NEVERNever
GL_ALWAYSAlways
GL_LESSref < stencil
GL_LEQUALref <= stencil
GL_GREATERref > stencil
GL_GEQUALref >= stencil
GL_EQUALref == stencil
GL_NOTEQUALref != stencil

glStencilOp operations

OperationEffect
GL_KEEPKeep current stencil value
GL_ZEROSet to 0
GL_REPLACESet to ref from glStencilFunc
GL_INCRIncrement (clamps at max)
GL_INCR_WRAPIncrement with wrap-around
GL_DECRDecrement (clamps at 0)
GL_DECR_WRAPDecrement with wrap-around
GL_INVERTBitwise 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

TokenValue
GL_ZERO0
GL_ONE1
GL_SRC_COLORSource color
GL_ONE_MINUS_SRC_COLOR1 − source color
GL_DST_COLORDestination color
GL_ONE_MINUS_DST_COLOR1 − destination color
GL_SRC_ALPHASource alpha
GL_ONE_MINUS_SRC_ALPHA1 − source alpha
GL_DST_ALPHADestination alpha
GL_ONE_MINUS_DST_ALPHA1 − destination alpha
GL_CONSTANT_COLORConstant set by glBlendColor
GL_ONE_MINUS_CONSTANT_COLOR1 − constant
GL_CONSTANT_ALPHAConstant alpha
GL_ONE_MINUS_CONSTANT_ALPHA1 − constant alpha
GL_SRC_ALPHA_SATURATEmin(src.a, 1 − dst.a)
GL_SRC1_COLOR / GL_ONE_MINUS_SRC1_COLORDual-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

EquationFormula
GL_FUNC_ADDsrc × srcFactor + dst × dstFactor (default)
GL_FUNC_SUBTRACTsrc × srcFactor − dst × dstFactor
GL_FUNC_REVERSE_SUBTRACTdst × dstFactor − src × srcFactor
GL_MINmin(src, dst) (factors ignored)
GL_MAXmax(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

EffectglBlendFunc 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);
}