IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

 C++ Discussion :

OpenGL et organisation du code


Sujet :

C++

  1. #1
    Membre actif Avatar de BioKore
    Homme Profil pro
    Dresseur d'Alpaga
    Inscrit en
    Septembre 2016
    Messages
    300
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : Dresseur d'Alpaga

    Informations forums :
    Inscription : Septembre 2016
    Messages : 300
    Points : 219
    Points
    219
    Par défaut OpenGL et organisation du code
    Bonjour à tous,

    J'apprends actuellement à développer avec OpenGL via différents tutoriaux à droite et à gauche (notamment ceux de ce site), et je dois dire que je suis plutôt content de ce que j'arrive à faire jusque là.
    Néanmoins, pour avancer correctement, je souhaiterais en savoir plus sur l'organisation de mon code dans le cadre d'un projet simple mais assez vaste, permettant concaténer l'ensemble des manipulations que fournissent les cours sur lesquels je me base.

    Mon manager de fenêtre est "SFML"

    Aujourd'hui, j'ai pu scinder mon code en différentes parties qui me semblent relativement juste, et qui se répartissent les rôles comme suivant :
    - Main : ne fait rien de spécial si ce n'est instancier et appeler une classe contenant mon manager de fenêtre ainsi que la boucle principale

    - Manager : ici, je configure SFML et ouvre ma fenêtre, lance la boucle principale dans un thread (l'affichage se fait dans ce thread), et continue sur le gestionnaire d'événements (gestion du clavier) dans un autre thread. C'est aussi dans cette classe que je j'instancie les différents objets à afficher

    - solid : le nom n'est peut être pas explicite, mais en gros, c'est la classe "objet" qui défini le comportement d'un objet au sein de mon environnement, comment ce dernier doit agir, gère sa position et les différentes matrices de transformation qui lui sont appliquées etc... Le but final étant de transformer, à terme, cette classe en classe "mère" des différents objets à afficher. Les objets de classe "solid" possèdent un modèle

    - shader : une classe assez simple, permettant de compiler et linker les vertex shaders ainsi que les fragment shaders, et permettant de retourner l'identifiant du programme compilé. Un objet de classe "shader" est instancié dans la classe model ; les codes glsl sont donc chargés et compilés à chaque instanciation d'un modèle...

    - model : nom assez explicite, mais c'est pour cette dernière que je me pose le plus de questions quant à son contenu. A ce jour, les coordonnées des vertex sont codés en dur, mais c'est cette classe qui, dans un avenir proche je l'espère, sera capable de charger les modèles et textures associées. A chaque instanciation, chaque objet compile les shaders, génère les buffers, les bind, leur envoie les data etc... On y retrouve aussi une fonction membre draw(), qui permet l'affichage du modèle à chaque appel (où l'on y retrouve le glDrawElements())

    - camera : je commence à peine à me pencher sur ce sujet, et il me semble pertinent d'avoir une classe dédiée pour configurer et piloter la caméra (on y retrouve donc les glm::lookAt et glm::perspective)

    Ma question est donc la suivante : est-ce vraiment à la classe model de gérer les "Vertex Buffer Object", Element Buffer Object" ou encore les "Vertex Array Objects" ? Car j'ai remarqué que, lorsque j'affiche deux objets différents, le premier modèle est affecté par l'affectation d'un "uniform" (la couleur par exemple) sur le second modèle... J'en déduis donc que, malgré une compilation des shader par instanciation, les ID du programme sont partagés ! J'ai pu aisément contourner cette contrainte, mais si c'est souhaitable, je préfère réorienter mon code maintenant que lorsqu'il sera plus complexe.
    Sinon, où puis-je trouver un tutoriel dans lequel quelques classes minimalistes illustrent une des organisation possible du code ? Sur tous les code que j'ai pu voir jusqu'à maintenant, pour des raison de commodité je pense, tous sont présentés en bloc dans le main.

    Merci d'avance !


    Petite démonstration du résultat actuel (sachant que le tétraèdre rouge tourne sur lui-même et est en couleur "remplie" par défaut) :

    Nom : og_tst.jpg
Affichages : 189
Taille : 24,3 Ko

  2. #2
    Expert éminent sénior

    Avatar de dragonjoker59
    Homme Profil pro
    Software Developer
    Inscrit en
    Juin 2005
    Messages
    2 045
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Software Developer
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2005
    Messages : 2 045
    Points : 11 368
    Points
    11 368
    Billets dans le blog
    10
    Par défaut
    Salut !

    Ce n'est pas au modèle de gérer le shader qui sert à l'afficher.
    En effet, plusieurs modèles peuvent utiliser le meme shader pour se dessiner.

    De mon coté, j'ai une classe SceneNode, qui gère les transformations (translate, rotate et scale) d'un objet.
    Une classe Mesh qui contient les données des sommets d'un objet (VBO), et les indices de ces sommets (IBO ou EBO, selon l'appellation qu'on lui donne).
    J'ai ensuite une classe Material qui contient les données du matériau (diffuse, specular, ...) et les textures associées.
    Enfin, j'ai la classe Object qui contient un Material, un SceneNode et un Mesh
    Si vous ne trouvez plus rien, cherchez autre chose...

    Vous trouverez ici des tutoriels OpenGL moderne.
    Mon moteur 3D: Castor 3D, presque utilisable (venez participer, il y a de la place)!
    Un projet qui ne sert à rien, mais qu'il est joli (des fois) : ProceduralGenerator (Génération procédurale d'images, et post-processing).

  3. #3
    Membre actif Avatar de BioKore
    Homme Profil pro
    Dresseur d'Alpaga
    Inscrit en
    Septembre 2016
    Messages
    300
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : Dresseur d'Alpaga

    Informations forums :
    Inscription : Septembre 2016
    Messages : 300
    Points : 219
    Points
    219
    Par défaut
    Bonjour, et merci pour ce retour rapide.
    Donc ok pour le shader ; je vais voir comment le transcrire ailleurs. Cela me semble effectivement une bonne idée.
    Par contre, tu dis avoir une classe contenant l'ensemble des données de ton model (vbo, ebo), mais finalement à quel moment est-ce que tu les Bind ? C'est ta classe Object qui s'en occupe où est-ce dans une classe encore plus haut niveau ?

    Merci encore, je vais réfléchir à une organisation plus segmentée dès demain.

  4. #4
    Expert éminent sénior

    Avatar de dragonjoker59
    Homme Profil pro
    Software Developer
    Inscrit en
    Juin 2005
    Messages
    2 045
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Bas Rhin (Alsace)

    Informations professionnelles :
    Activité : Software Developer
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2005
    Messages : 2 045
    Points : 11 368
    Points
    11 368
    Billets dans le blog
    10
    Par défaut
    Le binding se fait à un autre niveau, dans la RenderQueue, qui récupère les données nécessaires à la création de son command buffer (je bosse en Vulkan-like, mais faisais grosso modo la meme chose auparavant, c'est juste plus clean en Vulkan).
    Cette render queue est gérée par une render pass, (opaque, transparent, environment, shadow, ...) qui s'occupe au final de créer le shader approprié (mais là c'est assez particulier dans mon moteur, car je génère les shaders à la volée, depuis le C++, ça reste faisable de manière "classique", en utilisant des directives de préprocesseur dans tes shaders).
    Si vous ne trouvez plus rien, cherchez autre chose...

    Vous trouverez ici des tutoriels OpenGL moderne.
    Mon moteur 3D: Castor 3D, presque utilisable (venez participer, il y a de la place)!
    Un projet qui ne sert à rien, mais qu'il est joli (des fois) : ProceduralGenerator (Génération procédurale d'images, et post-processing).

  5. #5
    Membre actif Avatar de BioKore
    Homme Profil pro
    Dresseur d'Alpaga
    Inscrit en
    Septembre 2016
    Messages
    300
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : Dresseur d'Alpaga

    Informations forums :
    Inscription : Septembre 2016
    Messages : 300
    Points : 219
    Points
    219
    Par défaut
    Merci pour ces retours.

    Je n'ai pas la prétention de vouloir réaliser un "moteur graphique" complet non plus. Pour le moment, mes attentes sont de pouvoir suivre les tutoriaux que je réalise à droite et à gauche en modifiant seulement les nouveautés et en conservant un code propre, organisé, facile à comprendre (à mon niveau). Selon moi, j'utiliserais au mieux 2 shader, donc pas vraiment besoin de les créer à la volée..

    Donc, est-ce que dans un code minimal mais propre, ce genre d'organisation fonctionnerait ?

    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
     
     
    void CMesh::initBuffers()
    {
    	// generates buffers
    	glGenVertexArrays(1, &this->m_vao);
    	glGenBuffers(1, &this->m_vbo);
    	glGenBuffers(1, &this->m_nbo);
    	glGenBuffers(1, &this->m_cbo);
    	glGenBuffers(1, &this->m_ebo);
     
    	// generates, bind and fill buffers :
    	glBindVertexArray(this->m_vao);
    		//1) VBO
    		glBindBuffer(GL_ARRAY_BUFFER, this->m_vbo);
    			glBufferData(GL_ARRAY_BUFFER, this->m_vertex.size() * sizeof(GLfloat), &this->m_vertex[0], GL_STATIC_DRAW);
    			glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
    			glEnableVertexAttribArray(0);
     
    		//2) NBO
    		glBindBuffer(GL_ARRAY_BUFFER, this->m_nbo);
    			glBufferData(GL_ARRAY_BUFFER, this->m_normal.size() * sizeof(GLfloat), &this->m_normal[0], GL_STATIC_DRAW);
    			glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
    			glEnableVertexAttribArray(1);
     
    		//3) CBO
    		glBindBuffer(GL_ARRAY_BUFFER, this->m_cbo);
    			glBufferData(GL_ARRAY_BUFFER, this->m_color.size() * sizeof(GLfloat), &this->m_color[0], GL_STATIC_DRAW);
    			glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, (void*)0);
    			glEnableVertexAttribArray(2);
     
    		//3) EBO
    		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->m_ebo);
    			glBufferData(GL_ELEMENT_ARRAY_BUFFER, this->m_element.size() * sizeof(GLfloat), &this->m_element[0], GL_STATIC_DRAW);
     
    	// liberates buffers
    	glBindVertexArray(0);
    	glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    	glBindBuffer(GL_ARRAY_BUFFER, 0);
     
    }
     
    ///// DANS LA CLASSE RENDER, A EXECUTER DANS LA BOUCLE PRINCIPALE /////
    void CRender::draw(const CMesh &obj)
    {
    	glBindVertexArray(this->m_mesh_tst.getVAO());
    	glDrawElements(GL_TRIANGLES, this->obj.getElementSize(), GL_UNSIGNED_INT, 0);
            glBindVertexArray(0);
    }

    In fine, dans ma boucle principale, je veux uniquement avoir à mettre à jour mes objets (matrices etc), la camera, et afficher les objets (et gérer les lumières plus tard quand j'en serais rendu là). Je courrais les performances et sujets plus délicats lorsque j'aurais compris les sujets de base.
    "this.m_render.draw(this->m_object);"


    Merci encore.


    EDIT : Après avoir modifier le code ci-dessus, et en le portant à peu près sous cette forme dans mon code, je n'ai pas d'erreur, mais rien ne s'affiche du coup :/
    Je précise que les shader ont été chargés et activés au préalable. Il va faloir que je creuse un peu plus pour comprendre pourquoi... Personne n'a une petite idée ? Je passerais bien le code complet, mais ça fait un peu long sur le forum ; mais si besoin, je peux le fournir d'une manière ou d'une autre...

  6. #6
    Membre actif Avatar de BioKore
    Homme Profil pro
    Dresseur d'Alpaga
    Inscrit en
    Septembre 2016
    Messages
    300
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Canada

    Informations professionnelles :
    Activité : Dresseur d'Alpaga

    Informations forums :
    Inscription : Septembre 2016
    Messages : 300
    Points : 219
    Points
    219
    Par défaut
    Ok, sujet technique résolu. Le problème d'affichage venait principalement des EBO ! Ces derniers sont de type uint et pas float....
    Deux corrections mineures et le sujet est résolu.

    Question agencement du code donc, je me porte alors sur quelque chose de plus modulaire, comme proposé par "dragonjoker59"

    Néanmoins, si d'autres ont des suggestions / idées (voire même des tutoriels) concernant l'organisation du code, je suis preneur. Je pense que j'ai pas mal de marge de progression question "organisation" ; quelque soit le projet d'ailleurs...

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Persistance et organisation du code
    Par K-Kaï dans le forum Hibernate
    Réponses: 16
    Dernier message: 06/06/2007, 17h01
  2. Organisation du code source
    Par _kal_ dans le forum C
    Réponses: 18
    Dernier message: 04/08/2006, 14h15
  3. organisation du code.
    Par poporiding dans le forum C++
    Réponses: 36
    Dernier message: 13/07/2006, 10h15
  4. organisation du code.
    Par poporiding dans le forum C++
    Réponses: 3
    Dernier message: 28/06/2006, 17h10
  5. Réponses: 4
    Dernier message: 19/09/2005, 17h56

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo