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

Qt Discussion :

QGLWidget, QMatrix4x4 et OpenGL [2D/3D]


Sujet :

Qt

  1. #1
    Membre à l'essai
    Homme Profil pro
    informaticien géomètre
    Inscrit en
    Juillet 2012
    Messages
    20
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : informaticien géomètre
    Secteur : Bâtiment Travaux Publics

    Informations forums :
    Inscription : Juillet 2012
    Messages : 20
    Points : 11
    Points
    11
    Par défaut QGLWidget, QMatrix4x4 et OpenGL
    Bonjour à tous

    Suite à l'étude de plusieurs tutoriels sur Qt4.8 et OpenGL3, j'ai une petite question pour m'assurer que je ne me fourvoie pas.

    Il est bien précisé dans les tutos qu'il faut multiplier les matrices dans le bon ordre, à savoir (projection * view * model), or j'obtiens le même résultat à l’affichage en utilisant (projection * lookat).
    Peut on considérer que (view * model) correspond en quelque sorte à des coordonnées polaires, alors que (lookat) correspondrait à des coordonnées rectangulaires, d'où le résultat similaire ?

    Maintenant la Vrai question :
    J'ai besoin de récupérer les coordonnées 2D des vertex tel qu'affiché dans la fenêtre QGLWidget. Le but étant d'avoir les coordonnées UVmap de projection suivant la vue caméra.
    J'ai donc essayé de multiplier mes points 3D par la matrice d'affichage (résultat de projection * view * model) que je fournis au vertex shader, mais le résultat obtenu ne correspond pas du tout à ce que j'ai à l'affichage.
    Quelqu'un pourrait-il m'aiguiller vers une solution, car toutes mes recherches Internet aboutissent sur des contradictions, ou lorsqu'une personne claironne qu'elle a trouvé la solution... elle se garde bien de dire comment.

    Merci d'avance pour vos suggestions.

  2. #2
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    26 858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2008
    Messages : 26 858
    Points : 218 575
    Points
    218 575
    Billets dans le blog
    120
    Par défaut
    Bonjour,

    La dernière transformation qui vous manque et celle de la fenêtre, je crois. De mémoire, la transformation :
    point * projection * vue * model
    donne un résultat entre 0 et 1. (ou -1 et 1). Ces points doivent être transformé en coordonnées écran ( +1 / 2 * width ou height selon la dimension).
    Enfin, je crois que c'est cette partie qui vous manque.

    Pour la première partie de la question, je dois dire que je n'ai pas compris. Un lookat c'est une matrice de vue et si elle est seule, c'est qu'il n'y a pas de matrice modèle et le modèle se trouve au milieu (à l'origine) de la scène.
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  3. #3
    Membre à l'essai
    Homme Profil pro
    informaticien géomètre
    Inscrit en
    Juillet 2012
    Messages
    20
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : informaticien géomètre
    Secteur : Bâtiment Travaux Publics

    Informations forums :
    Inscription : Juillet 2012
    Messages : 20
    Points : 11
    Points
    11
    Par défaut
    Merci pour votre réponse

    J'approche enfin de la solution.
    Effectivement OpenGL place le centre de la vue en (0, 0) avec une plage d’affichage allant de -1 à +1.
    Donc maintenant j'arrive à récupérer des coordonnées valides en faisant (projection * view * model * point3D), mais... (hé oui il en fallait bien un ! )
    Si tout se passe bien quand je fais une rotation autour du Z caméra (roulis), en revanche avec une rotation suivant X ou Y les coordonnées obtenues sont alors fausses.

    Une petite idée ?


    (Pour ce qui est de la matrice lookat, maintenant que le programme fonctionne en partie, j'ai pu tester si (projection * lookat * point3D) permettait d'obtenir des coordonnées 2D valident. Mais ce n'est malheureusement pas le cas !)

    [EDIT] Contrairement à ce que j'ai écris, l'utilisation de lookat fonctionne bien, si on rajoute la division des coordonnées 2D par le terme w (comme décrit plus loin)

  4. #4
    Membre à l'essai
    Homme Profil pro
    informaticien géomètre
    Inscrit en
    Juillet 2012
    Messages
    20
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : informaticien géomètre
    Secteur : Bâtiment Travaux Publics

    Informations forums :
    Inscription : Juillet 2012
    Messages : 20
    Points : 11
    Points
    11
    Par défaut
    En fait je viens de constater que si la distance de la caméra est différente de 1 les valeurs sont fausses.

    Je pense que le code pourra peut-être aider à visualiser ce qui est incohérent.

    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
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    WinGL::WinGL( const QGLFormat& format, QWidget* parent )
        : QGLWidget( format, parent ),
          m_vrtxBuf( QGLBuffer::VertexBuffer )
    {
        this->setGeometry(100,100,640,480);
        // Défini un triangle
        pts[0] = -0.5f; pts[1] = -0.5f; pts[2] = 0.0f; pts[3] = 1.0f;
        pts[4] =  0.5f; pts[5] = -0.5f; pts[6] = 0.0f; pts[7] = 1.0f;
        pts[8] =  0.0f; pts[9] =  0.5f; pts[10] = 0.0f; pts[11] = 1.0f;
     
        // Orientation et position de départ camera
        xrot = 0;    // Une valeur différente donne un résultat faux
        yrot = 0;    // Une valeur différente donne un résultat faux
        zrot = 10;
        dist = -1;   // Une valeur différente donne un résultat faux
     
    }
     
    void WinGL::initializeGL(){
        qDebug();
     
        QGLFormat glFormat = QGLWidget::format();
        if (!glFormat.sampleBuffers()) qDebug() << "Ne peut pas activer les buffers";
     
        // Couleur d'effacement
        glClearColor(0.0f, 0.0f, 0.2f, 1.0f);
     
        // Chargement vertex shader
        bool ret = false;
        ret = m_shadProg.addShaderFromSourceFile(QGLShader::Vertex, ":/vertex.shad");
        if (!ret) qDebug() << "Vertex shader : " << m_shadProg.log();
     
        // Chargement fragment shader
        ret = m_shadProg.addShaderFromSourceFile(QGLShader::Fragment, ":/fragment.shad");
        if (!ret) qDebug() << "Fragment shader : " << m_shadProg.log();
     
        // Liaison des shader au programme
        ret = m_shadProg.link();
        if (!ret) qDebug() << "Echec liaison shadProg : " << m_shadProg.log();
     
        // Génère un identifiant sur les matrices de projection
        m_matLoc = m_shadProg.uniformLocation("matLoc");
        if (m_matLoc == -1) qDebug() << "Echec identifiant matrice !";
     
        // Création d'un vertex buffer
        ret = m_vrtxBuf.create();
        if (!ret) qDebug() << "Echec création buffer !";
     
        // Attache le vertex buffer au context GL
        ret = m_vrtxBuf.bind();
        if (!ret) qDebug() << "Echec contextualisation du vertex buffer !";
     
        // Affecte le tableau de points au vertex buffer
        m_vrtxBuf.allocate(pts, 12 * sizeof(float));
     
        // Attache le programme au context GL
        ret = m_shadProg.bind();
        if (!ret) qDebug() << "Echec contextualisation du programme !";
     
        // Assigne le vertex buffer au programme
        m_shadProg.setAttributeBuffer("vrtx", GL_FLOAT, 0, 4);
        // Active le vertex buffer pour le programme
        m_shadProg.enableAttributeArray("vrtx");
    }
     
     
    void WinGL::resizeGL(int w, int h){
        // Met à jour la taille de la fenêtre
        glViewport( 0, 0, w, qMax( h, 1 ) );
    }
     
     
    void WinGL::paintGL(){
        // Efface les buffers
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        glEnable(GL_DEPTH_TEST);
        glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
     
        // Renseigne la matrice de projection
        QMatrix4x4 proj;
        proj.perspective(60.0, this->width() / this->height(), 0.1, 100.0);
     
        // Renseigne la matrice du modèle
        QMatrix4x4 model;
        model.rotate(xrot, 1.0, 0.0, 0.0);
        model.rotate(yrot, 0.0, 1.0, 0.0);
        model.rotate(zrot, 0.0, 0.0, 1.0);
     
        // Renseigne la matrice de vue
        QMatrix4x4 view;
        view.translate(0.0, 0.0, dist);
     
        QMatrix4x4 result;
        result = proj * view * model;
     
        // Calcul du point 2D correspondant au triangle affiché
        QVector4D ec1 = result * QVector4D(pts[0], pts[1], pts[2], pts[3]);
        // Conversion en pixel pour controler
        int xpx1 = (ec1.x() * this->width() / 2) + (this->width() / 2);
        int ypx1 = (this->height() / 2) - (ec1.y() * this->height() / 2);
        // idem point 2
        QVector4D ec2 = result * QVector4D(pts[4], pts[5], pts[6], pts[7]);
        int xpx2 = (ec2.x() * this->width() / 2) + (this->width() / 2);
        int ypx2 = (this->height() / 2) - (ec2.y() * this->height() / 2);
        // idem point 3
        QVector4D ec3 = result * QVector4D(pts[8], pts[9], pts[10], pts[11]);
        int xpx3 = (ec3.x() * this->width() / 2) + (this->width() / 2);
        int ypx3 = (this->height() / 2) - (ec3.y() * this->height() / 2);
        qDebug() << "pt1(" << xpx1 << "," << ypx1 << ")" << "  pt2(" << xpx2 << "," << ypx2 << ")" << "  pt3(" << xpx3 << "," << ypx3 << ")";
     
        // Assigne la matrice résultante au programme
        m_shadProg.setUniformValue(m_matLoc, result);
     
        // Affiche le triangle
        glDrawArrays(GL_TRIANGLES, 0, m_vrtxBuf.size());
        glDisableClientState(GL_VERTEX_ARRAY);
    }
    Quelqu'un voit-il ce qui cloche ?
    Merci pour le coup de main.

  5. #5
    Responsable 2D/3D/Jeux


    Avatar de LittleWhite
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Mai 2008
    Messages
    26 858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Mai 2008
    Messages : 26 858
    Points : 218 575
    Points
    218 575
    Billets dans le blog
    120
    Par défaut
    Je vous conseillerai de faire un "look at" pour la vue, car, d'une part, je ne vois pas trop le problème et d'une autre part, car c'est la seule chose que je ne fais pas à l'identique.
    Sinon, pourrait on avoir le projet, que l'on puisse tester ? s'il vous plait
    Vous souhaitez participer à la rubrique 2D/3D/Jeux ? Contactez-moi

    Ma page sur DVP
    Mon Portfolio

    Qui connaît l'erreur, connaît la solution.

  6. #6
    Membre à l'essai
    Homme Profil pro
    informaticien géomètre
    Inscrit en
    Juillet 2012
    Messages
    20
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : informaticien géomètre
    Secteur : Bâtiment Travaux Publics

    Informations forums :
    Inscription : Juillet 2012
    Messages : 20
    Points : 11
    Points
    11
    Par défaut
    Merci pour votre intérêt

    Mon soucis n'était pas un problème d'affichage, mais de conversion des points 3D en points 2D tel que vue depuis la caméra et affiché sur l'écran.

    J'ai fini par trouver la solution
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    QVector4D pt2D, pt3D
    QMatrix4x4 proj, view, model
    pt2D = proj * view * model * pt3D
    (jusque là pas de changement)

    Mais pour que les coordonnées 2D soient bonne il faut ajouter le calcul suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    pt2D.setX(pt2D.x() / pt2D.w());
    pt2D.setY(pt2D.y() / pt2D.w());
    Ne me demandez pas pourquoi... je n'ai jamais rien compris aux maths
    Mais ce qui est sûr c'est que maintenant les coordonnées 2D sont valide quelque soit l'orientation ou la distance de la caméra à la scène.

    Si quelqu'un à besoin du code complet de démo, je pourrai le mettre.

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

Discussions similaires

  1. Directx ou opengl
    Par scorpiwolf dans le forum DirectX
    Réponses: 13
    Dernier message: 07/02/2003, 08h29
  2. interface utilisateur avec OpenGL
    Par demis20 dans le forum OpenGL
    Réponses: 6
    Dernier message: 03/10/2002, 12h27
  3. OpenGL et *.3ds
    Par tintin22 dans le forum OpenGL
    Réponses: 4
    Dernier message: 06/05/2002, 13h51
  4. OpenGL ou DirectX
    Par Nadir dans le forum DirectX
    Réponses: 6
    Dernier message: 02/05/2002, 12h48
  5. Opengl -- Les surfaces
    Par Anonymous dans le forum OpenGL
    Réponses: 2
    Dernier message: 02/05/2002, 10h14

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