Laboratoire 02

OpenGL – Données

Si nous essayions de réduire l’ensemble de l’API OpenGL à de grands concepts, ils seraient:

  • données
  • états
  • shaders

Shaders shader sera présenté pendant le cours.
Les états représentent un concept plus large, OpenGL étant en fait un grand automate fini avec beaucoup d'états et de possibilités de passer d'un état à un autre. Dans tous les laboratoires, certains de ces états seront utilisés pour obtenir les effets souhaités.
Les données contiennent les informations qui définissent la scène, ainsi que:

  • objets en trois dimensions
  • propriétés matérielles des objets (plastique, verre, etc.)
  • les positions, orientations et dimensions des objets dans la scène
  • toute autre information nécessaire décrivant les propriétés de l'objet ou de la scène

Par exemple, pour une scène carrée unique, nous avons les données suivantes:

  • les sommets du carré - 4 vecteurs tridimensionnels définissant la position de chaque pic dans l'espace
  • les caractéristiques des sommets
    • si la seule caractéristique d'une pointe en dehors de la position serait la couleur, nous aurions 4 autres vecteurs tridimensionnels (RVB)
  • la topologie du carré, c'est-à-dire la manière dont nous connectons ces sommets

OpenGL est une API graphique en trois dimensions, c'est-à-dire que tous les objets pouvant être définis sont liés à un système de coordonnées cartésiennes en trois dimensions. Cependant, nous pouvons utiliser l'API pour afficher des objets en deux dimensions, même s'ils sont définis par des coordonnées (x, y, z), en plaçant toutes les données dans un seul plan et en utilisant une projection appropriée.
En laboratoire, nous utiliserons la coordonnée Z = 0. Ainsi, tout point tridimensionnel deviendra P (x, y, 0).

Topologie

La primitive de base dans OpenGL est le triangle. Ainsi, comme on peut le voir dans l'image ci-dessus, dessiner un objet doit être spécifié par des triangles.

Le cube décrit ci-dessus est spécifié par la liste des 8 coordonnées de sommets et une liste de 12 triangles décrivant la manière dont les sommets spécifiés dans la liste précédente doivent être joints pour former les faces du cube. En utilisant des sommets et des index, nous pouvons décrire discrètement tout objet en trois dimensions.

Vous trouverez ci-dessous les principales primitives supportées par le standard OpenGL 3.3+.

Comme on peut le constater, il existe plusieurs méthodes permettant de spécifier la géométrie:

  • GL_LINES et GL_TRIANGLES sont les primitives les plus couramment utilisées pour définir la géométrie
  • GL_POINTS il est souvent utilisé pour créer des systèmes de particules
  • Les autres modèles ne représentent que des optimisations des 3 primitives de base, tant du point de vue de la mémoire que de la facilité à spécifier certaines topologies, mais leur utilité est souvent limitée car les objets les plus complexes ne peuvent être spécifiés qu'en utilisant de simples primitives.

Dans le cadre, vous pouvez définir le type de primitive utilisé par un objet à restituer via la fonction. Mesh::SetDrawMode(GLenum primitive)primitive peut être n'importe lequel des primitifs mentionnés dans l'image ci-dessus.

L'ordre de la spécification des sommets

Une observation importante liée à la topologie est l’ordre des sommets dans une primitive solide (pas une ligne, pas un point) avec plus de 2 sommets. Cet ordre peut être horaire ou antihoraire.

Face Culling

L'API OpenGL offre la possibilité de tester l'orientation apparente de chaque triangle à l'écran avant sa lecture et de l'ignorer en fonction du statut de suppression défini.: GL_FRONTGL_BACK. Cette fonctionnalité s'appelle Face Culling et est très important car cela réduit le coût total de traitement.

Exemple: pour un cube 3 faces au maximum peuvent être visibles à tout moment sur les 6 existantes. Dans ce cas, un maximum de 6 triangles seront traités pour être affichés à l'écran au lieu de 12.

Normalement, la sélection du visage est désactivée. Il peut être activé en utilisant la commande glEnable:

glEnable(GL_CULL_FACE);

Pour désactiver la sélection face-à-face, utilisez la commande glDisable:

