SFML community forums

Help => Graphics => Topic started by: BaneTrapper on April 20, 2014, 02:02:54 am

Title: How to simulate night deillumination but have lights like torch
Post by: BaneTrapper on April 20, 2014, 02:02:54 am
Hello.
I would like to achieve night effect like from this video
https://www.youtube.com/watch?v=QNA9uu4PLMo (https://www.youtube.com/watch?v=QNA9uu4PLMo)
It start from 0:40.
How do i achieve such a effect?
One thought is to make a Texture that will be completely black, and for each light draw following image
(http://img.photobucket.com/albums/v35/thir13en_fears/T_SpotlightProjection.jpg)

What are you suggestions?
The game is 2d, top down view
Example of what i attempted to make for night:
(http://s26.postimg.org/6d7159gsp/Day.png)
(http://s26.postimg.org/71fvo7fih/Night.png)
As it is clear, the light at day is too bright, but at night its colorless.
I achieve it by drawing a dark background then applying lights over it, and to be honest its not what i want visually.
Title: Re: How to simulate night deillumination but have lights like torch
Post by: FRex on April 20, 2014, 02:42:33 am
Maybe it's a custom shader or more elaborate texture at work (or both)?
Effect is almost 100% doable in SFML + GL since it's done with these in the video. ;D
You can try asking Jungletoe yourself: http://en.sfml-dev.org/forums/index.php?topic=11878.0
He seems kind of dormant but maybe will respond to a direct question or PM.
Title: Re: How to simulate night deillumination but have lights like torch
Post by: Laurent on April 20, 2014, 09:03:12 am
Clear a RenderTexture with black color. Then draw each light on it, using the kind of texture that you show in your first post. Finally, draw your render-texture on top of your scene with the sf::BlendMultiply blending mode. This way, white areas will show what's under and dark ones will remain black.
Title: Re: How to simulate night deillumination but have lights like torch
Post by: BaneTrapper on April 20, 2014, 12:10:32 pm
Thank you on help!
Using render texture works flawlessly.
All is left to do another effects that will be actual light showing at day to the player that there is light.
I will post examples and code when i get home, i am going to feast now.
Title: Re: How to simulate night deillumination but have lights like torch
Post by: eXpl0it3r on April 20, 2014, 12:58:54 pm
You could also play around with different lighting textures. Change the gradient a bit, add more opacity etc.
If you want the same effect as in Dwell, you can always ask the author (http://en.sfml-dev.org/forums/index.php?action=profile;u=7002) itself. Also check out his blog (http://jungletoe.tumblr.com/) to see the advancement in the lighting technique.
Title: Re: How to simulate night deillumination but have lights like torch
Post by: BaneTrapper on May 27, 2014, 07:34:48 pm
So i forgot to post, here you got the light system to get image:
(http://s26.postimg.org/qlh6g7hvt/Light_example.png)

So this system works as such.
There are two parts, DayNight which control is it dark on screen or not. And Light which is for color and data.
At DayNight i have RenderTexture that i use to create night effect, "Black screen" Then for each light i draw gradient circle to simulate light there.
At Light, it is just a normal light, A circle textured rectangle on which i control color, give it "Power" intensity via alpha color.
class Light
{
public:
        Light();
        Light(const int Radius, const sf::Color Color, const int PosX, const int PosY, bool IsBinded = 0, int UnitVecID = 0);
        int radius;
        sf::Color color;
        int posX, posY;

        bool isBindedToUnit;
        int unitVecID;
};
class LightHolder
{
public:
        LightHolder();
        void Loop(UnitList & objUnitList);
        void DrawLight(sf::RenderTexture & renTex, sf::RenderWindow & renWin);


        void AddLight(Light & light);
        void RemoveLight(const int VecID);
        void MoveLight(int VecID);

        std::vector<int> lightListEmptyPos;
        std::vector<Light> lightList;
//Light
public:
        sf::VertexArray verArrLight;
        sf::RenderStates renStatLight;
        sf::Texture texLight;
//Reveal
        sf::RenderStates renStatReveal;
        sf::Texture texReveal;
};
class DayNight
{
public:
        DayNight(daynight::TimeType typeOfTime);//0-100%, 0=Dark, 100=Light used to gain color from texture for day night
        void Loop();
        void Draw(sf::RenderWindow & renWin, sf::Vector2f & pos);

        sf::VertexArray verArr;
        sf::Color color;//Vertex color
//Night
        sf::Image imgColorForNight;
        double clockDuration;
        double increment;
        int value;
        int percent;
        daynight::TimeType timeType;
        sf::Color nightColor;
        sf::Sprite sprNight;
//Drawing
        sf::RenderTexture renTex;
        sf::RenderStates renStat;
};


//CPP FILES
DayNight::DayNight(daynight::TimeType typeOfTime)
{
        color = sf::Color(0, 30, 0, 126);
        verArr.setPrimitiveType(sf::PrimitiveType::Quads);
        verArr.append(sf::Vertex(sf::Vector2f(0,0), color, sf::Vector2f(0, 0)));
        verArr.append(sf::Vertex(sf::Vector2f(glob::WINDOW_WIDTH, 0), color, sf::Vector2f(0, 0)));
        verArr.append(sf::Vertex(sf::Vector2f(glob::WINDOW_WIDTH,glob::WINDOW_HEIGHT), color, sf::Vector2f(0, 0)));
        verArr.append(sf::Vertex(sf::Vector2f(0,glob::WINDOW_HEIGHT), color, sf::Vector2f(0, 0)));
        if(imgColorForNight.loadFromFile("./Files/Textures/NightColor.png") == false)
        {
                glob::PrintError("Unable to load image ./Files/Textures/NightColor.png From DayNight::DayNight");
        }

        renTex.create(glob::WINDOW_WIDTH, glob::WINDOW_HEIGHT);
        renStat.blendMode = sf::BlendMultiply;

        clockDuration = daynight::DAY_DURATION;
        increment = 1000/60;
        value = 0;
        percent = 0;

        timeType = typeOfTime;
        if(typeOfTime == daynight::TTDay)
                value = 100;
        else if(typeOfTime == daynight::TTNight)
                value = 0;
        else if(typeOfTime == daynight::TTDawn)
                value = 25;
        else if(typeOfTime == daynight::TTDusk)
                value = 75;
        nightColor = imgColorForNight.getPixel((value * imgColorForNight.getSize().x) / 100, 0);//24 because its max time of day
}

void DayNight::Loop()
{
//DAY
        if(timeType == daynight::TTDay)
        {
                clockDuration -= increment;
                if(clockDuration < 0)
                {//Set dusk
                        clockDuration = daynight::DUSK_DURATION;
                        timeType = daynight::TTDusk;
                        value = 0;
                }
                //nightColor = sf::Color::White;
        }
//DUSK SUN DOWN
        else if(timeType == daynight::TTDusk)
        {
                clockDuration -= increment;

                int percent = static_cast<double>(clockDuration) / daynight::DUSK_DURATION * 100;
                value = (imgColorForNight.getSize().x / 100) * percent;
                if(value < 0)
                        value = 0;
                else if(value > imgColorForNight.getSize().x-1)
                        value = imgColorForNight.getSize().x-1;
                nightColor = imgColorForNight.getPixel(value, 0);

                if(clockDuration < 0)
                {//Set night
                        clockDuration = daynight::NIGHT_DURATION;
                        timeType = daynight::TTNight;
                        value = 0;
                        nightColor = imgColorForNight.getPixel(0, 0);
                }
        }
//NIGHT
        else if(timeType == daynight::TTNight)
        {
                clockDuration -= increment;
                if(clockDuration < 0)
                {//Set dusk
                        clockDuration = daynight::DAWN_DURATION;
                        timeType = daynight::TTDawn;
                        value = 0;
                }
                //nightColor = sf::Color(0, 0, 30, 255);
        }
//DAWN SUN RISE
        else if(timeType == daynight::TTDawn)
        {
                clockDuration -= increment;

                int percent = static_cast<double>(clockDuration) / daynight::DUSK_DURATION * 100;
                value = imgColorForNight.getSize().x - ((imgColorForNight.getSize().x / 100) * percent);
                if(value < 0)
                        value = 0;
                else if(value > imgColorForNight.getSize().x-1)
                        value = imgColorForNight.getSize().x-1;
                nightColor = imgColorForNight.getPixel(value, 0);

                if(clockDuration < 0)
                {//Set night
                        clockDuration = daynight::DAY_DURATION;
                        timeType = daynight::TTDay;
                        value = 0;
                        nightColor = imgColorForNight.getPixel(imgColorForNight.getSize().x - 1, 0);
                }
        }
        renTex.clear(nightColor);


        /*
        //Calculate dayNightClock value from time of day
        dayNightClock += increment;
        if(dayNightClock >= imgColorForNight.getSize().x)
        {
                increment = -1;
                dayNightClock = imgColorForNight.getSize().x-1;
        }
        else if(dayNightClock <= 0)
        {
                increment = 1;
                dayNightClock = 0;
        }
        nightColor = imgColorForNight.getPixel(dayNightClock, 0);
//Set colors appropriate to day
        renTex.clear(nightColor);
        */

}

void DayNight::Draw(sf::RenderWindow & renWin, sf::Vector2f & pos)
{
        renTex.display();
        sprNight.setTexture(renTex.getTexture());
        sprNight.setPosition(pos);
        renWin.draw(sprNight, renStat);
}
Light::Light()
{
        radius = 0;
        color = sf::Color(255, 255, 255, 255);
        posX = 0;
        posY = 0;

        isBindedToUnit = false;
        unitVecID = 0;
}

Light::Light(const int Radius, const sf::Color Color, const int PosX, const int PosY, bool IsBinded, int UnitVecID) :
        radius(Radius), color(Color), posX(PosX), posY(PosY), isBindedToUnit(IsBinded), unitVecID(UnitVecID)
{

}

//////////////////////////////////////////////////////////////////////////

LightHolder::LightHolder()
{
        verArrLight.setPrimitiveType(sf::PrimitiveType::Quads);
        if(texLight.loadFromFile(light::LIGHT_TEXTURE_DIR + "Light.png") == false)
        {
                glob::PrintError("Failed loading texture '"+ light::LIGHT_TEXTURE_DIR + "Light.png" + " at LightHolder::LightHolder");
        }
        renStatLight.texture = &texLight;
        renStatLight.blendMode = sf::BlendAdd;

        if(texReveal.loadFromFile(light::LIGHT_TEXTURE_DIR + "Reveal.png") == false)
        {
                glob::PrintError("Failed loading texture '"+ light::LIGHT_TEXTURE_DIR + "Reveal.png" + " at LightHolder::LightHolder");
        }
        //renStatReveal.texture = &texReveal;
        renStatReveal.texture = &texReveal;
        renStatReveal.blendMode = sf::BlendAdd;
}

void LightHolder::Loop(UnitList & objUnitList)
{
        for(unsigned int i = 0; i < lightList.size(); i++)
        {
                if(lightList[i].isBindedToUnit)
                {
                        lightList[i].posX = objUnitList.unitList[lightList[i].unitVecID].ubp.posX;
                        lightList[i].posY = objUnitList.unitList[lightList[i].unitVecID].ubp.posY;
                        MoveLight(i);                  
                }
        }
        //lightList[0].posX = objUnitList.unitList[0].unitProperties.posX;
        //lightList[0].posY = objUnitList.unitList[0].unitProperties.posY;
        //MoveLight(0);

        //lightList[1].posX = objUnitList.unitList[1].unitProperties.posX;
        //lightList[1].posY = objUnitList.unitList[1].unitProperties.posY;
        //MoveLight(1);
}

void LightHolder::DrawLight(sf::RenderTexture & renTex, sf::RenderWindow & renWin)
{
        sf::Uint8 alphaColor;
        if(verArrLight.getVertexCount() > 0)
                alphaColor = verArrLight[0].color.a;
//Draw to texture
        for(unsigned int i = 0; i < verArrLight.getVertexCount(); i++)
        {
                verArrLight[i].color.a = 255;
        }
        renTex.draw(verArrLight, renStatReveal);
//Draw to window
        for(unsigned int i = 0; i < verArrLight.getVertexCount(); i++)
        {
                verArrLight[i].color.a = alphaColor;
        }
        renWin.draw(verArrLight, renStatLight);
}

void LightHolder::AddLight(Light & light)
{
        //Check if empy list has a position
                //If has pick from it
                //else make a new position
        int vecID;
        if(lightListEmptyPos.size() > 0)
        {
                vecID = lightListEmptyPos[lightListEmptyPos.size() -1];
                lightListEmptyPos.pop_back();
                //Modify light
                lightList[vecID] = light;

                MoveLight(vecID);
        }
        else
        {//Create new positions
                vecID = lightList.size();
                //Add and modify light
                lightList.push_back(light);

                verArrLight.append(sf::Vertex(sf::Vector2f(light.posX, light.posY), light.color, sf::Vector2f(0, 0)));
                verArrLight.append(sf::Vertex(sf::Vector2f(light.posX, light.posY), light.color, sf::Vector2f(texLight.getSize().x, 0)));
                verArrLight.append(sf::Vertex(sf::Vector2f(light.posX, light.posY), light.color, sf::Vector2f(texLight.getSize().x, texLight.getSize().y)));
                verArrLight.append(sf::Vertex(sf::Vector2f(light.posX, light.posY), light.color, sf::Vector2f(0, texLight.getSize().y)));
                MoveLight(vecID);
        }
}

void LightHolder::RemoveLight(const int VecID)
{
        //Remove from Light
        //Remove from VA
        lightListEmptyPos.push_back(VecID);
        verArrLight[VecID*4].texCoords = sf::Vector2f(0, 0);
        verArrLight[VecID*4+1].texCoords = sf::Vector2f(0, 0);
        verArrLight[VecID*4+2].texCoords = sf::Vector2f(0, 0);
        verArrLight[VecID*4+3].texCoords = sf::Vector2f(0, 0);

        verArrLight[VecID*4].position = sf::Vector2f(0, 0);
        verArrLight[VecID*4+1].position = sf::Vector2f(0, 0);
        verArrLight[VecID*4+2].position = sf::Vector2f(0, 0);
        verArrLight[VecID*4+3].position = sf::Vector2f(0, 0);
}

void LightHolder::MoveLight(int VecID)
{
        Light & light = lightList[VecID];
        int VerID = VecID*4;
        verArrLight[VerID].position = sf::Vector2f(light.posX-light.radius, light.posY-light.radius);
        verArrLight[VerID+1].position = sf::Vector2f(light.posX+light.radius, light.posY-light.radius);
        verArrLight[VerID+2].position = sf::Vector2f(light.posX+light.radius, light.posY+light.radius);
        verArrLight[VerID+3].position = sf::Vector2f(light.posX-light.radius, light.posY+light.radius);
}