Author Topic: Picking avec openGL  (Read 8343 times)

0 Members and 1 Guest are viewing this topic.

Offline ok3anos

Picking avec openGL
« on: 21 December 2010 à 19:22:56 »
Bonjour,

Quelqu'un s'est-il déjà essayé au picking d'objets 3D avec openGL (pointage/récupération d'un objet 3D coordonnées x,y,z par la souris coordonnées 2D OGL) ?

J'ai trouvé ce tuto avec glLoadName() http://gpwiki.org/index.php/OpenGL:Tutorials:Picking mais dès que je fais un hit il me liste tous les objets!!

J'ai essayé le color picking (attribuer une couleur unique a chaque objet puis faire un glReadPixels()) mais c'est encore pire (là il ne trouve rien)!!

Quelqu'un aurait-il une autre méthode pour faire correspondre les coordonnées 2D OGL de la souris et des coordonnées 3D ou m'expliquer pourquoi ça ne marche pas ???????

Merci d'avance.







Offline krabob

  • Base
    • Pouet.net
    • View Profile
    • www.m4nkind.com
  • Ancienneté: 1994
  • Groupe: Mankind
  • Rôle: code amiga / linux / OpenGL
  • Ville: Toulouse
Re : Picking avec openGL
« Reply #1 on: 21 December 2010 à 20:26:22 »
bah ouai, quand tu utilises des gros engine bien fait, tu as en général des fonctions picking ecran qui vont bien,
 ... mais quand tu es demomaker et que tu fais ton truc bas niveau avec ton moteur à toi, faut tout se taper !

D'abord faut bien maîtriser comment fonctionnent ta matrice camera (posé avec un glfrustum() ou un glortho(), et ta matrice modelview:
tu devrais etre capable de projeter un point à l'écran et de retrouver exactement la même position 2D que GL, pour valider ta maitrise sur la projection.
 Aprés, ben tu fais "les equations inverses": tu retrouves déjà l'équation de la ligne qui correspond à la projection de ton pixel d'écran, dans l'espace écran... et tu refais tout ce que tu fais dans ton moteur "à l'envers"  (appliquer l'inverse de la modelview pour mettre la ligne dans le repaire de l'objet a tester par example).

... normalement, le color picking c'est plus simple, mais faut tout redessiner sur un ecran off (FBO ou backscreen).. normalement en GL, tu passes forcément par glReadPixels avec ça: fait gaffe, ça prend en compte le glFrameBuffer() actif si je me souviens bien. Attention: si ton target est en 16 bit, ou si tu as déssiné en float et que tu lis en byte, ta couleurs peut perdre un bit de précision et pas etre pris pour la bonne.
« Last Edit: 21 December 2010 à 20:29:02 by krabob »
Votez comme ça Mélenchon ... ou Clément Wittman, ... ou Eva ! Oo

okeanos

  • Guest
Re : Picking avec openGL
« Reply #2 on: 22 December 2010 à 10:22:45 »
Merci pour ses explications,
Pour la matrice de projection, il s'agit juste d'un gluPerspective(), donc à priori le truc basique qui ne doit pas poser de problèmes.

J'ai viré tout mon code et j'ai tout repris de zéro! (La grosse galère!), et je me suis rendu compte que le picking en OpenGL c'était quand même assez lourd! =)

Bref, il vaut mieux ne pas utiliser les glLoadName() en dehors du rendermode GL_SELECT sinon apparemment ça merde (première erreur résolue)
Après avoir fait tout ça j'ai affiché 3 jolis cubes pour tester le picking. Cette fois il me sélectionnait bien les éléments voulus mais avec un décalage sur y!
J'ai tout repris , je ne voyais pas le problème... et là miracle j'ai compris!! Les coordonnées y sont inversées en OGL par rapport aux coordonnées de la souris (précision j'utilise l'API windows pour la fenêtre).
donc après avoir fait un MousePt.y = (int) g_window->screeny - HIWORD(lParam), je me retrouve avec les coordonnées qui correspondent et là ça marche super bien!

Donc, je me dis que mon code devait bien marcher, j'ai juste merdé sur les coordonnées de la souris... Le truc con quoi!


Offline ok3anos

Re : Picking avec openGL
« Reply #3 on: 22 December 2010 à 12:53:34 »
Autre précision importante,
la matrice de rotation doit être placée avant le glLoadName()

donc pour résumer:


1) Il ne faut utiliser que le glLoadName() en mode GL_SELECT sinon problème! (pas sûr mais dans le doute je m'abstiens)
2) Mettre la matrice de rotation avant le glLoadName() sinon ça ne marche pas ou pas correctement en tout cas.
3) la coordonnée Y de WinAPI est inversée par rapport au Y OGL  (et vice-versa) !! donc petit trick: MousePt.y = (int)g_window->screeny - HIWORD(lParam); pour avoir la correspondance.
4) ne pas oublier de swapper le buffer en mode GL_SELECT et d'avoir la même perspective en mode GL_RENDER et en mode GL_SELECT.

Ca marche impeccable. C'est même très précis... Enfin, j'ai quand même passé une journée dessus!

« Last Edit: 22 December 2010 à 14:18:56 by ok3anos »

Offline ponce

Re : Picking avec openGL
« Reply #4 on: 22 December 2010 à 16:15:12 »
Alors pour moi il y a deux méthodes :

- méthode compliquée mais correcte : tu fais l'algo du raycasting. Tu lances un rayon qui passe par ton pixel
C'est bien compliqué du coup, pour une scène large il faut une structure d'accélération etc... Pour tester l'intersection du rayon avec un objet il faudra souvent passer le rayon dans l'espace objet ie le transformer par la matrice de l'objet.

- méthode nawak avec un readback : tu lis le buffer à l'endroit du pixel cliqué, tu inverses la matrice world -> screen, tu transforme ton point et tu retrouve en espace monde. Là tu cherche un objet proche. J'ai du code qui fait la première partie, MP pour plus de détails. Sur la précision du depth-buffer : il ne faut pas que la rapport zfar / znear soit trop élevé genre plus de 9/10. Généralement le désavantage c'est le readback qui stalle ton GPU (mais bon vu que tu clique pas en continu ça va).

Pour tout ça c'est plus facile si tu fais toi-même tes matrices au lieu d'utiliser les fonctions d'OpenGL, j'ai du code domaine public qui fait ça et Patapom aussi.

Perso je pense qu'utiliser glLoadName et GL_SELECT c'est mal mais bon si ça marche touche rien.

« Last Edit: 22 December 2010 à 16:23:19 by ponce »

Offline flure

  • Base
    • Pouet.net
    • View Profile
  • Ancienneté: 1998
  • Groupe: PoPsY TeAm
  • Rôle: Codeur Linux
  • Ville: Lyon
Re : Picking avec openGL
« Reply #5 on: 22 December 2010 à 18:10:01 »
J'aurais une autre méthode. Je sais pas si c'est plus simple (il me semble que oui) ou plus rapide (il me semble que non) :

1) tu fais le rendu normalement à l'écran
2) tu fais le rendu dans un offscreen, mais un affectant une couleur unique par objet, qui va te servir d'ID (donc pas de shading etc)
3) tu lis le pixel dans l'offscreen à la coordonnée de ta souris, ça te donne l'ID de ton objet

Offline ok3anos

Re : Re : Picking avec openGL
« Reply #6 on: 22 December 2010 à 20:14:21 »

- méthode compliquée mais correcte : tu fais l'algo du raycasting. Tu lances un rayon qui passe par ton pixel
C'est bien compliqué du coup, pour une scène large il faut une structure d'accélération etc... Pour tester l'intersection du rayon avec un objet il faudra souvent passer le rayon dans l'espace objet ie le transformer par la matrice de l'objet.

J'ai vu cette méthode. C'est pas mal, mais la mise en oeuvre est trop fastidieuse pour ce que je veux en faire (quoique... vu le temps que j'ai passé dessus ;) )...

J'ai aussi vu une méthode avec gluProject() et gluUnproject(), mais je ne sais pas ce que ça donne.

Quote
Perso je pense qu'utiliser glLoadName et GL_SELECT c'est mal mais bon si ça marche touche rien.

Nan, je ne touche plus à rien! :D
Je sais pas si c'est mal ou pas, mais pour ce que je veux faire ça marche sur toutes les résolutions d'écran.

@flure: Oui ta méthode c'est celle du color picking. Le problème c'est que tu rends la scène en offscreen alors point de vue perfs c'est moyen. J'ai utilisé cette méthode qui ne marchait pas mais vu que j'avais le Y souris inversé... C'est normal! :)

