Je suis en train de tester un picking test à l'aide de la fonction glReadPixels.
L'idée est de redessiner unqiement chaque objet sélectionnable dans des couleurs bidons puis de tester la couleur du pixel trouvé.

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
 
// On met des couleurs basiques à tous les objets sélectionnables
    static GLfloat pickRed[] =  { 1.0f,0.8f,0.6f,0.4f,0.2f };
    static GLfloat pickGreen[]= { 1.0f,0.8f,0.6f,0.4f,0.2f };
    static GLfloat pickBlue[]=  { 0.0f,0.2f,0.4f,0.6f,0.8f  };
 
    // Trop d'objets à comparer - N'arrive jamais normalement- ??
    Assert(this->objects.size() <= 75,std :: string("Trop d'objets à comparer"));
 
    // Repère du tableau des couleurs basiques
    short int redCounter = 0;
    short int greenCounter = 0;
    short int blueCounter = 0;  
 
    // Dessin dans le buffer des objets pouvant être sélectionnés
    // On annule tout (lumière, texture etc ... )
    glDisable(GL_TEXTURE_2D);
    glDisable(GL_CULL_FACE);
    glDisable(GL_COLOR_MATERIAL);
 
    // Remise à no_select de tous les objets (puisqu'on a recliqué)
    for(IT it = this->objects.begin(); it != this->objects.end(); ++it)
    {
        Object* obj = Window :: gestionnary->getObject(*it);
        Assert(obj != 0,std::string("Object déclaré non trouvé"));
        obj->status[IS_SELECTED] = false;
    } 
 
 
    // Effacement de l'écran
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);	    
 
 
    // Affectation d'une couleur à tout objet visible, qui doit remplacer toute couleur existante (d'où le glTexEnvi)
   // (on est obligé de clicker sur un objet visible à l'écran)
    glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_REPLACE);
    for(Uint32 i=0; i < this->map->visibleObjects.size(); ++i)
    {
        Object* obj = Window :: gestionnary->getObject(this->map->   visibleObjects.at(i));
        Assert(obj != 0, std :: string("Object déclaré visible non trouvé dans le gestionnaire"));
 
        // Dessin de l'objet ansi coloré dans le buffer
        Color pColor(pickRed[redCounter],pickGreen[greenCounter],pickBlue[blueCounter]);
        glColor3f(pColor.red,pColor.green,pColor.blue);
        obj->pickColor = pColor;
        obj->drawSelect();   // Dessin spécial, sans texture ni rien
 
        // Incrémentation des compteurs
        if (++redCounter == 5) 
        {       
                redCounter = 0;
                if (++greenCounter == 5 ) 
                {
                    greenCounter = 0;
                    ++blueCounter;
                }
        }  
 
    }
 
 
    // Processus de "picking". Sur quelle couleur a-t-on clické ?
    // On lit le pixel clické                          
    GLint viewport[4];
    GLfloat pixel[3];
    glGetIntegerv(GL_VIEWPORT,viewport);
 
   // Récupérer les coordonnées de la souris
    int cursorX,cursorY;	    
    SDL_GetMouseState(&cursorX,&cursorY);
 
   // Conversion coordonnées SDL => coordonnées openGL. Attention au GLFloat !
   glReadPixels(cursorX,viewport[3]-cursorY,1,1,GL_RGB,GL_FLOAT,reinterpret_cast<void *>(&pixel[0]));
    Color foundColor(pixel[0],pixel[1],pixel[2]);
 
    /* Et maintenant on cherche quel objet possède la couleur basique clickée.   Ca peut être le mm que le précédent */
    std :: vector<Uint32> :: iterator vit;
    vit = find_if(this->map->visibleObjects.begin(),this->map->visibleObjects.end(),IsPicked(foundColor));
    if (vit != this->map->visibleObjects.end()) 
        Window :: gestionnary->getObject(*vit)->status[IS_SELECTED] = true; 
 
    // Retour à la couleur blanche de base pour annuler la pickcolor
    glColor3f(1.0f,1.0f,1.0f);
 
 
   // Affiche les résultats (pour tester) => foundcolor ne correspond pas 
   // toujours à la valeur attendue, sauf s'il se termine par un chiffre pair 8O
    std :: cout << "foundColor : " << pixel[0] << "/" << pixel[1] << "/" << pixel[2] << std::endl; 
    std::cout << "visibleObject.size : " << this->map->visibleObjects.size() << std::endl; 
    string test = (vit != this->map->visibleObjects.end()) ? "oui" : "non";
    std::cout << "Object trouvé ? " << test  << std::endl;        
 
    glEnable(GL_TEXTURE_2D);
    glEnable(GL_CULL_FACE);
    glEnable(GL_COLOR_MATERIAL);

Avant de faire le test j'ai pris de mettre dans le tableau "visibleObjects" uniquement les objets vus par la caméra.
Je passe aussi par un gestionnaire d'objets, me permettant d'utiliser seulement des "handle" d'objets plutôt que des pointeurs.

Je remarque une drôle de chose au sujet de glReadPixels. Si j'utilise des GLubyte pour la couleur, aucun problème de détection, les valeurs obtenues sont celles attendues.
Si j'utilise des GLfloat, et bien ça ne marche pas toujours, SAUF si mon tableau des pickRed, pickBlue et pickGreen ne contient que des nombres pairs (0.2f, 0.4f etc ...)
Si je m'attends à 0.3f, j'ai vu que la fonction me sortait des valeurs "proches" du genre 0.29032f mais pas 0.3f , et donc le click n'est pas reconnu.
J'aurai compris si j'avais eu 0.2999f par exemple mais là ...