Bienvenue, Invité. Merci de vous connecter ou de vous inscrire.
Avez-vous perdu votre e-mail d'activation ?

Auteur Sujet: Shader de flou gaussien  (Lu 2435 fois)

0 Membres et 1 Invité sur ce sujet

Clem83

  • Newbie
  • *
  • Messages: 10
    • Voir le profil
Shader de flou gaussien
« le: Octobre 21, 2018, 04:49:12 pm »
Bonjour ?  tous,

Récemment j'ai commencé ?  m'intéresser aux shaders, et notamment pour créer un effet de flou.
Je n'ai néanmoins pas trouvé de tutoriel, j'ai donc copié un exemple que j'ai trouvé... qui ne fonctionne pas : la fenêtre reste noire  ::).

Je dessine mes objets sur une renderTexture, avant d'appliquer le shader dessus, pour la dessiner dans la fenêtre avec un sprite.

Le code du main, avec la fonction qui modifie la texture au dessus (Attention le code design doit être un cauchemar  ;D) :
int main()
{
       
        sf::RenderWindow window(sf::VideoMode(256, 256), "Shader", sf::Style::Titlebar | sf::Style::Close);
        window.setVerticalSyncEnabled(true);

        // création de la render texture
        sf::RenderTexture base;
        base.create(256, 256);
        base.clear(sf::Color::Black);
       
       
        // dessine 2 cercles sur la texture : fonctionne

        sf::CircleShape first;
        first.setPosition(100, 10);
        first.setRadius(30);
        first.setFillColor(sf::Color::Cyan);

        sf::CircleShape second;
        second.setPosition(10, 50);
        second.setRadius(10);
        second.setFillColor(sf::Color::Blue);

        base.draw(first);
        base.draw(second);

        /////
       

        // déclaration et application du shader : ne fonctionne pas (les cercles ne s'affichent même pas)
        sf::Shader blur;
        sf::Texture local = base.getTexture();
        if (!blur.loadFromFile("blur_gen.frag", sf::Shader::Fragment)) {
                return -1;
        }
        if (!blur.isAvailable()) {
                return -1;
        }

        blur.setUniform("originalTexture", sf::Shader::CurrentTexture);
        blur.setUniform("blur_vector", sf::Glsl::Vec2(1.0, 0.0));
        blur.setUniform("texel_size", sf::Glsl::Vec2(10.f, 10.f));
        sf::Sprite world(local);
        world.setOrigin(0, local.getSize().y / 2);
        world.setPosition(0, 0);

        sf::RenderStates states;
        states.shader = &blur;
        states.blendMode = sf::BlendAlpha;
        base.draw(world, states);

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


        // création du sprite pour dessiner la texture dans la fenêtre
        sf::Texture texture = base.getTexture();
        sf::Sprite sprite;
        sprite.setTexture(texture);

        while (window.isOpen())
        {
                sf::Event event;
                while (window.pollEvent(event))
                {
                        if (event.type == sf::Event::Closed) window.close();
                        if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Escape) window.close();
                }

                window.clear();
                window.draw(sprite);
                window.display();
        }
        return 0;
}
 

et le code GLSL :
varying vec2 v_vTexcoord;
varying vec4 v_vColour;


uniform vec2 blur_vector;
uniform vec2 texel_size;

uniform sampler2D originalTexture;

