Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Fading without artifacts  (Read 15362 times)

0 Members and 1 Guest are viewing this topic.

Foaly

  • Sr. Member
  • ****
  • Posts: 453
    • View Profile
Fading without artifacts
« on: September 13, 2012, 06:29:31 pm »
Hello there,
for a little program I'm making, I am drawing a couple drawable objects on top of a Rendertexture, without clearing it. Now I want that the stuff that is already on the texture to slowly fade. To achieve this I made a RectangleShape as big as the Texture and has a semi-transparent black color, which is drawn on top of the Texture at the beginning of each render cycle.
The problem is that it only works partly. The texture fades a little bit, but after some time it stops and the old objects stay as dark artifacts.
Does anybody know whats wrong or another way how I could fade the texture?
Thanks in advance,
Foaly

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10801
    • View Profile
    • development blog
    • Email
Re: Fading without artifacts
« Reply #1 on: September 13, 2012, 07:05:13 pm »
Well you should provide a minimal example, it's hard to really follow, what the end effect will look like or what you want to achieve...
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Foaly

  • Sr. Member
  • ****
  • Posts: 453
    • View Profile
Re: Fading without artifacts
« Reply #2 on: September 13, 2012, 07:30:04 pm »
Yes sure. Here is a minimal code example:
#include <SFML/Graphics.hpp>
#include <iostream>


int main()
{
    sf::RenderWindow window(sf::VideoMode(1024, 768), "SFML");

    sf::RenderTexture m_RenderTexture;
    m_RenderTexture.create(window.getSize().x, window.getSize().y);
    sf::Sprite m_RenderSprite;

    sf::RectangleShape FadeRect(sf::Vector2f(window.getSize()));
    FadeRect.setFillColor(sf::Color(0, 0, 0, 1));

    sf::CircleShape circle;
    circle.setRadius(10);
    circle.setFillColor(sf::Color::Red);


    while (window.isOpen())
    {
        sf::Event event;
        while (window.pollEvent(event))
        {
            // Close Event
            if (event.type == sf::Event::Closed)
                window.close();

            // Escape key pressed
            if ((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Escape))
                window.close();

        }

        circle.setPosition(sf::Vector2f(sf::Mouse::getPosition(window)));



        // Draw everything
        m_RenderTexture.draw(FadeRect);
        m_RenderTexture.draw(circle);
        m_RenderTexture.display();

        window.clear();
        m_RenderSprite.setTexture(m_RenderTexture.getTexture());
        window.draw(m_RenderSprite);
        window.display();
    }

    return 0;
}
 
The red circle is following the mouse. It's drawn on the texture. The fade rectangle is also drawn on the texture. So the red circle should fade out. It fades a little bit, but then stops. I'm sure the example will show what I mean.

masskiller

  • Sr. Member
  • ****
  • Posts: 284
  • Pointers to Functions rock!
    • MSN Messenger - kyogre_jb@hotmail.com
    • View Profile
    • Email
Re: Fading without artifacts
« Reply #3 on: September 14, 2012, 01:06:16 am »
I don't know well if what I will say applies since I am new to SFML myself and I don't know if you want to do more than just making it fade, but if you want the circle to fade wouldn't decreasing the circle's alpha in the loop be better? You would have no need for a rectangle shape texture the size of the window. You would just need to use a speed for the fading and the loop handles the rest.
Programmer, Artist, Composer and Storyline/Script Writer of "Origin of Magic". If all goes well this could turn into a commercial project!

Finally back into the programming world!

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10801
    • View Profile
    • development blog
    • Email
Re: Fading without artifacts
« Reply #4 on: September 14, 2012, 02:22:53 am »
I guess that's the expected behavior, the color adding with sf::Color(0,0,0,1) will always have to let shine through something and at a certain point it just sticks to it.

You can demonstrate this also with the following code:
#include <SFML/Graphics.hpp>

int main()
{
    sf::RenderWindow window(sf::VideoMode(1024, 768), "SFML");
    window.setFramerateLimit(60);

    sf::RenderTexture m_RenderTexture;
    m_RenderTexture.create(window.getSize().x, window.getSize().y);
    sf::Sprite m_RenderSprite;

    sf::RectangleShape FadeRect(sf::Vector2f(window.getSize()));
    FadeRect.setFillColor(sf::Color(0, 0, 0, 1));

    sf::CircleShape circle;
    circle.setRadius(10);
    circle.setFillColor(sf::Color::Red);

    m_RenderSprite.setTexture(m_RenderTexture.getTexture());

    m_RenderTexture.draw(circle);
    m_RenderTexture.display();

    for(unsigned int i = 0; i < 1000; ++i)
    {
        m_RenderTexture.draw(FadeRect);
        m_RenderTexture.display();
    }

    while (window.isOpen())
    {
        sf::Event event;
        while (window.pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
                window.close();
        }

        circle.setPosition(sf::Vector2f(sf::Mouse::getPosition(window)));

        window.clear();
        window.draw(m_RenderSprite);
        window.display();
    }
}
 
You can now set the number in the for-loop to any value you want, but the circle will never disappear.

I'm not that good at color modification stuff, so it maybe possible with the way you were doing it, but I don't know and I'd try to find another method.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: Fading without artifacts
« Reply #5 on: September 14, 2012, 08:21:33 am »
Using the previous contents of a render-texture without clearing it is not clean.

You should rather use a variant of your solution: increase the alpha of the FadeRect until it is totally opaque, instead of accumulating the results of previous frames.
Laurent Gomila - SFML developer

Foaly

  • Sr. Member
  • ****
  • Posts: 453
    • View Profile
