| Home Page | Recent Changes | Preferences

Lens Flare

A lens flare is a visual effect assembled of several circles/hexagons that – when the person is moving – move opposite of the light source and don't stay on one spot. So they move in the direction that the person is moving. Lens flares aren't available in the current Unreal engine without some custom scripting.

The textures that are displayed around light sources, but stick at the place where the light is are coronas. For some reason they're frequently erroneously called "lens flare" as well.

[corona]

Making lens flares

Here's the code I used for a POC I threw together a short while back. References which might do a better job of explaning this stuff than I can are located in the comments.

//-----------------------------------------------------------
// FlareInteraction.
// Adds 1337 lens flares for lights w/ coronas.
// (c) 2002 jasonyu
//-----------------------------------------------------------
class FlareInteraction extends Interaction;

#exec OBJ LOAD FILE=Textures\FlareTextures.utx PACKAGE=LensFlare

var Actor PlayerOwner;
const HLSMAX = 240;
const RGBMAX = 255;


event Initialized()
{
    PlayerOwner = ViewportOwner.Actor;
    log("I LIVE!!!1", 'FTW');
}

// adapted from:
// http://plaza27.mbn.or.jp/~satomii/design/win32/hls2rgb.html
final simulated function float HueToRGB(float n1, float n2, float hue)
{
    if ( hue < 0 ) hue += HLSMAX;
    if ( hue > HLSMAX ) hue -= HLSMAX;

    /* return r,g, or b value from this tridrant */
    if ( hue < (HLSMAX/6) )
        return ( n1 + (((n2-n1)*hue + (HLSMAX/12))/(HLSMAX/6)) );
    if ( hue < (HLSMAX/2) )
        return n2;
    if ( hue < ((HLSMAX*2)/3) )
        return ( n1 + (((n2-n1)*(((HLSMAX*2)/3)-hue) + (HLSMAX/12))/(HLSMAX/6)) );
    else
        return n1;
}


final simulated function Color hls2rgb(byte hue, byte lum, byte sat)
{
    local Color C;
    local float Magic1, Magic2;
    local int R,G,B;

    if ( sat==0)
    {     /* achromatic case */
        C.R = (lum*RGBMAX) / HLSMAX;
        C.G = C.R;
        C.B = C.R;
    }
    else
    {       /* chromatic case */
        /* set up magic numbers */
        if (lum <= (HLSMAX/2))
            Magic2 = (lum*(HLSMAX+sat)+(HLSMAX/2)) / HLSMAX;
        else
            Magic2 = lum+sat - ((lum*sat)+(HLSMAX/2)) / HLSMAX;

        Magic1 = 2*lum - Magic2;

        /* get RGB, change units from HLSMAX to RGBMAX */
        R = (HueToRGB(Magic1, Magic2, hue+(HLSMAX/3))
                * RGBMAX + (HLSMAX/2)) / HLSMAX;
        G = (HueToRGB(Magic1, Magic2, hue)
                * RGBMAX + (HLSMAX/2)) / HLSMAX;
        B = (HueToRGB(Magic1, Magic2, hue-(HLSMAX/3))
                * RGBMAX + (HLSMAX/2)) / HLSMAX;
    }

    C.R = R;
    C.G = G;
    C.B = B;
    C.A = 255;
    return C;
}



