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.
Recommended starting point:
seta r_shadows 1
seta r_useShadowMap 1
seta r_shadowMapCSM 1
seta r_shadowMapHashedAlpha 1
vid_restartOptional experimental translucent-shadow overlay:
seta r_shadowMapTranslucentMoments 1
seta r_shadowMapTranslucentDensity 1.0
seta r_shadowMapTranslucentMinAlpha 0.02
vid_restartNotes:
r_shadowsmust 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 shadow-map by default (
r_shadowMapPointLights 1); they are the dominant light class in Quake 4 content. Setr_shadowMapPointLights 0to fall back to stencil shadows for point lights only. - 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_restartis the safest way to apply large changes such as map resolution, cascade layout, or switching the shadow pipeline on/off.
openQ4 currently supports:
- Projected-light shadow maps for regular projected lights.
- Point-light cubemap shadow maps for omni/point lights (the dominant Quake 4 light class), on by default.
- 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 1is enabled. - The translucent-shadow path is experimental and intentionally conservative.
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_restartseta 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_restartseta r_shadowMapFilterMode 1
seta r_shadowMapPointFilterMode 1
seta r_shadowMapStaticCache 1
vid_restartFor projected lights, r_shadowMapFilterMode 2 enables the experimental PCSS-lite path. Hardware depth-compare sampling cannot run the blocker search needed for PCSS-lite, so selecting filter mode 2 automatically switches the renderer to the manual raw-depth path even while r_shadowMapDepthCompare 1 is set.
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_restartseta 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| Setting | Default | Range | What it does |
|---|---|---|---|
r_shadows |
1 |
0..1 |
Master shadow toggle. |
r_useShadowMap |
0 |
0..1 |
Enables the shadow-map pipeline for supported lights. |
r_shadowMapCSM |
0 |
0..1 |
Enables cascaded shadow maps for projected lights. |
r_shadowMapProjectedCSM |
1 |
0..1 |
Allows ordinary projected lights to use CSM when r_shadowMapCSM is enabled; parallel/global lights keep their dedicated large-coverage policy. |
r_shadowMapConservativeCasters |
1 |
0..1 |
Keeps shadow-map caster submission separate from visible receiver scissors, so off-screen blockers can still shadow visible receivers. |
r_shadowMapSkipStencilShadows |
1 |
0..1 |
Skips stencil shadow volume generation and linking for lights that will render shadow maps, removing the duplicate CPU shadow work. A light that fails a shadow-map pass automatically restores its stencil volumes on the next frame. |
r_shadowMapCasterCulling |
2 |
0..2 |
Caster face culling: 0 renders casters two-sided, 1 stores light-facing faces, 2 stores back faces (fewer acne artifacts, slight detachment on thin geometry). Materials declared twoSided/backSided are always honored, so grates, foliage, and curtains cast correctly in every mode. |
r_shadowMapSize |
1024 |
128..4096 |
Base shadow-map resolution. Higher values cost more VRAM and GPU time. |
r_shadowMapAtlasSize |
4096 |
2048..8192 |
Edge size of the shared projected-light shadow atlas. Cached projected lights occupy r_shadowMapSize-sized cells inside it (CSM lights use a 2x2 cell block), so all cached lights stay resident in one texture. |
r_shadowMapFilterRadius |
2.0 |
0..8 |
Projected-light PCF filter radius in texels. |
r_shadowMapFilterTaps |
13 |
1..13 |
Projected-light PCF tap budget. Values up to 1, 5, 9, and 13 select progressively wider sample sets. |
r_shadowMapFilterMode |
0 |
0..2 |
Projected-light filter mode: fixed PCF, stable rotated Poisson, or experimental PCSS-lite with raw depth sampling. |
r_shadowMapDistantFilterScale |
0.35 |
0..1 |
Scales projected PCF and PCSS radii for parallel/global distant sources such as sky or sun lights. Their texels cover much more world space than local projectors, so a tighter kernel preserves caster silhouettes instead of over-blurring them. Set 1 to use the ordinary projected-light radii unchanged. |
r_shadowMapPCSSLightRadius |
4.0 |
0..16 |
Projected PCSS-lite blocker search radius in shadow texels. |
r_shadowMapPCSSMaxRadius |
8.0 |
0..16 |
Maximum projected PCSS-lite filter radius in shadow texels. |
r_shadowMapPointFilterRadius |
2.5 |
0..8 |
Point-light PCF filter radius in texels. |
r_shadowMapPointFilterTaps |
13 |
1..13 |
Point-light PCF tap budget. Values up to 1, 5, 9, and 13 select progressively wider sample sets. |
r_shadowMapPointFilterMode |
0 |
0..1 |
Point-light filter mode: fixed PCF or stable rotated Poisson. |
r_shadowMapDepthCompare |
1 |
0..1 |
Uses hardware comparison sampling (with hardware-filtered PCF taps) for projected depth maps. Selecting PCSS-lite (r_shadowMapFilterMode 2) automatically uses the manual raw-depth path instead. Set 0 if a driver has trouble with GLSL shadow samplers. |
r_shadowMapPointDepthCompare |
1 |
0..1 |
Uses hardware comparison sampling for point-light depth cubemaps when GLSL 1.30 support is available. |
r_shadowMapPointHighPrecision |
0 |
0..1 |
Stores point-light shadow depth in an fp16 color cubemap instead of packed RGBA8. The packed path quantizes finer at half the memory, and the default hardware-compare path samples the depth cubemap directly, so this only affects the manual fallback. |
r_shadowMapPointLights |
1 |
0..1 |
Shadow-maps point lights when r_useShadowMap 1 is enabled. Point lights are the dominant light class in Quake 4 content, so disabling this makes shadow mapping nearly a no-op; set 0 to fall back to stencil shadows for point lights only. |
r_shadowMapPointSize |
512 |
128..2048 |
Point-light cube face resolution, separate from r_shadowMapSize: each cached point light stores six faces of color and depth, so cube resolution dominates shadow VRAM. |
r_shadowMapHashedAlpha |
1 |
0..1 |
Uses hashed alpha testing for perforated/alpha-tested casters when supported. |
r_shadowMapStableAlphaHash |
1 |
0..1 |
Seeds hashed alpha from world-space caster coordinates to reduce atlas/camera-space dither drift. |
r_shadowMapProjectionPad |
0.15 |
0..1 |
Padding around projected-light shadow coverage. |
r_shadowMapPointFarScale |
1.25 |
1..4 |
Padding multiplier for point-light shadow range. |
r_shadowMapCascadeCount |
4 |
1..4 |
Number of projected-light cascades when CSM is enabled. |
r_shadowMapCascadeDistance |
1536 |
64..8192 |
Camera-space distance covered by projected-light cascades. |
r_shadowMapCascadeLambda |
0.75 |
0..1 |
Mix between uniform and logarithmic cascade split placement. |
r_shadowMapCascadeBlend |
0.15 |
0..0.5 |
Crossfade width between projected-light cascades. |
r_shadowMapCascadeStabilize |
1 |
0..1 |
Snaps cascade bounds to texels to reduce shimmering. |
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.
| Setting | Default | Range | What it does |
|---|---|---|---|
r_shadowMapStaticCache |
1 |
0..1 |
Reuses resident shadow maps for static-only projected and point lights. |
r_shadowMapStaticHysteresisFrames |
2 |
0..120 |
Frames to wait after dynamic casters disappear before a point light becomes cacheable again. Projected lights stay cached while dynamic casters move: their static tiles persist in the atlas and the moving casters are composed on top each frame. |
r_shadowMapResidentFrames |
120 |
1..3600 |
Frames an unused static shadow map can stay resident before its slot may be expired. |
r_shadowMapProjectedCacheSize |
8 |
0..16 |
Static projected-light cache slots inside the shared atlas. |
r_shadowMapPointCacheSize |
12 |
0..16 |
Static point-light cubemap cache slots. |
r_shadowMapCacheCSM |
0 |
0..1 |
Allows static-cache reuse for CSM/global shadow-map passes. Leave off unless you are testing a fixed-view or otherwise stable scene. |
r_shadowMapSubviewPolicy |
1 |
0..2 |
Shadow maps in mirror/remote-camera subviews: 0 renders them like main views, 1 reuses cached maps or falls back to stencil, 2 prefers stencil in subviews. When the target has no usable stencil attachment or an ownership contains map-only casters, Vulkan still renders the required fresh map rather than dropping its shadow. |
r_shadowMapTranslucentReceivers |
1 |
0..1 |
Lets translucent surfaces sample the shadow map like opaque receivers, matching the stencil path's r_stencilTranslucentShadows behavior. |
r_shadowMapMaxUpdatesPerView still limits discretionary 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. When the budget constrains a frame, updates go to the most important stale lights first (screen coverage, staleness, and view proximity ordered), and starved lights age up the priority list so every light is eventually refreshed; denied lights reuse their last cached map when one exists. On Vulkan, a receiver ownership containing a map-only caster can exceed the nominal budget because no equivalent complete stencil result exists, and those correctness-required maps are admitted before optional maps can consume bounded resources. 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.
Projected lights with moving casters no longer pay full re-renders: the light's static geometry stays cached in the shared atlas, and each frame the cached tiles are copied and only the moving casters are drawn on top. A walking character in a cached light costs one small copy plus its own triangles.
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 1is 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.
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_ONEstages. - 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:
| Setting | Default | Range | What it does |
|---|---|---|---|
r_shadowMapTranslucentMoments |
0 |
0..1 |
Enables the experimental blended/translucent shadow overlay. |
r_shadowMapTranslucentDensity |
1.0 |
0..8 |
Scales resolved translucent-shadow strength. |
r_shadowMapTranslucentMinAlpha |
0.02 |
0..1 |
Ignores very faint translucent stages below this alpha. |
r_shadowMapTranslucentFilterRadius |
-1.0 |
-1..8 |
Translucent moment filter radius in texels. -1 inherits the opaque shadow filter radius. |
r_shadowMapTranslucentMinVariance |
0.00001 |
0.000001..0.01 |
Minimum variance used when resolving translucent shadow moments. |
r_shadowMapTranslucentBleedReduction |
0.0 |
0..0.95 |
Reduces 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_shadowMapTranslucentDensityif the effect looks too weak. - Raise
r_shadowMapTranslucentMinAlphaif very faint blended surfaces create more shadowing than you want. - Use
r_shadowMapTranslucentFilterRadiuswhen translucent shadows need a different softness than opaque shadows. - Increase
r_shadowMapTranslucentBleedReductiononly 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.
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.
| Setting | Default | Range | What it does |
|---|---|---|---|
r_shadowMapBias |
0.00016 |
0..0.05 |
Constant receiver depth bias for projected lights. |
r_shadowMapNormalBias |
0.00075 |
0..0.05 |
Extra projected-light bias on sloped receivers. |
r_shadowMapTexelBiasScale |
0.45 |
0..8 |
Uses texel-aware receiver bias based on fitted cascade/light footprint. Constant bias acts as a compatibility floor. |
r_shadowMapNormalOffsetScale |
1.0 |
0..8 |
Normal-offset bias in shadow texels: pushes the receiver sample point along the surface normal on sloped surfaces, fixing acne without detaching contact shadows. The preferred first knob for slope acne. |
r_shadowMapReceiverPlaneBias |
0 |
0..1 |
Allows derivative receiver-plane bias for wider projected-light filters. |
r_shadowMapPolygonFactor |
0.75 |
0..16 |
Slope-scale caster depth offset applied by the caster shaders while rendering shadow maps (shadow casters write shader depth, which glPolygonOffset cannot bias). |
r_shadowMapPolygonOffset |
0.5 |
0..64 |
Constant caster depth offset in resolvable depth-buffer steps, applied by the caster shaders alongside the slope-scale term. |
Point-light tuning:
| Setting | Default | Range | What it does |
|---|---|---|---|
r_shadowMapPointBias |
0.00010 |
0..0.05 |
Constant receiver depth bias for point lights. |
r_shadowMapPointNormalBias |
0.0010 |
0..0.05 |
Extra 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. The slope-amplified texel-aware term is capped internally so grazing receivers do not create detached shadows.
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.
- Existing configs may keep older archived bias values. If detached shadows persist after updating, compare your local cvars against the defaults above.
- If CSM shimmers while moving the camera, keep
r_shadowMapCascadeStabilize 1. - Wider filter radii usually need more careful bias tuning.
| Setting / Command | Default | What it does |
|---|---|---|
r_shadowMapDebugMode |
0 |
Projected-light shadow debug mode. |
r_shadowMapDebugOverlay |
0 |
Draws a top-left mini-map of the selected shadow map plus frame counters. |
r_shadowMapReport |
0 |
Shadow-map diagnostics: 0 off, 1 summary, 2 per-light decisions, 3 verbose receiver-submit decisions. |
r_shadowMapReportInterval |
30 |
Frames between report prints when r_shadowMapReport is enabled. |
r_shadowMapMaxUpdatesPerView |
0 |
Optional per-view shadow-map update budget. 0 means unlimited. Lights over budget reuse their last cached map when one exists (shadows lag briefly instead of flickering to stencil); lights with no cached map fall back to stencil when that receiver ownership has a complete stencil result. Vulkan may exceed the nominal budget for an ownership containing map-only casters so it does not become falsely unshadowed. |
r_shadowMapGpuTimerQueries |
1 |
Uses non-blocking GL timer queries for shadow-map GPU timing when the driver supports them. |
r_shadowMapGpuSyncTimings |
0 |
Diagnostic-only GPU-synchronized pass timing using glFinish; leave off during normal play. |
reportShaderPrograms |
n/a | Prints current ARB/GLSL shader validity, including shadow programs. |
r_shadowMapDebugMode values:
0: Off1: Projected shadow atlas/depth2: Cascade index3: Projected UV4: Projected depth5: Projected W6: Invalid mask7: Bias heatmap8: Bias off9: PCF off10: Caster polygon offset off11: Receiver-plane/normal bias off12: Compare-depth delta13: Receiver eligibility14: Receiver fallback reason
Useful workflow:
- Enable
r_useShadowMap 1. - Set
r_shadowMapDebugMode 1to inspect projected atlas/depth content. - Set
r_shadowMapDebugOverlay 1to keep a live mini-map in the top-left corner while you play. - Use
r_singleLightto lock the overlay to one light; otherwise it follows the last successfully rendered mapped light that frame. - 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. - Point-light overlay tiles are face indices
0..5in a3x2layout:0 = +X,1 = -X,2 = +Y,3 = -Y,4 = +Z,5 = -Z. - Use
reportShaderProgramsif the scene looks unlit or obviously wrong. - Use
r_shadowMapReport 1,2, or3for live diagnostic logging. Summary lines include point depth-compare usage aspointCmp, timer-query totals asgpuQuery, and theSM cache:line reports cache hits, misses, resident reuse, budget reuse, evictions, active projected/point cache slots, and resident shadow VRAM. TheSM metrics:line reports per-frame updates, composed static/dynamic layer passes (composed), subview reuse/fallback activity, translucent receiver chains drawn with shadow sampling, and importance-budget denials. TheSM modern:line summarizes the modern path's consumption of the persistent atlas (live atlas slots, mapped/cache-reuse lights, and per-light blocking counts). Verbose projected CSM bias lines include per-cascade near/far range, fitted depth range, world texel size, and clip-space depth extent. Level3adds 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 reportclass=parallel type=pointwhen it uses the point-resource path. - 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.
- If shadows do not appear at all, check
r_shadows 1andr_useShadowMap 1, then runvid_restart. - If projected-light shadows shimmer while moving, keep
r_shadowMapCSM 1andr_shadowMapCascadeStabilize 1. - Parallel/global sky shadows automatically use the tighter
r_shadowMapDistantFilterScale 0.35policy. If a particular outdoor scene still looks too soft, lower it toward0; if you want the old shared projected-light softness, set it to1. - If cutout materials cast solid-looking shadows, make sure
r_shadowMapHashedAlpha 1is 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_shadowMapTranslucentDensityor disabler_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_shadowMapPointBiasorr_shadowMapPointNormalBias. - If projected-light shadows look detached, reduce
r_shadowMapBias,r_shadowMapNormalBias,r_shadowMapTexelBiasScale,r_shadowMapPolygonFactor, orr_shadowMapPolygonOffsetin small steps. - If projected-light acne appears only with large filter radii, try
r_shadowMapReceiverPlaneBias 1before greatly increasing constant bias. - If PCSS-lite seems unchanged, confirm
r_shadowMapFilterMode 2is active; the renderer selects the manual raw-depth path for that mode automatically. - 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 0or reducer_shadowMapResidentFrames. - If performance drops sharply after enabling translucent shadowing, turn off
r_shadowMapTranslucentMomentsfirst; it adds an extra pass for eligible lights.
| Platform | Shadow maps | Notes |
|---|---|---|
| Windows (GL3.3+) | Supported | Primary development and validation platform; the bit-exact regression net runs here. |
| Linux (GL3.3+) | Supported | Same GL feature path as Windows. |
| Steam Deck | Supported | Recommended: r_shadowMapSize 1024, r_shadowMapPointSize 512, r_shadowMapMaxUpdatesPerView 2, r_shadowMapCSM 1 with r_shadowMapCascadeCount 3. The importance-ordered update budget keeps per-frame shadow cost bounded. |
| macOS (Apple legacy GL2.1 tier) | Stencil only | The Apple compatibility corridor lacks the GLSL/FBO feature set the shadow-map receiver and caster programs require. Lights fall back to the retail stencil path automatically; this is expected and documented behavior, not an error. |
| macOS (opt-in Vulkan through MoltenVK) | Implemented, untested on Apple hardware | Requires r_renderApi vulkan and a full engine restart. MoltenVK is a Vulkan-on-Metal translation layer bundled in both macOS packages, not a Metal renderer. This path uses the same Vulkan shadow implementation as Windows and Linux — projected, point, parallel, and global lights, cascades, PCF/PCSS-lite, and static caching — but no real-Mac evidence exists yet, so treat it as experimental and expect problems. The default macOS renderer is still OpenGL, which uses the row above. |
The shadow-map pipeline fails closed per light: any light that cannot complete the map path (missing capability, failed framebuffer, unsupported receiver) renders with the retail stencil path for that light instead of losing its shadows.
Recommended default user setup:
r_shadows 1r_useShadowMap 1r_shadowMapCSM 1r_shadowMapHashedAlpha 1r_shadowMapCascadeStabilize 1r_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.