Shadow Mapping and Transparency Shadowing Guide

June 1, 2026 ยท View on GitHub

This guide covers openQ4's user-facing shadow-map settings, including projected-light shadow maps, experimental point-light shadow maps, cascaded shadow maps (CSM), alpha-tested transparency shadows, and the current experimental translucent-shadow path.

Quick Start

Recommended starting point:

seta r_shadows 1
seta r_useShadowMap 1
seta r_shadowMapCSM 1
seta r_shadowMapHashedAlpha 1
vid_restart

Optional experimental translucent-shadow overlay:

seta r_shadowMapTranslucentMoments 1
seta r_shadowMapTranslucentDensity 1.0
seta r_shadowMapTranslucentMinAlpha 0.02
vid_restart

Notes:

  • r_shadows must stay enabled for any shadow path to render.
  • If the shadow-map path is unavailable or fails for a light, openQ4 falls back to the legacy shadow path instead of leaving the light unshadowed.
  • Point lights use the legacy stencil shadow path by default; enable r_shadowMapPointLights 1 only when testing the experimental point-light cubemap path.
  • Lights touching animated, deformed, or packed character receivers can also fall back to the legacy stencil path so stock character lighting, mirrored seams, and eye materials retain retail-style interaction behavior.
  • Modern renderer diagnostics keep lighting visible when shadow-map receiver sampling is not ready, but full modern visible-frame replacement stays fail-closed so the legacy path continues to provide the actual shadowed frame.
  • Most shadow cvars can be changed live, but vid_restart is the safest way to apply large changes such as map resolution, cascade layout, or switching the shadow pipeline on/off.

What the System Does

openQ4 currently supports:

  • Projected-light shadow maps for regular projected lights.
  • Experimental point-light shadow maps for omni/point lights when r_shadowMapPointLights 1 is enabled.
  • Optional projected-light cascaded shadow maps (CSM).
  • Alpha-tested transparency shadows for cutout materials such as fences, grates, and foliage cards.
  • Optional experimental translucent-shadow accumulation for some blended materials.

High-level behavior:

  • Opaque materials cast normal solid shadows.
  • Alpha-tested or perforated materials cast cutout shadows in the shadow-map pass.
  • Blended/translucent materials do not cast translucent shadowing unless r_shadowMapTranslucentMoments 1 is enabled.
  • The translucent-shadow path is experimental and intentionally conservative.

Balanced Quality

seta r_shadows 1
seta r_useShadowMap 1
seta r_shadowMapCSM 1
seta r_shadowMapSize 1024
seta r_shadowMapFilterRadius 2.0
seta r_shadowMapFilterTaps 13
seta r_shadowMapPointFilterRadius 2.5
seta r_shadowMapPointFilterTaps 13
seta r_shadowMapHashedAlpha 1
seta r_shadowMapCascadeStabilize 1
vid_restart

Higher Quality

seta r_shadows 1
seta r_useShadowMap 1
seta r_shadowMapCSM 1
seta r_shadowMapSize 2048
seta r_shadowMapCascadeCount 4
seta r_shadowMapFilterRadius 2.5
seta r_shadowMapFilterTaps 13
seta r_shadowMapPointFilterRadius 3.0
seta r_shadowMapPointFilterTaps 13
seta r_shadowMapHashedAlpha 1
seta r_shadowMapCascadeStabilize 1
vid_restart

Optional Modern Filtering

seta r_shadowMapFilterMode 1
seta r_shadowMapPointFilterMode 1
seta r_shadowMapStaticCache 1
vid_restart

For projected lights, r_shadowMapFilterMode 2 enables the experimental PCSS-lite path when raw depth sampling is active. Leave r_shadowMapDepthCompare 0 for that mode; hardware depth-compare sampling cannot run the blocker search needed for PCSS-lite.

Performance-Focused

seta r_shadows 1
seta r_useShadowMap 1
seta r_shadowMapCSM 0
seta r_shadowMapSize 512
seta r_shadowMapFilterRadius 1.5
seta r_shadowMapFilterTaps 5
seta r_shadowMapPointFilterRadius 2.0
seta r_shadowMapPointFilterTaps 5
seta r_shadowMapHashedAlpha 1
vid_restart

