Lensflare update

A place to show off your latest screenshots and for people to comment on them. Only start a new thread here if you have some nice images to show off!
Post Reply
BHawk3D
Gnoblar
Posts: 4
Joined: Thu Jul 14, 2011 2:03 am

Lensflare update

Post by BHawk3D » Thu Jul 14, 2011 3:12 am

I am not sure if this is the right forum to post this. I wrote a lensflare class based on the lensflare code by David De Lorenzo: http://www.ogre3d.org/tikiwiki/LensFlare.cpp. It also incorporates various code snippets found on the Wiki and the forums. I added base flare rotation and scaling for the lensflare size and alpha. There is no occlusion. Source code, material file, and all images are public domain.

Here's is an example image:

Image

Here is an example movie:

[youtube]WhAaAQUN770[/youtube]

Here is the code:

Lensflare.h

Code: Select all

#ifndef _LENSFLARE_H_
#define _LENSFLARE_H_

#include <Ogre.h>

/**
2011 - BHawk3D
Based on Lensflare code by David De Lorenzo. http://www.ogre3d.org/tikiwiki/LensFlare.cpp
Source code, material file, and art is public domain
**/
class LensFlare {
  private:
  Ogre::SceneManager* mSceneManager;
  Ogre::Camera*       mCamera;
  Ogre::SceneNode*    mNode;
  Ogre::BillboardSet* mHaloSet;
  Ogre::BillboardSet* mCircleSet;
  Ogre::BillboardSet* mBurstSet;
  Ogre::Vector3       mLightPosition;
  Ogre::Real          mScale;
  Ogre::Real          mWidth;
  Ogre::Real          mHeight;
  int                 mNumHalos;
  int                 mNumCircles;
  int                 m2DLightLocationX;
  int                 m2DLightLocationY;
  Ogre::Real          mLensFlareBaseSize;
  bool                mVisible;
  Ogre::ColourValue   mBaseHaloColor;
  Ogre::ColourValue   mBaseCircleColor;

  void Reset();
  Ogre::Vector3 GetLensFlareDirectionVector();
  void SetLensFlareLocations(Ogre::Vector3 dir);
  void CalculateLensFlareScreenLocation();
  void CalculateLensFlareScale();
  void SetLensFlareAlpha();
  void SetLensFlareSize();
  void RotateLensFlareSource();
  Ogre::Real GetScale();
  
public:
  LensFlare();
  ~LensFlare();
  void Init(Ogre::SceneManager* sceneManager,
            Ogre::Camera* camera,       
            Ogre::Real width, Ogre::Real height,
            Ogre::Real lensFlareSourceSize,
            Ogre::Real lensFlareBaseSize,
            Ogre::String strHaloMaterialName,
            Ogre::String strCircleMaterialName,
            Ogre::String strSourceMaterialName);
  void Update();
  void End();

  void SetPosition(Ogre::Vector3 pos);
  void SetVisible(bool visible);
  bool GetVisible();
  void SetHaloColour(Ogre::ColourValue color);
  void SetCircleColour(Ogre::ColourValue color);
  void SetBurstColour(Ogre::ColourValue color);
};

#endif
Lensflare.cpp

Code: Select all

#include "LensFlare.h"

LensFlare::LensFlare() {
  Reset();
}

LensFlare::~LensFlare() { } 

void LensFlare::Init(Ogre::SceneManager* sceneManager,
                     Ogre::Camera* camera, 
                     Ogre::Real width, Ogre::Real height,
                     Ogre::Real lensFlareSourceSize,
                     Ogre::Real lensFlareBaseSize,
                     Ogre::String strHaloMaterialName,
                     Ogre::String strCircleMaterialName,
                     Ogre::String strSourceMaterialName) {
  
  mSceneManager = sceneManager;
  mCamera = camera;
  mWidth = width;
  mHeight = height;
  mLensFlareBaseSize = lensFlareBaseSize;

  mHaloSet = mSceneManager->createBillboardSet();
  mHaloSet->setMaterialName(strHaloMaterialName);
  mHaloSet->setCullIndividually(true);

  mCircleSet = mSceneManager->createBillboardSet();
  mCircleSet->setMaterialName(strCircleMaterialName);
  mCircleSet->setCullIndividually(true);

  mBurstSet= mSceneManager->createBillboardSet();
  mBurstSet->setMaterialName(strSourceMaterialName);
  mBurstSet->setCullIndividually(true);

  mNode = mSceneManager->getRootSceneNode()->createChildSceneNode();
  mNode->attachObject(mBurstSet);
  mNode->attachObject(mCircleSet);
  mNode->attachObject(mHaloSet);

  mNumHalos = 3;
  for(int i = 0; i < mNumHalos; i++)
    mHaloSet->createBillboard(0, 0, 0);

  mNumCircles = 12;
  for(int i = 0; i < mNumCircles; i++)
    mCircleSet->createBillboard(0, 0, 0);

  //This will represent the source of the light (i.e. the sun)
  mBurstSet->createBillboard(0, 0, 0);
  mBurstSet->getBillboard(0)->setDimensions(lensFlareSourceSize, lensFlareSourceSize);
  mBurstSet->getBillboard(0)->setColour(Ogre::ColourValue(1, 1, 1, 1));

  mHaloSet->setRenderQueueGroup(Ogre::RENDER_QUEUE_SKIES_LATE);
  mCircleSet->setRenderQueueGroup(Ogre::RENDER_QUEUE_SKIES_LATE);
  mBurstSet->setRenderQueueGroup(Ogre::RENDER_QUEUE_SKIES_LATE);

  mScale = 1;
}