// adapted from:
// http://www.gamedev.net/reference/articles/article813.asp
simulated function PostRender( canvas Canvas )
{
    local Light Other;
    local float Dist;
    local Vector X,Y,Z, Dir;

    local Vector V, C, L;
    local float Length;
    local float ScaleX, ScaleY;


    if ( ViewportOwner.Actor.Pawn != None ) PlayerOwner = ViewportOwner.Actor.Pawn;
    else PlayerOwner = ViewportOwner.Actor;

    if ( PlayerOwner != None )
    {
        ScaleX = Canvas.SizeX / 640.0;
        ScaleY = Canvas.SizeY / 480.0;

        C.X = Canvas.ClipX/2;
        C.Y = Canvas.ClipY/2;
        GetAxes(PlayerOwner.Rotation, X,Y,Z);
        ForEach PlayerOwner.RadiusActors(class'Light', Other, 2000)
        {
            Dir = Other.Location - PlayerOwner.Location;
            Dist = VSize(Dir);
            Dir = Dir/Dist;

            if ( (Dir Dot X) > 0.7 && Other.bCorona &&
                (   // yuck...
                (PlayerOwner.IsA('Pawn') &&  Pawn(PlayerOwner).LineOfSightTo(Other) ) ||
                (PlayerOwner.IsA('Controller') && Controller(PlayerOwner).LineOfSightTo(Other) )
                ) &&
                Other.LightRadius >= 64 && Other.DrawScale > 0.2 )
            {
                //Convert 3d location to 2d for display on the Canvas
                L = WorldToScreen(Other.location);

                V.X = L.X - C.X;
                V.Y = L.Y - C.Y;
                Length = VSize(V);
                V = Normal(V);

                Canvas.Style = PlayerOwner.ERenderStyle.STY_Additive;
                Canvas.DrawColor = hls2rgb(Other.LightHue, 15, 75);

                // place flares along directional vector
                Canvas.SetPos( (V.X*Length*1.2)-32*ScaleX+C.X, (V.Y*Length*1.2)-32*ScaleY+C.Y );
                Canvas.DrawTile(Texture'LensFlare3', 64*ScaleX,64*ScaleY,0.0, 0.0, 128, 128);

                Canvas.SetPos( (V.X*Length)-32*ScaleX+C.X, (V.Y*Length)-32*ScaleY+C.Y );
                Canvas.DrawTile(Texture'LensFlare1', 64*ScaleX,64*ScaleY,0.0, 0.0, 128, 128);

                Canvas.SetPos( (V.X*Length*0.66)-64*ScaleX+C.X, (V.Y*Length*0.66)-64*ScaleY+C.Y );
                Canvas.DrawTile(Texture'LensFlare1', 128*ScaleX,128*ScaleY,0.0, 0.0, 128, 128);

                Canvas.SetPos( (V.X*Length*0.33)-64*ScaleX+C.X, (V.Y*Length*0.33)-64*ScaleY+C.Y );
                Canvas.DrawTile(Texture'LensFlare0', 128*ScaleX,128*ScaleY,0.0, 0.0, 128, 128);

                Canvas.SetPos( (V.X*Length*0.125)-64*ScaleX+C.X, (V.Y*Length*0.125)-64*ScaleY+C.Y );
                Canvas.DrawTile(Texture'LensFlare2', 128*ScaleX,128*ScaleY,0.0, 0.0, 128, 128);

                Canvas.SetPos( (V.X*Length*-0.21)-64*ScaleX+C.X, (V.Y*Length*-0.21)-64*ScaleY+C.Y );
                Canvas.DrawTile(Texture'LensFlare3', 128*ScaleX,128*ScaleY,0.0, 0.0, 128, 128);

                Canvas.SetPos( (V.X*Length*-0.30)-32*ScaleX+C.X, (V.Y*Length*-0.30)-32*ScaleY+C.Y );
                Canvas.DrawTile(Texture'LensFlare4', 64*ScaleX,64*ScaleY,0.0, 0.0, 128, 128);

                Canvas.SetPos( (V.X*Length*-0.5)-90*ScaleX+C.X, (V.Y*Length*-0.5)-90*ScaleY+C.Y );
                Canvas.DrawTile(Texture'LensFlare4', 180*ScaleX,180*ScaleY,0.0, 0.0, 128, 128);
            }
        }
    }
}

defaultproperties
{
   bVisible=true
   bActive=true
}

A compiled .u with textures and activating mutator may be located at http://www.boilingpoint.com/~jasonyu/ut/LensFlare.zip

Enjoy.

capt.

Comments

Mychaeel: I've always wanted to code a small actor that makes real lens flares, I'm just not sure where to get the right flare textures for it...