Offline TomS4wy3R

Re : Picking avec openGL
« Reply #7 on: 23 December 2010 à 10:54:00 »
@Ok3anos : Apparemment le mode sélection d'Opengl serait très lent sur certains drivers récents. Dans le doute, à titre perso j'utilise le color picking (comme flure).

Offline flure

  • Base
    • Pouet.net
    • View Profile
  • Ancienneté: 1998
  • Groupe: PoPsY TeAm
  • Rôle: Codeur Linux
  • Ville: Lyon
Re : Picking avec openGL
« Reply #8 on: 23 December 2010 à 12:19:22 »
Et puis le color picking on peut aussi éventuellement le faire par exemple juste avec les bounding {boxes|spheres}, dans un offscreen de plus basse résolution, etc...

Enfin perso je ne l'ai jamais fait, mais si j'avais à le faire j'essayerais ça en premier...

Offline u2Popsy

  • Base
    • View Profile
    • u2 Blog
  • Ancienneté: 1996
  • Groupe: PoPsY TeAm
  • Rôle: coder
  • Ville: Lyon
Re : Picking avec openGL
« Reply #9 on: 23 December 2010 à 13:11:03 »
Quote
- méthode compliquée mais correcte : tu fais l'algo du raycasting. Tu lances un rayon qui passe par ton pixel
C'est bien compliqué du coup, pour une scène large il faut une structure d'accélération etc... Pour tester l'intersection du rayon avec un objet il faudra souvent passer le rayon dans l'espace objet ie le transformer par la matrice de l'objet.

Ce n'est pas compliqué du tout il suffit d'avoir l'algorithme qui tu permet de savoir si un rayon 3D touche un triangle ( tu devrais trouver ca par ici )
même avec une scène larges avec plusieurs 100K de triangles sans aucune accélération ( bouding box, Octree )  tu ne fais finalement qu'un teste lorsque l'utilisateur bouge ou clic sa souris, soit une requête qui n'intervient même pas 1 fois par frame, cela reste négligeable.
pour calculer le rayon tu procède ainsi :
StartRayon = vec3( PositionScreen.x, 1-PositionScreen.y, startZ ) * MatriceInverse( WorldToScreen )
EndRayon = vec3( PositionScreen.x, 1-PositionScreen.y, EndZ ) * MatriceInverse( WorldToScreen )

ensuite :
pour chaque triangle T de la scene
 si T est coupé par rayon( StartRayon, EndRayon )
 alors ajouter T dans liste de triangle touchés
fin

ta fonction d'intersection peut aussi renvoyé la distance sur le rayon qui te permettra de ne choisir que le 1er.

Voila les autres technique a base d'images fonctionnent aussi mais elle seront moins précises et paradoxalement plus lourde a mettre en place si tu fais un rendu de couleur dans la carte graphique.

a+



Offline Patapom

  • Base
    • View Profile
    • www.patapom.com
  • Ancienneté: 1988
  • Groupe: Bomb!
  • Rôle: Coder
  • Ville: Lyon
Re : Picking avec openGL
« Reply #10 on: 23 December 2010 à 13:26:11 »
Voila les autres technique a base d'images fonctionnent aussi mais elle seront moins précises et paradoxalement plus lourde a mettre en place si tu fais un rendu de couleur dans la carte graphique.

Ouais mais t'es pas obligé de garder une copie de la géométrie en mémoire système... 'fin après c'est un choix à faire. Au pire tu download la géométrie depuis la carte graphique vers la mémoire système objet par objet uniquement quand tu fais un lancer de rayon, comme ça tu perds presque pas de mémoire, mais ça bouffe + de temps.