Experimental Blended Transparency

seta r_shadows 1
seta r_useShadowMap 1
seta r_shadowMapCSM 1
seta r_shadowMapHashedAlpha 1
seta r_shadowMapTranslucentMoments 1
seta r_shadowMapTranslucentDensity 1.0
seta r_shadowMapTranslucentMinAlpha 0.02
vid_restart

Core Shadow Settings

SettingDefaultRangeWhat it does
r_shadows10..1Master shadow toggle.
r_useShadowMap00..1Enables the shadow-map pipeline for supported lights.
r_shadowMapCSM00..1Enables cascaded shadow maps for projected lights.
r_shadowMapProjectedCSM10..1Allows ordinary projected lights to use CSM when r_shadowMapCSM is enabled; parallel/global lights keep their dedicated large-coverage policy.
r_shadowMapConservativeCasters10..1Keeps shadow-map caster submission separate from visible receiver scissors, so off-screen blockers can still shadow visible receivers.
r_shadowMapSize1024128..4096Base shadow-map resolution. Higher values cost more VRAM and GPU time.
r_shadowMapFilterRadius2.00..8Projected-light PCF filter radius in texels.
r_shadowMapFilterTaps131..13Projected-light PCF tap budget. Values up to 1, 5, 9, and 13 select progressively wider sample sets.
r_shadowMapFilterMode00..2Projected-light filter mode: fixed PCF, stable rotated Poisson, or experimental PCSS-lite with raw depth sampling.
r_shadowMapPCSSLightRadius4.00..16Projected PCSS-lite blocker search radius in shadow texels.
r_shadowMapPCSSMaxRadius8.00..16Maximum projected PCSS-lite filter radius in shadow texels.
r_shadowMapPointFilterRadius2.50..8Point-light PCF filter radius in texels.
r_shadowMapPointFilterTaps131..13Point-light PCF tap budget. Values up to 1, 5, 9, and 13 select progressively wider sample sets.
r_shadowMapPointFilterMode00..1Point-light filter mode: fixed PCF or stable rotated Poisson.
r_shadowMapDepthCompare00..1Uses hardware comparison sampling for projected depth maps. Leave off if a driver has trouble with GLSL shadow samplers.
r_shadowMapPointDepthCompare00..1Uses hardware comparison sampling for point-light depth cubemaps when GLSL 1.30 support is available.
r_shadowMapPointHighPrecision10..1Stores point-light shadow depth in a high-precision float cubemap instead of the older packed RGBA8 depth path.
r_shadowMapPointLights00..1Opts into experimental point-light shadow maps. When disabled, point lights use the legacy stencil shadow path even if r_useShadowMap 1 is enabled.
r_shadowMapHashedAlpha10..1Uses hashed alpha testing for perforated/alpha-tested casters when supported.
r_shadowMapStableAlphaHash10..1Seeds hashed alpha from world-space caster coordinates to reduce atlas/camera-space dither drift.
r_shadowMapProjectionPad0.150..1Padding around projected-light shadow coverage.
r_shadowMapPointFarScale1.251..4Padding multiplier for point-light shadow range.
r_shadowMapCascadeCount41..4Number of projected-light cascades when CSM is enabled.
r_shadowMapCascadeDistance153664..8192Camera-space distance covered by projected-light cascades.
r_shadowMapCascadeLambda0.750..1Mix between uniform and logarithmic cascade split placement.
r_shadowMapCascadeBlend0.150..0.5Crossfade width between projected-light cascades.
r_shadowMapCascadeStabilize10..1Snaps cascade bounds to texels to reduce shimmering.

Residency and Update Budgeting

openQ4 can keep static-only shadow maps resident and reuse them across backend views. This is enabled by default for regular projected and point lights. Dynamic casters, translucent caster passes, and view-fitted CSM/global passes are conservative by default and continue to update normally unless explicitly opted in.

