IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

OpenGL Discussion :

Appliquer plusieurs shaders à un objet


Sujet :

OpenGL

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Inscrit en
    Mai 2009
    Messages
    62
    Détails du profil
    Informations forums :
    Inscription : Mai 2009
    Messages : 62
    Par défaut Appliquer plusieurs shaders à un objet
    Bonsoir,

    Peut on appliquer plusieurs shaders à un objet ?
    Je m'explique, si je crée par exemple une primitive 2D( un carré ), peut-on faire ceci:

    1°)Créer , compiler et exécuter le vertex shader a part(donc on aura seulement le vertex shader linké avec le programm (glCreateProgram()).
    2°) Créer, compiler et exécuter le fragment shader a part, et donc le linké avec un autre programme différent du premier.

    de façon a obtenir un truc comme ça:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    -glUseProgramm(programm1);
    -glUseProgramm(programm2);
     
    -Dessin de la primitive
     
    glUseProgramm(0);
    Le problème c'est que j'ai une classe Window qui gére les matrices de modelview et de projection et j'applique dans cette classe un shader pour tout objet qui sera dessiné car je dois envoyer les matrices a mon shader.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
     Primitive2D carre;
     
        while (event.quit())
        {
            event.update();
     
            window.beginDraw(bgcolor); /* la classe Window gére une pile de matrice*/
     
     
            carre.draw();
     
     
            window.endDraw();
        }
    nb:ici le carré est dessiné.

    Voici les fonctions membre beginDraw() et endDraw():
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
     
    void WindowHandler::beginDraw(const core::Colorf& color)
    {
    _bgcolor.setColor(color);
    glClear (GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
        glClearColor(_bgcolor.getRed(),_bgcolor.getGreen(),_bgcolor.getBlue(),_bgcolor.getAlpha());
     _pMatrixStack.push();/* matrice de projection */
    /* je fais référence ici a mon exemple du carre, donc ceci et le premier shader(vertex), j'envoi juste mes matrices pour calculer la position de chaque vertex*/
     _shaderHandler.use(true);
     _shaderHandler.sendMatrix("mvMatrix",_mvMatrixStack.getCurrentMatrix());
     _shaderHandler.sendMatrix("pMatrix",_pMatrixStack.getCurrentMatrix());
     
    }
     
    void WindowHandler::endDraw(void)
    {
     
        _shaderHandler.use(false);/* equivalent à glUseProgramm(0);*/
        this->popProjectionMatrix();
        glFlush();
        SDL_GL_SwapBuffers();
    }
    Maintenant pour le cas du fragment shader j'aimerai faire ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
     
    Primitive2D carre;
        Shader f;
     
        f.setType(EST_FRAGMENT);
        f.loadFile("Shaders/defaultFragmentShader_flat.txt");
        p.setShaders(NULL,&f);
        p.compile(); /* compilation et création du programm*/
        p.bindAttribute(EAA_COLOR,"ex_Color");
        p.execute(); /* linker le programm */
     
        while (event.quit())
        {
            event.update();
     
            window.beginDraw(bgcolor);
    p.use(true); /* ici ça foire si j'applique le fragment shader */
            carre.draw();
    p.use(false);
     
            window.endDraw();
        }
    nb: ici le carré n'est plus visible .

    voici les shaders utilisés:

    -Shader par defaut utilisé par la classe Window
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    #version 330
     
    in vec2 in_Position;
    uniform mat4 mvMatrix;
    uniform mat4 pMatrix;
     
    void main(void) 
    {
      gl_Position = mvMatrix * pMatrix * vec4(in_Position, 0.0, 1.0);	
    }
    -Fragment shader pour la couleur du carré
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    #version 330
     
    in vec4 ex_Color;
    out vec4 fragColor;
     
    void main(void) 
    { 
     
      fragColor = ex_Color;
     
    }
    j'espere que je suis assez clair.
    Voila Merci d'avance.

    EDIT:
    Je fais ceci juste pour ne pas créer 2 shaders par primitive, imaginez que dans mon programme il y a des 10aines de primitives(2*10) 20 shader quand même...
    Si vous avez des techniques je suis preneur , merci encore.

  2. #2
    Membre émérite

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2006
    Messages
    450
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Avril 2006
    Messages : 450
    Par défaut
    Ton design a l'air bizarre. C'est quoi le resultat final a l'ecran que tu veux? Si tu expliques ce que tu veux comme resultat final, surement que l'on pourra te donner un autre design peut-etre plus adapte pour ton application.

    Dans tous les cas, non tu ne peux pas appliquer plusieurs shaders en meme temps a ton objet mais tu peux appliquer plusieurs shaders a un objet et apres composer les differents resultats en un. Mais tu peux aussi appliquer en une passe plusieurs effets sur un objet et les melanger dans un meme shader...

  3. #3
    Membre éprouvé Avatar de Robxley
    Homme Profil pro
    Docteur ingénieur traitement d'image
    Inscrit en
    Mai 2009
    Messages
    158
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France

    Informations professionnelles :
    Activité : Docteur ingénieur traitement d'image

    Informations forums :
    Inscription : Mai 2009
    Messages : 158
    Par défaut
    Salut,

    Si tu cherches à obtenir l'effet de deux shaders le seul moyen est d'écrire les algo de tes deux shaders dans un seul. La succession de plusieurs glUseProgram ne fonctionne malheureusement pas, le dernier appelé étant actif uniquement. (fonctionne comme une fonction de bindage opengl tels que les textures, couleurs seul le dernier appelle compte).

    Si non une des méthodes pour appliquer deux shaders est d'utiliser un buffer tampon (ex : FBO) dans lequel tu enregistres le résultat du premier shaders, et dans le deuxième shader tu utilises le résultat sauvegardé dans le tampon (souvent à l'aide du texture crée par FBO), mais bon la encore il y a des limitations dû à la projection des données dans un espace 2D (buffer) du premier shader. Cette méthode est plus souvent utilisée pour du post-traitement sur le rendu final d'une scène. Quand le 2ème shader affecte aussi la géométrie de la scène c'est difficilement réalisable ayant perdu la notion d'espace 3D dans la projection du 1er shader vers le buffer.


    Si non pour en revenir à ton vertex shader, à première vue il a un mauvais ordre dans l'appelle de tes matrice de modelview et projection.

    La matrice de projection est généralement appelée en dernière étant donné que la projection à l'écran est souvent la dernière étape de mise en forme de la scène.


    Dans ton vertex shader tu mets :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    gl_Position = mvMatrix * pMatrix * vec4(in_Position, 0.0, 1.0);
    Essais d'inverser mvMatrix et pMatrix de la façon suivante :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    gl_Position = pMatrix * mvMatrix *  vec4(in_Position, 0.0, 1.0);
    Ce qui à plus de sens, dans un premier temps avec ta matrice de modelview (mvMatrix ), tu repositionnes ton objet (rotation, translation, reposition dans le champ de la caméra ...) mais toujours dans un "espace 3d", enfin une fois que ton objet est bien positionnée dans l'espace, tu peux le projeter sur l'écran avec ta matrice de projection (pMatrix ), "espace 2d". L’ordre des multiplication matrice/vecteur est importante, la multiplication matricielle n'étant pas commutatif.


    Si non une petite remarque en passant qui n'a rien avoir avec ton problème, dans la couleur d’effacement du buffer écran :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    glClear (GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
    glClearColor(_bgcolor.getRed(),_bgcolor.getGreen(),_bgcolor.getBlue(),_bgcolor.getAlpha());
    Généralement on déclare d'abord la couleur d'effacement avec (glClearColor), puis enfin on efface le buffer couleur avec glClear. En déclarant comme tu l'as fais (glClear puis glClearColor), la première image ne sera pas de la bonne couleur mais de la couleur de l'ancien glClearColor, il faudra attendre la 2ème image pour obtenir la bonne couleur. Alors c'est sûr pour l'affichage d'une scène avec plus de 60 images par seconde, le temps d'affichage de la 1ère image est tellement courte que tu ne verra pas la différence, mais pour une scène plus complexe si le nombre d'image pas seconde diminue cela peut donner quelque chose d'indésirable.

  4. #4
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Par défaut
    Peut on appliquer plusieurs shaders à un objet ?
    Je m'explique, si je crée par exemple une primitive 2D( un carré ), peut-on faire ceci:

    1°)Créer , compiler et exécuter le vertex shader a part(donc on aura seulement le vertex shader linké avec le programm (glCreateProgram()).
    2°) Créer, compiler et exécuter le fragment shader a part, et donc le linké avec un autre programme différent du premier.
    Je me permets d'intervenir pour préciser un point (qui me semble implicite dans la question et les réponses, mais c'est toujours mieux en le disant explicitement) : quand on dit que l'on ne peut pas mettre plusieurs shaders dans un programme, on parle bien de plusieurs shaders de même type dans un programme ! On peut peut mettre sans problème dans un programme un vertex shader et un fragment shader (et autres).

    Je précise ce point parce que tu parles de créer un programme contenant uniquement un vertex shader et un autre contenant un fragment shader. Si tu avais voulu appliquer 2 vertex shaders par exemple sur une même primitive, je comprendrais le problème mais là, je ne vois pas l'intérêt de créer 2 programmes différents (ou alors je n'ai pas compris le problème).

  5. #5
    Membre confirmé
    Inscrit en
    Mai 2009
    Messages
    62
    Détails du profil
    Informations forums :
    Inscription : Mai 2009
    Messages : 62
    Par défaut
    @ Robxly: merci effectivement parfois j'avais des résultats un peux bizzare

    Bon pour mieux comprendre voici un exemple(qui marche bien):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
     
    #include "MPGE.h"
     
    #define WIDTH 800
    #define HEIGHT 600
     
    MPGEint main (MPGEint argc, char** argv )
    {
        WindowHandler window;
        EventHandler event;
        FileHandler file;
     
        Colorf bgcolor(0.0,0.0,1.0);
     
        window.init(WIDTH,HEIGHT,32,MPGE_OPENGL_2D,false);
     
        Primitive2D background ,carre;
     
        Shader* v=file.loadShader("Shaders/defaultVertexShader_texture.txt",EST_VERTEX);
        Shader* f=file.loadShader("Shaders/defaultFragmentShader_texture.txt",EST_FRAGMENT);
     
        Shader* v1=file.loadShader("Shaders/defaultVertexShader_flat.txt",EST_VERTEX);
        Shader* f1=file.loadShader("Shaders/defaultFragmentShader_flat.txt",EST_FRAGMENT);
     
        background.setColor(Colorf(0.2,0.2,0.2,1.0));
        background.setTexture(file.loadTexture("media/textures/dark1.jpg"));
     
        ShaderHandler sh,sh1;
     
        sh.setShaders(v,f);
        sh.compile();
        sh.sendAttribute(EAA_VERTEX,"in_Position");
        sh.sendAttribute(EAA_COLOR,"in_Color");
        sh.sendAttribute(EAA_TEXTURE,"in_TexCoord");
        sh.execute();
     
        sh1.setShaders(v1,f1);
        sh1.compile();
        sh1.sendAttribute(EAA_VERTEX,"in_Position");
        sh1.sendAttribute(EAA_COLOR,"in_Color");
        sh1.execute();
     
        background.setPosition(Vector(400.0,400.0,0.0,0.0));
        carre.setDimension(Vector(200,300));
        carre.setPosition(Vector(20,280));
     
        event.setFrameRate(30);
     
        while (event.quit())
        {
            event.update();
     
            window.beginDraw(bgcolor);
     
            if(carre.isCollision(event.getMousePosition())) carre.setColor(Colorf(0.7,0.7,0.7,0.2));
            else carre.setColor(Colorf(0.5,0.5,0.5,0.2));
     
            window.pushProjectionMatrix();
            sh.use(true);
            sh.sendMatrix("mvMatrix",window.getModelViewMatrixStack().getCurrentMatrix());
            sh.sendMatrix("pMatrix",window.getProjectionMatrixStack().getCurrentMatrix());
            background.draw();
            sh.use(false);
            window.popProjectionMatrix();
     
     
            window.pushProjectionMatrix();
            window.setTranslation(carre.getPosition());
            sh1.use(true);
            sh1.sendMatrix("mvMatrix",window.getModelViewMatrixStack().getCurrentMatrix());
            sh1.sendMatrix("pMatrix",window.getProjectionMatrixStack().getCurrentMatrix());
            carre.draw();
            sh1.use(false);
            window.popProjectionMatrix();
     
     
            window.endDraw();
            event.delay();
        }
     
        (void)argc;
        (void)argv;
     
        return 0;
     
     
    }
    Donc comme vous voyez dans le code à chaque primitive j'applique 2 shaders vertex et fragment.

    Ce programme affiche 2 carrés , un qui représente l'arrière plan de la fenêtre avec une texture et l'autre qui est juste un carré avec une couleur.
    Donc pour chaque primitive je dois créer deux shaders, si dans mon programme j'ai une centaine de primitives, je ne vais quand même pas appliquer 200 shaders ...
    EDIT: voici les shaders utilisés:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    /* defaultFragmentShader_flat.txt*/
    #version 330
     
    in vec4 ex_Color;
    out vec4 fragColor;
     
    void main(void) 
    { 
     
      fragColor = ex_Color;
     
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    /* defaultVertexShader_flat.txt*/
    #version 330
     
    in  vec2 in_Position;
    in  vec4 in_Color;
    uniform mat4 mvMatrix;
    uniform mat4 pMatrix;
    out vec4 ex_Color;
     
    void main(void) 
    {
        ex_Color = in_Color;
       gl_Position = pMatrix * mvMatrix* vec4(in_Position, 0.0, 1.0);	
    }

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     
    /* defaultVertexShader_texture.txt*/
    #version 330
     
    in  vec2 in_Position;
    in  vec4 in_Color;
    in  vec2 in_TexCoord; 
    uniform mat4 mvMatrix;
    uniform mat4 pMatrix;
    out vec4 ex_Color;
    out vec2 out_TexCoords;
     
    void main(void) 
    {
        ex_Color = in_Color;
    	out_TexCoords=in_TexCoord;
        gl_Position = pMatrix * mvMatrix* vec4(in_Position, 0.0, 1.0);	
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    /* defaultFragmentShader_texture.txt*/
    #version 330
     
    uniform sampler2D colorMap;
    in vec4 ex_Color;
    out vec4 fragColor;
    in vec2 out_TexCoords;
     
    void main(void) 
    { 
     
      fragColor = clamp(texture2D(colorMap,out_TexCoords.st)*ex_Color,0.0,1.0);
     
    }

  6. #6
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Par défaut
    Ça parait déjà plus claire comme ça !

    Donc, tu ne veux pas appliquer 2 Program Shader sur 1 objet mais bien 2 Program Shader sur 2 objets différents. Remarque : ne confond pas primitive (quad, triangle, ligne, etc.) et objet (qui est constitué de plusieurs centaine/millier de primitives)

    Dans la vie réelle (i.e. dans une vraie application), tu ne dessines pas un simple carré. Chaque Program Shader s'applique à plusieurs centaine d'objets, chacun étant constitué de plusieurs millier de primitives. Le coût en terme de performance pour changer de Program Shader pendant le rendu est très négligeable dans ce contexte.
    Et il est bien évident que tu ne vas pas appliquer le même Program Shader pour chaque "catégorie" d'objets : tu auras un Program Shader pour le paysage, un pour les bâtiments, un pour les personnages, etc. Donc il faut en effet créer plusieurs Program Shader, dessiner chaque "catégorie" d'objet et changer de programme entre 2.

    La solution d'avoir 1 seul shader dans ce cas c'est pas viable : il faudrait donner l'information de quel Program Shader appliquer pour chaque vertex (1 int par vertex à transmettre au processeur graphique) puis faire un test dans chaque vertex pour choisir le bon code à appliquer. Le coût serait (à priori) bien supérieur.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Appliquer un shader sur un objet 3d simple
    Par n2engineer5 dans le forum API graphiques
    Réponses: 2
    Dernier message: 07/02/2012, 09h40
  2. Question de rendu pour appliquer plusieurs shaders
    Par kaliban dans le forum OpenGL
    Réponses: 9
    Dernier message: 12/09/2007, 12h51
  3. Réponses: 2
    Dernier message: 15/08/2007, 21h01
  4. Réponses: 2
    Dernier message: 01/09/2006, 04h19
  5. appliquer plusieurs templates
    Par Manu_Just dans le forum XSL/XSLT/XPATH
    Réponses: 7
    Dernier message: 04/04/2003, 16h26

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo