Bonjour à tous,
Je prends un peu le temps d'avancer un projet laissé de côté il y a quelques mois, lié à l'intelligence artificielle, mais dans lequel je nécessite une représentation graphique.
Pour se faire, mon choix s'est porté sur SFML et l'utilisation de GLM pour tout ce qui est déplacements, le but étant de permettre une éventuelle évolution vers un rendu plus complexe et sous openGL. initialement, les déplacements étaient "hard codés" avec les fonctions trigo de base, et fonctionnaient correctement, mais ça avait ses limites.
Le projet est simple, dans un premier temps sans utilisation de mon "moteur IA", et consiste simplement à déplacer des pastilles de couleur dans un espace continu (en 2D), chacune étant indépendante des autres.
J'ai de solides bases en méca générale de part ma formation initiale, mais concernant la compréhension du fonctionnement des transformations GLM, j'ai un peu plus de mal (question d'organisation du code je pense).
En effet, j'ai bien compris le fait de donner une matrice de transformation globale à mon objet, je comprends, bien entendu, l'ordre de ces transformations (rotation puis translation). Mais peu importe la manière dont je traite le sujet, les rotations se font toujours par rapport au repère de base et non par rapport à la position précédente de mon objet.
Étant en période de test, le code est assez simpliste et pas forcément propre. Dans un premier temps, je veux comprendre l'implémentation des transformations avec glm.
Ici, le code de mon objet :
Et là, le code du thread d'affichage (en gros, la boucle principale quoi) :Code:
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 // m_pos : position du centre de la pastille // m_trans : tenseur des transformations (souvent appelé modelView dans les tutos) agent::agent(const float radius): m_pos(.0f, .0f, .0f, 1.0f), m_trans(1.0f), m_radius(radius) { this->m_model.setRadius(radius); // rayon de la pastille this->m_model.setFillColor(sf::Color(50.0f, .0f, .0f)); // couleur de la pastille this->m_model.setPosition(this->m_pos.x - this->m_radius, this->m_pos.y - this->m_radius); // position de la pastille (moins le rayon afin de centrer les coordonnées par rapport à la pastille) } agent::agent(const agent &src): m_pos(src.m_pos), m_trans(src.m_trans), m_model(src.m_model), m_radius(src.m_radius) { this->m_model.setFillColor(sf::Color(50.0f, .0f, .0f)); this->m_model.setPosition(this->m_pos.x - this->m_radius, this->m_pos.y - this->m_radius); } agent::~agent() { } void agent::setPosition(const float &px, const float &py, const float &pz) { this->m_trans = glm::translate(this->m_trans, glm::vec3(px, py, pz)); // la position initiale est intégrée dans le tenseur de l'agent } void agent::rotate(const float &angle) { this->m_trans = glm::rotate(this->m_trans, glm::radians(angle), glm::vec3(.0f, .0f, 1.0f)); // la rotation est applique au tenseur de l'agent } void agent::translate(const float &tx, const float &ty, const float &tz) { this->m_trans = glm::translate(this->m_trans, glm::vec3(tx, ty, tz)); // la translation est appliquée au tenseur de l'agent } void agent::update() { this->m_pos = this->m_trans * this->m_pos; this->m_model.setPosition(this->m_pos.x - this->m_radius, this->m_pos.y - this->m_radius); this->m_trans = glm::mat4(1.0f); // flush du tenseur afin d'éviter de repositionner infiniment l'agent } void agent::display(sf::RenderWindow &win) { this->update(); win.draw(this->m_model); // simple affichage de la pastille par sfml... } // END
Je vous fait grâce de l'implémentation du reste du code, selon moi, inutile à la compréhension du problème.Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 void renderingThread(sf::RenderWindow *win) { win->setActive(true); glViewport(0,0, 800, 600); agent circle(30); // création d'un agent = une pastille de rayon 30 circle.setPosition(400, 300, 0); // on positionne l'agent au centre de la fenêtre circle.display(*win); // affichage de l'agent while(win->isOpen()) { // flush buffers (so the screen) glClearColor(.0f, .0f, .2f, .0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // draw scene here..... //circle.rotate(.2f); //circle.translate(.5f, .0f, .0f); circle.display(*win); win->display(); // --> rendering buffers exchange } }
Le code tel que présenté ci dessus fonctionne bien. Une pastille de couleur rouge est bien affichée au centre de la fenêtre. Mais si je lui demande une rotation, cette dernière se fait depuis le point 0,0,0 et non sur l'objet lui-même.
J'ai bien tenté de conserver le "m_trans" plutôt que de le rendre identité dans la fonction "agent::update()", mais dans ce cas la translation 400, 300, 0 se répète 144 fois par secondes (c'est mon framerate) à partir du moment où m_pos = m_trans * m_pos;
Bref, j'ai l'impression d'être proche de la réponse mais je n'arrive pas à voir comment tourner mon code pour que ça fonctionne... Tous les exemples que je trouve sur le net concernant glm ne traitent quasiment que de son application en 3D sur de l'openGL pur. En ce qui me concerne, openGL viendra plus tard, et en 2D seulement dans un premier temps.
Pour info, il me faut impérativement
- une fonction pour tourner l'objet sur lui-même
- une fonction pour translater (que je déclinerais peut être plus tard en 4 fonctions : avant, gauche, arrière, droite selon l'intégration de mon IA à l'application)
Voilà. Si certains se sont déjà cassés les dents (ou pas d'ailleurs) sur ce sujet, je serais heureux de connaître votre recette ! Merci d'avance.