J'utilise OpenGL depuis un certain temps et j'ai lu un grand nombre de tutoriels. Mis à part le fait que beaucoup d'entre eux utilisent toujours le pipeline fixe, ils jettent généralement toutes les initialisations, les changements d'état et le dessin dans un fichier source. C'est très bien pour la portée limitée d'un tutoriel, mais j'ai du mal à trouver comment le faire évoluer jusqu'à un jeu complet.
Comment répartissez-vous votre utilisation d'OpenGL entre les fichiers? Conceptuellement, je peux voir les avantages d'avoir, disons, une classe de rendu qui restitue purement des trucs à l'écran, mais comment les trucs comme les shaders et les lumières fonctionneraient-ils? Dois-je avoir des cours séparés pour des choses comme les lumières et les shaders?
la source
Réponses:
Je pense que OO OpenGL n'est pas si nécessaire. C'est différent lorsque vous parlez de shader, de modèle, etc. de classe.
Fondamentalement, vous feriez d'abord l'initialisation du jeu / moteur (et d'autres choses). Ensuite, vous chargez des textures, des modèles et des shaders dans la RAM (si nécessaire) et des objets tampons, et téléchargez / compilez des shaders. Après cela, vous, dans votre structure de données ou classe de shader, modèle, avez des identifiants int de shaders, de modèle et d'objets de tampon de texture.
Je pense que la plupart des moteurs ont des composants moteurs et chacun d'entre eux a certaines interfaces. Tous les moteurs que j'ai examinés ont un composant tel que Renderer ou SceneManager ou les deux (cela dépend de la complexité du jeu / moteur). Vous pouvez alors avoir la classe OpenGLRenderer et / ou DXRenderer qui implémentent l'interface Renderer. Ensuite, si vous avez SceneManager et Renderer, vous pouvez effectuer certaines des opérations suivantes:
Le rendu appellera probablement la fonction de dessin de l'objet qui appellera la fonction de dessin de chaque maillage qui est composé et le maillage liera l'objet de texture, liera le shader, appellera la fonction de dessin d'OpenGL, puis utilisera les shaders, les objets de texture et les objets de tampon de données.
REMARQUE: ceci n'est qu'un exemple, vous devez étudier SceneManager plus en détail et analyser votre cas d'utilisation pour voir quelle est la meilleure option d'implémentation
Vous auriez bien sûr d'autres composants du moteur, tels que MemoryManager , ResourceLoader, etc., qui prendraient en charge l'utilisation de la mémoire vidéo et RAM, afin qu'ils puissent charger / décharger certains modèles / shaders / textures selon les besoins. Les concepts pour cela incluent la mise en cache de la mémoire, le mappage de la mémoire, etc. etc. Il y a beaucoup de détails et de concepts sur chaque composant.
Jetez un oeil à une description plus détaillée des autres moteurs de jeu, ils sont nombreux et leur documentation est à peu près disponible.
Mais oui, les cours facilitent la vie; vous devez les utiliser totalement et vous souvenir de l'encapsulation, de l'héritage, des interfaces et d'autres trucs sympas.
la source
OpenGL contient déjà quelques concepts «Object».
Par exemple, tout ce qui a un identifiant peut être considéré comme un objet (il y a aussi des choses spécifiquement nommées «Objets»). Buffers, Textures, Vertex Buffer Objects, Vertex Array Objects, Frame Buffer Objects et ainsi de suite. Avec un peu de travail, vous pouvez envelopper les cours autour d'eux. Il vous donne également un moyen facile de revenir aux anciennes fonctions OpenGL obsolètes si votre contexte ne prend pas en charge les extensions. Par exemple, un VertexBufferObject pourrait retomber sur l'utilisation de glBegin (), glVertex3f (), etc.
Il y a quelques façons dont vous pourriez avoir besoin de vous éloigner des concepts OpenGL traditionnels, par exemple vous voulez probablement stocker des métadonnées sur les tampons dans les objets tampons. Par exemple, si le tampon stocke des sommets. Quel est le format des sommets (c'est-à-dire la position, les normales, les texcoords, etc.). Quelles primitives il utilise (GL_TRIANGLES, GL_TRIANGLESTRIP, etc ...), les informations de taille (combien de flottants sont stockés, combien de triangles ils représentent, etc ...). Juste pour le rendre facile à brancher dans les commandes draw arrays.
Je vous recommande de regarder OGLplus . Il s'agit de liaisons C ++ pour OpenGL.
Aussi glxx , c'est seulement pour le chargement d'extension.
En plus d'encapsuler l'API OpenGL, vous devriez envisager de créer un niveau légèrement supérieur au-dessus.
Par exemple, une classe de gestionnaire de matériel qui est responsable de tous vos shaders, de les charger et de les utiliser. Il serait également responsable de leur transférer des propriétés. De cette façon, vous pouvez simplement appeler: materials.usePhong (); material.setTexture (someexture); material.setColor (). Cela permet une plus grande flexibilité car vous pouvez utiliser des choses plus récentes comme des objets de tampon uniforme partagés pour n'avoir qu'un seul grand tampon contenant toutes les propriétés que vos shaders utilisent dans 1 bloc, mais si cela ne vous prend pas en charge, vous pouvez revenir au téléchargement vers chaque programme de shader. Vous pouvez avoir 1 grand shader monolithique et permuter entre différents modèles de shader en utilisant des routines uniformes si cela est pris en charge ou vous pouvez revenir à l'utilisation d'un tas de différents petits shaders.
Vous pouvez également consulter les dépenses à partir des spécifications GLSL pour écrire votre code de shader. Par exemple, le #include serait incroyablement utile et très facile à implémenter dans votre code de chargement de shader (il y a aussi une extension ARB pour cela). Vous pouvez également générer votre code à la volée en fonction des extensions prises en charge, par exemple utiliser un objet uniforme partagé ou recourir à des uniformes normaux.
Enfin, vous voudrez une API de pipeline de rendu de niveau supérieur qui fait des choses comme les graphiques de scène, les effets spéciaux (flou, lueur), les choses qui nécessitent plusieurs passes de rendu comme les ombres, l'éclairage et autres. Et en plus de cela, une API de jeu qui n'a rien à voir avec l'API graphique mais qui traite uniquement des objets d'un monde.
la source
oglplus::Context
classe rend cette dépendance très visible - serait-ce un problème? Je crois que cela aidera les nouveaux utilisateurs d'OpenGL à éviter beaucoup de problèmes.Dans OpenGL moderne, vous pouvez presque totalement séparer les objets rendus les uns des autres, en utilisant différents vaos et programmes de shader. Et même l'implémentation d'un objet peut être séparée en plusieurs couches d'abstraction.
Par exemple, si vous souhaitez implémenter un terrain, vous pouvez définir un TerrainMesh dont le constructeur crée les sommets et les indices du terrain, et les définit dans des tampons de tableau, et - si vous lui donnez une position d'attribut - il ombrage vos données. Il doit également savoir comment le restituer, et il doit prendre soin de rétablir tous les changements de contexte qu'il a effectués pour configurer le rendu. Cette classe elle-même ne devrait rien savoir du programme de shader qui va le rendre, et elle ne devrait rien savoir des autres objets de la scène. Au-dessus de cette classe, vous pouvez définir un Terrain, qui connaît le code du shader, et son travail consiste à créer la connexion entre le shader et TerrainMesh. Cela devrait signifier obtenir des positions d'attribut et uniformes et charger des textures, et des choses comme ça. Cette classe ne devrait rien savoir de la façon dont le terrain est implémenté, de l'algorithme LoD qu'elle utilise, elle est juste responsable de l'ombrage du terrain. Au-dessus de cela, vous pouvez définir la fonctionnalité non-OpenGL comme le comportement et la détection de collision et autres.
Pour en venir au fait, même si OpenGL est conçu pour être utilisé à bas niveau, vous pouvez toujours créer des couches d'abstraction indépendantes, qui vous permettent de vous adapter aux applications avec la taille d'un jeu Unreal. Mais le nombre de couches que vous voulez / avez besoin dépend vraiment de la taille de l'application que vous souhaitez.
Mais ne vous mentez pas à propos de cette taille, n'essayez pas d'imiter le modèle d'objet d'Unity dans une application en ligne 10k, le résultat sera un désastre complet. Construisez les couches progressivement, n'augmentez le nombre de couches d'abstraction que lorsque cela est nécessaire.
la source
ioDoom3 est probablement un excellent point de départ, car vous pouvez en quelque sorte compter sur Carmack pour suivre une excellente pratique de codage. Je pense également qu'il n'utilise pas megatexturing dans Doom3, il est donc relativement simple comme canal de rendu.
la source