Pages: 1
Bonjour à tous, j'aimerai savoir comment sélectionner un objet 3d qui est lui même dans un objet 3d. Mon objectif est de pouvoir sélectionner n'importe quel objet 3d de ma scène. J'utilise pour ça les fonctions getRayFromScreenCoordinates ou getSceneNodeFromScreenCoordinatesBB mais rien n'y fait. Le volume contenant prime toujours.
Voici quelques images qui illustrent mon problème.
Tous les screenshots représentent en gros des robots dans des salles. J'ai mis une flèche noire pour matérialiser le curseur de ma souris qui n'est pas vue par l'imprime écran.
Tous les objets 3d sont des mesh de type ".3DS" ou ".OBJ". Ma sélection d'objet se visualise par l'affichage en "wireframe" de celui-ci. Visiblement, l'objet est sélectionnable lorsqu'une partie de lui même n'est pas à l'intérieur d'un autre objet.
Soit, est-il possible de contourner ce problème? Le filtre "idBitMask" des méthodes getRayFromScreenCoordinates et getSceneNodeFromScreenCoordinatesBB peut-m'aider ?
Merci à vous.
Dernière modification par Gehogor (02-06-2009 18:58:43)
Hors ligne
Tous les objets 3d sont des mesh de type ".3DS" ou ".OBJ". Ma sélection d'objet se visualise par l'affichage en "wireframe" de celui-ci. Visiblement, l'objet est sélectionnable lorsqu'une partie de lui même n'est pas à l'intérieur d'un autre objet.
J'avoue ne jamais m'être penché sur ce genre de problème.
Pour ce qui est des objets contenus (et donc caché si l'on peu dire et si je ne me trompe pas) , je dirais que dans
le mesure ou tu fais un test de picking, tu passes dans ce cas tous les objets de ta scene en revu pour savoir celui
ou ceux qui se trouve dans la ligne de pointage.
Donc, même les objets contenu doivent être détectés. Après, à toi de pondre, je pense, un algo pour par exemple ne
retenir que le plus proche, ou encore de switcher objet par objet, du plus proche au plus éloigné par exemple au
fil des click de souris. non ?
Hors ligne
En effet, hier j'ai fini par me dire que je devais faire l'algo moi même. Mais avant ça, en espérant éviter de réinventer la roue, j'aimerai savoir si le fonctionnement des méthodes "getRayFromScreenCoordinates" et "getSceneNodeFromScreenCoordinatesBB" confirment bien les faits constatés, à savoir, un objet dans un autre objet n'est pas visible. La petite phrase d'explication sur la doc ne précise pas ce point. N'étant pas un spécialiste, je me penche vers vous.
Donc, en revenant sur ta réponse, il faut que j'utilise la méthode "getRayFromScreenCoordinates" pour obtenir un line3d et qu'après je convertisse mes mesh en ITriangleSelector afin d'utiliser la méthode "getCollisionPoint". Et, que je fasse le test pour tous mes objets...?
Merci encore et bonne nuit.
Dernière modification par Gehogor (04-06-2009 00:57:10)
Hors ligne
je ne sais pas si tu as lu ce sujet, mais il pourrait très certainement bien éclairer tes lanternes...
http://www.irrlicht.fr/forum/viewtopic.php?id=900
Hors ligne
En effet, j'avais déjà lu ce sujet. Du coup, je vais opter pour la solution des TriangleSelectors. Dès le bon fonctionnement de celui-ci, je ferai un petit bilan pour tout remettre à plat et le code qui va bien sur cette même discussion.
Merci encore, bon weekend et à la semaine prochaine.
Hors ligne
Bon WE a toi, en attendant de tes nouvelles
Hors ligne
Bonsoir, je viens donc aux nouvelles...
J'aurais souhaité faire un bilan sur les petites fonctions de collision et de détections d'objet mais avant ça je voulais faire un affichage du résultat avec la gui d'Irrlicht, et finalement ça me pose plus de problème que le problème initial:
Une fois ma liste de ISceneNode remplie grâce à une fonction que j'ai nommée "QList<ISceneNode*> findNodeWithScreenPos(position2d<s32> pos);" (dons ça fonctionne bien, comme tu me l'avais indiqué tmyke, merci...), je voulais l'afficher dans un menu contextuel. Et là, j'affiche bien mon menu contextuel avec tous les noms des objets croisés par le curseur de ma souris mais impossible de cliquer dessus, d'ailleurs, rien n'est cliquable. J'ai essayé de rajouter rapidement des boutons, des combos, le fenêtre "addColorSelectDialog(L"Vive les couleurs ........");" et rien, impossible de sélectionner, de bouger les éléments de celle-ci, tous s'affichent mais rien n'est cliquable.
Avez vous une idée sur ce problème? J'ai pris plusieurs exemples de la doc et du forum pour comparer et rien de plus une nouvelle fois...
Connaissez vous des pièges dans lesquelles les gens tombent facilement sur ce sujet?
Merci encore. Sinon, et bien bonne soirée à vous.
Hors ligne
Si je comprends bien, tu veux dire par là que tu n'a aucune interaction possible avec les élément gui que tu affiche ?
(passes-tu bien par un 'event.GUIEvent' pour intercepter les dans IEventReceveiver tes événement éventuellement lié a ta gui ? )
Hors ligne
Oui, tout à fait. Tu as parfaitement compris. Il y a l'affichage mais sans interaction possible. Et en plus, je passe bien par un 'event.GUIEvent' pour intercepter les évènements dans IEventReceveiver.
J'avais déjà implémenté la méthode OnEvent pour ma souris et quelques boutons du clavier, et tout ça fonctionnent correctement.
De plus, j'ai recompilé un des exemples d'Irrlicht (le UserInterface) et là, ça fonctionne parfaitement, je peux cliquer comme un fou, même si le "OnEvent est commenté, on peut quend même cliquer mais ça ne fait aucune action évidemment.
Par contre, sur mon code principale, aucune interaction. Les fenêtres se rafraichissent, si je change du texte, genre un compteur qui s'incrémente, on voit bien le changement. Si j'ajoute d' autres fenêtres ou IGUiElement; il n'y a pas de soucis à part qu'il n'y a aucune interaction possible. Très étranges.
J'espère que la présence de la librairie Qt n'y est pour rien sachant que je créé une fenêtre purement "Irrlicht" (On peut inclure une fenêtre Irrlicht dans une autre fenêtre avec le "WindowId" de "SIrrlichtCreationParameters" mais j'ai abandonné cette solution car cette partie n'est pas implémentée pour linux, mais que pour Windows. Dommage...) Du coup, j'ai opté pour la création simple d'une fenêtre par Irrlicht, fonctionnel pour Windows et Linux. Soit, je pense être dans un cas classique d'utilisation d'Irrlicht.
Oups, désolé pour cette parenthèse, c'est juste pour donner des informations, le code est bien trop grand pour être mis en post.
Sur ce, bonne nuit en espérant .... ET merci.
Hors ligne
J'espère que la présence de la librairie Qt n'y est
Voici malgré tout une amorce d'explication, du moins peut-être. JE sais que ce n'est certainement pas facile, mais t'est-il possible
de faire tourner (même boiteusement) ton application sans Qt, pour voir si il y a des changements ?
Hors ligne
Bon, là j'ai fait très fort en matière de bêtise... Finalement, j'ai fait comme tu m'as dit, j'ai tout viré, soit plus de Qt, plus de méthode perso, plus rien, et là, toujours un problème de fonctionnement, je RE_RE_RE_regarde mon code pour le comparer avec un des exemples d'Irrlicht et là, soudain, je remarque que la méthode "OnEvent" se finie par un "return false" alors que moi, j'avais mis un "return true" à la fin....
Voilà c'était juste ça, je pense qu'en faite je devais bloquer tout autre évènement comme le "déplacer" ou encore le "cliquer" en retournant constamment true dans la méthode "OnEvent".
Et bien, Merci .
Dernière modification par Gehogor (17-06-2009 00:54:45)
Hors ligne
L'essentiel c'est que tu es trouvé la solution, et que tu puisse continuer à avancer
Hors ligne
Bon, comme promis, je vais faire un petit bilan sur l'intitulé de cette discussion, à savoir, comment sélectionner un objet dans un objet.
Tout d'abord pour faire simple, j'ai déclaré dans mon .h un tableau de ITriangleSelector:
ITriangleSelector* m_TriangleSelector[NB_MAX_OBJETS_3D]; // Objet Irrlicht représentant les objets 3D en triangle 3D
int m_NbObjectForCollision; // Nombre d'objet détecté dans le scène 3D dont l'identifiant est différent de -1
int m_Node_ID[NB_MAX_OBJETS_3D]; // Représentation des identifiants des objets 3D classés
Pour des raisons particulières, j'ai créé un tableau statique, il est clair qu'il est préférable de faire une liste dynamique moins gourmande en mémoire.
Ensuite, j'ai créé une fonction qui scanne une grande fourchette d'ID pour récupérer tous les nodes présents dans la scène dont l'ID est différent de-1:
void QIrrlicht::ComputeCollision()
{
m_NbObjectForCollision=0;
if(m_Smgr->getSceneNodeFromId(-1) != NULL){
printf("Il y a au moins un objet 3D avec l'identifiant à -1");
printf("Si l'identifiant d'un objet 3D est à -1, il ne sera pas pris en compte pour la gestion de la sélection");
}
for(int i=0;i<NB_MAX_OBJETS_3D;i++){ // NB_MAX_OBJETS_3D fixé à 2000
ISceneNode* Node = m_Smgr->getSceneNodeFromId(i); // Récupération des nodes en fonction de leur ID
if(Node != NULL){
m_TriangleSelector[m_NbObjectForCollision] = m_Smgr->createTriangleSelectorFromBoundingBox(Node);
// On attache au node un ITrangleSelector pour faire de la collision Volume/Volume par exemple mais inutile pour notre cas.
Node->setTriangleSelector(m_TriangleSelector[m_NbObjectForCollision]);
m_Node_ID[m_NbObjectForCollision] = i; // On peut récupérer cette valeur grâce à "int* getNode_ID();"
m_NbObjectForCollision++; // On peut récupérer cette valeur grâce à "int getNbObjectForCollision()"
}
}
}
int* QIrrlicht::getNode_ID() // Récupération du tableau des IDs des nodes classés
{
return m_Node_ID;
}
int QIrrlicht::getNbObjectForCollision() // Récupération du nombre d'objet détecté pour de la sélection ou de la collision
{
return m_NbObjectForCollision;
}
Il faut appeller cette méthode après le chargement d'une scène irrEdit par exemple ou dès l'ajout d'un nouvel élément pour qu'il soit pris en compte.
Maintenant, la dernière fonction, celle qui retourne une liste de "ISceneNode*" en fonction de la position de la caméra (ici "m_Camera_FPS", variable membre qui est ma caméra) et celle de la souris également (ici le paramètre "pos"). Ma liste est en fait une QList car j'utilise Qt pour ce projet.
Petite note: On pourrait très clairement passé le paramètre de la caméra également pour rendre plus portable cette petite méthode.
QList<ISceneNode*> QIrrlicht::findNodeWithScreenPos(position2d<s32> pos) { vector3df outCollisionPoint; triangle3df outTriangle; QList<ISceneNode*> listSceneNode; // Liste locale qui sera retournée line3df line = m_Collision->getRayFromScreenCoordinates(pos,m_Camera_FPS); for(int i=0;i<getNbObjectForCollision();i++) // Permet de récupérer le nombre d'objet pris en compte et transformer en "TriangleSelector" { // S'il y a une collison entre une ligne (projection du curseur de la souris sur le monde en fonction de ma caméra) et un objet 3d if(m_Collision->getCollisionPoint(line,getTriangleSelector()[i],outCollisionPoint,outTriangle) == true) { ISceneNode* node = m_Smgr->getSceneNodeFromId(getNode_ID()[i]); // On récupère le bon ID venant de l'indice "i" if(node != NULL) listSceneNode.append(node); // Ajout du node trouvé dans une liste } } return listSceneNode; // On retourne la liste de node }
Et voilà, après on peut appeler cette méthode dans le gestionnaire des évènements d'Irrlicht par exemple et afficher une boundingbox autour des nodes trouvés....
Je sais que c'est très simple, mais ça peut toujours aider. Bonne soirée à vous.
Dernière modification par Gehogor (20-09-2009 09:19:28)
Hors ligne
Pages: 1