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

Author Topic: Making a trail/fading effect using render textures (except blending is hard...)  (Read 2048 times)

0 Members and 1 Guest are viewing this topic.

Blackomodo

  • Newbie
  • *
  • Posts: 3
    • View Profile
Hi, I'm making a simple game and I'm trying to give it a sort of trail/fading effect by clearing the main render texture with a low alpha value.

The effect works as intended except one thing, when moving, the player and objects will leave a permanent trail of themselves too. I suppose that it's because I don't clear the window so the render texture will blend with the previous non-cleared window's texture (maybe ?) and I haven't found a solution after searching for days about custom blending mode, tried making shaders, using another render texture under the main one etc.

To illustrate my problem better, here is a gif : https://imgur.com/dc2R47X

And here are some parts of my code that I think are the most important :

Rendering :

    sf::RenderWindow *window = adata->window;
    float delta = adata->app_clock.getElapsedTime().asSeconds();
    sf::Vector2f view_position = adata->game_view.getCenter();
    sf::Vector2f camera_lag;

    adata->rtex_main->clear(sf::Color(0, 0, 0, 5));
    adata->rtex_hud->clear(sf::Color::Black);

    camera_lag.x = LERP(view_position.x, adata->player->position.x, CAMERA_LAGGING_DISTANCE * delta);
    camera_lag.y = LERP(view_position.y, adata->player->position.y, CAMERA_LAGGING_DISTANCE * delta);

    adata->game_view.setCenter(camera_lag);
    adata->rtex_main->setView(adata->game_view);

    render_gameobjects(adata);
    render_player(adata);

    adata->rtex_hud->setView(adata->hud_view);

    render_texts(adata);

    adata->rtex_main->display();
    adata->rtex_hud->display();

    sf::Texture main_texture = adata->rtex_main->getTexture();
    sf::Texture hud_texture = adata->rtex_hud->getTexture();
    sf::Shader *overlay_shader = get_shader(adata, "overlay");

    overlay_shader->setUniform("game_texture", main_texture);
    overlay_shader->setUniform("hud_texture", hud_texture);
    adata->sprite_main.setTexture(main_texture);
    adata->sprite_hud.setTexture(hud_texture);
    window->draw(adata->sprite_main, adata->state_main);
    window->display();
 

Initialization of render textures :

    sf::RenderWindow window(sf::VideoMode(WIN_W, WIN_H), "Application");

    load_assets(adata);

    adata->window = &window;
    adata->rtex_main = new sf::RenderTexture();

    if (!adata->rtex_main->create(WIN_W, WIN_H)) {
        adata->exit_code = EXIT_FAILURE;
        return;
    }

    adata->rtex_hud = new sf::RenderTexture();

    if (!adata->rtex_hud->create(WIN_W, WIN_H)) {
        adata->exit_code = EXIT_FAILURE;
        return;
    }

    sf::RenderStates state_main;

    state_main.blendMode = sf::BlendAlpha;
    state_main.shader = get_shader(adata, "overlay");
    state_main.texture = NULL;
    state_main.transform = sf::Transform::Identity;

    adata->state_main = state_main;

    sf::RenderStates state_hud;

    state_hud.blendMode = sf::BlendNone;
    state_hud.shader = NULL;
    state_hud.texture = NULL;
    state_hud.transform = sf::Transform::Identity;

    adata->state_hud = state_hud;

    init_player(adata);
    load_interface(adata);
    window_loop(adata);
 

Window loop :

    sf::RenderWindow *window = adata->window;

    while (window->isOpen()) {
        sf::Event event;

        while (window->pollEvent(event)) {
            register_event(adata, event);
        }

        float elapsed_seconds = adata->app_clock.getElapsedTime().asSeconds();

        if (elapsed_seconds > GLOBAL_RATE) {
            update_app(adata);
            render_app(adata);

            adata->app_clock.restart();
        }
    }
 

(btw the shader just make it so the overlay and the main texture are added together, removing it doesn't change anything, removing the hud render texture doesn't change anything either).

The code's a bit messy, I hope you can read it without too much hassle.

« Last Edit: June 10, 2023, 04:56:23 pm by Zerdo902 »

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
If one effect is affecting everything when it should only be affecting some things, the effect should only be applied to those 'some things'.

With that in mind, I feel it would require extra steps. Use a render texture for the effect where you draw the things that should have that effect applied and then draw that to the window (or final render texture) but only draw the things that should not use that effect straight to the window (or final render texture), therefore bypassing the effect.

It's worth noting that using an 'uncleared' render texture for this effect can have unpredictable effects depending on how the implementation decides to deal with doing this so it can appear differently on different devices.

It may be better to consider actually drawing the effect directly rather than 'hacking' the render texture to make this effect. You can draw the effect by simply remembering each of the previous states and drawing them simultaneously with, of course, varying degrees of alpha. At least this way, you can have predictable results - exactly what you draw!



You could also do it by managing multiple render textures and changing the order that they are drawn.



As a side note, the 'onion skin' effect does look pretty cool 8)
« Last Edit: June 11, 2023, 04:23:23 pm by Hapax »
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

Blackomodo

  • Newbie
  • *
  • Posts: 3
    • View Profile
Thanks you very much for your reply.

I agree that it would be a better practice to actually focus on specific objects for the effect, I was trying to make a whole-screen effect that wouldn't last for too long to see how great it would look.

This isn't a serious project anyway so I think I'll stick with the better approach for the next game in which I'll try to implement this effect.

It does looks cool haha, I find it great to convey an effect of "speed"  :)

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Honestly, I like it enough that I'm considering making a version using that multiple render texture idea that could be applied to anything. Sounds like a fun thing to attempt!
Not sure of the limitations of render textures though so wonder if it's uncommon to be able to use many of them.

The best way is probably keeping track of the objects and stuff but that could be 'harder' due to having to store every (the most recent few) past state of all the objects that need it.

I'll let you know if I do implement it (for fun, of course!).

Sometimes the best ideas come to us when we're not working on something seriously... ;)
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
It turns out that I fancied having a go at this and ended up making something pretty small that does the job.

It might not necessarily be the most efficient way to apply this effect (this is the multiple render texture method that I mentioned in passing above) but it's pretty simply to use!

Have a look at this video showing it in action (demo based loosely on your visuals):


If you're interested, the repo is here:
https://github.com/Hapaxia/Onsk


To show how easy it is to use, this is the exact draw code of that demo:
                sf::RenderTexture& onskLayer{ (++onsk).getCurrentLayer() };
                onskLayer.clear(sf::Color::Transparent);
                onskLayer.draw(rectangleSatellite);
                onskLayer.draw(rectangle);
                onskLayer.display();

                window.clear();
                window.draw(circle);
                window.draw(onsk);
                window.display();

p.s. thanks for the challenge! ;)
« Last Edit: June 13, 2023, 11:44:39 pm by Hapax »
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

Blackomodo

  • Newbie
  • *
  • Posts: 3
    • View Profile
That looks neat, I’ll definitely give it a try.
Glad you found a worthy challenge here  ;D

 

anything