SettingDefaultRangeWhat it does
r_shadowMapStaticCache10..1Reuses resident shadow maps for static-only projected and point lights.
r_shadowMapStaticHysteresisFrames20..120Frames to wait after dynamic casters disappear before a light becomes cacheable again.
r_shadowMapResidentFrames1201..3600Frames an unused static shadow map can stay resident before its slot may be expired.
r_shadowMapProjectedCacheSize40..8Static projected-light cache slots.
r_shadowMapPointCacheSize40..8Static point-light cubemap cache slots.
r_shadowMapCacheCSM00..1Allows static-cache reuse for CSM/global shadow-map passes. Leave off unless you are testing a fixed-view or otherwise stable scene.

r_shadowMapMaxUpdatesPerView still limits dynamic shadow-map work. Resident cache hits do not consume that update budget, so static light reuse can reduce update pressure without starving moving lights. Cache signatures include caster materials, alpha/hash settings, caster offset settings, point-light range/depth mode, and view-fitted CSM state, so changing those inputs forces a fresh shadow map instead of reusing stale resident data.

Transparency Shadowing

Cutout / Alpha-Tested Materials

These are materials with holes cut by alpha test, such as:

  • Chain-link fences
  • Grates
  • Leaf cards
  • Other perforated or masked surfaces

Behavior:

  • They cast cutout shadows in both projected and point shadow-map paths.
  • r_shadowMapHashedAlpha 1 is the recommended mode and is enabled by default.
  • If a perforated stage uses explicit texture coordinates, OpenQ4 can render it with either hashed alpha or hard alpha-test shadowing; unsupported animated texgen cutouts cast conservative solid depth instead of dropping the shadow.
  • Translucent shadow coverage stages preserve the same material alpha-test mode, so blended foliage/glass masks stay consistent with opaque cutouts.

Hashed alpha notes:

  • Usually gives more stable distant foliage/fence shadows than hard binary alpha test.
  • Can look slightly noisy on some surfaces.
  • If you prefer harder but cleaner cutout edges, set r_shadowMapHashedAlpha 0.

Blended / Translucent Materials

These are materials with real blending instead of alpha-test cutouts, such as:

  • Some glass-like surfaces
  • Certain layered blended materials
  • Some effect-style soft transparency

Behavior:

  • Off by default.
  • Optional with r_shadowMapTranslucentMoments 1.
  • Implemented as an additional experimental translucent shadow overlay on top of the main shadow map.

Current limits:

  • Supported stages currently include old-style alpha and premultiplied-alpha stages with explicit ST texture coordinates, plus common additive blend add / GL_ONE, GL_ONE stages.
  • When a translucent shell/tint stage is layered on top of a separate explicit-ST coverage stage, openQ4 now reuses that coverage stage, including its alpha-test threshold when present, so layered pickup-orb and similar materials can cast shaped transmitted shadows instead of only uniform blobs.
  • Supported translucent casters now derive colored transmission from the material inputs available to that stage: texture alpha, sampled texture RGB, stage color, and applicable vertex color.
  • View-dependent reflection cubemaps are treated as tinted transmissive shells instead of using the reflected sample directly, so pickup orbs can tint transmitted light without camera-dependent shadow color shifts.
  • The current high-quality path stores separate translucent shadow moments for red, green, and blue, so each channel resolves blocker depth independently instead of sharing one grayscale depth distribution.
  • GUI/subview materials are skipped.
  • BSE/FX particles, unusual custom stage setups, and many effect-style materials are intentionally not forced into the translucent shadow pass.
  • Colored transmission is still approximate rather than a full deep-shadow solution, but it is materially closer to real tinted transmission than the earlier scalar/grayscale model.
  • This path adds extra GPU work because eligible lights render an additional translucent caster pass.
  • The feature now expects enough hardware for 3 translucent MRT attachments and 3 extra texture samplers in the receiver path; if that is unavailable, openQ4 disables this experimental translucent-shadow feature.

Controls:

SettingDefaultRangeWhat it does
r_shadowMapTranslucentMoments00..1Enables the experimental blended/translucent shadow overlay.
r_shadowMapTranslucentDensity1.00..8Scales resolved translucent-shadow strength.
r_shadowMapTranslucentMinAlpha0.020..1Ignores very faint translucent stages below this alpha.
r_shadowMapTranslucentFilterRadius-1.0-1..8Translucent moment filter radius in texels. -1 inherits the opaque shadow filter radius.
r_shadowMapTranslucentMinVariance0.000010.000001..0.01Minimum variance used when resolving translucent shadow moments.
r_shadowMapTranslucentBleedReduction0.00..0.95Reduces light bleed in the translucent moment resolve. Higher values can make translucent shadows harsher.

