D3DBook:Light Streaks

From GDWiki
Jump to: navigation, search

Light Streaks

Background

Light streaks are the result of light scattering as it passes through a lens or aperture. Cracks, scratches, grooves, dust, and lens imperfections cause light to scatter and diffract. Eyelashes and even the eye's lens can diffract and scatter incoming light. The more intense the incoming light is relative to the surrounding ambient light level, the more perceivable the scattering will be. Light scattering is therefore an important visual cue that help the viewer discern the relative brightness of light sources in comparison to their surroundings [Spencer].

Painting light streaks would be done with a brush by pressing a bit harder on the common point and releasing the pressure while moving the brush away from this point. This is very similar to what a light streak filter is doing while it is "smearing" a bright spot into several directions, so that it looks like a star or a cross consisting of two or more arms.

A common implementation for a common cross-like light streak is based on a 4-tap kernel. It runs in two passes per streak over the whole render target (read more in [Kawase][Oat]).

The first pass starts at the pixel being rendered as shown in Figure 11.

Image:LightStreaks.jpg
Figure 11 - Light Streak filter passes

The second pass than samples at every fourth neighboring pixel in the direction of the streak. Both passes are used to generate one streak resulting in 8 passes for light streaks in form of a cross. Every additional strike direction requires then 4 additional passes. This idea can be simplified on hardware that supports more than four texture fetches at once by creating a 7-tap filter that does two streaks at once like this.

Image:LightStreakSampling7tap.jpg
Figure 12 - One Pass Light Streak

The obvious drawback is that especially the center of the resulting streak is not sampled as often and therefore does not look as soft. To make up for this, a blur filter can be run over the resulting image. In case of a cross like light streak pattern about 4 - 6 passes will result in good looking results.To  adjust the strength of the streaks the samples are weighted differently with the following equation.

Image:WeightEQ.gif
Equation 21

With the 7-tap approach the value in is used in both directions from the third sampling point on. To be able to bend the streak filter in any direction, Oat [Oat] added an orientation vector that is used to show the direction from which the samples need to be taken like this.

Image:SampleCoordinateEQ.gif
Equation 22

The variable SC holds the texture coordinate in T, b holds the power value of four or seven -depending on how many fetches are done in the pixel shader-, V is the vector that represents the streak direction vector, the variable TxSize holds the texel size (1.0f / SizeOfTexture) and the sample number in s. As shown by Oat storing orientation vectors in a look-up texture offers interesting effects like light streaks that follow the bending of the windshield.

Implementation

Most light streak effects consist of two or three light streaks that form a star like pattern. The following code shows how to draw one of those light streaks in one pass.

float4 Color = 0.0f;
 
// get the center pixel
// Weights represents four w values from equation 21. It is calculated on the application level and send to the pixel shader
Color = saturate(Weights.x) * tex2D(RenderMapSampler, TexCoord.xy);
 
// setup the SC variable of equation 22
// the streak vector and b is precomputed and send down from the application level to the pixel shader
float2 SC = LightStreakDirection.xy * b * TexelSize.xy;
 
// take sample 2 and 4 (figure 12)
Color += saturate(Weights.y) * tex2D(RenderMapSampler, TexCoord.xy + SC);
Color += saturate(Weights.y) * tex2D(RenderMapSampler, TexCoord.xy - SC); 
 
// take sample 1 and 5 (figure 12)
SC += SC;
 
Color += saturate(Weights.z) * tex2D(RenderMapSampler, TexCoord.xy + SC);
Color += saturate(Weights.z) * tex2D(RenderMapSampler, TexCoord.xy - SC); 
 
// take sample 0 and 6 (figure 12)
SC += SC;
 
Color += saturate(Weights.w) * tex2D(RenderMapSampler, TexCoord.xy + SC);
Color += saturate(Weights.w) * tex2D(RenderMapSampler, TexCoord.xy - SC); 
 
return saturate(Color);

By picking antipodal texture coordinates the effort to setup the texture fetches is minimized. To emphasize the light streak, the whole effect can be repeated with different b values for each pass.

Personal tools