WebGL permet d’afficher des graphismes 3D dans le navigateur et, comme le rappelle cet article issu d’une série, il s’agit aussi d’une API 2D sous-jacente qui exige des textures et des coordonnées propres. Pour afficher une image sur une forme, il faut charger une image, créer une texture et copier l’image dans la texture, tout en gérant l’asynchrone du chargement des ressources. Nous allons explorer comment utiliser un canvas comme texture, les enjeux des mipmaps et les limites liées aux dimensions des textures, ainsi que quelques architectures de rendu courantes.
Chargement asynchrone des textures et deux approches courantes
Étant donné que nous ne dessinons qu’un seul rectangle (deux triangles, en fait), nous devons indiquer à WebGL l’emplacement dans la texture auquel chaque point du rectangle correspond. Étant donné que nous ne dessinons qu’un seul rectangle (deux triangles, en fait), nous devons indiquer à WebGL l’emplacement dans la texture auquel chaque point du rectangle correspond. Étant donné que nous sommes dans un navigateur, les images se chargent de manière asynchrone. Nous devons donc réorganiser un peu notre code pour attendre que la texture se charge.
Il existe généralement 2 solutions à cela: soit commencer à dessiner et utiliser la texture dès que l’image est téléchargée, soit commencer le rendu immédiatement et copier l’image dans la texture après chargement. Dans le premier cas, on obtient une image temporaire utilisée comme texture, puis on la remplace lorsque l’image est prête; dans le second, le rendu démarre avec une texture provisoire et se met à jour à mesure que l’image se télécharge. Ces principes s’appliquent aussi lorsque l’on réplique des textures à partir d’un canvas interne ou d’un canvas dédié à la préparation d’images.
Texcoords, coordonnées d’espace de découpe et mise en forme des textures
WebGL attend des coordonnées de texture lors de la lecture d’une texture et non des coordonnées en pixels. Pour chaque point du rectangle, il faut transmettre les coordonnées de texture correspondantes via des variables attribuées dans le vertex shader et interpolées dans le fragment shader. Par défaut, la texture se répète (wrap) si les coordonnées dépassent [0,1], ce qui peut être utile ou problématique selon le design. Pour éviter les repetitions, on peut utiliser CLAMP_TO_EDGE afin de bloquer les valeurs à la bordure.
La texture du type « F » et les mips ont été cités comme démonstrations typiques des effets graphiques. Lorsque l’on utilise des textures puissantes (par exemple 1024x1024 ou 2048x2048), le GPU active automatiquement des mipmaps pour améliorer le filtrage et les performances, en particulier lors du rendu à distance ou lorsque l’on réduit l’échelle de la texture à l’écran.
Mipmaps et filtrage
La génération de mipmaps via gl.generateMipmap permet de créer des versions de taille réduite de la texture, optimisant le filtrage lorsque l’image est vue à différentes tailles. LINEAR_MIPMAP_LINEAR offre le meilleur compromis entre qualité et coût, mais reste plus lent que LINEAR ou NEAREST dans certains scénarios. NEAREST_MIPMAP_NEAREST peut être utile lorsque l’on cherche une esthétique pixellisée ou une performance maximale pour des textures simples. Le choix du filtrage influence directement le rendu et la vitesse, et les jeux modernes peuvent nécessiter l’utilisation de plusieurs textures en même temps.
Problèmes de dimensions et textures non puissance de 2
Les textures qui ne sont pas des puissances de deux (non power-of-two) ne peuvent pas toujours être utilisées avec les mêmes paramètres de wrapping et de mipmaps. Par exemple, une texture de 320x240 n’est pas une puissance de 2 et peut échouer sans ajustement. La solution la plus simple est de rendre les textures « complètes » en les passant par gl.generateMipmap ou en ajustant les paramètres d’édition pour accepter des dimensions non puissantes selon le contexte et le matériel.
La règle générale est de privilégier des textures puissances de deux lorsque c’est possible (par exemple 256x256 ou 512x512). Lorsque l’image source ne respecte pas cette contrainte, il faut adapter le chargement et le traitement afin de garantir que le rendu reste correct et stable, en particulier lors du rendu vers un framebuffer ou lors du traitement multi-pass.
Textures et atlas, textures multi-unités
Pour afficher des textures sur différents objets ou faces, on peut multiplier les textures via des textures units et des shaders qui sélectionnent quelle texture lire. Une autre approche courante est l’utilisation d’un atlas de textures où plusieurs textures sont packagées dans une seule image et des coordonnées UV spécifiques permettent d’accéder à chaque sous‑image. Cela permet d’économiser des appels et des états de texture et est particulièrement utilisé dans les applications hautes performances (jeux) qui manipulent plusieurs textures en parallèle.
Texture sur un canvas et limites liées au rendu sur le backbuffer
La différence principale entre WebGL et le rendu traditionnel en 2D réside dans le fait que WebGL exploite l’accélération matérielle et le backbuffer comme source de données. Dans certains cas, l’alpha et le comportement de composition peuvent provoquer des différences entre les moteurs OpenGL et WebGL, notamment sur la manière dont l’arrière-plan est composé avec le canevas. L’utilisation d’un fond coloré permet de diagnostiquer les effets d’alpha et de composition et d’évaluer si le backbuffer est correctement géré.
Utiliser un canvas comme texture peut aussi servir à des traitements d’image via des shaders personnalisés. Un noyau de convolution 3x3 peut être appliqué directement dans le nuanceur pour réaliser des effets courants, et le rendu en passant par des framebuffers permet d’écrire les résultats dans une texture intermédiaire avant de les afficher.
Rendu, pipeline et organisation du code WebGL
La pipeline de rendu WebGL comprend la génération et le traitement des données, la création des points (sommets), la transformation des formes vectorielles, la rasterisation, la coloration et l’affichage. Le Vertex Shader transforme les coordonnées des sommets et prépare les données pour les étapes suivantes, tandis que le Fragment Shader calcule la couleur finale des fragments. Pour dessiner des images et des textures, il est nécessaire d’établir les buffers, de lier les programmes GLSL et de passer les attributs et les uniforms appropriés.
En pratique, on demande souvent au navigateur d’initialiser une scène 2D qui peut être progressivement étendue vers la 3D. Cependant, WebGL peut être tout à fait accessible et simple lorsque l’on comprend comment transformer des rectangles en pixels via l’espace de découpe (-1 à +1) et comment convertir des rectangles en unités compatibles WebGL. Pour illustrer, on peut exploiter un seul programme GLSL capable de générer plusieurs effets en utilisant des uniforms et des variations entre les passations de texture et d’éclairage.
Applications pratiques et usages avancés
Vous pouvez générer des formes plus complexes en combinant plusieurs triangles et en explorant des concepts avancés comme les textures et les transformations. Animer les données et créer des animations 3D interactives est une autre voie passionnante, notamment en utilisant des bibliothèques d‘animation ou des frameworks dédiés à WebGL. L’approche « vanilla WebGL » reste utile pour optimiser les débogages et réduire la taille des dépendances, tout en vous donnant une compréhension plus solide des mécanismes internes.
Le traitement d’images en WebGL peut être étendu via des systèmes de shaders multiples et des framebuffers pour créer des pipelines de post-traitement dynamiques. On peut également envisager des usages avancés comme appliquer des textures depuis des domaines externes (CORS) ou charger des textures provenant d’autres domaines, tout en maîtrisant les limites et les permissions de chargement.
Conclusion technique et perspectives
Ce chapitre a montré comment établir et manipuler une texture à partir d’un canvas et comment gérer les détails pratiques comme le mipmapping, le filtrage, les dimensions et l’atlas. La compréhension des concepts fondamentaux de WebGL, des coordonnées UV et de la gestion asynchrone des textures permet d’explorer des rendus 2D et 3D plus riches dans le navigateur sans dépendre exclusivement de bibliothèques lourdes comme Three.js, tout en restant conscient des compromis en matière de performances et de compatibilité.
