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

Author Topic: Shader flickering  (Read 5099 times)

0 Members and 1 Guest are viewing this topic.

Geheim

  • Full Member
  • ***
  • Posts: 201
    • View Profile
    • Email
Shader flickering
« on: July 26, 2013, 09:13:49 pm »
Hello guys,
I wanted to start making some light effects with a fragment shader, but I get some strange behaviour.

Thats the issue:


I made a simple class which draws the light on a renderTexture to have multiple lights, however the mixing seems not like it should be for me and I get the strange flickering. I have a vector of the lights and if I make green after blue and red, the flickering is gone, which is quite strange to me.

I can't find the mistake though.
Thats how I draw the lights on the texture:
game.cpp:
void Game::render()
{
        // Clears the texture
        texture.clear();

        // Draws all lights on the texture
        for(auto&& light : lightList)
                light.render(texture);

        // Draws the texture
        window.draw(sf::Sprite(texture.getTexture()));
}

And pointLight.cpp:
void PointLight::render(sf::RenderTexture& texture)
{
        // Sets the parameters
        shader.setParameter("radius", light.getRadius());
        shader.setParameter("color", light.getFillColor());
        shader.setParameter("texture", sf::Shader::CurrentTexture);
        shader.setParameter("center", sf::Vector2f(light.getPosition().x + light.getRadius(), light.getPosition().y + light.getRadius()));

        // Draws the light on the texture
        texture.draw(sf::Sprite(texture.getTexture()), &shader);
}

And of course the shader:
uniform vec4 color;
uniform vec2 center;
uniform float radius;
uniform sampler2D texture;

void main()
{
        // Takes the pixel and calculates the difference to the center of the light
        vec4 pixel = texture2D(texture, gl_TexCoord[0].xy);
        float difference = distance(vec2(gl_FragCoord), center) / radius;
       
        // Calculates the alpha value and sets the light color
        float alpha = 1.0 - difference;
        vec4 light = vec4(color.x, color.y, color.z, alpha);
       
        // The actual color is the addition of the pixel color and the light color
        vec4 col = pixel + light;
        gl_FragColor = vec4(col.xyz, alpha);
}

Hopefully somebody knows what I am making wrong.
Thx and Greetings!
Geheim
Failing to succeed does not mean failing to progress!

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11030
    • View Profile
    • development blog
    • Email
Re: Shader flickering
« Reply #1 on: July 26, 2013, 09:32:43 pm »
Please create a minimal and complete example, so we can directly test it and don't have to write our own framework. ;)

Also I see some kind of structure shining through the blue there. Is that the issue you're talking about, or is that a texture you're using. If it's a texture, could you provide that as well?
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Geheim

  • Full Member
  • ***
  • Posts: 201
    • View Profile
    • Email
Re: Shader flickering
« Reply #2 on: July 26, 2013, 09:57:31 pm »
Alright I squeezed the minimal code ugly into the main.cpp ;)
(Put the shader.frag where the main is)

Pastebin:
main.cpp --> http://pastebin.com/uEADum75
shader.frag --> http://pastebin.com/ZY2Vr9qF

Zip-file:
main.cpp + shader.frag + exe --> https://dl.dropboxusercontent.com/u/8088302/Bug_Example.zip
« Last Edit: July 26, 2013, 10:00:23 pm by Geheim »
Failing to succeed does not mean failing to progress!

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11030
    • View Profile
    • development blog
    • Email
Re: Shader flickering
« Reply #3 on: July 27, 2013, 01:03:41 am »
Okay, I can reproduce the problem on my AMD card, but since I've no idea about shaders I can't help you further...
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

FRex

  • Hero Member
  • *****
  • Posts: 1848
  • Back to C++ gamedev with SFML in May 2023
    • View Profile
    • Email
Re: Shader flickering
« Reply #4 on: July 27, 2013, 02:09:38 am »
 texture.draw(sf::Sprite(texture.getTexture()), &shader);
You can't draw to a texture using itself and that's not how light should be implemented, lights get drawn to black buffer using additive blending and then they get drawn onto scene that looks fully lit using multiplicative blending. You should probably also not use gl_FragCoord because
Quote
gl_FragCoord assumes a lower-left origin for window coordinates
http://www.opengl.org/sdk/docs/manglsl/xhtml/gl_FragCoord.xml and that is a bit bothersome. So your shader and code should be:
#include <SFML/Graphics.hpp>
#include <vector>