void LensFlare::End() {
  mNode->detachObject(mHaloSet);
  mNode->detachObject(mCircleSet);
  mNode->detachObject(mBurstSet);
  mSceneManager->destroyBillboardSet(mHaloSet);
  mSceneManager->destroyBillboardSet(mCircleSet);
  mSceneManager->destroyBillboardSet(mBurstSet);
  mSceneManager->destroySceneNode(mNode);

  Reset();
}

void LensFlare::Reset() {
  mSceneManager = NULL;
  mCamera = NULL;
  mNode = NULL;
  mHaloSet = NULL;
  mCircleSet = NULL;
  mBurstSet = NULL;
  mLightPosition = Ogre::Vector3::ZERO;
  mScale = 0;
  mWidth = 0;
  mHeight = 0;
  mNumHalos = 0;
  mNumCircles = 0;
  m2DLightLocationX = 0;
  m2DLightLocationY = 0;
  mLensFlareBaseSize = 0;
  mBaseHaloColor = Ogre::ColourValue(1, 1, 1, 1);
  mBaseCircleColor = Ogre::ColourValue(1, 1, 1, 1);
  mVisible = false;
}

void LensFlare::Update() {
  //If the Light is out of the Camera field Of View, the lensflare is hidden.
  if (!mCamera->isVisible(mLightPosition)) {
    SetVisible(false);
    mScale = 0;
    return;
  }

  //TODO: If there is an entity between the camera and the lensflare source the
  //Lensflare is hidden
  /*if(ObjectBlockingFlare()) {
    SetVisible(false);
    mScale = 0;
    return;
  }*/

  SetVisible(true);

  CalculateLensFlareScreenLocation();
  SetLensFlareLocations(GetLensFlareDirectionVector());
  CalculateLensFlareScale(); //mScale will be 0 - 1
  SetLensFlareAlpha();
  SetLensFlareSize();
  RotateLensFlareSource();
}

Ogre::Vector3 LensFlare::GetLensFlareDirectionVector() {
  Ogre::Vector3 camPos = mCamera->getDerivedPosition();
  Ogre::Real lightDistance = (camPos - mLightPosition).length();
  Ogre::Vector3 cameraVect = camPos + (lightDistance * mCamera->getDirection());
  return cameraVect - mLightPosition;
}

void LensFlare::SetLensFlareLocations(Ogre::Vector3 dir) {
  //Flares behind the Sun
  mCircleSet->getBillboard(0)->setPosition(dir * -0.4); 
  mHaloSet->getBillboard(0)->setPosition(dir * -0.3);

  //Sun
  mBurstSet->getBillboard(0)->setPosition(Ogre::Vector3::ZERO);

  //Five Circles and a gap
  mCircleSet->getBillboard(1)->setPosition(dir * 0.1);
  mCircleSet->getBillboard(2)->setPosition(dir * 0.2);
  mCircleSet->getBillboard(3)->setPosition(dir * 0.4);
  mCircleSet->getBillboard(4)->setPosition(dir * 0.45);
  mCircleSet->getBillboard(5)->setPosition(dir * 0.5);

  mCircleSet->getBillboard(6)->setPosition(dir * 0.8);
  mCircleSet->getBillboard(7)->setPosition(dir * 0.9);
  mCircleSet->getBillboard(8)->setPosition(dir * 1.0);
  mCircleSet->getBillboard(9)->setPosition(dir * 1.1);
  mCircleSet->getBillboard(10)->setPosition(dir * 1.2);
  mCircleSet->getBillboard(11)->setPosition(dir * 1.3);

  //Two Halos
  mHaloSet->getBillboard(1)->setPosition(dir * 1.8);
  mHaloSet->getBillboard(2)->setPosition(dir * 2.1);
}