The Alien: Lens flares aren't doable in UEd 2 AFAIK :( Creating lens flares would require variable partial transparencies aside from the code which UEd doesn't have. :(

Mychaeel: Variable partial transparencies? Wouldn't sticking a couple of translucent textures on the user's screen suffice? At least it seems the usual "lens flare" effects of common image editing applications work that way...

The Alien: It would, but the problem with translucent textures in UEd is that they're all 50% translucent which is too much for lens flares. That's not the big problem - the big problem is that two or more overlapping translucent textures in UEd will make the whole thing 0% transparent, thus blocking the view :(, which is exactly what happens with lensflares except that the transparency will just decrease (not to 0), so you will still be able to look through the lens flare. I imagine you'd need transparencies of 10-35% to create the desired effect.

Mychaeel: That notion of texture transparency in the Unreal engine is not correct – software rendering aside. Transparent textures are rendered so that black parts are completely transparent and white parts are completely opaque, and interpolated inbetween. To make something more or less transparent, just make it lighter or darker. That's the same way the various fade-in/fade-out logo effects work (CSHP's logo, for instance).

Mychaeel: Technically, I believe transparency is calculated as follows (using ColorTexture and ColorBackground for a given pixel, and assuming the arithmetic operators work on a per-component basis): ColorResult = ColorBackground + (ColorWhite - ColorBackground) * ColorPixel / ColorWhite.

The Alien: Hmm...if that is true, lens flares would be very possible. The part about partial transparencies is true with coronas – I was thinking more in the lines of the texture properties, because I once noticed that two overlapping transparent sheets would be 0% transparent. Dunno why they didn't implement lens flares. I always thought it was because overlapping transparencies would cause problems. But you should try it sometime. :)

Zedsquared: From a philosophical point of view, should you use lens flares when the character you're playing has normal eyes? Lens flares are an artifact of compound optical systems so, fair enough, use lens flares if the viewpoint presented in the game is that of a robot drone or similar but when you're a human grunt up against the alien hordes... don't! Beware the cheese factor also, lens flares are just *so* overdone these days :-)

Dma: Yeah. To get a "Serious Sam"- or "JDoom"-style lens flare, one would probably need to have access to the Canvas object on the client side. Could possibly use the same kind of code used for the BotPack.GuidedWarShell?. You could like subclass Light (UT) or some other class and override PostRender and just plop the lensflares on the viewport. Shouldn't slow down stuff too much. I think it involves dot products and other marvelously fun stuff! By the way, I think lensflares got popular because people see them on TV and many people spend most of their lives watching the thing, so they think that is how reality SHOULD look. You could probably come up with some lens flare stuff by looking at the JDoom package.

Capt. K. An implementation method I was masticating on sometime back involved calculating a vector from the light source to a point to the side of or above the player inverse to the light source's positioning along the z-plane in relation to the path of the player's viewtarget. Spawn and position the rings along that vector and have the size mirror corona behavior.

Mychaeel: As far as I can see from popular image editing programs' behavior, lens flares aren't much more than placing a couple of translucent textures on the line between the light source's position on the screen and the screen middle, scaled by the 2D distance between those two points. There's actually no vector maths involved in that. (I'd also draw those textures directly on the screen rather than spawning them as separate actors that have to be moved in the world.)

Wormbo: There actually is some vector math involved for calculating the exact location of the light source on the screen. (The redeemer code is far from optimal btw.)

Dma: I think I might just use the excellent info at http://www.wildtangent.com/developer/howtos/LensFlareHowTo/ to do it. (It has images too, along with a java simulation!) I could just use STY_Translucent or STY_Modulated and use Canvas.DrawIcon after setting the style and I wouldn't need to care about how bad it looked because it would just be a proof of concept. :-) Oh, by the way... the color of the light should have some effect on the colors of the lens flares.

Dma: I think I will go ahead and try to make this thing work. I might just use the textures on http://www.blackpawn.com/texts/lensflare/default.html or somewhere.

BuddhaMaster: is it possible to make that lens flares running on the old UT ;) ? ..if not, its not

possible to import all the 'mother-classes' who lensflare mutator needs? or is that a 2 engine

related operation =) ? ...sorry for my english im from switzerland... ..if anyone needs textures, i can make some but i need to know how they have to look ;)

Tynan: If you guys are having trouble with opacity, you could simply consider using a texture with an alphamap. This way, you can set the transparency to anything you like, or even have it vary.


BuddhaMaster: how can i make a new 'post' on this page? i have another light related question. ..and why has my text always a line space between the lines?

Wormbo: Read Wiki Markup and New Contributors Quick Start. There's nothing like "posts" at a Wiki, you can only edit pages.
BTW: edit this page to find a solution to your problem. ;)

The Unreal Engine Documentation Site

Wiki Community

Topic Categories

Image Uploads

Random Page

Recent Changes

Offline Wiki

Unreal Engine

Console Commands

Terminology

Mapping Topics

Mapping Lessons

UnrealEd Interface

Questions&Answers

Scripting Topics

Scripting Lessons

Making Mods

Class Tree

Questions&Answers

Modeling Topics

Questions&Answers

Log In