int main()
{
    sf::RenderWindow window(sf::VideoMode(800, 600, 32), "Bug_Example", sf::Style::Close);
    window.setFramerateLimit(60);
    sf::Event windowEvent;

    sf::Shader shader;
    if (!shader.loadFromFile("shader.frag", sf::Shader::Fragment))
        window.close();
    sf::RenderTexture texture;
    if (!texture.create(800, 600))
        window.close();
    std::vector<sf::CircleShape> lightList;
    for (int i = 0; i != 3; ++i)
        lightList.push_back(sf::CircleShape(400));
    lightList[0].setFillColor(sf::Color::Red);
    lightList[0].setPosition(200.0f, 200.0f);
    lightList[1].setFillColor(sf::Color::Green);
    lightList[1].setPosition(500.0f, 200.0f);
    lightList[2].setFillColor(sf::Color::Blue);
    lightList[2].setPosition(350.0f, 400.0f);

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


        texture.clear();
        sf::RenderStates states;
        states.blendMode = sf::BlendAdd;
        states.shader = &shader;
        for (auto&& light : lightList)
        {
            shader.setParameter("radius", light.getRadius());
            shader.setParameter("center", sf::Vector2f(light.getPosition().x, light.getPosition().y));
            sf::VertexArray q(sf::Quads, 4);
            q[0].color = q[1].color = q[2].color = q[3].color = light.getFillColor();
            q[1].texCoords = q[1].position = sf::Vector2f(0.f, 600.f);
            q[2].texCoords = q[2].position = sf::Vector2f(800.f, 600.f);
            q[3].texCoords = q[3].position = sf::Vector2f(800.f, 0.f);
            texture.draw(q, states);
        }

        texture.display();
        window.clear(sf::Color::White);
        window.draw(sf::Sprite(texture.getTexture()), sf::BlendMultiply);
        window.display();
    }

    return EXIT_SUCCESS;
}
uniform vec2 center;
uniform float radius;
     
void main()
{
    float difference = distance(vec2(gl_TexCoord[0].xy), center) / radius;
    difference=max(0.0,difference);

    gl_FragColor = (1.0-difference) * gl_Color;
}

 
Of course this is not perfect(passing color through gl_Color and using one big quad) but it's just the general idea.
Back to C++ gamedev with SFML in May 2023

Geheim

  • Full Member
  • ***
  • Posts: 201
    • View Profile
    • Email
Re: Shader flickering
« Reply #5 on: July 27, 2013, 01:18:45 pm »
Alright thank you very much FRex, everything works fine now and I hope that I understand everything you said:

My black buffer is the renderTexture, I should use TexCoord instead of FragCoord, because of the lower-left origin coordinates and I should not draw on the texture using itself!

The blending makes sence too now, but I have one question though:
You said, that it's not perfect using the vertexArray and gl_Color, what would be better then?

I thought about it and came to this two ideas: To pass the color and to use a second renderTexture OR to draw the light directly on the black buffer. Would this be "possible"/better than the vertexArray?
Failing to succeed does not mean failing to progress!

FRex

  • Hero Member
  • *****
  • Posts: 1848
  • Back to C++ gamedev with SFML in May 2023
    • View Profile
    • Email
Re: Shader flickering
« Reply #6 on: July 27, 2013, 01:51:51 pm »
I don't know what is perfect but this is too simple to be perfect. ;D It probably depends on what you need.
Quote
To pass the color and to use a second renderTexture
I don't know what you mean by that, pass the color where and why would you need a second buffer? Light don't care about each other and don't use the buffer texture for anything. You can draw everything to one buffer using additive blending and then multiply it with the scene. You can draw cricle shapes, vertex arrays, whatever geometry you want, you can use shaders or not, use textures(if you want textured light for something). I used shader here because I guessed you wanted a fading with distance effect, you could also do that effect by using a triangle fan and texturing outer vertices to black and inner to your light's color.
http://fd.fabiensanglard.net/doom3/additive_blending/allLights.jpg
This is doom 3 screen from fabien sanglard's website, you can see how three lights of basic colors mix like in the famous RGB venn's graph(three circles that overlap in the middle to make white), it all was rendered to one black buffer and then multiplicated with the scene textures(diffuse maps), there's also specular and bump mapping involved with light but you're not doing either. You should of course take this with a grain of salt, I might be wrong in many aspects. ;)
Back to C++ gamedev with SFML in May 2023

Geheim

  • Full Member
  • ***
  • Posts: 201
    • View Profile
    • Email
Re: Shader flickering
« Reply #7 on: July 27, 2013, 02:49:50 pm »
Alright I see, I have read/experimented too less with shaders and your solution works fine, so I will take it for now. Thanks for your help. Simple does not mean that it is bad ;)
Failing to succeed does not mean failing to progress!