Lens Flares - won't draw (source heavy)
by Jaimi McEntire · in Torque Game Engine Advanced · 08/22/2008 (10:11 pm) · 16 replies
I've added some code to FxSunlight to draw actual lens flares (you know, the overused kind that go through the screen center - many people don't like these, but lets not discuss that part).
Everything is working all the way down to the actual call to draw the flares - but the flares don't get drawn. I can't even get a square of solid color to draw. The Zbuffer is turned off ( I modified the drawBitmapStretch to specifically disable it), the Flare rectangles are on the screen (Yes, I stopped it in the debugger - it's passing all the tests and calling the draw routines). The texture handles are valid, and the DrawBitmapStretch is resetting the BaseRenderState.
Here is the code, I've added it right after Primbuild::end(); in the RenderObject function (yes, the sizes and the bitmap is currently hard coded... I'll change that after I get it working):
Obviously I am doing something wrong - but I can't seem to figure it out. Neither the DrawRect (for testing) or the DrawBitmapStretch will actually draw anything. It's late, and I've probably forgotten something simple... But does anyone have any idea what I'm forgetting, or what I need to reset? Any help is appreciated.
Everything is working all the way down to the actual call to draw the flares - but the flares don't get drawn. I can't even get a square of solid color to draw. The Zbuffer is turned off ( I modified the drawBitmapStretch to specifically disable it), the Flare rectangles are on the screen (Yes, I stopped it in the debugger - it's passing all the tests and calling the draw routines). The texture handles are valid, and the DrawBitmapStretch is resetting the BaseRenderState.
Here is the code, I've added it right after Primbuild::end(); in the RenderObject function (yes, the sizes and the bitmap is currently hard coded... I'll change that after I get it working):
if (LocalSun)
{
RectI viewport = GFX->getViewport();
MatrixF projection = GFX->getProjectionMatrix();
MatrixF world = GFX->getWorldMatrix();
world.mul(GFX->getViewMatrix());
Point3F ScreenPoint;
Point3F ObjectPoint;
if(MathUtils::projectWorldToScreen(mSunlightPosition,ScreenPoint,viewport,world,projection))
{
Point3F ScreenCenter((viewport.extent.x-viewport.point.x)/2,(viewport.extent.y-viewport.point.y)/2,0.0f);
Point3F FlareVector = ScreenCenter - ScreenPoint;
F32 FlareVectorLen = FlareVector.magnitudeSafe();
if (FlareVectorLen > 1.0f)
{
FlareVector.normalize();
FlareVectorLen *= 2;
float BaseSize = (ScreenCenter.y / 10); // vary the sizes of the flare based on the screen size
float Sizes[5] = { 1.0f, 0.8f, 1.3f, 2.0f, 0.8f };
float VectorPos[5] = { 0.3f, 0.60f, 0.68f, 0.80f, 1.0f }; // how far along the line to draw
for (int i=0.0;i<5.0f;i++)
{
float post = i;
float FlareSize = Sizes[i] * BaseSize;
Point3F Vec = FlareVector * VectorPos[i];
Point3F FlarePos = ScreenPoint + Vec;
float HalfSize = FlareSize /2.0f;
RectI Flare((int)(FlarePos.x-HalfSize),(int)(FlarePos.y-HalfSize),FlareSize,FlareSize);
if (Flare.intersect(viewport))
{
//GFX->getDrawUtil()->drawRect(Flare,ColorI(255,128,0,255));
// Todo: use a separate bitmap with mutliple flare images.
GFX->getDrawUtil()->drawBitmapStretch(mRemoteFlareTextureHandle,Flare);
}
}
}
else
{
// White out the screen?
}
}And, here is the Flare rectandle and the viewport- Flare {point={...} extent={...} } RectI
+ point {x=178 y=188 } Point2I
+ extent {x=39 y=39 } Point2I
- viewport {point={...} extent={...} } RectI
+ point {x=0 y=0 } Point2I
+ extent {x=800 y=600 } Point2IObviously I am doing something wrong - but I can't seem to figure it out. Neither the DrawRect (for testing) or the DrawBitmapStretch will actually draw anything. It's late, and I've probably forgotten something simple... But does anyone have any idea what I'm forgetting, or what I need to reset? Any help is appreciated.
#2

The source file, generated from Photoshop.

Edit: fixed links
08/23/2008 (12:06 am)
I won't help very much, but I created some kind of similar effect with fxSunLight bitmaps (in plain old TGE):
new fxSunLight(fxSunLight) {
position = "10.0045 -444.123 124.058";
rotation = "1 0 0 0";
scale = "1 1 1";
Enable = "1";
LocalFlareBitmap = "common/lighting/LensFlares22";
RemoteFlareBitmap = "common/lighting/corona";
SunAzimuth = "0";
SunElevation = "30";
LockToRealSun = "1";
FlareTP = "1";
Colour = "1.000000 0.790000 0.216000 1.000000";
Brightness = "1";
FlareSize = "1.4";
FadeTime = "0.1";
BlendMode = "0";
AnimColour = "0";
AnimBrightness = "0";
AnimRotation = "0";
AnimSize = "0";
AnimAzimuth = "0";
AnimElevation = "0";
LerpColour = "1";
LerpBrightness = "1";
LerpRotation = "1";
LerpSize = "1";
LerpAzimuth = "1";
LerpElevation = "1";
LinkFlareSize = "0";
SingleColourKeys = "1";
MinColour = "1.000000 1.000000 0.370000 1.000000";
MaxColour = "1.000000 0.790000 0.216000 1.000000";
MinBrightness = "0";
MaxBrightness = "1";
MinRotation = "0";
MaxRotation = "359";
minSize = "0.2";
MaxSize = "0.4";
MinAzimuth = "0";
MaxAzimuth = "359";
MinElevation = "-30";
MaxElevation = "210";
RedKeys = "AZA";
GreenKeys = "AZA";
BlueKeys = "AZA";
BrightnessKeys = "AZA";
RotationKeys = "AZA";
SizeKeys = "AZA";
AzimuthKeys = "AZ";
ElevationKeys = "AZ";
ColourTime = "5";
BrightnessTime = "5";
RotationTime = "5";
SizeTime = "5";
AzimuthTime = "5";
ElevationTime = "5";
canSaveDynamicFields = "1";
};The source file, generated from Photoshop.

Edit: fixed links
#3
That looks pretty good! So what did you do to get that working? Just added the fxSunLight resource or something because I'm looking to add that my in project.
08/23/2008 (1:17 am)
@Stephan,That looks pretty good! So what did you do to get that working? Just added the fxSunLight resource or something because I'm looking to add that my in project.
#4
08/23/2008 (5:36 am)
Wow, thanks alot I have been looking for this for a while.
#5
Look at the bold part of the fxSunLight code I provided above: ;-)
People are not using these features very much, generally keeping both bitmaps the same. What a waste!
The first one is the picture used for the remote star. Real world speaking, a simple more or less blurred circle is enough.
The second bitmap is masked when an object is blocking the view. For example the lens flare you see on the picture above will be hidden if you are behind a .dif or a .dts (the terrain as well). Only the remote bitmap will be rendered.
In my opinion it is a very cheap method to add some atmosphere.
08/23/2008 (5:44 am)
@Tek0: Thanks. 8-)Look at the bold part of the fxSunLight code I provided above: ;-)
new fxSunLight(fxSunLight) {
position = "10.0045 -444.123 124.058";
rotation = "1 0 0 0";
scale = "1 1 1";
Enable = "1";
[b]LocalFlareBitmap = "common/lighting/LensFlares22";
RemoteFlareBitmap = "common/lighting/corona";[/b]People are not using these features very much, generally keeping both bitmaps the same. What a waste!
The first one is the picture used for the remote star. Real world speaking, a simple more or less blurred circle is enough.
The second bitmap is masked when an object is blocking the view. For example the lens flare you see on the picture above will be hidden if you are behind a .dif or a .dts (the terrain as well). Only the remote bitmap will be rendered.
In my opinion it is a very cheap method to add some atmosphere.
#6
I haven't played with TGEA that much, because there is no OPenGL support - hence it is of no use for me.
08/23/2008 (6:12 am)
Quote:Just added the fxSunLight resourceWell, the fxSunLight is integrated in latest TGE 1.5.2 (and since 1.4 I think).
I haven't played with TGEA that much, because there is no OPenGL support - hence it is of no use for me.
#7
I see, so Garage Games intergrated it. That's good. Now that LenFlares22 that you posted, is that the source image for the sun effect?
08/23/2008 (2:20 pm)
@Stephan,I see, so Garage Games intergrated it. That's good. Now that LenFlares22 that you posted, is that the source image for the sun effect?
#8
The sun settings used on my example image are these ones:
08/23/2008 (3:09 pm)
Quote:is that the source image for the sun effect?Sure. Use my fxSunLight definition, the provided lensflare picture, check for pathnames, and you should achieve the same effect.
The sun settings used on my example image are these ones:
new Sun() {
azimuth = "30";
elevation = "2";
color = "0.500000 0.400000 0.400000 1.000000";
ambient = "0.225000 0.175000 0.175000 1.000000";
canSaveDynamicFields = "1";
position = "0 0 0";
direction = "0.57735 0.57735 -0.57735";
rotation = "1 0 0 0";
scale = "1 1 1";
CastsShadows = "1";
locked = "False";
};
#9
This will give you a different effect than Stephan's - these flares will move as the sun position changes. Adjust the colors/sizes/positions as needed to get the effect you want.
08/23/2008 (8:58 pm)
I got the dynamic flares working - I ended up needing to project the flare pos, and then unproject all the flares back into the scene (goofy, eh?). This will give you a different effect than Stephan's - these flares will move as the sun position changes. Adjust the colors/sizes/positions as needed to get the effect you want.
if (LocalSun)
{
RectI viewport = GFX->getViewport();
MatrixF projection = GFX->getProjectionMatrix();
MatrixF world = GFX->getWorldMatrix();
world.mul(GFX->getViewMatrix());
Point3F ScreenPoint;
Point3F ObjectPoint;
if(MathUtils::projectWorldToScreen(mSunlightPosition,ScreenPoint,viewport,world,projection))
{
Point3F ScreenCenter((viewport.extent.x-viewport.point.x)/2,(viewport.extent.y-viewport.point.y)/2,0.0f);
Point3F FlareVector = ScreenCenter - ScreenPoint;
F32 FlareVectorLen = FlareVector.magnitudeSafe();
if (FlareVectorLen > 1.0f)
{
//FlareVector.normalize();
//FlareVectorLen *= 2;
float BaseSize = (ScreenCenter.y / 10); // vary the size of the flare based on the screen size to keep it looking similar. Use Y because of widescreens.
float Sizes[5] = { 1.0f, 0.8f, 1.3f, 3.0f, 0.8f };
float VectorPos[5] = { 0.6f, 1.20f, 1.4f, 1.6f, 2.0f };
for (int i=0.0;i<5.0f;i++)
{
float FlareSize = Sizes[i] * BaseSize;
Point3F Vec = FlareVector * VectorPos[i];
Point3F FlarePos = ScreenPoint + Vec;
float HalfSize = FlareSize /2.0f;
float X1 = FlarePos.x-HalfSize;
float Y1 = FlarePos.y-HalfSize;
RectI Flare((int)X1,(int)Y1,FlareSize,FlareSize);
if (Flare.intersect(viewport))
{
float X2 = FlarePos.x+HalfSize;
float Y2 = FlarePos.y+HalfSize;
Point3F spoints[4];
Point3F wpoints[4];
spoints[0] = Point3F(X1,Y1,0.5f);
spoints[1] = Point3F(X2,Y1,0.5f);
spoints[2] = Point3F(X2,Y2,0.5f);
spoints[3] = Point3F(X1,Y2,0.5f);
for (int i=0;i<4;i++)
{
// you'll need to get mNearPlane and mFarPlane from
// the state, in PrepRenderImage. Or just make them 0.1f and 1000.0f (should do it)
MathUtils::projectScreenToWorld(spoints[i],wpoints[i],viewport,world,projection,mFarPlane,mNearPlane);
}
// place holders because we'll end up varying the color and textures
PrimBuild::color4f(0.2f,0.5f,1.0f,0.3f);
GFX->setTexture(0, mLocalFlareTextureHandle);
PrimBuild::begin( GFXTriangleFan, 4 );
PrimBuild::texCoord2f(0, 0);
PrimBuild::vertex3fv(wpoints[0]);
PrimBuild::texCoord2f(1, 0);
PrimBuild::vertex3fv(wpoints[1]);
PrimBuild::texCoord2f(1, 1);
PrimBuild::vertex3fv(wpoints[2]);
PrimBuild::texCoord2f(0, 1);
PrimBuild::vertex3fv(wpoints[3]);
PrimBuild::end();
}
}
}
else
{
// White out the screen?
}
}
#10
08/23/2008 (8:59 pm)
Note: This is somewhat reliant on the position of fxSunlight in your mission. Be sure it's near the end (after the water and terrain, so it draws over them!)
#11
It also means we can now use the localBitmap for something else, doesn't it? ;-)
Edit: what about a screenshot Jaimi?
08/23/2008 (11:15 pm)
@Jaimi: I suppose this is compatible with TGE?It also means we can now use the localBitmap for something else, doesn't it? ;-)
Edit: what about a screenshot Jaimi?
#12
The theory is the same, but some of the function calls would probably be different. Shouldn't be too hard to port though. If you want to port it, I can help, but you may want to wait until I have the final version.
In the final version, yes, because we'll have a separate bitmap for flares (I'm thinking four flare bitmaps would be enough, and then you could scale and recolor them to produce infinite flares).
Here's a screencap I did when I was testing out some AI this morning. (I cropped most of the AI stuff out)
Note: this is NOT the final version, it's using the local bitmap for everything...
*edit* see the link a couple of messages down.
08/24/2008 (2:35 pm)
@Stephan:Quote:I suppose this is compatible with TGE?
The theory is the same, but some of the function calls would probably be different. Shouldn't be too hard to port though. If you want to port it, I can help, but you may want to wait until I have the final version.
Quote:It also means we can now use the localBitmap for something else, doesn't it? ;-)
In the final version, yes, because we'll have a separate bitmap for flares (I'm thinking four flare bitmaps would be enough, and then you could scale and recolor them to produce infinite flares).
Here's a screencap I did when I was testing out some AI this morning. (I cropped most of the AI stuff out)
Note: this is NOT the final version, it's using the local bitmap for everything...
*edit* see the link a couple of messages down.
#13
08/24/2008 (2:39 pm)
Doh, no love from YouTube... "video is no longer available".
#14
*edit* that doesn't appear to be working... Worked last time... here's a direct link:
www.youtube.com/watch?v=gzSN5je_JZo
08/24/2008 (3:12 pm)
I think this one will work. Youtube quality is terrible, though.*edit* that doesn't appear to be working... Worked last time... here's a direct link:
www.youtube.com/watch?v=gzSN5je_JZo
#15
08/24/2008 (3:40 pm)
Nice work, Jaimi!
#16
08/24/2008 (10:42 pm)
Good job Jaimi. 8-)
Associate Jaimi McEntire
King of Flapjacks