| 
      | 
    
      
        The static lightmap generation system has been redesigned and reengineered 
        from the ground up to accommodate the growing need for better lighting 
        in Ritual’s games. These changes have required code changes to the 
        map compiling utility (q3map.exe), the map editor (q3radiant.exe), and 
        the core game engine itself. This document is meant to serve three purposes: 
        first, to extend the TDD (Technical Design Doc) as it relates to the specific 
        features of the lighting system; second, as a tutorial for level designers 
        and lighting specialists; third, as a canonical reference resource for 
        future lighters, engineers, and programmers alike. 
      
       In designing each aspect of the new lighting system, input was gathered 
        from a number of contributors both inside Ritual and out. The resulting 
        design was a consolidation of all of these inputs and, for the most part, 
        accommodates the desires of each (at least in spirit if not in specific 
        implementation details). Efforts have been made to create the system in 
        such a way that it is flexible enough to encompass different methods and 
        techniques into a generalized system that can service the needs of everyone 
        involved. 
      The most obvious philosophical change in lighting paradigms is that map 
        lighters now have a much greater amount of control over various aspects 
        of the light. A light’s brightness is now independent of its falloff 
        geometry, which in turn is broken up into several individually controllable 
        aspects. Each of these aspects will be covered in detail throughout the 
        course of this document. 
      Another important philosophical design decision of the new lighting system 
        can be summarized by the phrase: “realism is good; total control 
        is better”. Lighting engineers now have the ability to (reasonably) 
        reproduce realistic behavior in their lights; however, they also have 
        the ability to explicitly change any aspect of a light such that it will 
        behave in a less realistic but more desirable fashion. 
      
       The following is a step-by-step process of how lighting works in the 
        TikiEngine. 
      Step 1: Placement of light entities in Radiant 
        The lighting engineer uses the map editor to create, copy, and modify 
        light sources in a map. Lights are previewed visually in the editor, both 
        in the orthogonal (2d) and perspective (3d) views. OpenGL is used to render 
        spotlights as cones, point-lights as spheres, and so on. The lighting 
        engineer tweaks each of the lighting keys (discussed later) until (s)he 
        gets the desired light shape and properties. The map is then saved. 
      Step 2: Compilation of static lightmap data using q3map 
        The lighting engineer then generates the static lightmap data for the 
        map by running the map compiler on the level, using the command: 
       
        
       
      Or by running each stage of q3map as a separate task: 
       
        
       
      At this stage, the q3map tool calculates the lightmap data for the entire 
        level by applying the following steps: 
      
        -  For each surface in the world, a sample point is generated for every 
          16 world units, forming a coarse grid overlaying the entire surface 
          area of the world.
 
           
         
        -  For each sample point, every light source in the map is checked to 
          see if it contributes any light to that sample point. If the sample 
          point is outside a point-light’s (or spotlight’s) maximum 
          radius (called “falloff_end_dist”), that light is not considered 
          for that sample point.
 
           
         
        -  For point-lights, the amount of light added to the lightmap at each 
          sample point is calculated using the following steps: 
 
           
          
            - a. If the sample point is inside the inner radius of the light 
              (called “falloff_start_dist”), the light is applied 
              to the sample point at the light’s maximum brightness.
 
               
             
            - b. If the sample point is outside the inner radius of the light, 
              the amount of light is somewhere between 0 and maximum brightness; 
              the exact value depends on the distance the sample point is away 
              from the inner radius as well as the nature of the falloff curvature 
              (“falloff_curvature”), which can be anywhere from a 
              straight-linear drop-off to a steep, inverse-squared drop-off.
 
               
             
           
         
        -  For spotlights, the amount of light added to the lightmap at each 
          sample point is calculated using the following steps:
 
           
          
            -  a. If the sample point is inside the area of the inner cone (“angle_hotspot”), 
              it is lit normally as if the light were a normal point light.
 
               
             
            - b. If the sample point is outside the inner cone but still within 
              the outer cone (“angle_penumbra”), it is partially lit 
              in proportion to its closeness to the inner cone.
 
               
             
            - c. If the sample point lies outside the outer cone, it is not 
              lit by the spotlight at all (unless the “spherical_ambient” 
              key is nonzero for that light).
 
               
             
           
         
        -  For sunlight, the amount of light added to the lightmap at each sample 
          point is calculated using the following steps: 
 
           
          
            - a. A ray is traced from the sample point backward along the direction 
              of the sunlight vector. If the ray collides with a sky brush or 
              sky portal before any other solid object, that sample point is fully 
              lit by the sunlight source.
 
           
         
       
      Step 3: The map is rendered by the engine using textures and lightmap 
        data. 
        When drawing a surface of the world, the engine generally makes (at least) 
        two rendering passes. The first pass is the opaque application of the 
        surface’s texture. The second pass is the application of the lightmap 
        data that was precalculated during the q3map –light stage. The lighting 
        pass is done using the lightmap’s RGB value as a color filter against 
        pixels in the texture at each pixel on the surface; each of the lightmap’s 
        RGB components is multiplied by the pixel’s matching component to 
        produce the net resulting color component. Thus, a lightmap of (1.0, 0.5, 
        0.0) on a medium-grey texel (0.6, 0.6, 0.6) will produce a resulting pixel 
        value of (0.6, 0.3, 0.0). 
      
       There are several different types of light sources available to lighting 
        engineers. All types are represented by a single “light” entity; 
        however, some types require additional objects in order to be properly 
        defined: 
      Type 1: Point Lights 
        A point light is the most common type of light. It is the simplest to 
        define, the easiest to visualize in the editor, and the fastest to calculate 
        during the q3map –light phase of map precompilation.  
      Point lights emit light outward spherically from their origin, affecting 
        all surfaces within their outermost radius (or “falloff_end_dist”, 
        discussed below). They cast static shadows onto the lightmap when a line 
        of sight ray between the point light source and the surface sample point 
        is obstructed by another object. 
      Type 2: Spotlights 
        A spotlight is the next most common type of light. It bears all the properties 
        of a point light; however, a spotlight confines its area of affect into 
        a cone along the direction of the spotlight. This direction is determined 
        by associating the light with a target – usually an info_null – 
        that has a “targetname” key matching the light’s own 
        “target” key. In order to turn a point light into a spotlight, 
        simply associate it to a target entity in this manner. 
      Type 3: Sunlights 
        Sunlights are essentially point lights that are infinitely far away. They 
        are constructed in a manner similar to a spotlight (i.e. using an info_null 
        as a target entity). To make a spotlight into a sunlight, simply check 
        the box in the Light Properties dialog labeled “Directional (parallel) 
        light source”.  
      Once a light becomes a sunlight, its actual position becomes completely 
        meaningless. The light now simply serves as a prototype for defining a 
        light source infinitely far away (such as the sun or moon). All sky brushes 
        and sky portals in the level will now act as parallel emitters for this 
        sunlight; in other words, light of the type specified will be cast in 
        parallel lines along the vector specified by the light’s target 
        entity from every point on the surface of every sky brush or sky portal. 
      
       In the map editor, a light source is represented as an entity. Each 
        entity has a number of key-value pairs (or epairs) which store the various 
        properties of that light. The following is a description of each of the 
        newly-added epair keys: 
      “brightness” 
        Called Overall Brightness in the Light Properties dialog, this determines 
        the maximum brightness multiplier for the light at its brightest point 
        (i.e. its origin). If “brightness” is 1.0, the light makes 
        any surface inside its inner radius appear fullbright (assuming the light 
        is pure white). If “brightness” is 0.5, the light’s 
        brightest spot is only 50% as bright as a normal light at any given point. 
        Note, however, that its geometry – including inner and outer radius, 
        falloff curvature, etc. – will be completely unchanged. 
      Note also that if “brightness” is negative, the light is 
        subtractive rather than additive; i.e. it actually removes light from 
        surrounding surfaces rather than adding light to them. 
      The “brightness” key may hold any value between –1.0 
        and 1.0. 
      “dot_product_weight” 
        Called Dot Product Effect in the Light Properties dialog, this determines 
        the degree to which the dot product (angle of incidence) will affect a 
        light’s effect on a surface. When “dot_product_weight” 
        is 0.0, the angle of the surface being lit is not taken into account at 
        all (other than the fact that surfaces facing completely away from the 
        light are never lit). When “dot_product_weight” is 1.0, the 
        amount of light received on a given surface is proportional to how perpendicular 
        / straight-on that surface is to the source of the light. A value of 0.0 
        produces unrealistic (but easy-to-control) quake-like lighting; a value 
        of 1.0 produces realistic lighting with more complex subtleties. In general, 
        a value somewhere in-between these two extremes is desirable. The default 
        value is 0.5. 
      “_color” 
        The color of the light emitted by a light source. This key has a 3-float 
        vector for its value, such as “1.0 0.5 0.0” (an orange color). 
        The “_color” key is set by choosing a color in the entity 
        color-picker (default “K” in Radiant), although it may also 
        be edited by hand. Clicking on the color sample in the Light Properties 
        dialog also opens the color picker for all currently selected objects. 
      Note that lights may never have a color that is not component-saturated; 
        in other words, all light colors must have at least one component (either 
        Red, Green, or Blue) that is set to 1.0. Non-saturated colors are automatically 
        saturated by Radiant (if set through the color picker) and by q3map at 
        load-time. 
      “falloff_curvature” 
        Called Falloff Curvature in the Light Properties dialog, this determines 
        the steepness of the falloff in intensity as it decreases from maximum 
        at the inner radius (“falloff_start_dist”) to the zero at 
        the outer radius (“falloff_end_dist”). A “falloff_curvature” 
        of 0.0 represents a gentle linear falloff; a value of 1.0 represents a 
        steep, rapidly-decreasing (inverse-squared) falloff. As with “dot_product_weight”, 
        “falloff_curvature” is easiest to control (and least realistic) 
        at 0.0 and is most realistic (but more subtly complex to control) at 1.0. 
        The default value is 0.5. 
      “falloff_start_dist” 
        Called Falloff Start Distance in the Light Properties dialog. This is 
        the inner radius; that is, the distance – in world units – 
        away from the light source within which any surface is fully lit by the 
        light. Note that although this means “fullbright” in some 
        cases, other factors are considered as well: the color of the light, the 
        dot product of the light’s angle hitting the surface (if enabled), 
        and so on. The “falloff_start_dist” value of a currently selected 
        light is represented graphically in both 2d and 3d views in Radiant as 
        translucent spheres of the (normalized) color of the light. (Note: make 
        sure “Show actual colors in XY” is checked ON in Edit->Preferences.) 
      For spotlights, this represents the height of the inner cone, as is consistent 
        with spherical lights (considering the cone as a segment of a sphere). 
      The hotkeys to quickly adjust “falloff_start_dist” for all 
        selected lights is (by default) : ALT + CTRL + [ to decrease, ALT + CTRL 
        + ] to increase. 
      “falloff_end_dist” 
        Called Falloff End Distance in the Light Properties dialog. This is the 
        outer radius; that is, the distance – in world units – away 
        from the light source outside of which any surface is totally unaffected 
        by the light. The “falloff_end_dist” value of a currently 
        selected light is represented graphically in both 2d and 3d views in Radiant 
        as translucent spheres of the (normalized) color of the light. (Note: 
        make sure “Show actual colors in XY” is checked ON in Edit->Preferences.) 
      For spotlights, this represents the height of the outer cone, as is consistent 
        with spherical lights (considering the cone as a segment of a sphere). 
      The hotkeys to quickly adjust “falloff_end_dist” for all 
        selected lights is (by default) : ALT + SHIFT + [ to decrease, ALT + SHIFT 
        + ] to increase. 
      “angle_hotspot” (spotlights only) 
        Called Hotspot Angle in the Light Properties dialog, this field is used 
        only by spotlights. The “angle_hotspot” value of the light 
        determines the total angle, in degrees, of the inner cone of the spotlight. 
        Any point within this inner cone is lit as though the light source were 
        a normal spherical point light. Likewise, any point within this inner 
        cone AND within the inner radius (as determined by “falloff_start_dist”) 
        is fully lit by the light. 
      The hotkeys to quickly adjust “angle_hotspot” for all selected 
        lights is (by default) : ALT + CTRL + < to decrease, ALT + CTRL + > 
        to increase. 
      “angle_penumbra” (spotlights only) 
        Called Penumbra Angle in the Light Properties dialog, this field is used 
        only by spotlights. The “angle_penumbra” value of the light 
        determines the total angle, in degrees, of the outer cone of the spotlight. 
        Any point outside this outer cone is completely unlit / unaffected by 
        the spotlight (unless “spherical_ambient” is nonzero – 
        see below). Points that fall outside the inner cone (“angle_hotspot”) 
        but inside the outer cone (“angle_penumbra”) are partially 
        lit by the spotlight, with a lateral linear falloff from normal brightness 
        (at the edge of the inner cone) to total darkness (at the edge of the 
        outer cone). 
      The hotkeys to quickly adjust “angle_penumbra” for all selected 
        lights is (by default) : ALT + SHIFT + < to decrease, ALT + SHIFT + 
        > to increase. 
      “spherical_ambient” (spotlights only) 
        Called Spherical Ambient in the Light Properties dialog, this field is 
        used only by spotlights. The “spherical_ambient” value of 
        the light determines the fractional amount of the spotlight’s intensity 
        that is conveyed outside the outer (“angle_penumbra”) cone. 
        A value of 0.0 (default) indicates that the spotlight emits no light outside 
        its outer cone. A value of 0.5 indicates that surfaces outside the spotlight’s 
        cone are lit as if by a normal, spherical point light of half the intensity 
        of the spotlight (but with the same basic geometry, in terms of “falloff_start_dist”, 
        “falloff_end_dist”, and “falloff_curvature”). 
        A value of 1.0 (maximum) makes the spotlight behave exactly like a normal 
        spherical point light, since points outside the cone are lit with an equal 
        amount of intensity as the points inside the cone. 
      
      
        - Sunlights ignore the following keys: falloff_curvature, falloff_start_dist, 
          falloff_end_dist, hotspot_angle, hotspot_penumbra, spherical_ambient
 
           
         
        - Point lights ignore the following keys: hotspot_angle, hotspot_penumbra, 
          spherical_ambient
 
           
         
        - falloff_start_dist can never be greater than falloff_end_dist; similarly, 
          falloff_end_dist can never be less than falloff_start_dist. (Note that 
          the distinction between these two statements refers to two different 
          types of clamps, depending on which value is being changed to exceed 
          the other.) The Light Properties dialog will automatically stretch the 
          other field to accommodate the one being moved in excess of these limits.
 
           
         
        - Likewise, angle_hotspot can never be greater than angle_penumbra, 
          and vice-versa. Also enforced by the Light Properties dialog.
 
           
         
        -  The keys light, style, falloff, minlight, radius, angles, spot_angle, 
          spot_dir, and other legacy quake-style lighting epair keys are now obsolete 
          and are completely ignored by the compiler.
 
           
         
        -  Sunlights automatically enforce a dot_product_weight of 1.0. 
 
       
         |