Salut tout le monde, j'ai eu dernièrement l'idée de faire du picking sur une scène 3D en OpenGL.
De nombreux tuto existe, même en français, mais ça ne m'a pas empêcher de m'arracher les cheveux pour y arriver.
http://www.developpez.net/forums/d66...e/#post3882413

Donc pour répondre a la demande de Shenron666 je vais poster les sources du code que j'ai pondu, dans lequel j'ai rajouter des commentaires histoire d'aider au mieux sur ce sujet la :
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
/*
** Par Yves Desgraupes
** yves.desgraupes@free.fr
** bddy.free.fr
** 2008 tous droits pas reservés :)
** ------------------------------
** Test de picking sur une scène 3D (2 carrés superposés)
** Système de fenetrage : SDL
** API graphique : OpenGL
** Librairies nécessaires : SDL && gl && glu
** Fichiers nécessaires : SDL.dll || SDL.so
** Langage : C++ (bien que ca soit du C+ :s)
*/
 
#include <iostream>                                                             //Pour écrire sur la sortie standard/erreur
#include <SDL/SDL.h>                                                            //Pour créer une fenetre et gérer les évènements
#include <GL/gl.h>                                                              //On fait de l'OpenGL, non ?
#include <GL/glu.h>                                                             //Parce qu'elle est bien pratique cette lib (un conseil : recodez 'gluPerspective' et 'gluLookAt' pour gagner en perf)
 
/*
** Déclaration du prototype de toutes les fonctions meme si là, ca ne sert pas à grand chose
*/
void	checkevents();
void    draw();
void    processHits(GLint hits, GLuint *buffer);
void    picking();
void    drawsquare(bool cas);
void	taketime(bool cas);
bool    initGL();
 
/*
** Déclaration de variables globales, c'est mieux que des #define, le type des variables étant déclaré
*/
const int WIN_X = 800;                                                          //Largeur de la fenetre
const int WIN_Y = 600;                                                          //Hauteur de la fenetre
const int BUFSIZE = 1024;                                                       //Taille du buffer de selection
 
/*
** Déclaration de variables globales, mais cette fois c'est TRES MOCHE
** pour une raison de clarté, je les laisse ici plutot que de les mettre dans plusieurs struct
** ou une éventuelle class.
** mais ca reste très moche !!! donc, recodez sans global de ce genre !!!
*/
int         sTime;
int         cTime;
int         eTime;
int         mx = 0;
int         my = 0;
bool        go = true;
bool        click;
SDL_Event   event;
SDL_Surface *screen;
 
/*
** Initialisation de la fenetre qui contiendra notre scène
*/
bool    initGL()
{
    if (SDL_Init(SDL_INIT_VIDEO))                                               //On démarre la SDL avec le système d'affichage
    {                                                                           //et on vérifie qu'elle se soit bien chargée
        std::cerr << "SDL_Init : [FAILED]" << std::endl;                        //On écrit d'ou vient la panne
        return (false);                                                         //et on s'en va
    }
    SDL_WM_SetCaption("OpenGL Rox", NULL);                                      //On ajoute un titre à notre future fenetre
    if (!(screen = SDL_SetVideoMode(WIN_X, WIN_Y, 32, SDL_OPENGL)))             //On set le système d'affichage
    {                                                                           //et on vérifie que tout se soit bien passé
        std::cerr << "SDL_SetVideoMode : [FAILED]" << std::endl;                //On écrit d'ou vient la panne
        return (false);                                                         //et on s'en va
    }
    glEnable(GL_DEPTH_TEST);                                                    //Activation des tests de profondeur du z-buffer
    SDL_WarpMouse(screen->w / 2, screen->h / 2);                                //On centre le pointeur de la souris au milieu de notre fenetre
    return (true);
}
 
/*
** Gestion du temps pour chaque tour de boucle de notre programme
*/
void	taketime(bool cas)                                                      //cas : différencier le moment d'appel dans la boucle
{
  if (!cas)                                                                     //cas 0 : on est en début de boucle
    sTime = SDL_GetTicks();                                                     //alors on prend le temps au départ de la boucle
  else                                                                          //cas 1 : on est en fin de boucle
    {
      cTime = SDL_GetTicks();                                                   //alors on prend le temps en fin de boucle
      eTime = cTime - sTime;                                                    //On calcule le temps écoulé entre le début et la fin
      if (eTime < 10)                                                           //et si la boucle a duré moins de 10ms
        SDL_Delay(10 - eTime);                                                  //On met en pause le programme pour 10ms moins le temps déjà écoulé
    }
}
 