Suggested use:

  • Start with r_shadowMapTranslucentMoments 1, r_shadowMapTranslucentDensity 1.0, r_shadowMapTranslucentMinAlpha 0.02.
  • Raise r_shadowMapTranslucentDensity if the effect looks too weak.
  • Raise r_shadowMapTranslucentMinAlpha if very faint blended surfaces create more shadowing than you want.
  • Use r_shadowMapTranslucentFilterRadius when translucent shadows need a different softness than opaque shadows.
  • Increase r_shadowMapTranslucentBleedReduction only when moment light bleed is visibly worse than the added hardness.
  • Turn the feature back off if you want the most predictable performance and compatibility.

Bias and Artifact Tuning

Shadow artifacts are usually one of two classes:

  • Shadow acne or speckling: bias is too low.
  • Peter Panning or detached shadows: bias is too high.

Projected-light tuning:

Projected shadow maps store Quake 4's authored light falloff depth directly, so the projected defaults are intentionally small. Raise them only when you see acne or speckling.

SettingDefaultRangeWhat it does
r_shadowMapBias0.000350..0.05Constant receiver depth bias for projected lights.
r_shadowMapNormalBias0.00150..0.05Extra projected-light bias on sloped receivers.
r_shadowMapTexelBiasScale1.00..8Uses texel-aware receiver bias based on fitted cascade/light footprint. Constant bias acts as a compatibility floor.
r_shadowMapReceiverPlaneBias00..1Allows derivative receiver-plane bias for wider projected-light filters.
r_shadowMapPolygonFactor1.250..16Slope-scale caster polygon offset used while rendering shadow maps.
r_shadowMapPolygonOffset1.00..64Constant caster polygon offset used while rendering shadow maps.

Point-light tuning:

SettingDefaultRangeWhat it does
r_shadowMapPointBias0.000200..0.05Constant receiver depth bias for point lights.
r_shadowMapPointNormalBias0.00200..0.05Extra point-light bias on sloped receivers.

Point-light constant and texel-aware receiver bias also use the larger value rather than stacking both terms, so tuning one path does not automatically over-bias the other.

Practical advice:

  • Raise bias values slowly in very small steps.
  • If shadows detach from contact points, lower the relevant bias before changing many other settings.
  • If CSM shimmers while moving the camera, keep r_shadowMapCascadeStabilize 1.
  • Wider filter radii usually need more careful bias tuning.

Debugging and Diagnostics

Setting / CommandDefaultWhat it does
r_shadowMapDebugMode0Projected-light shadow debug mode.
r_shadowMapDebugOverlay0Draws a top-left mini-map of the selected shadow map plus frame counters.
r_shadowMapReport0Shadow-map diagnostics: 0 off, 1 summary, 2 per-light decisions, 3 verbose receiver-submit decisions.
r_shadowMapReportInterval30Frames between report prints when r_shadowMapReport is enabled.
r_shadowMapMaxUpdatesPerView0Optional per-view shadow-map update budget. 0 means unlimited.
r_shadowMapGpuTimerQueries1Uses non-blocking GL timer queries for shadow-map GPU timing when the driver supports them.
r_shadowMapGpuSyncTimings0Diagnostic-only GPU-synchronized pass timing using glFinish; leave off during normal play.
reportShaderProgramsn/aPrints current ARB/GLSL shader validity, including shadow programs.

r_shadowMapDebugMode values:

  • 0: Off
  • 1: Projected shadow atlas/depth
  • 2: Cascade index
  • 3: Projected UV
  • 4: Projected depth
  • 5: Projected W
  • 6: Invalid mask
  • 7: Bias heatmap
  • 8: Bias off
  • 9: PCF off
  • 10: Caster polygon offset off
  • 11: Receiver-plane/normal bias off

