A light_source is not a visible object: it is a point or an area from which light comes. It is still counted as an object, so it can be put in a CSG union with other objects, and it can be transformed. A scene without light sources is dark. The number of light sources should not exceed 127 (a limit that the manual gives for the shared counter). Light sources are used by the diffuse and highlight terms of the finish (see Normals and finishes).
Syntax
light_source {
<location> [,] [colour]
[spotlight | cylinder | parallel | shadowless]
[point_at <v>] [radius r] [falloff f] [tightness t]
[area_light <axis1>, <axis2>, size1, size2]
[adaptive n] [jitter] [circular] [orient] [area_illumination [bool]]
[fade_distance d] [fade_power p]
[media_interaction [bool]] [media_attenuation [bool]]
[looks_like { object }] [projected_through { object }]
[photons { … }]
[translate | rotate | scale | transform | matrix …]
}
The location and the colour come first. A light source can also be an identifier: #declare L = light_source { … } and then light_source { L } (or object { L }). Only the red, green and blue parts of the colour are used; a filter or transmit value is ignored. The colour is also the intensity: rgb 0.5 is a white light at half strength, and values above 1 are allowed. If no colour is written the light is white (rgb 1). No object modifiers other than transformations may be used (the parser stops at the first other word). The items can be in any order, but spotlight or cylinder must come before radius, falloff and tightness, and parallel before point_at for a plain light.
A light has one type: a point light (the default), a spotlight, a cylinder light, a parallel light or a shadowless (fill) light. area_light can be combined with any of them.
Keywords and defaults
| Keyword | Value | Default | Meaning |
|---|---|---|---|
| location | vector | none (first item) | position of the light; the centre of an area light |
| colour | colour | rgb 1 | colour and strength of the light |
spotlight | point light | a cone of light that is full in the centre and falls off to zero at the edge. Sets radius 30, falloff 45 and tightness 0 (and resets them if written after them) | |
cylinder | point light | light constrained by a cylinder, for laser beams. It is still a point source: the rays are not parallel, they are only cut off. Sets radius 0.75, falloff 1, tightness 0 and makes the light parallel internally | |
parallel | off | all rays are parallel, like sunlight. Rays start from the closest point of a plane through the light location, perpendicular to the direction given by point_at. Parts of objects beyond that plane (on the light’s side) still get lit but cast and receive no shadows. fade_distance, fade_power and area light calculations still use the light location | |
shadowless | off | the light casts no shadows (a fill light). It also gives no highlights on illuminated objects. It must not be mixed with the spot keywords (the type is replaced by the last one written) | |
point_at | vector | <0, 0, 1> | the point the spotlight, cylinder or parallel light points at. The line from the location to this point is the axis. A plain point light gives the error “Not with standard light source” |
radius | number | spotlight 30, cylinder 0.75 | spotlight: half the opening angle in degrees of the bright centre cone (the hot spot), where the intensity is uniform. Cylinder: the distance from the axis within which the intensity is uniform. A negative radius is accepted for spotlights |
falloff | number | spotlight 45, cylinder 1 | spotlight: half the opening angle in degrees of the whole cone, where the intensity drops to zero. Cylinder: the distance from the axis where it drops to zero. Radius and falloff close or equal make a sharp edge. Both angles must be less than 90 degrees |
tightness | number | 0 | an additional exponential softening: the intensity is multiplied by cos(angle) ^ tightness (for a cylinder by (1 − distance / falloff) ^ tightness). It affects the light inside the radius too. 0 to 100 make sense. For full control by tightness use radius 0 falloff 90 |
area_light | <axis1>, <axis2>, size1, size2 | none (point) | a rectangle centred on the location, edges given by the two axis vectors (should be perpendicular), with size1 × size2 point lights. The sizes are whole numbers of at least 1 (otherwise “Area size must be greater than zero.”) and their product must fit an integer. A size of 1 in one direction gives a linear light. The brightness of each point is reduced so that the total equals the colour. Together with the spot items it makes an area spotlight, a way to limit the soft-shadow calculation to part of the scene |
adaptive | integer ≥ 0 | 100 | adaptive sampling of the area light: the light is sampled at its four corners and split only where they differ. The value is the number of splits done before the adaptive phase: 0 is at least 4 shadow rays, 1 at least 9, 2 at least 25, 3 at least 81. The number of rays never exceeds size1 × size2, so the default 100 means no adaptive sampling for ordinary sizes. Try adaptive 1 first |
jitter | off | randomly moves the point lights of the array to hide shadow banding. The result differs from render to render, so do not use it in animations | |
circular | off | squashes the array into a circle (or ellipse if the axes differ), for round shadows. Both sizes must be more than 1 (“Circular area light must have more than 1 point per axis”). A circular light has about 78.5 per cent of the area of the rectangle. No sense on linear lights or 2 × 2 sizes. Without area_light a warning is given | |
orient | off | turns the area light toward the point being shadow-tested, so the axis directions do not matter and the light looks three-dimensional (with equal axes and circular it simulates a sphere). The manual lists these rules: only for circular lights, the two axes the same length, and the same number of samples on both axes, more than 1 (the program corrects the first two with a warning and fails on the third). Without area_light a warning is given | |
area_illumination | [bool] | off (on if written without a value) | the whole area gives diffuse and specular illumination, not only the shadow (experimental). The sizes then set the quality of the lighting too |
fade_distance | number | 0 | distance at which the light has its full given intensity |
fade_power | number | 0 (no fading) | rate of falloff: 1 linear, 2 quadratic |
media_interaction | [bool] | on | the light interacts with fog and media of the scene (lights up media). off removes it |
media_attenuation | [bool] | off | the light itself is dimmed as it travels through fog or media (distance-based exponential falloff) |
looks_like | { object } | invisible | gives the light a visible shape, see below |
projected_through | { object } | none | only light that goes through the object reaches the scene, see below |
photons | { refraction bool reflection bool area_light } | see below | photon mapping switches of this light |
colour_map | colour map | undocumented and without effect: the parser gives the warning “Undocumented syntax ignored (colour_map in light_source)” | |
translate, rotate, scale, transform, matrix | as for objects | move, orient or scale the light; they also move point_at, area axes and an attached looks_like object |
The manual says that the cylinder defaults radius 0.75 and falloff 1 are in degrees. In the source (Attenuate_Light in source/core/lighting/lightsource.cpp) they are distances from the axis, and the page lists them so. The manual’s overview also lists radius 70, falloff 70 and tightness 10 as light defaults, which are not what the parser sets for either type.
Intensity of spotlights and cylinder lights
For a spotlight the parser stores the cosines of the two angles. For a ray at the angle θ from the axis the intensity factor is zero if θ is 90 degrees or more (the light is behind the spot), otherwise cos(θ) ^ tightness, and further multiplied by a cubic spline between 1 (at the radius angle) and 0 (at the falloff angle) when θ is beyond the radius. For a cylinder, the point must be in front of the light (positive along the axis), the factor is zero at the falloff distance from the axis or beyond and (1 − d / falloff) ^ tightness inside, with a cubic spline between the radius and the falloff distance. After that, if fade_power is positive, the fading factor below is applied.
Light fading
By default light does not weaken with distance. With fade_power greater than 0, the intensity is multiplied by
2 / (1 + (d / fade_distance) ^ fade_power)
where d is the distance from the light. At d = fade_distance the factor is 1, so the colour is the intensity there; closer than that the light is brighter. Only light coming straight from the source is attenuated, not reflected or refracted light. From language version 3.8, fade_distance 0 with a positive fade_power gives the inverse power law d ^ −fade_power at all distances, with the nominal intensity at distance 1. In older language versions that combination gives a warning, and the fading is ignored. For realism use fade_power 2 and a fade_distance of about the radius of the glowing body, and brighten the colour if the light is then too dim.
looks_like
looks_like { object } puts an object at the position of the light, so that the light has a visible shape (a lamp, a sun). The object should be modelled at the origin; the parser moves it to the light location. It may have object modifiers after it inside the braces. Only one looks_like is allowed (“Only one looks_like allowed per light_source.”). The object and the light get no_shadow, so the light can leave an opaque object. It works with point lights and spotlights, not with parallel lights. If the object should block light, use a union of the light and the object instead, with some part transparent.
projected_through
projected_through { object } works with every type of light, including area lights. Only the light rays that go through the object contribute to the scene; it is the opposite of a shadow. Objects between the light and that object, and surfaces inside it, cast no shadows. Textures and interiors of the object are removed and it is not seen. Only one is allowed (“Only one projected through allowed per light_source.”).
Photons
| Item | Value | Meaning |
|---|---|---|
refraction | bool | non-zero sets the “refraction on” flag of this light (photons are shot toward refracting objects), zero sets the “refraction off” flag |
reflection | bool | the same for reflecting objects |
area_light | treat the light as an area light for the photon shooting (the photon area light flag) |
The global photon settings are on Global settings. The photon keywords of objects (target, pass_through, collect) are on Object modifiers; a light group takes them too.
light_group
light_group {
light_source | object | light_group …
[global_lights [bool]]
[translate | rotate | scale | transform | matrix …]
[photons { target [density] refraction bool reflection bool pass_through [bool] collect [bool] }]
}
A light group is a union of lights and objects. The lights in the group light only the objects in the group (this includes scattering media, which must be in the group too). The objects in the group are lit by the lights of the group and, only with global_lights on (a number above 0.5; written without a value it is on), also by the global lights. The default is off, so the global lights do not reach the objects of a group. Light groups can be nested: an inner group also gets the lights of the group it is in. A light group can be used in CSG. Only transformations, global_lights and photons may follow the contents; other object modifiers are not accepted. Light groups help when some objects are too dark but the overall light is right, since the lights of the group do not change the global lighting.
Lights in CSG and shadows
A light source can be a member of a union together with objects, and the whole union can be moved with one translate or rotate. A union that holds only light sources is marked as a light source union. A looks_like object belongs to its light and is moved with it. A light source is flagged no_shadow itself, so it does not block other lights; the object of a looks_like also gets no_shadow.
For each light and each surface point the renderer shoots a shadow ray toward the light. An opaque object in the way blocks the light. A transparent one lets light pass, filtered by its colour. An object with no_shadow never blocks. An area light shoots one ray for each of the lights of the array (or fewer with adaptive), so a partly hidden area light gives a soft shadow. A shadowless light shoots no shadow rays. If the light has media_interaction on and media_attenuation on, the shadow ray also takes part in the dimming by fog and media in between.
Examples
// a point light that fades with distance
light_source {
<10, 20, -10>, rgb 1
fade_distance 20
fade_power 2
}
// a spotlight: full intensity inside 10 degrees, zero beyond 20 degrees
light_source {
<0, 10, 0>, rgb <1, 0.9, 0.7>
spotlight
point_at <0, 0, 0>
radius 10
falloff 20
tightness 10
}
// a cylinder light: radius and falloff are distances from the axis
light_source {
<-5, 5, -5>, rgb <1, 0, 0>
cylinder
point_at <0, 0, 0>
radius 0.5
falloff 1
}
// a parallel light, like the sun
light_source {
<0, 100, 0>, rgb 0.5
parallel
point_at <0, 0, 0>
}
light_source {
<0, 8, 0>, rgb 1
area_light <2, 0, 0>, <0, 0, 2>, 5, 5
adaptive 1
jitter
circular
orient
area_illumination on
}
light_source {
<6, 5, -6>, rgb 0.6
area_light x*3, y*0.2, 8, 1
spotlight
point_at 0
radius 20
falloff 40
}
#declare Bulb = sphere { 0, 0.3 pigment { rgbf <1, 1, 0.8, 0.5> } finish { emission 1 diffuse 0 } }
light_source {
<3, 4, -3>, rgb 1
looks_like { Bulb }
media_interaction on
media_attenuation off
}
light_source {
<-3, 6, -2>, rgb 1
shadowless
projected_through { box { -1, 1 } }
}
#declare Lamp = light_group {
light_source { <-5, 5, -5>, rgb <1, 0, 0> }
sphere { <4, 0, 0>, 1 pigment { rgb 1 } }
global_lights off
translate y
}
object { Lamp }
union {
light_source { <0, 3, 0>, rgb <0, 0, 1> }
sphere { <0, 3, 0>, 0.1 pigment { rgb <0, 0, 1> } finish { emission 1 } }
rotate y*30
}
Not described
Known, not yet covered
- Reference: the shadow-ray code was summarised from the renderer source (
source/core/render/trace.cpp) and the manual, not followed line by line, and the effect ofno_shadowon transparent objects in an area light is not described. - Reference: the photon switches of a light are listed from the parser; how they combine with the global photon settings (
photonsinglobal_settings) was not checked in the photon code.