glDisable(GL_CULL_FACE);

Pour spécifier l'orientation des faces à ignorer, utilisez la commande glCullFace

// GL_FRONT, GL_BACK, and GL_FRONT_AND_BACK are accepted.
// The initial value is GL_BACK.
glCullFace(GL_BACK);

Maillage

Un „maillage” est un objet en trois dimensions défini par des points et des indices. Au laboratoire, vous pouvez télécharger des maillages dans presque tous les formats possibles en classe. Mesh.

Vertex Buffer Object (VBO)

Un vertex buffer object (objet tampon de sommet) représente un conteneur dans lequel nous stockons des données liées au contenu des sommets, telles que:

  • position
  • normal
  • couleur
  • coordonnées de texture
  • etc…

Un vertex buffer object peut être créé à l'aide de la commande OpenGL glGenBuffers:

	GLuint VBO_ID;			// L'ID (nom ou référence) du tampon qui sera requis du GPU
	glGenBuffers(1, &VBO_ID);	// l'identifiant de tampon (nom) est généré

Comme vous pouvez le voir dans l'explication de l'API, la fonction glGenBuffers reçoit le nombre de tampons à générer et l'emplacement en mémoire où les références générées (ID) seront sauvegardées.
Dans l'exemple ci-dessus, un seul tampon est généré et l'ID est enregistré dans la variable VBO_ID.

Pour détruire un VBO et libérer ainsi la mémoire du GPU utiliser la commande glDeleteBuffers:

glDeleteBuffers(1, &VBO_ID);

Pour pouvoir mettre les données dans un tampon, nous devons d’abord lier ce tampon à un „target”. Pour un vertex buffer this „binding point” ça s'appelle GL_ARRAY_BUFFER et peut être spécifié par la commande glBindBuffer:

glBindBuffer(GL_ARRAY_BUFFER, VBO_ID);

À ce stade, nous pouvons télécharger des données de la mémoire du CPU au GPU à travers la commande glBufferData:

glBufferData(GL_ARRAY_BUFFER, sizeof(vertices[0]) * vertices.size(), &vertices[0], GL_STATIC_DRAW);
  • La commande lit à partir de l'adresse spécifiée, dans l'exemple ci-dessus étant l'adresse du premier sommet &vertices[0], et copier dans la mémoire vidéo la taille spécifiée par le paramètre 2.
  • GL_STATIC_DRAW représente un indice pour le pilote vidéo sur l'utilisation du tampon. Ce symbole peut avoir plusieurs valeurs, mais dans le laboratoire il suffit pour la spécification présentée. Plus d'informations peuvent être trouvées sur la page de manuel de fonction glBufferData

Pour mieux comprendre l'API OpenGL, nous vous recommandons de lire la documentation fournie avec chaque commande soumise. Quand une nouvelle commande est soumise, si vous cliquez sur son nom, vous serez redirigé vers la page de manuel de cette commande.
En outre, la documentation officielle et complète de l’API OpenGL est disponible sur la page OpenGL 4 Reference Pages

Index Buffer Object (IBO)

Un index buffer object (objet tampon d’index) est un conteneur dans lequel nous stockons des sommets. Comme VBO si IBO sont des tampons, ils sont extrêmement similaires dans leur construction, leur chargement et leur suppression.

glGenBuffers(1, &IBO_ID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IBO_ID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices[0]) * indices.size(), &indices[0], GL_STATIC_DRAW);

Comme avec VBO, nous créons un IBO et le lions ensuite à un point de connexion, mais cette fois, le point de connexion est GL_ELEMENT_ARRAY_BUFFER. Les données sont envoyées au tampon mappé à ce point de liaison. Dans le cas des index, tous auront la taille d'un seul entier.

Vertex Array Object (VAO)

Dans un vertex array object (objet tableau de sommets) nous pouvons stocker toutes les informations relatives à l'état de la géométrie dessinée. Nous pouvons utiliser un grand nombre de tampons pour stocker chacun des différents attributs („separate buffers”). Nous pouvons stocker plusieurs attributs (ou tous) dans un seul tampon („interleaved” buffers). Normalement, avant chaque commande de dessin, toutes les commandes “de liaison” pour les tampons ou les attributs décrivant les données à restituer doivent être spécifiées. Pour simplifier cette opération, on utilise un objet tableau de sommets prenant en compte tous ces liens.