Par contre, l'intérêt fondamental d'une methode par tagging de couleur c'est aussi de te permettre de picker des objets procéduraux, comme par exemple un brin d'herbe instancié et déplié par geometry shader, sinon il faudrait refaire toute la procédure côté software...
Finalement, si t'as codé une depth-pass ou une passe de shadow mapping et que tes objets peuvent être rendus dans une depth/shadow map avec un shader surchargé (i.e. override du matériau de base) alors ils peuvent aussi sans doute être rendus dans un buffer d'ID avec un autre shader non ?

'fin c'est que de la théorie, je l'ai jamais fait en pratique, mais si je devais le faire, je trouverais ça plus avantageux de faire le picking en screen space avec un buffer de tags...
.  Pom  .

Offline xoofx

  • Base
    • Pouet.net
    • View Profile
    • xoofx
  • Ancienneté: 1989
  • Groupe: FRequency
  • Rôle: code (+musique), web
  • Ville: Grenoble
Re : Picking avec openGL
« Reply #11 on: 23 December 2010 à 13:39:02 »
'fin c'est que de la théorie, je l'ai jamais fait en pratique, mais si je devais le faire, je trouverais ça plus avantageux de faire le picking en screen space avec un buffer de tags...
Je suis d'accord aussi, c'est beaucoup plus viable avec des techniques procédurales, utilisant du geometry-shader ou autre, puis ça s'intègre bien dans un système type defered, une fois que l'on a ça, c'est pas compliqué de l'ajouter...

Offline u2Popsy

  • Base
    • View Profile
    • u2 Blog
  • Ancienneté: 1996
  • Groupe: PoPsY TeAm
  • Rôle: coder
  • Ville: Lyon
Re : Picking avec openGL
« Reply #12 on: 23 December 2010 à 14:14:39 »
Pata & @lex :

faites attention a l'Overengineering :) ca sert a rien d'après moi de pouvoir picker un poil de cul procédural généré par un Geom compute shader 5.0.
Dans la vie réelle je pense qu'un simple gizmo placé au centre d'un objet permettra surement de sectionné convenablement ce que l'utilisateur désir..
Dans ce cas avoir une database de BoudingBox ou d'un mesh simplifié me semble être la solution la plus efficace ( pas de dépendance de donnée avec le GPU ) et est indépendant de la résolution de l'ecran.

Après tout ce discute et tout dépend du résultat désiré.

Offline Patapom

  • Base
    • View Profile
    • www.patapom.com
  • Ancienneté: 1988
  • Groupe: Bomb!
  • Rôle: Coder
  • Ville: Lyon
Re : Picking avec openGL
« Reply #13 on: 23 December 2010 à 14:27:54 »
Pata & @lex :

faites attention a l'Overengineering :) ca sert a rien d'après moi de pouvoir picker un poil de cul procédural généré par un Geom compute shader 5.0.
Dans la vie réelle je pense qu'un simple gizmo placé au centre d'un objet permettra surement de sectionné convenablement ce que l'utilisateur désir..
Dans ce cas avoir une database de BoudingBox ou d'un mesh simplifié me semble être la solution la plus efficace ( pas de dépendance de donnée avec le GPU ) et est indépendant de la résolution de l'ecran.

Après tout ce discute et tout dépend du résultat désiré.

Ouais, c'est clair que picker au pixel on en a rien à foutre en pratique. Par contre je maintiens l'intérêt pour les trucs procéduraux !
En contrepartie, en faisant un picking en screen space, on perd la possibilité de faire comme dans Max, c'est-à-dire de pouvoir picker tous les objets le long d'un rayon chacun son tour si on déplace pas la souris. Et ça, c'est drôlement pratique !
Dans l'outil qu'on utilisait à Widescreen, j'avais implémenté un système comme tu décris, David : on avait une copie en mémoire de la géométrie et je ray-tracais dedans lors d'une opération de picking puis ça me renvoyait la liste des intersections, triées.

C'était également super utile pour faire plein d'autres trucs : un baking d'AO, le placement d'objets dans le décor, l'alignement automatique avec le sol, l'aplatissement de trucs contre les murs (posage de décals, entre autres), des calculs d'angles et de distances pour les graphistes, des outils de peinture pour le terrain (végétation, painting du texture atlas mixer, herbe), etc.
.  Pom  .