/*
** On déclare les objets de notre scène
*/
void    drawsquare(bool cas)                                                    //cas : différencier le mode de rendu (RENDER/SELECT)
{
    if (cas)                                                                    //Cas 1 : on est en mode SELECT, le picking est actif
        glLoadName(1);                                                          //alors on attribut un nom (1) à l'objet qui suit
    glColor3ub(255, 255, 255);                                                  //On déclare la couleur de l'objet (pour le coup : blanc)
    glBegin(GL_QUADS);                                                          //On déclare le type de l'objet
        glVertex3d(0, 0, 0);                                                    //On décrit chacun des 4 points que comprend notre carré
        glVertex3d(0, 10, 0);
        glVertex3d(10, 10, 0);
        glVertex3d(10, 0, 0);
    glEnd();                                                                    //On déclare la fin de notre objet
                                                                                //On recommence avec un carré rouge
    if (cas)                                                                    //Cas 1 : on est en mode SELECT, le picking est actif
        glLoadName(2);                                                          //alors on attribut un nom (2) à l'objet qui suit
    glColor3ub(255, 0, 0);                                                      //On déclare la couleur de l'objet (pour le coup : rouge)
    glBegin(GL_QUADS);                                                          //On déclare le type de l'objet
        glVertex3d(3, 3, 0.2);                                                  //On décrit chacun des 4 points que comprend notre carré
        glVertex3d(3, 7, 0.2);
        glVertex3d(7, 7, 0.2);
        glVertex3d(7, 3, 0.2);
    glEnd();                                                                    //On déclare la fin de notre objet
}
 
/*
** On décortique ce que le picking nous renvoie
*/
void    processHits(GLint hits, GLuint *buffer)                                 //hits : nombre d'objets touchés ; buffer : pointeur sur le buffer de selection
{
    GLuint  names;                                                              //Sauvegardera le nombre de noms d'un Hit
    GLuint  *ptr;                                                               //Pointeur pour parcourir le buffer
 
    std::cout << "hits = " << hits << std::endl;                                //On affiche le nombre de Hit
    ptr = (GLuint *)buffer;                                                     //On fait pointer notre pointeur sur celui du buffer
    for (int i = 0; i < hits; i++)                                              //Et on parcourt tous nos Hits
    {
        names = *ptr;                                                           //Sauvegarde du nombre de noms du Hit
        std::cout << " number of names for this hit = " << names << std::endl;  //Affichage du nombre de noms du Hit
        ptr++;                                                                  //On déplace le pointeur dans la mémoire
        std::cout << "  z1 is " << (float)*ptr / 0x7fffffff;                    //Affichage de la valeur minimale de la coordonnée Z
        ptr++;                                                                  //On déplace le pointeur dans la mémoire
        std::cout << " z2 is " << (float)*ptr / 0x7fffffff << std::endl;        //Affichage de la valeur maximale de la coordonnée Z
        ptr++;                                                                  //On déplace le pointeur dans la mémoire
        std::cout << "   NAMES ";                                               //Affichage pour faire joli
        for (unsigned int j = 0; j < names; j++)                                //On parcourt tous les noms du Hit
        {
            std::cout << *ptr << std::endl;                                     //Affichage du nom
            ptr++;                                                              //On déplace le pointeur dans la mémoire
        }
        std::cout << std::endl;                                                 //Affichage pour faire joli
    }
    std::cout << std::endl << "--------------------" << std::endl << std::endl; //Affichage pas pour faire joli mais pour y voir plus clair
}
 
/*
** On regarde ce qu'il se cache sous le pointeur de la souris
*/
void    picking()
{
    GLuint  selectBuf[BUFSIZE];                                                 //Création d'un buffer de sélection de la taille de BUFSIZE
    GLint   hits;                                                               //Contiendra le nombre d'objet touchés par le pointeur de la souris
    GLint   viewport[4];                                                        //Contiendra les valeurs du viewport
 
    glGetIntegerv(GL_VIEWPORT, viewport);                                       //Récupération des valeurs du viewport
 
    glSelectBuffer(BUFSIZE, selectBuf);                                         //Etablit un buffer pour les valeurs du mode SELECT
    (void)glRenderMode(GL_SELECT);                                              //Sélection de la méthode de rastérisation
 
    glInitNames();                                                              //Initialisation de la pile de nom
    glPushName(0);                                                              //On initialise la pile de nom avec (0)
 
    glMatrixMode(GL_PROJECTION);                                                //On passe par la matrice de projection
    glPushMatrix();                                                             //On sauvegarde la matrice courante
    glLoadIdentity();                                                           //et on la réinitialise
    gluPickMatrix((GLdouble) mx, (GLdouble) (viewport[3] - my), 2.0, 2.0, viewport); //On définit la région du picking et sa précision
    gluPerspective(70, float(WIN_X / WIN_Y), 0.1, 1000);                        //On donne à notre matrice les proportions de la scène
 
    drawsquare(true);                                                           //On affiche les 2 carrés et on leur attribut un (ou plusieurs) nom(s)
 
    glPopMatrix();                                                              //On recharge la matrice précédemment sauvegardée
    glPopName();                                                                //On supprime le nom de la pile
    glFlush();                                                                  //On flush les commandes OpenGL
 
    hits = glRenderMode(GL_RENDER);                                             //On récupère le nombre d'objets touchés tout en sortant du mode SELECT
    processHits(hits, selectBuf);                                               //On traite notre sélection
}
 
