Fake contrast is a feature of the original vanilla Doom engine, which consists in making walls oriented parallel to the East-West axis brighter, while walls parallel to the North-South axis are darker. The aim of fake contrast is to help accentuate the angles in the map's geometry, because with the simple lighting system of the Doom engine (ambient omnidirectional light, no shadows) and the low-resolution paletted textures, the angles could seem flat in rooms.
The system, however, is not perfect. It only works for orthogonal geometry, even though getting free of the orthogonality constraint present in older raycaster engines (such as Wolfenstein 3D) was one of the main points of the Doom engine. The relatively steep difference detracts from it as well, and has even been perceived as a bug.
ZDoom provides two alternatives to vanilla fake contrast: even lighting and smooth lighting. The choice between the three options is determined by the value of the r_fakecontrast console variable, and can also be set through the display options menu.
Even lighting applies the front sector light to all walls, regardless of angle. This avoids the stark discrepancy that can detract from a map's look; but at the same time can lead to the apparent flatness that fake contrast was meant to cure.
Smooth lighting takes advantage of ZDoom's finer granularity in light levels to compute the adjustment linearly from the wall angle, rather than by simply looking whether it is horizontal or vertical. The effect researched by fake contrast is therefore fully achieved.
While ZDoom offers a global setting, it is also possible to set in MAPINFO which fake contrast mode a map should use by default, with the map definition keywords evenlighting and smoothlighting. Furthermore, the amplitude of the light adjustment can be modified with the horizwallshade and vertwallshade properties.
It is possible in UDMF to mark walls as using even lighting with the nofakecontrast flag or smooth lighting with the smoothlighting flag; and it is also possible to directly provide a lighting value (regardless of wall angle and lighting mode) with the lightabsolute flag and the light property.
In vanilla, it corresponds to a part of the functions R_RenderMaskedSegRange() and R_StoreWallRange() in r_segs.c, specifically code segments like this:
// Calculate light table. // Use different light tables // for horizontal / vertical / diagonal. Diagonal? // OPTIMIZE: get rid of LIGHTSEGSHIFT globally curline = ds->curline; frontsector = curline->frontsector; backsector = curline->backsector; texnum = texturetranslation[curline->sidedef->midtexture]; lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT)+extralight; if (curline->v1->y == curline->v2->y) lightnum--; else if (curline->v1->x == curline->v2->x) lightnum++; if (lightnum < 0) walllights = scalelight; else if (lightnum >= LIGHTLEVELS) walllights = scalelight[LIGHTLEVELS-1]; else walllights = scalelight[lightnum];
The vanilla engine has 16 light levels corresponding to the 256 light values, so increasing or decreasing lightnum as done here corresponds to increasing or decreasing the effective sector light for the wall by 16. A perfectly "horizontal" wall is brightened, while a perfectly "vertical" one is darkened; every other wall uses the light level of the front sector.
In ZDoom, these two code segments are factorized into a single function, side_t::GetLightLevel(), present in p_sectors.cpp. The function handles all three lighting options as well as wall and map flags.