void main(void){
        vec4 out_color;
        vec2 offset_factor = texel_size * blur_vector;

        out_color += texture2D(originalTexture, v_vTexcoord- 7.4240691*offset_factor) * 0.0562937;
    out_color += texture2D(originalTexture, v_vTexcoord-5.4441177*offset_factor) * 0.0951791;
    out_color += texture2D(originalTexture,v_vTexcoord-3.5653500*offset_factor) * 0.1369112;
    out_color += texture2D(originalTexture, v_vTexcoord-1.4847002*offset_factor) * 0.1675553;
    out_color += texture2D(originalTexture, v_vTexcoord) * 0.0881212;
    out_color += texture2D(originalTexture, v_vTexcoord + 1.4847002*offset_factor) * 0.1675553;
    out_color += texture2D(originalTexture, v_vTexcoord+3.5653500*offset_factor) * 0.1369112;
    out_color += texture2D(originalTexture,v_vTexcoord+5.4441177*offset_factor) * 0.0951791;
    out_color += texture2D(originalTexture, v_vTexcoord+ 7.4240691*offset_factor) * 0.0562937;

        gl_FragColor = v_vColour *out_color;
}

 
Pourriez-vous m'indiquer, s'il vous plaît, d'où vient mon erreur, voire m'aiguiller vers une autre manière de procéder ?

Merci d'avance

PS: Chapeau ?  toute la team SFML pour cette magnifique librairie, pour leur réactivité sur le forum.
« Modifié: Octobre 21, 2018, 04:53:46 pm par Clem83 »

Laurent

  • Administrator
  • Hero Member
  • *****
  • Messages: 32504
    • Voir le profil
    • SFML's website
    • E-mail
Re: Shader de flou gaussien
« Réponse #1 le: Octobre 21, 2018, 05:40:17 pm »
Déja, est-ce que la même chose sans shader fonctionne (ie. est-ce que le seul problème est le shader) ?

Ensuite dans ton shader, je pense que les variables v_vTexcoord et v_vColour ne sont pas initialisées ; regarde les exemples de shader de SFML pour savoir comment récupérer les coordonnées de texture et la couleur de vertex.
Laurent Gomila - SFML developer

Clem83

  • Newbie
  • *
  • Messages: 10
    • Voir le profil
Re: Shader de flou gaussien
« Réponse #2 le: Octobre 22, 2018, 11:34:41 am »
Bonjour,
en effet le seul problème est le shader. Je n'ai pas trouvé de tutoriels prorpre sur le sujet, j'avais donc copié le code que j'avais trouvé. J'ai regardé l'exemple "blur" de la SFML mais l'effet n'était pas assez important (même en changeant le radius) : pour obtenir l'effet souhaité, je devait appliquer le shader 4/5 fois ?  la suite, beaucoup moins performant que la petite fonction que j'avais créée :

void createblur(sf::RenderTexture &renderTexture, int boxSize, int iterations = 1)
{
        for (int n = 0; n < iterations; ++n)
        {
                sf::Image img = renderTexture.getTexture().copyToImage();
                sf::Image _new;
                _new.create(img.getSize().x, img.getSize().y);

                for (int i = 0; i < img.getSize().x; ++i)
                {
                        for (int j = 0; j < img.getSize().y; ++j)
                        {

                                int sum = 0, r = 0, g = 0, b = 0, a = 0;
                                for (int ii = -boxSize / 2; ii < boxSize / 2; ++ii)
                                {
                                        for (int jj = -boxSize / 2; jj < boxSize / 2; ++jj)
                                        {
                                                if (sf::IntRect(0, 0, img.getSize().x, img.getSize().y).contains(sf::Vector2i(ii + i, jj + j)))
                                                {
                                                        sum += 1;
                                                        sf::Color color = img.getPixel(i + ii, j + jj);
                                                        r += color.r;
                                                        b += color.b;
                                                        g += color.g;
                                                        a += color.a;
                                                }
                                        }
                                }
                                if (sum == 0)
                                        _new.setPixel(i, j, sf::Color(0, 0, 0, 0));
                                else
                                        _new.setPixel(i, j, sf::Color(round(r / sum), round(g / sum), round(b / sum), round(a / sum)));
                        }
                }
                renderTexture.clear();
                sf::Texture texture;
                texture.loadFromImage(_new);
                sf::Sprite sprite(texture);
                renderTexture.draw(sprite);
                renderTexture.display();
        }
}

Du coup je ne pense pas passer par des shaders. Merci beaucoup quand même