葫芦画瓢
Reference
http://www.ogre3d.org/wiki/index.php/Displaying_LensFlare
http://www.gamedev.net/reference/articles/article874.asp
http://www.gamedev.net/reference/articles/article813.asp
Recent Resources
-
The Core Mechanics of Influence Mapping
-
Learning Android Development with Unity
-
Developing a Mobile Application with Flash
-
Video Game Localisation - A Tricky Game
-
Comparing Shadow Mapping Techniques with Shadow...
-
New Incentives and a Whole New Platform From Th...
-
Autodesk Previews a Games Production Solution
Lens Flare Tutorial
Published Oct 19 1999 06:50 PM in Lens FlaresObjective
To explain how to create the over-used, totally hyped "Lens Flare" effect that everyone seems to be talking about these days.
"Did you see the screenshots for , they had the coolest Lens Flares!!!"
Assumptions
I assume that you are familiar with 2d coordinate systems.
I assume that you are capable of using blit to compose the image.
Explanation of the Concepts
The basic idea is that when a bright light passes in front of a camera in real life, it typically creates a glare on each of the lenses within your camera. The physics of why and how the optics of lens flares work are irrelevant to achieving a believable effect.
Now, in your typical polygon-based 3d engine, you don't actually use multiple lenses in your calculations so we need to find a way to "fake" the illusion that the light is glaring off of several lenses within your virtual camera.
Ingredients:
The position of a light in screen coordinates(lx,ly).
The position of the center of the screen in screen coordinates(cx,cy).

// find the direction vector from the center to the light
vx = cx - lx;
vy = cy - ly;
NOTE: STORE THE LENGTH OF THE VECTOR...we'll call ours "length"
You'll also need several images to use as components of the effect. One of these images is typically a star-burst type of image. The others are usually halo type images. See below.

OK, so now we have three vectors:
cx,cy = center of the screen
lx,ly = position of the light
vx,vy = normalized direction vector from the center to the light
Here comes the easy part...
Simply scale the normalized direction vector by the length to get the center coordinate of where to draw the primary "star-burst" image.
vx = vx * distance;
vy = vy * distance;
top = vy - 64 + cy;
left = vx - 64 + cx;
right = vx + 64 + cx;
bottom = vy + 64 + cy;
// NOTE: MAKE SURE TO OFFSET BY THE CENTER POINT
I've found the following values to work quite well...
Flare | Length Scale | Image Scale |
Primary Flare | length | 1.0 |
First Halo | length/2 | .5 |
Small Burst | length/3 | .25 |
Next Halo | length/8 | 1.0 |
Next Burst | -(length/2) | .5 |
Next Halo | -(length/4) | .25 |
Next Burst | -(length/5.5) | .25 |
Below you can see a shot of the effect at work...Notice the lack of proper alpha-blending, this was due to the fact that I slapped the lens flare test project together with C++ Builder using straight SRCAND-style "blits"...gets the point across and only took about a half-hour to code...

