Creating a Fading Trail Behind a Moving Object in SFML?

72 Views Asked by At

I'm working on a project using SFML where I want to create a visually appealing, fading trail behind a moving object. I've attempted a couple of methods, but each seems to fall short due to what appears to be rounding errors. My issue is that subtracting a small value from the texture's color doesn't result in a complete fade-out over time.

Naive Approach

I tried overlaying a semi-transparent rectangle over my entire scene in each frame, expecting the trail to gradually darken and fade away. Here's the code snippet for this approach:

#include <SFML/Graphics.hpp>

#define W 800
#define H 600

int main() {
    sf::RenderWindow window(sf::VideoMode(W, H), "SFML works!");
    sf::CircleShape shape(10.f);
    shape.setFillColor(sf::Color::Green);
    sf::RenderTexture renderTexture;
    renderTexture.create(W, H);
    renderTexture.clear();
    sf::Vector2f p(W/2, H/2);
    sf::Vector2f v(0.3, -0.7);
    sf::RectangleShape rect(sf::Vector2f(W, H));
    rect.setFillColor(sf::Color(0.0, 0, 0, 1));
    while (window.isOpen()) {
        sf::Event event;

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

        p += v;
        if (p.x < 0 or p.x > W) v.x *= -1;
        if (p.y < 0 or p.y > H) v.y *= -1;
        shape.setPosition(p);

        renderTexture.draw(rect);
        renderTexture.draw(shape);
        renderTexture.display();
        sf::Sprite sprite(renderTexture.getTexture());

        window.draw(sprite);
        window.display();
    }
}

enter image description here

This method showed some fading effect, but the trail never completely darkened as expected.

Shader-Based Method

Next, I experimented with a shader-based approach, using two textures and a fragment shader. Here, I noticed that if the coefficient is set to less than -0.002f, the fading trail effect doesn't work as intended, and the trail fails to disappear completely.

#include <SFML/Graphics.hpp>

#define W 800
#define H 600

int main() {
    sf::RenderWindow window(sf::VideoMode(W, H), "SFML works!");
    sf::CircleShape shape(10.f);
    shape.setFillColor(sf::Color::Green);
    sf::RenderTexture tex;
    tex.create(W, H);
    tex.clear();
    sf::RenderTexture tex1;
    tex1.create(W, H);
    tex1.clear();
    sf::Vector2f p(W/2, H/2);
    sf::Vector2f v(0.3, -0.7);
    sf::RectangleShape rect(sf::Vector2f(W, H));
    rect.setFillColor(sf::Color(0.0, 0, 0, 1));

    sf::Shader shader;
    shader.loadFromFile("shader.frag", sf::Shader::Fragment);

    while (window.isOpen()) {
        sf::Event event;

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

        p += v;
        if (p.x < 0 or p.x > W) v.x *= -1;
        if (p.y < 0 or p.y > H) v.y *= -1;
        shape.setPosition(p);

        tex.draw(rect);
        tex.draw(shape);
        tex.display();
        sf::Sprite sprite(tex.getTexture());
        tex1.draw(sprite, &shader);
        tex1.display();
        sf::Sprite sprite1(tex1.getTexture());
        tex.clear();
        tex.draw(sprite1);
        tex.display();

        window.draw(sprite1);
        window.display();
    }
}

Fragment Shader:

uniform sampler2D texture;

void main() {
    vec4 texColor = texture2D(texture, gl_TexCoord[0].xy);
    gl_FragColor = vec4(texColor.rgb - 0.002f, 0.8);
}

enter image description here

Adding a second fragment shader with a gamma effect on window.draw(sprite1, &gamma); would help, but it relies on the maximum tail length from sprite1, I cannot achieve longer tail

enter image description here

uniform sampler2D texture;

void main() {
    vec4 texColor = texture2D(texture, gl_TexCoord[0].xy);
    float gamma = 4.1;
    gl_FragColor = vec4(pow(texColor.rgb, vec3(1.0/gamma)), texColor.a);
}

Shader + Countdown

Adding an ugly counter on the rendering loop would help, but I am sure this is not the proper approach:

    if (i++ > 10) {
        i = 0;

        tex1.draw(sprite, &shader);
        tex1.display();
        sf::Sprite sprite1(tex1.getTexture());
        tex.clear();
        tex.draw(sprite1);
        tex.display();
    }
    window.draw(sprite, &gamma);
    window.display();

enter image description here

I'm looking for insights or suggestions on how to effectively create a fading trail effect in SFML. Any help or guidance would be greatly appreciated!

0

There are 0 best solutions below