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 :

Implémentation d'un color picking sous Qt5 [OpenGL 4.x]


Sujet :

OpenGL

  1. #1
    Invité
    Invité(e)
    Par défaut Implémentation d'un color picking sous Qt5
    Bonjour à tous !

    Je cherche a implémenter du color picking pour changer la couleur d'objets au survol de la souris, dans un projet en core OpenGL et Qt5.
    J'ai cherché a éviter les surcouches à OpenGL de Qt qui complexifiaient mon apprentissage, et jusqu'à présent tout marchait comme sur des roulettes, aussi bien l'affichage, les shaders, les passages de variable uniformes, etc. À part mon objet principal qui hérite de QOpenGLWidget, et quelques surcouches personnelles qui ont besoin d'hériter de QOpenGLFunctions_3_3_Core pour accéder aux types et fonctionnalités d'OpenGL, tout est de l'OpenGL bien brut.

    Pour l'implémentation, j'ai lu et suivi une partie du tutoriel sur OGLdev. Ainsi, je dispose de l'exact même objet PickingTexture. Mon fragment shader de picking se contentent pour le moment de renvoyer toujours le même vecteur de trois floats (1.0, 0.0, 0.0).
    Première surprise, dans ma fonction paintGL() l'ajout de la phase de picking avant mon habituelle phase d'affichage a supprimé l'affichage des primitives à l'écran. Aucune erreur OpenGL.
    Je supprime des lignes pour en faire un code minimal, je me rends compte que cela provient de l'appel à glBendFrameBuffer.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    void Display::paintGL(void)
    {
        // Picking phase (super raccourcie)
        /* --/!\-- Commenter cette ligne permet d'afficher de nouveau les vertices --/!\-- */
        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
     
        // Display phase (qui marche si on décommente la ligne au dessus)
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
         _displayShader->use();
        glBindVertexArray(this->_VAO);
        _camera.attach(*_displayShader, _screenWidth, _screenHeight);
        glDrawArrays(GL_TRIANGLES, 0, (_peptide->getVerticesArraySize()) / 6);
    }
    Je ne parviens pas à repasser sur le framebuffer par défaut (nommé back buffer, il me semble). Je lis pourtant bien dans OpenGL SuperBible, seventh edition que passer 0 au second paramètre de cette fonction doit permettre de faire le rendu dans le buffer par défaut, celui géré par le système de fenêtres. Est-ce Qt qui me jouerait un tour ?

    Un peu en râlant de cette solution de fortune, et trouvant peu d'aide sur le net, je me contente de faire la phase de picking après la phase de rendu. Seulement maintenant c'est glReadPixels(x, y, 1, 1, GL_RGB, GL_FLOAT, &Pixel) qui me joue un tour. Au premier clic sur le rendu, la fonction readPixel() me fournit un PixelInfo avec trois variables settées n'importe comment. Les clics suivants, je n'ai que des zéro, valeurs par défaut des attributs de PixelInfo.
    Ci-dessous le code de readPixel. Il s'agit du même code que celui d'OGL.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    PickingTexture::PixelInfo PickingTexture::readPixel(unsigned int x, unsigned int y)
    {
        glBindFramebuffer(GL_READ_FRAMEBUFFER, _fbo);
        glReadBuffer(GL_COLOR_ATTACHMENT0);
     
        PixelInfo Pixel;
        glReadPixels(x, y, 1, 1, GL_RGB, GL_FLOAT, &Pixel); /* Lui là, il n'édite plus rien dès le second clic */
     
        glReadBuffer(GL_NONE);
        glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
     
        return Pixel;
    }
    Voici ma fonction PaintGL() :
    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
     
    void Display::paintGL(void)
    {
        /* Display phase */
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        _displayShader->use();
        glBindVertexArray(this->_VAO);
        _camera.attach(*_displayShader, _screenWidth, _screenHeight);
        glDrawArrays(GL_TRIANGLES, 0, (_peptide->getVerticesArraySize()) / 6);
     
        /* Picking phase */
        _pickingShader->use();
        _camera.attach(*_pickingShader, _screenWidth, _screenHeight);
        _pickMap.enableWriting();
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glDrawArrays(GL_TRIANGLES, 0, (_peptide->getVerticesArraySize()) / 6);
        _pickMap.disableWriting();
     
        glBindVertexArray(0);
    }
    Mon vertex shader de presque-picking (c'est surtout un test du remplissage du FBO actuellement) :
    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
     
    #version 330 core
    layout (location = 0) in vec3 position;
     
    uniform mat4 model;
    uniform mat4 view;
    uniform mat4 projection;
     
    out vec3 pos;
     
    void main()
    {
        gl_Position = projection * view * model * vec4(position, 1.0);
        pos = vec3(gl_Position.x, gl_Position.y, gl_Position.z);
    }
    Mon fragment shader
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    #version 330 core
     
    out vec3 FragColor;
     
    in vec3 pos;
     
    void main()
    {
        FragColor = pos;
    }
    Ma PickMap est une PickingTexture, qui est exactement la même classe que celle du tutorial.

    Les seules solutions a ce problème que j'ai trouvé sur le net consistaient à dire "Instancie un QOpenGLFramebufferObject que tu exportes dans une QImage, puis tu lis le pixel x y depuis la QImage". Mais cette solution me déplaît profondément (déjà car des sucouches Qt, et ensuite car cela fait des créations d'instances en plus à chaque frame pour quelque chose de relativement simple a faire en temps normal).

    J'ai l'impression que les deux problèmes rencontrés sont fondamentalement liés par une même cause. Qu'en pensez-vous ? Est-ce mon code qui comporte des erreurs, ou bien une incompatibilité avec une utilisation dans un contexte Qt ? Ai-je mal compris un principe d'utilisation des FBO ?

    Je remercie d'avance tous ceux qui s’intéressent à mon problème

  2. #2
    Membre chevronné Avatar de Jbx 2.0b
    Homme Profil pro
    Développeur C++/3D
    Inscrit en
    Septembre 2002
    Messages
    476
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur C++/3D
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2002
    Messages : 476
    Points : 1 785
    Points
    1 785
    Par défaut
    Hello,

    QOpenGLWidget fait son rendu dans son propre FramebufferObject (ce qui n'était pas le cas avec QGLWidget). As-tu essayé de binder sur celui-ci ?

    => defaultFramebufferObject

  3. #3
    Invité
    Invité(e)
    Par défaut
    Salut Jbx 2.0b

    Effectivement, binder ce FBO a redonné un comportement logique d'affichage, et me permet de remettre la phase de picking avant la phase d'affichage. Les vertices s'affichent. Merci !

    Par contre le picking ne fonctionne toujours pas. Je viens de faire en sorte que mon fragment shader de picking retourne de nouveau (1.0, 0.0, 0.0) quel que soit le cas, et j'observe le même comportement : des valeurs hasardeuses au premier clic (le dernier exemple en date 0.0980392 0.109804 0.129412) puis trois zéros pour chacun des clics suivants.
    J'ai réalisé que j'avais le même comportement lorsque supprimais le code de picking de ma fonction paintGL(). Ce qui veut dire que c'est un résultat possible quand rien n'a été écrit dans le FBO, qu'il a seulement été initialisé. Je ne sais pas pourquoi le contenu du FBO devient alors zéro alors que que j'ai supprimé aussi glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

    J'appelle _pickMap.init(_screenWidth, _screenHeight) depuis la fonction resizeGL() de ma classe principale.
    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
     
    bool PickingTexture::init(unsigned int WindowWidth, unsigned int WindowHeight)
       {
       initializeOpenGLFunctions();
     
       /* Creation du handle sur le nouveau frame buffer object (FBO) pour le picking */
       glGenFramebuffers(1, &_fbo);
       /* Rend m_fbo le frame buffer courant à la place de celui par défaut */
       glBindFramebuffer(GL_FRAMEBUFFER, _fbo);
     
       /* Creation d'une texture OpenGL pour être un buffer d'information des primitives */
       glGenTextures(1, &_pickingTexture);
       glBindTexture(GL_TEXTURE_2D, _pickingTexture);
       glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, WindowWidth, WindowHeight, 0, GL_RGB, GL_FLOAT, NULL);
       glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _pickingTexture, 0);
     
       /* Creation d'une texture OpenGL pour être un buffer de la profondeur (depth buffer) - je ne sais pas si c'est la peine de faire ça pour mon besoin */
       glGenTextures(1, &_depthTexture);
       glBindTexture(GL_TEXTURE_2D, _depthTexture);
       glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, WindowWidth, WindowHeight, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
       glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, _depthTexture, 0);
     
       /* ...pour éviter un bug sur certaines vieilles CG */
       glReadBuffer(GL_NONE);
     
       glDrawBuffer(GL_COLOR_ATTACHMENT0);
     
       /* Le FBO s'est-il correctement initialisé ? */
       GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
       if (status != GL_FRAMEBUFFER_COMPLETE) {
          logError("GL", "PICKING::FRAMEBUFFER::INCOMPLETE") << status;
          return false;
       }
     
       /* Restore le framebuffer par défaut */
       glBindTexture(GL_TEXTURE_2D, 0);
       glBindFramebuffer(GL_FRAMEBUFFER, 0);
     
       return true;
        }
    Pourquoi dans la fonction resizeGL() : pour deux raisons. D'une part je ne connais pas encore les dimensions de la fenêtre lors de l'appel à initializeGL(), j'avais fais la bourde la première fois, mes paramètres WindowWidth et WindowHeight n'étaient pas initialisés, OpenGL m'a insulté . La fonction de resizeGL() étant appelée avant le premier paintGL() je pense que ce n'est pas une mauvaise chose. Mais aussi car je me dis que plus tard il faudra que je change la taille de la texture au redimensionnement de la fenêtre. PickingTexture.init() changera alors de nom pour plus de clarté. En attendant je conçois que redimensionner la fenêtre donnera des décalages dans la textures.

    Sur ce coup là, je doute que le problème provienne d'une mauvaise utilisation de Qt. Je pensais qu'en résolvant le problème du FBO, le retour du picking se serait amélioré. Ce qui n'est pas la cas.
    Je pense que j'ai dû faire une erreur pour le remplissage de mon FBO de picking.
    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
     
    void Display::paintGL(void)
    {
        glBindVertexArray(this->_VAO);
     
        /* Picking phase */
        _pickingShader->use();
        _camera.attach(*_pickingShader, _screenWidth, _screenHeight);
        _pickMap.enableWriting();
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glDrawArrays(GL_TRIANGLES, 0, (_peptide->getVerticesArraySize()) / 6);
        glBindFramebuffer(GL_DRAW_FRAMEBUFFER, defaultFramebufferObject());
     
        /* Display phase */
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        _displayShader->use();
        _camera.attach(*_displayShader, _screenWidth, _screenHeight);
        glDrawArrays(GL_TRIANGLES, 0, (_peptide->getVerticesArraySize()) / 6);
     
        glBindVertexArray(0);
    }
    Encore merci Jbx 2.0b pour ton aide sur le binding du FBO.

    Quelqu'un a-t-il une idée sur le pourquoi de mon second problème ?
    Merci d'avance !

  4. #4
    Invité
    Invité(e)
    Par défaut
    J'ai une piste.
    Si je commente glReadBuffer(GL_NONE) dans la fonction d'initialisation de la PickingTexture, le premier clic me donne bel et bien le retour voulu (1.0, 0.0, 0.0). Les clics suivants continuent de me fournir trois zéros.
    J'ai également supprimé un appel à glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0) qui restait a cet endroit.

    Dans le tutoriel d'OGL il était dit que cette ligne servait a éviter certains bugs sur de vieilles cartes graphiques.

  5. #5
    Membre chevronné Avatar de Jbx 2.0b
    Homme Profil pro
    Développeur C++/3D
    Inscrit en
    Septembre 2002
    Messages
    476
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur C++/3D
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2002
    Messages : 476
    Points : 1 785
    Points
    1 785
    Par défaut
    J'ai cherché un peu mais je vois rien qui me choque; J'suis pas vraiment un habitué du picking par couleur (plutôt du picking par scenegraph + lancer de rayon et mieux + octree).
    Mais juste pour te dire que resizeGL() a des chances d'être appelée plusieurs fois (même si ta fenêtre n'est pas redimensionnable, j'ai pu remarquer que les méthode resizeEvent & resizeGL étaient parfois appelées plusieurs fois au démarrage). Et donc que tu dois faire attention de recycler ton fbo et ta texture (glDeleteFramebuffers & glDeleteTextures) pour pas faire exploser la mémoire graphique.
    Enfin j'imagine que tu y avais peut-être pensé, mais on sait jamais

    Pour le reste je vois pas trop. Je comprends pas vraiment l'utilité d'un glReadBuffer(GL_NONE) au passage.

  6. #6
    Invité
    Invité(e)
    Par défaut
    A force de changer deux ou trois petits détails, je finis par avoir un picking presque fonctionnel. Mais je dois avouer ne pas être suffisamment à l'aise pour comprendre ce qui se passe.
    Quand je clique sur un objet, j'obtiens sa couleur. Problème, c'est la couleur de l'objet dans le back buffer quej'obtiens, et pas celui de mon fbo personnel.
    Quand je bind mon framebuffer et que je fais un glClearColor(0.0, 0.0, 0.0, 1), c'est le fond du backbuffer change.
    On dirait que le fait de binder mon propre FBO n'a aucun effet.

    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
        void Display::paintGL(void)
        {
            glBindVertexArray(this->_VAO);
     
            /* Picking phase */
            _pickingShader->use();
            _camera.attach(*_pickingShader, _screenWidth, _screenHeight);
            _pickMap.enableWriting();
            glClearColor(0.0, 0.0, 0.0, 1); // Pourquoi ça ne change pas la couleur de fond de _fbo uniquement ?
            glDrawArrays(GL_TRIANGLES, 0, (_peptide->getVerticesArraySize()) / 6);
     
            /* Display phase */
            glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebufferObject()); /* Warning : Qt's default frame buffer is not 0, use defaultFramebufferObject() instead */
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
            _displayShader->use();
            _camera.attach(*_displayShader, _screenWidth, _screenHeight);
            glDrawArrays(GL_TRIANGLES, 0, (_peptide->getVerticesArraySize()) / 6);
     
            glBindVertexArray(0);
        }
     
        void Display::mousePressEvent(QMouseEvent *event)
        {
            if (event->buttons() & Qt::RightButton)
            {
                auto test = _pickMap.readPixel(event->x(), _screenHeight - event->y());
     
                qDebug() << test.ObjectID << test.DrawID << test.PrimID;
                            glBindFramebuffer(GL_DRAW_FRAMEBUFFER, defaultFramebufferObject());
            }
        }
    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
        bool PickingTexture::init(unsigned int WindowWidth, unsigned int WindowHeight)
        {
            initializeOpenGLFunctions();
     
            /* Creation du handle sur le nouveau frame buffer object (FBO) pour le picking */
            glGenFramebuffers(1, &_fbo);
            /* Rend m_fbo le frame buffer courant à la place de celui par défaut */
            glBindFramebuffer(GL_FRAMEBUFFER, _fbo);
     
            /* Creation d'une texture OpenGL pour être un buffer d'information des primitives */
            glGenTextures(1, &_pickingTexture);
            glBindTexture(GL_TEXTURE_2D, _pickingTexture);
            glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, WindowWidth, WindowHeight, 0, GL_RGB, GL_FLOAT, NULL);
            glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _pickingTexture, 0);
     
            /* Creation d'une texture OpenGL pour être un buffer de la profondeur (depth buffer) */
            glGenTextures(1, &_depthTexture);
            glBindTexture(GL_TEXTURE_2D, _depthTexture);
            glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, WindowWidth, WindowHeight, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
            glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, _depthTexture, 0);
     
            /* ...pour éviter un bug sur certaines vieilles CG */
            //glReadBuffer(GL_NONE);
     
            glDrawBuffer(GL_COLOR_ATTACHMENT0);
     
            /* Le FBO s'est-il correctement initialisé ? */
            GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
            if (status != GL_FRAMEBUFFER_COMPLETE) {
                logError("GL", "PICKING::FRAMEBUFFER::INCOMPLETE") << status;
                return false;
            }
     
            /* Restore le framebuffer par défaut */
            glBindTexture(GL_TEXTURE_2D, 0);
     
            return true;
        }
     
        void PickingTexture::enableWriting(void)
        {
            glBindFramebuffer(GL_DRAW_FRAMEBUFFER, _fbo);
        }
     
        PickingTexture::PixelInfo PickingTexture::readPixel(unsigned int x, unsigned int y)
        {
            glBindFramebuffer(GL_FRAMEBUFFER, _fbo);
            glReadBuffer(GL_COLOR_ATTACHMENT0);
     
            PixelInfo Pixel;
            glReadPixels(x, y, 1, 1, GL_RGB, GL_FLOAT, &Pixel);
     
           //glReadBuffer(GL_NONE);
     
            return Pixel;
        }
     
        PickingTexture::PixelInfo::PixelInfo(void)
        {
            ObjectID = 0.0f;
            DrawID   = 0.0f;
            PrimID   = 0.0f;
        }
    Commenter la ligne
    _displayShader->use();
    appellée depuis PaintGL() me donne le bon résultat dans la console au clic de la souris. Mais en contrepartie j'affiche aussi les mauvaises couleurs, celles issues de mon shader de picking. C'est pourquoi j'ai l'impression que tout se joue dans le back buffer, comme si je n'arrivais pas à alterner entre mon _fbo et le framebuffer par défaut.

  7. #7
    Membre chevronné Avatar de Jbx 2.0b
    Homme Profil pro
    Développeur C++/3D
    Inscrit en
    Septembre 2002
    Messages
    476
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur C++/3D
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2002
    Messages : 476
    Points : 1 785
    Points
    1 785
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    glClearColor(0.0, 0.0, 0.0, 1);
    Ne changera effectivement la couleur qu'à l'appel de :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    glClear(GL_COLOR_BUFFER_BIT);
    C'est donc bien le buffer de ton widget qui va changer de couleur.

    Il te manque au moins un glClear() dans ton code, même si je suis pas sûr que ça résolve le problème.

  8. #8
    Invité
    Invité(e)
    Par défaut
    Citation Envoyé par Jbx 2.0b Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    glClearColor(0.0, 0.0, 0.0, 1);
    Ne changera effectivement la couleur qu'à l'appel de :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    glClear(GL_COLOR_BUFFER_BIT);
    C'est donc bien le buffer de ton widget qui va changer de couleur.

    Il te manque au moins un glClear() dans ton code, même si je suis pas sûr que ça résolve le problème.
    Tout a fait, tu as raison. Ça résout déjà une partie de mon incompréhension, merci !

    Je touche au but.
    J'ai supprimé l'objet PickingTexture temporairement, et je fais ma tambouille dans mon objet principal. Je constate que j'écris bel et bien dans mon FBO de picking a chaque tour de boucle, voilà pourquoi :
    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
    void Display::paintGL(void)
    {
        if (init_picking == false)
        {
                initPicking();
                init = true;
            }
        glBindVertexArray(this->_VAO);
     
        /* Picking phase */
        _pickingShader->use();
        _camera.attach(*_pickingShader, _screenWidth, _screenHeight);
        glBindFramebuffer(GL_FRAMEBUFFER, _pickingFBO);
        glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glDrawArrays(GL_TRIANGLES, 0, (_peptide->getVerticesArraySize()) / 6);
        PickingTexture::PixelInfo texel;
        glReadPixels(0, 0, 1, 1, GL_RGB, GL_FLOAT, &texel);
        qDebug() << texel.ObjectID << texel.DrawID << texel.PrimID;
        glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebufferObject());
     
        /* Display phase */
        glClearColor(0.10f, 0.11f, 0.13f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        _displayShader->use();
        _camera.attach(*_displayShader, _screenWidth, _screenHeight);
        glDrawArrays(GL_TRIANGLES, 0, (_peptide->getVerticesArraySize()) / 6);
     
        glBindVertexArray(0);
    }
    Ce code m'affiche bien la bonne couleur du pixel (0; 0) du FBO de picking, grâce au qDebug() de la ligne 19. Comme je peux effectuer une rotation de la camera, j'ai pu placer et déplacer des objets sur ce pixel donc j'en suis assurée.
    Dans la phase de picking, je suis sûre et certaine que le FBO de picking est correctement bindé. Je n'écris pas dans le back buffer du FBO par défaut, puisque si je commente la phase de display, plus rien ne s'affiche.

    Donc j'ai un FBO de picking qui marche, youpi ! Sauf que dans mousePressEvent() c'est la couleur du backbuffer qui est lue. Quand bien même je bind mon FBO de picking juste avant de faire le glReadPixels() :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    void Display::mousePressEvent(QMouseEvent *event)
    {
        if (event->buttons() & Qt::RightButton)
        {
            glBindFramebuffer(GL_FRAMEBUFFER, _pickingFBO);
            glReadBuffer(GL_COLOR_ATTACHMENT0);
            PickingTexture::PixelInfo texel;
            glReadPixels(event->x(), _screenHeight - event->y(), 1, 1, GL_RGB, GL_FLOAT, &texel);
            qDebug() << texel.ObjectID << texel.DrawID << texel.PrimID;
            glReadBuffer(GL_NONE);
            glBindFramebuffer(GL_DRAW_FRAMEBUFFER, defaultFramebufferObject());
        }
    }
    C'est vraiment bizarre. Peut-être que je ne lis pas dans le bon buffer du FBO. Ou peut-être qu'il ne se bind pas bien dans cette fonction là. Pourtant j'ai mis un nom de target valide et _pickingFBO a la bonne valeur.
    Une idée ?

  9. #9
    Membre chevronné Avatar de Jbx 2.0b
    Homme Profil pro
    Développeur C++/3D
    Inscrit en
    Septembre 2002
    Messages
    476
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur C++/3D
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2002
    Messages : 476
    Points : 1 785
    Points
    1 785
    Par défaut
    Un bind en READ suffit dans le mousePressEvent() non ?

    J'avoue que je vois pas le soucis non plus... en gros ton picking fonctionne mais uniquement dans paintGL() ?
    La seule différence que je vois c'est que le contexte n'est pas rendu courant dans le mouseEvent(). Essaye de faire un makeCurrent() avant de binder ton FBO. Il faut savoir que Qt utilise OpenGL en interne et que seule les fonctions xxxGL() de QOpenGLWidget rendent le contexte courant. Ça pourrait expliquer le problème. Ou pas

  10. #10
    Invité
    Invité(e)
    Par défaut
    Un bind en READ suffit dans le mousePressEvent() non ?
    J'ai changé des GL_DRAW_FRAMEBUFFER en GL_FRAMEBUFFER a plusieurs reprises dans les cas de bufferisation.
    Pareil pour les cas de lecture du buffer ou j'ai parfois changé des GL_READ_FRAMEBUFFER en GL_FRAMEBUFFER pour essayer de voir ce qui se passerait. Mon code doit contenir encore pas mal de ces expérimentations malheureuses, merci de m'avoir indiqué cet oubli

    en gros ton picking fonctionne mais uniquement dans paintGL() ?
    Exactement. Je découvre que j'ai une erreur 1282 (je ne sais pas encore trop ce que c'est) retournée par glGetError() dans la fonction de Display::mousePressEvent().
    Cette erreur n'arrive pas lorsque je fais du picking directement dans la fonction Display::paintGL()

    La seule différence que je vois c'est que le contexte n'est pas rendu courant dans le mouseEvent(). Essaye de faire un makeCurrent() avant de binder ton FBO.
    Oh ça marche !!
    Je ne suis pas bien sûre de savoir pourquoi, mais ça fonctionne ! J'ai l'affichage des vertices en mode display, et les clics de souris m'affichent maintenant en console les indices que je souhaitais voir sur l'objet. J'ai toujours des erreurs 1282, mais cette fois je les trouve dans la fonction Display::paintGL(). Je vais essayer de corriger cela. Je ne sais pas trop comment gérer les erreurs OpenGL de manière intelligente, j'imagine que pour le coup Qt aura peut-être une solution a me proposer, comme une callback. Pour une fois je ne dirai pas non a une surcouche.

    Je crois comprendre à te lire, que Qt dispose de son propre contexte OpenGL, et qu'il doit switcher entre le mien et le sien pour permettre l'affichage de la fenêtre. Dans les fonctions d'event, c'était son contexte qui était utilisé, le handler correspondant à mon framebuffer ne correspondait à rien. D'où le comportement étrange.

    Merci beaucoup, je ne sais pas combien de temps j'aurais pu y passer sans ton intervention.

  11. #11
    Membre chevronné Avatar de Jbx 2.0b
    Homme Profil pro
    Développeur C++/3D
    Inscrit en
    Septembre 2002
    Messages
    476
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur C++/3D
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2002
    Messages : 476
    Points : 1 785
    Points
    1 785
    Par défaut
    Je crois comprendre à te lire, que Qt dispose de son propre contexte OpenGL, et qu'il doit switcher entre le mien et le sien pour permettre l'affichage de la fenêtre. Dans les fonctions d'event, c'était son contexte qui était utilisé, le handler correspondant à mon framebuffer ne correspondait à rien. D'où le comportement étrange.
    C'est exactement ça, à noter qu'il pourrait l'être si les contextes étaient partagés.

    Je ne sais pas trop comment gérer les erreurs OpenGL de manière intelligente, j'imagine que pour le coup Qt aura peut-être une solution a me proposer, comme une callback. Pour une fois je ne dirai pas non a une surcouche.
    Perso j'ai une méthode checkError() que j'appelle régulièrement. Beaucoup diraient que pour avoir une hygiène parfaite, il faudrait l'appeler après chaque méthode OpenGL, mais je trouve que ça réduit la lisibilité du code. Et oui sinon Qt possède sa surcouche, regarde du côté de QOpenGLDebugLogger . Je peux pas t'en dire plus, j'ai jamais testé !

  12. #12
    Expert éminent sénior

    Avatar de dragonjoker59
    Homme Profil pro
    Software Developer
    Inscrit en
    Juin 2005
    Messages
    2 045
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Software Developer
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2005
    Messages : 2 045
    Points : 11 368
    Points
    11 368
    Billets dans le blog
    10
    Par défaut
    Si tu as accès aux extension de débug OpenGL, tu peux voir un truc que j'ai posté ici il y a un moment: http://jeux.developpez.com/telecharg...via-extensions

    Et je checke les erreurs à chaque appel de commande OpenGL. je me suis fait une classe qui wrappe tous les appels OpenGL.
    Bon, c'est clair, je me suis fait c***r, mais maintenant je peux personnaliser mes appels, en utilisant notamment les objets mathématiques de base de mon moteur.
    Si vous ne trouvez plus rien, cherchez autre chose...

    Vous trouverez ici des tutoriels OpenGL moderne.
    Mon moteur 3D: Castor 3D, presque utilisable (venez participer, il y a de la place)!
    Un projet qui ne sert à rien, mais qu'il est joli (des fois) : ProceduralGenerator (Génération procédurale d'images, et post-processing).

  13. #13
    Invité
    Invité(e)
    Par défaut
    Merci beaucoup !
    Je regarde dessuite.

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

Discussions similaires

  1. Mise en place d'un algorithme de color picking
    Par GLDavid dans le forum OpenGL
    Réponses: 46
    Dernier message: 26/08/2008, 16h25
  2. coloration syntaxique sous spe
    Par nico_h dans le forum EDI/RAD
    Réponses: 6
    Dernier message: 19/05/2008, 22h41
  3. Coloration syntaxique sous VIM/GVIM
    Par Neuromancien2 dans le forum Applications et environnements graphiques
    Réponses: 3
    Dernier message: 31/12/2007, 20h40
  4. [3.1.2.][Plugin][WebTools]La coloration syntaxique sous Eclipse
    Par Alexandre T dans le forum Eclipse Java
    Réponses: 1
    Dernier message: 04/04/2007, 16h18
  5. Coloration syntaxique sous Visual C++
    Par chris_wafer_2001 dans le forum MFC
    Réponses: 1
    Dernier message: 25/09/2005, 10h58

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