Page 1 of 3

LensFlareSceneNode with occlusion query

Posted: Sun Sep 04, 2011 6:14 am
by tbw
Hi,

for my tech demo I needed a sun with lensflare. Though there is a lensflare scene node in irrExt I was a little bit unhappy with it.
For large camera far values the flares are hopping (I assume that this is a rounding issue in getRayFromScreenCoordinates).
So I decided to create a new one. Here is the result.
sample download with sources
http://www.van-helsing-band.de/irrlicht/lensflare.zip

Image

you are able to custimize the flares:

Code: Select all

        // enum with different flare types (used by SFlareData)
        enum E_FLARE_TYPE
        {
                EFT_SUN = 0,
                EFT_GLOW,
                EFT_LENS,
                EFT_STREAKS,
                EFT_RING,
                EFT_HALO,
                EFT_CIRCLE,
                EFT_POLY,
                EFT_COUNT
        };
 
        // struct holding the flare specification
        struct SFlareData
        {
        public:
                // constructor
                SFlareData(E_FLARE_TYPE type, float position, float scale, video::SColor& color)
                {
                        Type = type;
                        Position = position;
                        Scale = scale;
                        Color = color;
                }
 
                // flare type
                E_FLARE_TYPE Type;
                // position
                f32 Position;
                // flare scale
                f32 Scale;
                // flare color
                video::SColor Color;
        };
Intances of SFlareData are stored in an array

Code: Select all

        protected:
                // flare data array
                core::array<SFlareData> FlareData;
with the corresponding accessor method

Code: Select all

                // returns the flare data array
                core::array<SFlareData>& getFlareData();
you can modify the flares from outside the class.

the render method is straight forward

Code: Select all

void CLensFlareSceneNode::render()
{
        // get the videodriver and the active camera
        video::IVideoDriver* driver = SceneManager->getVideoDriver();
        ICameraSceneNode* camera = SceneManager->getActiveCamera();
 
        // return if we don't have a valid driver or a valid camera 
        // or if we have no texture attached to the material
        if (!camera || !driver || !Material.getTexture(0))
                return;
 
        // get screencenter
        const core::vector2d<s32> screenCenter = core::vector2d<s32>(
                SceneManager->getVideoDriver()->getScreenSize().Width, 
                SceneManager->getVideoDriver()->getScreenSize().Height)/2;
        
        // get screencoordinates of the node
        const core::vector2d<s32> lightPos = SceneManager->getSceneCollisionManager()->getScreenCoordinatesFrom3DPosition(
                getAbsolutePosition(), 
                camera);
 
        // store old projection matrix 
        core::matrix4 oldProjMat = driver->getTransform(video::ETS_PROJECTION);
        
        // store old view matrix 
        core::matrix4 oldViewMat = driver->getTransform(video::ETS_VIEW); 
 
        // clear the projection matrix 
        driver->setTransform(video::ETS_PROJECTION, core::IdentityMatrix); 
        
        // clear the view matrix 
        driver->setTransform(video::ETS_VIEW, core::IdentityMatrix); 
        
        // set the transform
        driver->setTransform(video::ETS_WORLD, core::IdentityMatrix); 
        
        // set the material
        driver->setMaterial(Material);
        
        // calculate some handy constants
        f32 texPos = 1.0f/EFT_COUNT;
        s32 texHeight = s32(Material.getTexture(0)->getSize().Height*0.5f);
        f32 screenWidth = f32(driver->getScreenSize().Width);
        f32 screenHeight = f32(driver->getScreenSize().Height);
        
        // render the flares
        for (u32 i=0; i<FlareData.size(); ++i)
        {
                // get the flare element
                SFlareData& flare = FlareData[i];
 
                // calculate center of the flare
                core::vector2d<s32>flarePos = screenCenter.getInterpolated(lightPos, -2.0*flare.Position);
 
                // calculate flareposition in vertex coordinates using the scalefactor of the flare
                s32 flareScale = s32((texHeight*flare.Scale));
                core::rect<f32> flareRect = core::rect<f32>(
                        -1.f + 2.f * f32(flarePos.X-flareScale) / screenWidth, 
                        -1.f + 2.f * f32(screenHeight-flarePos.Y-flareScale) / screenHeight, 
                        -1.f + 2.f * f32(flarePos.X+flareScale) / screenWidth, 
                        -1.f + 2.f * f32(screenHeight-flarePos.Y+flareScale) / screenHeight);
                
                // calculate flarecolor in dependence of occlusion
                f32 flareAlpha = f32(flare.Color.getAlpha()) / 255.f;
                video::SColor flareColor(255,
                        (u32)(Strength * flareAlpha * flare.Color.getRed()),
                        (u32)(Strength * flareAlpha * flare.Color.getGreen()),
                        (u32)(Strength * flareAlpha * flare.Color.getBlue()));
                
                // set vertex colors
                Vertices[0].Color = flareColor;
                Vertices[1].Color = flareColor;
                Vertices[2].Color = flareColor;
                Vertices[3].Color = flareColor;
                
                // set texture coordinates
                Vertices[0].TCoords.set(    flare.Type * texPos, 1.0f);
                Vertices[1].TCoords.set(    flare.Type * texPos, 0.0f);
                Vertices[2].TCoords.set((flare.Type+1) * texPos, 0.0f);
                Vertices[3].TCoords.set((flare.Type+1) * texPos, 1.0f);
 
                // set vertex positions
                Vertices[0].Pos.set(flareRect.UpperLeftCorner.X, flareRect.UpperLeftCorner.Y, 0);
                Vertices[1].Pos.set(flareRect.UpperLeftCorner.X, flareRect.LowerRightCorner .Y, 0);
                Vertices[2].Pos.set(flareRect.LowerRightCorner.X, flareRect.LowerRightCorner.Y, 0);
                Vertices[3].Pos.set(flareRect.LowerRightCorner.X, flareRect.UpperLeftCorner.Y, 0);
 
                //draw the mesh
                driver->drawIndexedTriangleList(Vertices, 4, Indices, 2);
        }
        
        // restore view matrix 
        driver->setTransform(video::ETS_VIEW, oldViewMat); 
        
        // restore projection matrix 
        driver->setTransform(video::ETS_PROJECTION, oldProjMat); 
}
using

Code: Select all

                // sets the strength (visibility) of the flares
                void setStrength(f32 strength) { Strength = core::clamp(strength, 0.0f, 1.0f); }
gives the possibility to use an occlusion query result to set the strength of the flares.
In the example I included a SceneNodeAnimatorFollowCamera class that keeps the relative position of the sun constant.
The sample is compiled against a newer trunk of irrlicht (which includes the occlusion query feature)
Thats it, I hope you enjoy it.

Re: LensFlareSceneNode with occlusion query

Posted: Sun Sep 04, 2011 8:35 pm
by hybrid
Sounds really cool. Can we add this to irrExt or even Irrlicht core?

Re: LensFlareSceneNode with occlusion query

Posted: Mon Sep 05, 2011 5:12 am
by tbw
yes, of course! :D

Re: LensFlareSceneNode with occlusion query

Posted: Tue Sep 06, 2011 12:23 am
by Granyte
wow your stuff is awsome as always

Re: LensFlareSceneNode with occlusion query

Posted: Thu Nov 03, 2011 2:17 am
by Justei
This is a REALLY neat looking thing you have got here!
I have a problem though, when I try this out on my project I get the following:
error: 'class irr::video::IVideoDriver' has no member named 'addOcclusionQuery'|

Which is the line
driver->addOcclusionQuery(sunMeshNode, sunMeshNode->getMesh());

Any ideas? :(

Re: LensFlareSceneNode with occlusion query

Posted: Thu Nov 03, 2011 8:09 am
by hybrid
That's a feature of the upcoming Irrlicht 1.8. Maybe just remove any occurences of these methods, and set the flag which checks the occlusion to always succeeding.

Re: LensFlareSceneNode with occlusion query

Posted: Thu Nov 03, 2011 9:09 am
by ACE247
Thanks for the nice code! Copy pasting into my project. :)

Re: LensFlareSceneNode with occlusion query

Posted: Thu Nov 03, 2011 12:06 pm
by Justei
hybrid wrote:That's a feature of the upcoming Irrlicht 1.8. Maybe just remove any occurences of these methods, and set the flag which checks the occlusion to always succeeding.
Huh, I see... How different is 1.8 from 1.7.1? I use that and haven't updated in quite a while, but would love to, however don't want to break my whole project lol. Too much work put into it ^^. And are the general changes big or pretty much the same? :)

Re: LensFlareSceneNode with occlusion query

Posted: Thu Nov 03, 2011 12:14 pm
by ACE247
Very similar changes, mainly just added features and bug fixes. But yeah update now while you still can do so easily and update regularly, else it becomes very difficult bringing something made with 1.7 to say version 2.

Re: LensFlareSceneNode with occlusion query

Posted: Sun Nov 06, 2011 2:13 pm
by Justei
I just updated to 1.7.2, however this still doesn't seem to work, is there a newer version of irrlicht I should try using to get this to work properly? :/
If there is could sum1 link me to a sdk or something like that?

Re: LensFlareSceneNode with occlusion query

Posted: Sun Nov 06, 2011 3:05 pm
by hybrid
You can use the latest development version of Irrlicht only by compiling the engine on your own from code in SVN. There's also a nightly build usually, but it might worth switching to SVN anyway if you want to keep up with the development branch.

Re: LensFlareSceneNode with occlusion query

Posted: Fri Nov 25, 2011 12:20 pm
by blackMasoon
I have compiled the latest version of Irrlicht from SVN and two interesting things happened:

1) Occlusion queries didn't make the lensFlareNode hiding behind other nodes like buildings.

2) Suddenly all collisions (triangle selectors etc.) stopped working thanks to new Irrlicht o.O

Why is that happening?

Re: LensFlareSceneNode with occlusion query

Posted: Thu Jan 12, 2012 11:10 pm
by Granyte
hey i'm trying to use your lensflare in a 3d context where the sun position cannot be abstracted to a constant position i tryed adapting by adapting your position detection code but until now i havent had any sucess

Re: LensFlareSceneNode with occlusion query

Posted: Fri Jan 13, 2012 7:51 am
by tbw
...the sun position cannot be abstracted to a constant position i tryed adapting by adapting your position detection code ...
Hey Granyte,
can you give me a little bit of code, so I can have a deeper look into it?

Re: LensFlareSceneNode with occlusion query

Posted: Fri Jan 13, 2012 8:22 am
by Granyte
at first i tryed making the node a child of a sun node i position at (0,0,0) with the camera at an arbitrary (149598,6371,0) the lensflare is not aligned with the node and behave wierd after a while i tryed to update the render() function without sucess