> Tutoriel OpenGL moderne : créez un contexte avec GLFW, envoyez des données dans un VBO/VAO et écrivez des shaders minimaux pour afficher votre premier triangle.

*Source : https://coder-studio.com/tutoriels/tutoriel-opengl-premier-triangle/*

---

[// Graphisme & jeux](https://coder-studio.com/tutoriels/)

# Introduction à OpenGL : afficher son premier triangle

Par **Kévin Papot** · publié le 12 avril 2025

Afficher un triangle à l’écran est le « Hello World » de la programmation graphique. Avec **OpenGL** moderne, cet exercice apparemment trivial demande de comprendre tout un pipeline : contexte, tampons de données et _shaders_. C’est justement ce qui en fait un excellent point de départ. Ce **tutoriel OpenGL** vous guide pas à pas, de la création de la fenêtre au premier triangle coloré, en utilisant l’approche à shaders programmables — la seule pertinente aujourd’hui.

## OpenGL ancien contre OpenGL moderne

Beaucoup de vieux tutoriels montrent du code en `glBegin`/`glEnd`, où l’on énumère les sommets un par un. Ce **pipeline fixe** est obsolète. OpenGL moderne (3.3 et au-delà) repose sur un **pipeline programmable** : vous envoyez les données des sommets à la carte graphique une fois pour toutes, puis vous écrivez de petits programmes — les _shaders_ — qui décrivent comment traiter ces sommets et colorer les pixels.

C’est un peu plus verbeux au début, mais c’est ainsi que fonctionnent tous les moteurs actuels. Apprendre directement la bonne méthode évite de tout réapprendre plus tard.

## Les bibliothèques nécessaires

OpenGL ne sait pas créer de fenêtre ni gérer le clavier : ce n’est qu’une API de rendu. Il faut donc deux compléments.

-   **GLFW** crée la fenêtre, le contexte OpenGL et gère les entrées. Léger et multiplateforme, c’est le choix standard.
-   **GLAD** (ou GLEW) charge les pointeurs de fonctions OpenGL modernes, indispensables car le système ne les expose pas directement.

Sous Linux, on installe par exemple `libglfw3-dev` ; GLAD se génère sur son site web et s’ajoute au projet sous forme d’un fichier source. La compilation lie ensuite le tout avec la bibliothèque OpenGL du système.

## Créer une fenêtre et un contexte

Tout commence par l’initialisation de GLFW et la création d’une fenêtre associée à un contexte OpenGL 3.3.

```
#include <glad/glad.h>
#include <GLFW/glfw3.h>

int main() {
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

    GLFWwindow* fenetre = glfwCreateWindow(800, 600, "Premier triangle",
                                           nullptr, nullptr);
    glfwMakeContextCurrent(fenetre);
    gladLoadGLLoader((GLADloadproc)glfwGetProcAddress);
    // ... suite ...
}
```

Les `glfwWindowHint` réclament un contexte moderne en profil _core_. `gladLoadGLLoader` charge ensuite les fonctions OpenGL : sans cette ligne, tout appel `gl…` planterait.

## Décrire le triangle

Un triangle, c’est trois sommets, chacun défini par ses coordonnées. OpenGL travaille dans un espace normalisé où les coordonnées vont de -1 à +1.

```
float sommets[] = {
    -0.5f, -0.5f, 0.0f,   // bas gauche
     0.5f, -0.5f, 0.0f,   // bas droit
     0.0f,  0.5f, 0.0f    // sommet
};
```

Ces données doivent être transférées dans la mémoire de la carte graphique. On utilise pour cela deux objets fondamentaux : le **VBO** (Vertex Buffer Object), qui stocke les sommets, et le **VAO** (Vertex Array Object), qui mémorise _comment_ interpréter ce tampon.

```
unsigned int VAO, VBO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);

glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(sommets), sommets, GL_STATIC_DRAW);

glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
```

`glVertexAttribPointer` est la ligne clé : elle explique que chaque sommet occupe trois flottants et se trouve à l’emplacement 0, celui que le shader lira.

## Écrire les shaders

Deux shaders minimaux suffisent. Le **vertex shader** positionne chaque sommet ; le **fragment shader** décide de la couleur des pixels.

```
// Vertex shader
#version 330 core
layout (location = 0) in vec3 aPos;
void main() {
    gl_Position = vec4(aPos, 1.0);
}
```

```
// Fragment shader
#version 330 core
out vec4 FragColor;
void main() {
    FragColor = vec4(1.0, 0.5, 0.2, 1.0);  // orange
}
```

Le `layout (location = 0)` correspond à l’emplacement défini plus haut. Le fragment shader renvoie une couleur constante : notre triangle sera uniformément orange.

## Compiler et lier les shaders

Les shaders sont fournis sous forme de texte et compilés à l’exécution, puis liés dans un _programme_.

```
unsigned int vs = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vs, 1, &sourceVertex, nullptr);
glCompileShader(vs);

unsigned int fs = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fs, 1, &sourceFragment, nullptr);
glCompileShader(fs);

unsigned int programme = glCreateProgram();
glAttachShader(programme, vs);
glAttachShader(programme, fs);
glLinkProgram(programme);
glDeleteShader(vs);
glDeleteShader(fs);
```

En pratique, pensez à vérifier la compilation avec `glGetShaderiv` et à lire les journaux d’erreur : une virgule oubliée dans un shader est une source de bugs très fréquente.

## La boucle de rendu

Reste à dessiner en continu jusqu’à la fermeture de la fenêtre.

```
while (!glfwWindowShouldClose(fenetre)) {
    glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);

    glUseProgram(programme);
    glBindVertexArray(VAO);
    glDrawArrays(GL_TRIANGLES, 0, 3);

    glfwSwapBuffers(fenetre);
    glfwPollEvents();
}
glfwTerminate();
```

À chaque image, on efface l’écran, on active le programme de shaders et le VAO, puis `glDrawArrays` dessine trois sommets sous forme de triangle. `glfwSwapBuffers` affiche le résultat et `glfwPollEvents` traite le clavier et la souris.

## Ce que vous avez appris

Ce petit triangle cache l’essentiel d’OpenGL moderne : un contexte créé par GLFW, des données envoyées dans un VBO décrit par un VAO, et deux shaders qui transforment ces données en pixels colorés. Chaque projet graphique, si complexe soit-il, repose sur ces mêmes briques. Les étapes suivantes naturelles sont d’ajouter des couleurs par sommet, des textures, puis les matrices de transformation pour passer à la 3D.

## À lire ensuite

-   Renforcez le C++ sous-jacent avec notre guide du [langage C](https://coder-studio.com/tutoriels/langage-c/).
-   Gérez proprement vos ressources graphiques grâce au [RAII en C++](https://coder-studio.com/tutoriels/raii-cpp/).
-   Pour une approche 2D plus douce, essayez [une balle rebondissante en OCaml + SDL](https://coder-studio.com/tutoriels/ocaml-sdl-bouncing-ball/).