void LensFlare::CalculateLensFlareScreenLocation() {
  Ogre::Vector2 r;
  Ogre::Vector3 point = mCamera->getProjectionMatrix() * 
                        (mCamera->getViewMatrix() * mLightPosition);
  r.x = (point.x / 2) + 0.5f;
  r.y = 1 - ((point.y / 2) + 0.5f);
  m2DLightLocationX = (int)(r.x * mWidth);
  m2DLightLocationY = (int)(r.y * mHeight);
}

void LensFlare::CalculateLensFlareScale() {
  //2D coordinates of the source of the lens flare
  Ogre::Vector2 currentLocation;
  //2D coordinates of the center of the screen
  Ogre::Vector2 centerLocation;

  //Claculete the distance between the center of the screen and a corner
  currentLocation.x = mWidth - 1;
  currentLocation.y = mHeight - 1;
  centerLocation.x = mWidth / 2;
  centerLocation.y = mHeight / 2;
  Ogre::Real maxDist = (currentLocation - centerLocation).length();

  //Calculate the distance from the center of the screen to the
  //Lens Flare source location
  currentLocation.x = m2DLightLocationX;
  currentLocation.y = m2DLightLocationY;
  Ogre::Real dist = (currentLocation - centerLocation).length();

  mScale = (1 - (dist / maxDist));
}

void LensFlare::SetLensFlareAlpha() {
  Ogre::Real total = mHaloSet->getNumBillboards();
  for(int i = 0; i < total; i++) {
    mHaloSet->getBillboard(i)->setColour(mBaseHaloColor * mScale);
  }

  total = mCircleSet->getNumBillboards();
  for(int i = 0; i < total; i++) {
    mCircleSet->getBillboard(i)->setColour(mBaseCircleColor * mScale);
  }
}

void LensFlare::SetLensFlareSize() {
  Ogre::Real size = mLensFlareBaseSize * mScale; 

  //Flares behind the Sun
  mCircleSet->getBillboard(0)->setDimensions(size * 2, size * 2); 
  mHaloSet->getBillboard(0)->setDimensions(size * 3, size * 3);

  //Five Circles and a gap
  mCircleSet->getBillboard(1)->setDimensions(size * 2, size * 2);
  mCircleSet->getBillboard(2)->setDimensions(size * 3, size * 3);
  mCircleSet->getBillboard(3)->setDimensions(size * 2.2, size * 2.2);
  mCircleSet->getBillboard(4)->setDimensions(size * 0.5, size * 0.5);
  mCircleSet->getBillboard(5)->setDimensions(size, size);

  mCircleSet->getBillboard(6)->setDimensions(size, size);
  mCircleSet->getBillboard(7)->setDimensions(size * 4, size * 4);
  mCircleSet->getBillboard(8)->setDimensions(size * 2, size * 2);
  mCircleSet->getBillboard(9)->setDimensions(size * 3, size * 3);
  mCircleSet->getBillboard(10)->setDimensions(size * 2, size * 2);
  mCircleSet->getBillboard(11)->setDimensions(size * 1.5, size * 1.5);

  //Two Halos
  mHaloSet->getBillboard(1)->setDimensions(size * 7, size * 7);
  mHaloSet->getBillboard(2)->setDimensions(size * 12, size * 12);
}

void LensFlare::RotateLensFlareSource() {
  Ogre::Vector2 source(m2DLightLocationX, m2DLightLocationY);
  Ogre::Vector2 dest(mWidth - 1, mHeight - 1);
  Ogre::Real rotMaxDist = dest.length();
  Ogre::Real rotDist = (dest - source).length();
  Ogre::Real rotScale = (1 - (rotDist / rotMaxDist));

  mBurstSet->getBillboard(0)->setRotation(Ogre::Radian(Ogre::Degree(90 * rotScale)));
}

void LensFlare::SetVisible(bool visible) {
  mHaloSet->setVisible(visible);
  mCircleSet->setVisible(visible);
  //mBurstSet->setVisible(visible);
  mVisible = visible;
}

bool LensFlare::GetVisible() {
  return mVisible;
}

void LensFlare::SetHaloColour(Ogre::ColourValue color) { 
  mBaseHaloColor = color;
}