/*
** On crée un rendu graphique
*/
void    draw()
{
    glViewport(0, 0, WIN_X, WIN_Y);                                             //Création de la taille du ViewPort pour indiquer les frontières du cadrage actif
    glMatrixMode(GL_PROJECTION);                                                //On passe par la matrice de projection
    glLoadIdentity();                                                           //et on la réinitialise pour éviter de cumuler les transformations
 
    gluPerspective(70, float(WIN_X / WIN_Y), 0.1, 1000);                        //On donne les proportions de notre scène en modifiant la matrice courante
    glMatrixMode(GL_MODELVIEW);                                                 //On passe par la matrice modelview
    glLoadIdentity();                                                           //et on la réinitialise pour éviter de cumuler les transformations
 
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);                         //Effacement du tampon d'affichage
    gluLookAt(-10, -10, 10, 0, 0, 0, 0, 0, 1);                                  //Mise en place du point de vue
 
    drawsquare(false);                                                          //On affiche seulement les 2 carrés sans leur attribuer de nom
 
    glFlush();                                                                  //Flushage des commandes OpenGL
    SDL_GL_SwapBuffers();                                                       //Affichage du buffer dans la fenetre
}
 
/*
** On gère les évènements (clavier / souris)
*/
void	checkevents()
{
    if (event.type == SDL_QUIT)                                                 //Si on clique sur la croix pour fermer la fenetre
        go = false;                                                             //on passe go a false
    else if (event.type == SDL_KEYDOWN)                                         //Si un bouton du clavier est appuyé
        if (event.key.keysym.sym == SDLK_ESCAPE || event.key.keysym.sym == SDLK_DELETE) //et que c'est l'un de ceux-là (Echap ou Suppr)
            go = false;                                                         //on passe go a false
    if (event.type == SDL_MOUSEMOTION)                                          //Si on bouge la souris
    {
        mx = event.motion.x;                                                    //On sauvegarde sa position en x
        my = event.motion.y;                                                    //On sauvegarde sa position en y
    }
    else if (event.type == SDL_MOUSEBUTTONDOWN)                                 //Si on clique sur l'un des boutons de la souris (molette haut/bas compris)
    {
        if (event.button.button == SDL_BUTTON_LEFT)                             //et que c'est le click gauche
            click = true;                                                       //on passe le click a true
    }
    else if (event.type == SDL_MOUSEBUTTONUP)                                   //Si on relache le click sur l'un des boutons de la souris
    {
        if (event.button.button == SDL_BUTTON_LEFT)                             //et que c'est le click gauche
            click = false;                                                      //on passe le click a true
    }
}
 
/*
** Faut bien commencer quelque part
*/
int main(int argc, char **argv)
{
#ifdef WIN32                                                                    //SDL redirige de lui-meme les sorties standard/erreur
  freopen("CON","w", stderr);                                                   //En fonction de l'OS il y aura besoin de réouvrir les sorties
  freopen("CON","w", stdout);                                                   //pour afficher sur la console et non plus dans des fichiers
#endif
    if (!initGL())                                                              //Initialisation de la fenetre SDL/OpenGL
        return (1);                                                             //si ca loupe, on quitte en failure
    while (go)                                                                  //Notre programme tourne tant que (go == true)
    {
        taketime(false);                                                        //Prise du temps du départ de la boucle
 
        while (SDL_PollEvent(&event))                                           //SDL parcourt pour nous les évènements clavier/souris et les stocks dans 'event'
            checkevents();                                                      //On fait notre gestion des évènements
        draw();                                                                 //On affiche la scène
        if (click)                                                              //Si le click gauche est appuyé
            picking();                                                          //on tente de picker la scène
 
        taketime(true);                                                         //Prise du temps de la fin de boucle et pause du programme
    }
    SDL_Quit();                                                                 //On ferme la fenetre SDL et toute autre initialisation liée à elle
 
    return (0);                                                                 //Le programme quitte correctement
}
je me suis aidé des liens suivant :
http://glinfrench.apinc.org/article.php3?id_article=83
http://helios.univ-reims.fr/Labos/LE...enGL/td10.html
http://www.lighthouse3d.com/opengl/picking/

en espérant avoir servit
cordialement