Un objet tableau de sommets est créé à l'aide de la commande glGenVertexArrays:

unsigned int VAO;
glGenVertexArrays(1, &VAO);

Il est lié à glBindVertexArray:

glBindVertexArray(VAO);

Avant de créer les VBO et l'IBO requis pour un objet, le VAO de l'objet sera lié et il se souviendra automatiquement de tous les liens spécifiés ultérieurement.

Une fois tous les liens spécifiés, il est recommandé de commander glBindVertexArray(0) désactiver le lien avec le VAO actuel, car sinon, nous risquons que d'autres commandes OpenGL ultérieures soient liées au même VAO, ce qui facilitera grandement les erreurs dans le programme.

Avant la commande de dessin, il suffit de lier uniquement le VAO pour qu'OpenGL connaisse toutes les liaisons créées lors de la construction de l'objet.

Laboratoire 2

Description du laboratoire

En laboratoire, nous allons apprendre à utiliser VAO, VBO, IBO et ainsi nous générons et chargeons une géométrie simple.
Le laboratoire fournit la structure VertexFormat qui servira de base à la création de la géométrie.

struct VertexFormat
{
	// position of the vertex
	glm::vec3 position;		
 
	// vertex normal
	glm::vec3 normal;
 
	// vertex texture coordinate
	glm::uvec2 text_coord;
 
	// vertex color
	glm::vec3 color;
};

La classe Mesh offre la possibilité de télécharger une géométrie simple en utilisant diverses méthodes:

// Initialise l'objet maillé à l'aide d'un tampon VAO GPU contenant le nombre spécifié d'index.
bool InitFromBuffer(unsigned int VAO, unsigned short nrIndices);
 
// Initialise l'objet maillé et télécharge les données sur les GPU à l'aide des tampons de données fournis.
bool InitFromData(std::vector<VertexFormat> vertices,
		std::vector<unsigned short>& indices);
 
// Initialise l'objet maillé et télécharge les données sur les GPU à l'aide des tampons de données fournis.
bool InitFromData(std::vector<glm::vec3>& positions,
		std::vector<glm::vec3>& normals,
		std::vector<unsigned short>& indices);

Touches de contrôle pour la camerá

  • W, A, S, D, Q, E - avant, gauche, arrière, droite, bas, haut
  • MOUSE RIGHT + MOUSE MOVE - rotation de la camerá

F3 - affiche / masque la grille dans la scène
Space - dessiner des primitives uniquement par points ou lignes (wireframe) ou géométrie opaque

Tâches de laboratoire

Toutes les tâches de chargement de géométrie doivent être résolues par la fonction Laborator2::CreateMesh mais vous pouvez utiliser les méthodes Mesh::InitFromData() pour vérifier la validité de la géométrie.

  1. Complétez la géométrie et la topologie d'un cube: les sommets et les vecteurs d'index de l'initialisation. VertexFormat est une structure de sommet avec 2 paramètres (position, couleur).
  2. Compléter la fonction Laborator2::CreateMesh afin que vous puissiez charger la géométrie sur le GPU
    • créer un VAO
    • créer un VBO et y ajouter des données
    • créer un IBO et y ajouter des données
    • afficher le nouvel objet (RenderMesh[cube3]) afin qu'il ne chevauche pas un autre objet
  3. Créez une nouvelle forme géométrique simple, telle qu'un tétraèdre, et dessinez-la dans la scène.
  4. Lorsque la touche F2 est enfoncée basculer entre le mode de sélection GL_BACK et GL_FRONT
    • n'oubliez pas d'activer et de désactiver l'utilisation de la sélection glEnable() / glDisable()
  5. Créez un carré composé de 2 triangles de manière à ce que chaque triangle ne soit visible que d'un côté
    • A tout moment, il ne faut voir qu'un seul triangle
egc/laboratoare/fr/02.txt · Last modified: 2019/10/10 05:09 by alexandru.gradinaru
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0