Shadow System Technical Documentation (Killing Floor 2)

From Killing Floor 2 Wiki
Jump to navigation Jump to search

Static Shadows

!--T:1--> Warning Warning: There is currently a bug in the SDK where Masked Materials will not produce Precomputed Static Shadows for Lightmaps.
Bug Report Thread and Workaround:

Primitives that have CastShadow=TRUE and CastStaticShadow=TRUE will cast static shadows on the environment.

NOTE: A primitive can still receive static shadows from the environment even if it is not set to cast any shadows.

The shadows for all the lights affecting a primitive are flattened and stored as a single shadowmap per primitive. This allows us to render the static shadows for a primitive in a single pass during the Geometry Pass of deferred shading. The only exception being shadows from the dominant directional light. The static shadows from the dominant directional light are stored in a separate channel of the shadowmap to prevent blending issues at the edge of the cascaded shadow maps.

Note: Due to the above, there should only be one dominant directional light per map.

The static shadows from the dominant directional light (sun shadows) and static shadows from all other lights take up 2 channels of the G-Buffer.

Dynamic Whole Scene Shadows

Dynamic shadow casting lights (CastWholeSceneDynamicShadows=TRUE) cast whole scene shadows for static geometry. Whole scene shadows are always blended with static shadows and are mutually exclusive - you cannot have the same light casting static only shadows for certain primitives and dynamic shadows for others.

These are handled differently for punctual lights and directional lights.

Punctual Lights

Spot lights cast a single whole scene shadow based on the direction of the spotlight, and point lights cast 6 whole scene shadows for each of the 6 directions.

The whole scene shadows are faded out based on WholeSceneShadowFadeOutDistance and are completely culled past the WholeSceneShadowCutoffDistance. These values are specified in SystemSettings.ini.

The dynamic shadow is faded out linearly between the above range. The fade opacity is constant for the light (not per pixel). The dynamic shadow for the light is faded in as a whole (dissolve effect). There is no transition line from static to dynamic shadows.

Note : The distance settings are from the player view to the light bounds and not light origin.

Directional Lights

Dominant directional lights cast Cascaded Shadows on the environment. The settings for the cascaded shadows are available in the light - WholeSceneDynamicShadowRadius, NumWholeSceneDynamicShadowCascades, CascadeDistributionExponent.

The fade opacity is computed per pixel on the shadowed fragment. This leads to a visible transition line at the threshold of the cascaded shadows.

Dynamic Per Object Shadows

Lights that have (CastPerObjectDynamicShadows=TRUE) can cast per object dynamic shadows on primitives that have (AllowPerObjectShadows=TRUE). This works whether the light casts a whole scene dynamic shadow (CastWholeSceneDynamicShadows) or not. Note: The object should also have (CastDynamicShadows=TRUE) in order to cast per object shadows.

Setting a primitive to use per object shadows (AllowPerObjectShadows=TRUE) automatically turns off static shadows for that primitive.

Per object shadows are expensive especially when accompanied by per object preshadows, and should be used sparingly - mainly for characters and other dynamic actors of interest.

Per Object shadows are superimposed on any other whole scene shadows or static shadows. This has the additional benefit of allowing you to mix static shadows and dynamic (per object) shadows for a light.

There are 2 levels of control over per object shadow culling which work simultaneously. Per object shadow cull distance can be set per primitive using the PerObjectShadowCullDistance property. Additionally Per Object Shadows can be faded and culled out based on resolution using the following settings in SystemSettings.ini : ShadowFadeResolution and MinShadowResolution. The shadows are faded starting at ShadowFadeResolution and are culled past MinShadowResolution.

Per Object Shadow Batching

The following setting in SystemSetting.ini control the behavior of the shadow batching system.

bAllowGroupedPerObjectShadows Whether to allow batched per object shadows

GroupedPerObjectShadows_MinRadius What radius to use to group shadows for dynamic primitives (per object shadows) that are closest to the viewer

GroupedPerObjectShadows_MaxRadius What radius to use to group shadows for dynamic primitives (per object shadows) that are farthest from the viewer

GroupedPerObjectShadows_RampUpFactor Determines how quickly the shadow group radius will ramp up from GroupedPerObjectShadows_MinRadius to GroupedPerObjectShadows_MaxRadius based on the view distance.

GroupedPerObjectShadows_RampCutoff At what distance from the viewer to enforce GroupedPerObjectShadows_MaxRadius. The shadow group radius will increase at the rate of GroupedPerObjectShadows_RampUpFactor from GroupedPerObjectShadows_MinRadius to GroupedPerObjectShadows_MaxRadius until GroupedPerObjectShadows_RampCutoff is reached. After that, GroupedPerObjectShadows_MaxRadius will be used for merging shadows.


Pre shadows are shadows cast by the environment onto dynamic actors such as characters. Pre shadows can be handled in 2 different ways.

If a character is within a whole scene dynamic shadow, it will receive environment shadows by default just like any other primitive within the whole scene shadow. This is relatively cheap and the fade is controlled by WholeSceneShadowFadeOutDistance and WholeSceneShadowCutoffDistance.

Per Object Preshadows are more expensive and should be used sparingly. Per Object Preshadows are only allowed for lights that have AllowPerObjectPreShadow=TRUE. Currently this set by default on the dominant directional light.

The PerObjectShadowCullDistance is applicable to preshadows as well. Additionally, per object Preshadows can be faded out and culled based on resolution using MinPreShadowResolution and PreShadowFadeResolution inside SystemSettings.ini

NOTE: Even though a character may use per object Preshadows, it is substituted with whole scene dynamic shadows when the subject is within the whole scene dynamic shadow radius. This achieves the same (or better) effect at a cheaper cost.

NOTE: Preshadows can be batched as well just like per object shadows. They use the same settings as per object shadows.