For an actual high-quality example of this algorithm at work, be sure to download the Venom demo on March 2, 1998.
I hope you have enjoyed this short tutorial, if you have any questions or would like the source code to the C++ Builder project that this screen shot is from, send me an email.
- Alan Gordie
Date: February 20, 1999
Copyright © 1999
Introduction
A few authors recently have discussed methods of alpha blending. For those of you who are clueless as to what alpha blending is, I'd suggest reading some of the other alpha blending tutorials on GameDev.net for a more extensive tutorial. This will be a tough article to work through, and will require a lot of effort on your part to learn everything involved with creating beautiful flares, but the results will be well worth the effort.
Alpha Blending
The basic break-down of the effect is that you create a new color by splitting up two colors, source1 and source2, into their RGB components. You then take percentages of each color component (usually on a 0..255 scale), and add them up to create a destination color component:
Figure 1.
Dest_r = ((source1_r * alpha) + (source2_r * (255-alpha))/255;
Dest_g = ((source1_g * alpha) + (source2_g * (255-alpha))/255;
Dest_b = ((source1_b * alpha) + (source2_b * (255-alpha))/255;
Alpha Blending Speed-ups
Now if one were to attempt to perform fast alpha blending, you may find that the equations in Figure 1 are not too efficient. Some common speed-ups involve storing the inverse alpha value into a new variable so that it doesn't have to be recalculated each time, ie:
Figure 2.
int inverse_alpha = 255 - alpha;
Dest_r = ((source1_r * alpha) + (source2_r * inverse_alpha))/255;
Dest_g = ((source1_g * alpha) + (source2_g * inverse_alpha))/255;
Dest_b = ((source1_b * alpha) + (source2_b * inverse_alpha))/255;
Examining Figure 2, we can clearly see that the biggest drawbacks in speed lie in the fact that 6 multiplications and 3 divides are performed. But one thing that really jumps out is the value 255. We won't assume that the compiler optimizes this code in any form and replace the three divides by bit shift operations.
Figure 3.
int inverse_alpha = 255 - alpha;
Dest_r = ((source1_r * alpha) + (source2_r * inverse_alpha)) >> 8;
Dest_g = ((source1_g * alpha) + (source2_g * inverse_alpha)) >> 8;
Dest_b = ((source1_b * alpha) + (source2_b * inverse_alpha)) >> 8;
Here is where things get interesting, we can eliminate at least three multiplications and one subtract instruction by storing our bitmap differently. The rest of these optimizations will apply only to those who don't need to constantly modify their alpha values.
Let's check out some sample data:
Figure 4.

The color data is simply a composite of the red, green, and blue channels. You can see what those channels would look like in the lower left corner of Figure 4. I've added the coloring so it is easier to distinguish between the three channels, but normally they appear in grayscale format. The alpha data represents the level of translucency that the corresponding pixel in the color data should maintain when blitted onto another color surface.
Okay, so here is what we can do. We can use the same amount of space as before with minimal-to-no loss in quality. Simply pre-divide each pixel in the color data by it's corresponding alpha component FIRST.
Figure 5 illustrates how this can be done.
Figure 5.
/*
In mathematics, you learn something known as an distributive property of real numbers. We can illustrate that property as:
(A + B) C = AC + BC
Where A, B, and C are real numbers.
Now lets see what that looks like in code by expanding the source below :
*/
int inverse_alpha = 255 - alpha;
Dest_r = (source1_r * alpha)/255 + (source2_r * inverse_alpha)/255;
Dest_g = (source1_g * alpha)/255 + (source2_g * inverse_alpha)/255;
Dest_b = (source1_b * alpha)/255 + (source2_b * inverse_alpha)/255;
Also, our original bitmap format will include some sort of alpha channel. As you can see in the previous code samples, we are only using it in the line:
int inverse_alpha = 255 - alpha;
The equation then gets reduced to:
Figure 6.
// Remember that alpha now contains the inverse value (255-alpha)
Dest_r = source1_r + (source2_r * alpha) >> 8;
Dest_g = source1_g + (source2_g * alpha) >> 8;
Dest_b = source1_b + (source2_b * alpha) >> 8;
Lens Flare Translucency
Well, I just explained to you everything you'll need to know about alpha blending. Now put that aside, because for lens flares we will utilize additive blending. Blending in this manner is what causes flares to appear purely white over bright surfaces.
Additive blending is done in unoptimized form as follows:
Figure 7.
Dest_r = source1_r + source2_r
Dest_g = source1_g + source2_g
Dest_b = source1_b + source2_b
if (Dest_r > 255) Dest_r = 255;
if (Dest_g > 255) Dest_g = 255;
if (Dest_b > 255) Dest_b = 255;
We assume that Dest_r, Dest_g, and Dest_b are capable of handling numbers greater than 255. One solution could be to leave those values as short 16-bit integers. Though, there may be a better brute-force solution which will allow us to use 8-bit integers and get rid of those nasty "if" statements.
Create a ( 256+256) byte look-up TABLE as follows:
Figure 8.
unsigned char alut [512];
for (int i = 0; i < 512; i++)
{
alut [i] = i;
if (i > 255) alut [i] = 255;
}
alut [0] = 0;
alut [1] = 1;
alut [2] = 2;
...
alut [255] = 255;
alut [256] = 255;
...
alut [511] = 255;
Figure 9.
Dest_r = alut [source1_r + source2_r];
Dest_g = alut [source1_g + source2_g];
Dest_b = alut [source1_b + source2_b];
I have left out some rather vital information for putting the destination pixel back together, but this can be commonly found in most alpha blending tutorials for various pixel formats.
Parts of a Flare
1. Main Flare - The main flare is the most prominent portion of a lens flare. It is what should typically come to mind when you think of lens flares. See below for several examples

The main flare can be broken down into four distinct parts:
The rest of the flare varies widely between flares. These parts usually appear as small, very translucent, circles.

Here, we don't really see too much variation in relation to how the circles are created. The diagram below gives you a basic insight as to how they are created. Generally, you create a ring of any color, and smoothly transition to another color using smaller and smaller rings until your final ring has a radius of 0. Note that you'll need to utilize a blur filter to make it look the most correct.
Figure 11.

The optimal way to create the secondary rings is to create a function which takes at least a radius, an outer ring color, and an inner ring color. You then interpolate the R, G, B values starting from the outer ring color and continuing until you reach the final inner ring color. Looking at figure 11, we could say that the outer ring's color is some shade of purple, while the inner ring color is pure black.
Breaking the Screen Down : Cartesian Coordinates
In order to easily draw lens flares, we'll need to take notice of a property that they all share.
Examine the flare below, and see if you can determine a trend in the positions of the primary flare in relation to the secondary parts of the flare.

If you haven't noticed yet, all parts of the flare pivot around the center of the image. So as such, we will utilize a coordinate system that is conducive to this sort of pivoting. The Cartesian coordinate system, as demonstrated in figure 10, is perfect for the creation of lens flares because all points are centered around the middle of the graph.
Figure 10.

In order to utilize a Cartesian coordinate system on-screen, we simply set our origin to (X = SCREEN_WIDTH / 2, Y = SCREEN_HEIGHT / 2). We then plot all points on screen in Cartesian coordinates, with the x-extents being +/-(SCREEN_WIDTH / 2) and the y-extents being +/-(SCREEN_HEIGHT / 2).
Converting back to screen coordinates is also easy. We simply add our (X, Y) values for the origin to each (X, Y) pair in Cartesian coordinates.
The Lens Flare Vector
The lens flare we create will have parts that all lie on a straight line. The method that I like to utilize when positioning parts of the lens flare is to set position coordinates only for the main flare using a standard (h, k) center, plotted in cartesian coordinates. All other secondary portions are inverted and/or scaled (h, k) coordinates. While you may use a 2d vector, or a 3d vector if you want the flare to have capabilities of being hidden by geometry (such as a sun behind a star), I find this to be the easiest.
Figure 11.

Remember, (h, k) are simply points in the cartesian coordinate system you set up. They more specifically represent the CENTER of the main flare. The other coordinates are simply scaled and/or inverted h, k coordinates. Note that you can pick out virtually any number to scale the coordinates, and invert any coordinate set as you wish.
What happens when you invert the h, k coordinates is that if your main flare is in the top right corner, the new coordinates would be in the bottom left corner of the screen.
Main Flare | h | k |
Secondary Flare | -h | -k |
Secondary Flare | -h / 2 | -k / 2 |
Secondary Flare | -h / 1.2 | -k / 1.2 |
Secondary Flare | h / 3.2 | k / 3.2 |
Screen_coord_x = h + SCREEN_W / 2;
Screen_coord_y = k + SCREEN_H / 2;
When blitting the flare portions to the screen using additive blending, don't forget to blit the flare you generate with the new screen coordinates being in the absolute center of the sprite, rather than the top right corner like most blitting functions work.
Using Graphics Programs to Create Flares
Well, we just spent a considerable amount of time talking about how you can graphically generate your very own lens flares. Well, it may not be very practical for most programmers to spend the time writing routines to generate lens flares. So what you need to do is grab a good graphics program like Photoshop and create your own using filters!
Simply render them to a black background and use a crop tool to pick out only the parts you want.
But, for those of you who can't afford an expensive graphics program like Photoshop, I've taken the liberty of creating a few flares for you.
Just click on the flare you like. They are stored in 32-bit TARGA files.

Good Luck!
The tutorial and the code are written by User:Sphinkie.
If you implement this effect in your project, please send me a screenshot, I'll add it here.
A lens-flare effect is an optical effect that appears on the lens of a camera when a strong light is in the field of view.
The effect is composed with several elements: halos (like a shining circle) or "burst" (like a shining star). You need images with transparency for this (tga or png files usually).
On computers, this effect can be rendered with 2D or with 3D.
The 2D way
A plane is created in front of the camera. Halos and bursts will be drawn on this plane.
- C : The point at the X-Y center of the screen.
- L : The point at the X-Y position of the light source (projected on the screen).
- Now, draw a line between C and L with a distance d. The halos are on this line, at d/2 (for instance).
The article that help me for the theory can be found on gamedev.net (Austin Game Conference).
The 3D way
A 3D line is created between a point in front of the camera and the light source. The halos and burst are drawn along this line.
- L: The Light source Position
- C: The Camera position
- R: The Distance between C and L.
- F: This point is in fromt of the camera, at the same distance thna the light. (Draw a line following the Camera direction, with a distance R).
- Now you can draw a line between L and F with a distance d. Halos will be drawn on this line, at d/2, d/3, etc.
A good rendering will be obtain by placing the following elements:
Type Position Scale Main d 1 halo d/2 1/2 burst d/3 1/4 halo d/5 1 burst -d/2 1/2 halo -d/4 1/4 burst -d/5 1/4
Code
The following code will use the 3D method.
This code is not perfect, because the effect is a little bit far from the camera and some 3D objects can pass between the camera and the effect. (And the effect is supposed to take place, on the camera lens itself .
This code is not very difficult, but need a lot of try, and adjustement to have a nice rendering.
Usage
This is the LensFlare class.
You create the lensflare with the createLensFlare function, and then call update in your frameListener, to update the effect according to the camera position, and direction.
LensFlare *lensflare; bool frameStarted(const FrameEvent& evt) { .. .. lensflare->update(); } CreateScene(void) { ... ... lensflare = new LensFlare(Vector3(0,10,0),mCamera, mSceneMgr); }
This code will also need a dedicated material file.
Source files
Alias: Displaying_LensFlare
Contributors to this page: jacmoe and OgreWikiBot .
Page last modified on Wednesday 22 of December, 2010 15:49:04 UTC by jacmoe .
The content on this page is licensed under the terms of the Creative Commons Attribution-ShareAlike License.
As an exception, any source code contributed within the content is released into the Public Domain.