Useful workflow:

  1. Enable r_useShadowMap 1.
  2. Set r_shadowMapDebugMode 1 to inspect projected atlas/depth content.
  3. Set r_shadowMapDebugOverlay 1 to keep a live mini-map in the top-left corner while you play.
  4. Use r_singleLight to lock the overlay to one light; otherwise it follows the last successfully rendered mapped light that frame.
  5. The overlay stats are: POINT / PROJ = light type, L / G = local/global interaction pass, F / C = point faces or projected cascades, MAP / FB = whether the selected pass stayed on shadow maps or fell back. The extra caster row reports alpha, translucent, rejected, and expanded off-screen caster counts.
  6. Point-light overlay tiles are face indices 0..5 in a 3x2 layout: 0 = +X, 1 = -X, 2 = +Y, 3 = -Y, 4 = +Z, 5 = -Z.
  7. Use reportShaderPrograms if the scene looks unlit or obviously wrong.
  8. Use r_shadowMapReport 1, 2, or 3 for live diagnostic logging. Summary lines include point depth-compare usage as pointCmp, timer-query totals as gpuQuery, and the SM cache: line reports cache hits, misses, resident reuse, budget reuse, evictions, and active projected/point cache slots. Verbose projected CSM bias lines include per-cascade near/far range, fitted depth range, world texel size, and clip-space depth extent. Level 3 adds receiver-submit diagnostics for mapped-light cases that had visible receivers but no GLSL interaction submissions. Per-light lines separate semantic light class from backing shadow-map resource shape. For example, a stock authored parallel light may report class=parallel type=point when it uses the point-resource path.
  9. When rejected casters are present, the SM caster-reject: line breaks them down by reason, such as view-only entities, depth-hack models, disconnected portal areas, GUI/subview surfaces, non-shadowing materials, or disabled/unsupported translucent casters.

Troubleshooting

  • If shadows do not appear at all, check r_shadows 1 and r_useShadowMap 1, then run vid_restart.
  • If projected-light shadows shimmer while moving, keep r_shadowMapCSM 1 and r_shadowMapCascadeStabilize 1.
  • If cutout materials cast solid-looking shadows, make sure r_shadowMapHashedAlpha 1 is enabled and the material is actually alpha-tested with explicit texture coordinates. Unusual animated texgen cutouts may cast conservative solid depth until that stage type is supported.
  • If translucent shadows are too strong or too noisy, lower r_shadowMapTranslucentDensity or disable r_shadowMapTranslucentMoments.
  • If blended materials still do not cast translucent shadows, that material may be outside the currently supported stage set. Common additive pickup orbs are supported, but many particle/effect materials still are not.
  • If point-light shadows look too detached, reduce r_shadowMapPointBias or r_shadowMapPointNormalBias.
  • If projected-light shadows look detached, reduce r_shadowMapBias, r_shadowMapNormalBias, r_shadowMapTexelBiasScale, r_shadowMapPolygonFactor, or r_shadowMapPolygonOffset in small steps.
  • If projected-light acne appears only with large filter radii, try r_shadowMapReceiverPlaneBias 1 before greatly increasing constant bias.
  • If PCSS-lite seems unchanged, confirm r_shadowMapFilterMode 2 is active and r_shadowMapDepthCompare 0 is still selected.
  • If point-light depth compare causes shader trouble on a driver, leave r_shadowMapPointDepthCompare 0; the renderer falls back to the high-precision color-depth cubemap path.
  • If static-cache reuse hides expected updates while testing unusual content, set r_shadowMapStaticCache 0 or reduce r_shadowMapResidentFrames.
  • If performance drops sharply after enabling translucent shadowing, turn off r_shadowMapTranslucentMoments first; it adds an extra pass for eligible lights.

Summary

Recommended default user setup:

  • r_shadows 1
  • r_useShadowMap 1
  • r_shadowMapCSM 1
  • r_shadowMapHashedAlpha 1
  • r_shadowMapCascadeStabilize 1
  • r_shadowMapStaticCache 1

Only enable r_shadowMapTranslucentMoments 1 if you specifically want experimental blended transparency shadows and accept the extra cost and current material-support limits.