Re: Fading without artifacts
« Reply #6 on: September 14, 2012, 12:05:48 pm »
Hmm well that's the problem... My program needs to draw everything to a render-texture, without clearing it. I can't show you right now, because I'm not on my computer. But I'll post the program tomorrow, so you can see what I mean.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: Fading without artifacts
« Reply #7 on: September 14, 2012, 12:20:39 pm »
I'm not sure to understand what you mean, but instead of fading the render-texture, you could fade the sprite that draws the contents of the render-texture. This way you leave the render-texture untouched.
Laurent Gomila - SFML developer

Foaly

  • Sr. Member
  • ****
  • Posts: 453
    • View Profile
Re: Fading without artifacts
« Reply #8 on: September 14, 2012, 12:30:21 pm »
Yeah I tried that, but it doesn't work. The effect I want to achieve is that the longer an objects is on the render-texture the more it fades until it disappears. Fading the sprite means that everything is faded.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: Fading without artifacts
« Reply #9 on: September 14, 2012, 01:03:52 pm »
Then I don't understand what you want to achieve. I thought you wanted to fade the render-texture.

You should explain your goal more clearly.
« Last Edit: September 22, 2012, 01:24:00 pm by Laurent »
Laurent Gomila - SFML developer

Foaly

  • Sr. Member
  • ****
  • Posts: 453
    • View Profile
Re: Fading without artifacts
« Reply #10 on: September 22, 2012, 12:10:49 pm »
I need the fade for this program: http://en.sfml-dev.org/forums/index.php?topic=9222.0
Open it and try the fade mode, by pressing "f" it will slowly fade, but there are always weird artifacts in the background.

Foaly

  • Sr. Member
  • ****
  • Posts: 453
    • View Profile
Re: Fading without artifacts
« Reply #11 on: October 01, 2012, 08:41:25 am »
I don't know if you gave the program a try, but if you did, you see the problem I'm having again. This issue is starting to really get to me. I tryed a lot of things but nothing seems to work. The only idea I could come up with that might have solved the issue was to draw a rectangle with a subtractive blend mode over the entire scene, but the request for a subtractive blend mode got rejected. Can anybody help me and point me in the right direction of how to fade an entire render texture?
Thanks in advance, foaly

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: Fading without artifacts
« Reply #12 on: October 01, 2012, 08:46:16 am »
Can you explain again what you want to do? Sometimes you talk about a rectangle that covers the whole window, sometimes you talk about fading individual entities. This is not clear. You should also tell us what kind of fading you want to achieve (fade to black? fade to transparent? ...).
Laurent Gomila - SFML developer

Foaly

  • Sr. Member
  • ****
  • Posts: 453
    • View Profile
Re: Fading without artifacts
« Reply #13 on: October 01, 2012, 10:48:09 am »
Ok I'm sorry I have to admit that my explanation got pretty confusing. To not bother you with the details of my program I thought of a simple example. Imagine that you want to visualize the trail of a mouse. So you create a circle and set its position to the mouse coordinates. That is updated every frame. Then you create a render texture the circle is drawn to the rendertexture every frame. The rendertexture is than drawn to the window. The rendertexture is never cleared so that the trail of the mouse stays. Here comes my problem: I want to fade the rendertexture, so that the old circles slowly fade out. (I want to fade to black for now, although fade to transparent is actually a very interesting idea, I might come back to that later) my first idea was to simply draw a semi opaque rectangle on the rendertexture at the beginning of each frame, but that leads to weird artifacts I discribed above. I experimented with the blend modes, but none of them seems to work. I thought a subtractive blend mode might help, so I tryed implementing it, but I wasn't able to. Then I tryed to use a shader to achieve the effect. But that didn't work either so I'm stuck now. How can I fade the render texture?!?

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 10801
    • View Profile
    • development blog
    • Email
Re: Fading without artifacts
« Reply #14 on: October 01, 2012, 11:38:48 am »
IIRC it's not very good to not clear the RenderTexture every frame iteration, so you might want to keep track of all the objects you have and fade one after the other slowly.

For example like this:
#include <SFML/Graphics.hpp>
#include <vector>
#include <iostream>

int main()
{
    sf::RenderWindow window(sf::VideoMode(300, 300), "Test");
    window.setFramerateLimit(60);

    sf::Vector2f old_pos(0, 0);
    static const int STEP = 5;

    std::vector<sf::CircleShape> points;

    while(window.isOpen())
    {
        sf::Event event;
        while(window.pollEvent(event))
        {
            if(event.type == sf::Event::Closed)
                window.close();
        }

        sf::Vector2f pos = static_cast<sf::Vector2f>(sf::Mouse::getPosition(window));
        if(pos != old_pos)
        {
            sf::CircleShape cs;
            cs.setRadius(10);
            cs.setPosition(pos);
            cs.setFillColor(sf::Color::Red);
            points.push_back(cs);

            old_pos = pos;
        }

        window.clear();

        for(auto it = points.begin(); it != points.end(); ++it)
        {
            window.draw(*it);
            if(it->getFillColor().a-STEP < 0)
                it = points.erase(it);
            else
                it->setFillColor(sf::Color(255, 0, 0, it->getFillColor().a-STEP));
        }

        window.display();
    }
}
 

Keep in mind that calling erase on a std::vector isn't very performant and could be avoided with a better structure. With another structure you could also make use of that the fading process is linear and thus the oldest element can get removed first. Also to minimize the memory usage/object creation you could also just store the positions and draw a single shape/sprite/etc. while changing it's position and it's transparency.

I guess there could be other ways but that was just the most straight forward one that popped into my head.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/