void LensFlare::SetCircleColour(Ogre::ColourValue color) { 
  mBaseCircleColor = color; 
}

void LensFlare::SetBurstColour(Ogre::ColourValue color) {
  Ogre::Real total = mBurstSet->getNumBillboards();
  for(int i = 0; i < total; i++) {
    mBurstSet->getBillboard(i)->setColour(color);
  }
} 

void LensFlare::SetPosition(Ogre::Vector3 pos) { 
  mLightPosition = pos;
  mNode->setPosition(mLightPosition); 
}

Ogre::Real LensFlare::GetScale() { 
  return mScale;
}
LensFlare.material

Code: Select all

material LensFlareHalo
{
	technique
	{
		pass
		{
		  ambient 1 1 1
		  diffuse 1 1 1
		  lighting off
		  scene_blend add
		  depth_write off
		  depth_check off

		  texture_unit
		  {
			texture LensFlareHalo.png
		  }
		}
	}
}

material LensFlareCircle
{
	technique
	{
		pass
		{
		  ambient 1 1 1
		  diffuse 1 1 1
		  lighting off
		  scene_blend add
		  depth_write off
		  depth_check on

		  texture_unit
		  {
		  	texture LensFlareCircle.png
		  }
		}
	}
}


material LensFlareBurst
{
	technique
	{
		pass
		{
		  ambient 1 1 1
		  diffuse 1 1 1
		  lighting off
		  scene_blend add
		  depth_write off
		  depth_check on

		  texture_unit
		  {
			texture LensFlareBurst.png
		  }
		}
	}
}
Images:

LensFlareBurst.png
Image

LensFlareCircle.png
Image

LensFlareHalo.png
Image

Usage is as follows:

1) Include the header

Code: Select all

#include "Lensflare.h"
2) Declare an instance of the class

Code: Select all

LensFlare *flare;
3) Call the Init function when setting up the scene

Code: Select all

flare = new LensFlare();
flare->Init(mSceneMgr, mCamera, mScreenWidth, mScreenHeight,
                2700, //The size of the Sun flare 
                75, //The base size of all the other flares
                "LensFlareHalo", "LensFlareCircle", "LensFlareBurst");
4) Every frame call SetPosition and Update. For example, to create a sun in the sky with a lensflare that the user can never get to:

Code: Select all

//Every frame this code is run
Ogre::Vector3 skyBoxLocation = mSceneMgr()->getSkyBoxNode()->_getDerivedPosition();  
light->setPosition(skyBoxLocation + Ogre::Vector3(1000, 300, -1800));

flare->SetPosition(light->getDerivedPosition());
flare->Update();
5) When shutting down the program call this:

Code: Select all

flare->End();
delete flare;
flare = NULL;
Everything can be modified easily. The demo and image are just an example of how it can be used. Hopefully this will be useful to someone.
0 x

User avatar
xavier
OGRE Retired Moderator
OGRE Retired Moderator
Posts: 9481
Joined: Fri Feb 18, 2005 2:03 am
Location: Dublin, CA, US

Re: Lensflare update

Post by xavier » Thu Jul 14, 2011 4:53 am

Recommend you put this in the Wiki -- it will just get lost in here.
0 x
Do you need help? What have you tried?

Image

Angels can fly because they take themselves lightly.

User avatar
boyamer
Orc
Posts: 459
Joined: Sat Jan 24, 2009 11:16 am
Location: Italy

Re: Lensflare update

Post by boyamer » Thu Jul 14, 2011 7:37 am

Nice work :)
Would be fine if you create also a zip with all files, maybe sample and all media stuff (materials, textures etc).

Thanks
0 x

scratchyrice
Gnome
Posts: 324
Joined: Thu Apr 27, 2006 9:14 pm
Location: United Kingdom - England

Re: Lensflare update

Post by scratchyrice » Thu Jul 14, 2011 3:05 pm

Great work! Im looking to implement a lens flare effect of some kind into our engine, Will take a look at this.

Cheers.
0 x
Intel I5 750 OC'd to 4.2Ghz per core, Geforce 580GTX 1.5Gb GPU, 280GTX for PhysX, 8Gb DDR 3 ram

User avatar
lonewolff
Ogre Magi
Posts: 1199
Joined: Wed Dec 28, 2005 12:58 am
x 2

Re: Lensflare update

Post by lonewolff » Sun Jul 17, 2011 1:16 am

Wow! That looks awesome. I'll be playing with that today for sure :)
0 x

Post Reply