Game Connection 2013 – Europe : Techniques OpenGL ES avancées dans la série des GTA

Alexandre Laurent

La première session technique durant la Game Connection 2013 a été présentée par Thomas Williamson, CEO chez War Drum Studios.

Commentez

- Titre : Game Connection 2013 – Europe : Techniques OpenGL ES avancées dans la série des GTA

- Auteur : Alexandre Laurent

- Parution : 16 janvier 2014

- Mise à jour : 9 octobre 2019

- Licence : Copyright ® 2013 Alexandre Laurent. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- Navigation

- I. Introduction

- II. OpenGL ES 2

- III. Empêcher les saccades du pilote

- III-A. Tampons

- III-B. Shaders

- III-C. Textures

- IV. Améliorer le nombre d'images par seconde

- IV-A. Vidage du pipeline

- V. Rendre le jeu visuellement plaisant

- V-A. Gestion des couleurs

- V-B. Ombres

- V-C. Réflexions en temps réel

- V-C-1. Revue des différentes techniques

- V-C-2. Sphere mapping et un peu plus

- V-C-3. Implémentation

- VI. Derniers points sur les graphismes sur mobiles

- VII. Questions/réponses

- Navigation

Navigation

Retrouvez les autres conférences et le compte rendu de l'événement.

I - Introduction

War Drum Studios est un studio de développement créé en 2007 en Floride (États-Unis).

À l'origine, ils développaient pour les consoles, mais depuis ils ont changé de cible pour se consacrer aux mobiles.

Parmi leurs réalisations, nous pouvons compter : Ghost Busters (PS2), Max Payne, GTA 3 et GTA Vice City.

II - OpenGL ES 2

OpenGL ES 2 est présent depuis 2007 et a entraîné une explosion de la qualité des graphismes sur les mobiles. C'est loin d'être une technologie morte et le récent iPhone 5c est compatible avec OpenGL ES 2 et non pas OpenGL ES 3. La spécification a donc encore beaucoup de route devant elle.

Dans le court terme, OpenGL ES 3 apporte une fragmentation entre les périphériques sur le marché.

III - Empêcher les saccades du pilote

Un gros enjeu dans le développement de jeux mobiles est d'empêcher les saccades provoquées par le pilote graphique. En effet, de telles saccades dégraderaient énormément le plaisir de jeu.

Sur un graphique représentant la durée des appels aux fonctions OpenGL, on remarquera que les fonctions prenant le plus de temps sont :

- glDeleteTextures ;

- glDrawArrays ;

- glBindBuffer ;

- glFlush ;

- glGenTextures.

III-A - Tampons

Le pilote graphique gère la mémoire de façon basique. Il ne sait pas quel est le meilleur moment pour libérer la mémoire et peut donc appeler le ramasse-miettes à un moment pénalisant. De plus, la mémoire devient de plus en plus fragmentée, provoquant de plus en plus de saccades. La solution est de n'effectuer qu'une seule allocation pour tous les tampons. De plus, il est conseillé de construire ses tampons de façon à utiliser au mieux le cache. Finalement, le second avantage est que le rassemblement des tampons vous permettra d'éviter des changements d'état. En étant flexible sur les attributs de sommets, il vous sera possible de stocker différents formats dans un même tampon.

Ne faites jamais de glBufferSubData() l'implémentation de cette fonction est horrible.

III-B - Shaders

La compilation des shaders est effectuée à la volée durant l'exécution. Afin d'éviter des ralentissements dus à cette compilation, il est nécessaire d'exécuter (avec zéro triangle) chaque shader durant le chargement de l'application. De plus, il est nécessaire de le faire avec tous les formats de cible de rendu utilisés ainsi que les états de transparence afin que l'exécution du shader ne soit pas optimisée et que toutes les portions de code soient parcourues.

III-C - Textures

Vous pouvez éviter les glDeleteTextures() en gérant vous-même une liste FIFO de textures libres. Ainsi, lorsque vous avez besoin d'envoyer une texture sur la carte graphique, vous pouvez réutiliser un emplacement libéré auparavant et ainsi éviter une gestion de la mémoire par le pilote. Lors de votre recherche pour un emplacement libre, vous devez vérifier la taille des textures. Finalement, ne mettez pas à jour une texture qui a été affichée quelques images auparavant.

IV - Améliorer le nombre d'images par seconde

Les pilotes graphiques présument que vous effectuez une mise en cache des données d'états. En le faisant, vous pouvez ainsi réduire le nombre d'appels aux fonctions OpenGL.

Dans les shaders, vous devez utiliser le type ayant la précision la plus faible autant que possible.

Triez l'ordre de rendu de vos objets. Faites-le toujours suivant les états de fondu et sur les puces Tegra, commencez par les objets proches pour finir par les objets au loin.

Utilisez les mipmaps et les données de sommet compressées afin d'économiser la bande passante, qui est un goulot d'étranglement commun.

IV-A - Vidage du pipeline

Le pilote graphique possède une queue de commandes qui se remplit au fur et à mesure des appels aux fonctions de dessin. Pour les mobiles, celle-ci peut se remplir après environ 300 appels (nombre qui peut être plus petit avec les moteurs de rendu en tuiles). Une fois que la queue est pleine, le pilote vide entièrement la queue avant de redonner la main au programme appelant.

Pour contourner cela, il est nécessaire de gérer soi-même le threading des appels OpenGL. La majorité de ces appels ne nécessite pas de connaître les valeurs de retour. Tout le monde pense que le pilote ne bloque pas sur les appels de la bibliothèque OpenGL. En écrivant un système de queue basé sur le principe du producteur/consommateur où chaque appel OpenGL posséderait une surcharge permettant de soumettre la commande à la queue qui sera traitée par un thread exclusif.

Il est nécessaire de faire un petit travail supplémentaire pour les textures et les tampons. De plus, il est possible de faire facilement des opérations atomiques avec __sync_fetch_and_sub afin d'éviter les verrous.

V - Rendre le jeu visuellement plaisant

V-A - Gestion des couleurs

Les consoles ont leurs propres algorithmes pour le rendu des couleurs. Afin d'avoir une palette, vous pouvez créer une texture 3D de dimension 16 x 16 x 16 pour représenter toutes les couleurs visibles. Ensuite, vous pouvez demander à vos artistes de personnaliser cette palette.

Il n'est pour autant pas facile d'utiliser une telle texture sur les mobiles. L'utilisation d'une texture 3D n'est pas directement supportée et si vous souhaitez le faire, cela nécessite d'utiliser des opérations mathématiques coûteuses. Une utilisation directe est aussi coûteuse à cause du placement de la texture en cache.

Pour éviter tout cela, utilisez une simple régression linéaire sur les 256 couleurs pour déterminer une approximation du dégradé et interceptez chaque couleur d'une dimension par rapport aux dimensions des autres couleurs. Ainsi, vous pourrez déterminer la contribution de chacune.

Ces opérations sont rapides et assez précises. Comme ce sont de simples matrices, l'interpolation linéaire entre elles est simple. Toutefois, sachant que les courbes de couleurs ne sont que de simples lignes, la balance et les ajustements de contraste sont limités. Vous pouvez le coder comme suit :

precision mediump float;
uniform sampler2D Diffuse;
varying mediump vec2 Out_Tex0;
uniform mediump vec4 RedGrade;
uniform mediump vec4 GreenGrade;
uniform mediump vec4 BlueGrade;
void main(){
vec4 color = texture2D(Diffuse, Out_Tex0);
gl_FragColor.x = dot(color, RedGrade);
gl_FragColor.y = dot(color, GreenGrade);
gl_FragColor.z = dot(color, BlueGrade);
};

Vous pouvez créer plusieurs approximations et les ajouter par composante.

V-B - Ombres

Voici les différentes passes utilisées chez War Drum Studios pour obtenir les ombres :

Pour le tampon d'ombre, il est conseillé d'utiliser un fond noir et une transparence additive avec du blanc. La phase de combinaison utilise la différence entre les lumières ambiantes et les lumières directionnelles comme couleur pour l'ombre.

Cette méthode fonctionne avec les techniques d'ombrage basées sur le « decal », le « stencil » et les « shadow maps » et cela, pour toutes les plateformes et donne de meilleures ombres. Toutefois, la résolution de l'image d'ombrage peut provoquer un petit délai dans le pilote graphique.

V-C - Réflexions en temps réel

V-C-1 - Revue des différentes techniques

Méthode

Avantages

Désavantages

Cube mapping

- Précis.

- Support natif pour l'accès à la texture.

- Six cibles de rendu différentes.

Dual paraboloid mapping

- Mieux qu'avec une sphère.

- Deux accès aux textures au lieu d'un unique.

- Calcul des coordonnées de texture imprécis dans le vertex shader et trop coûteux dans le pixel shader.

Sphere mapping

- Rendu rapide.

- Accès rapide dans le vertex shader.

- Très imprécis sur les bords.

- Ne fonctionne pas très bien avec des polygones avec peu de triangles.

V-C-2 - Sphere mapping et un peu plus

Finalement, War Drum Studios a utilisé la technique du « sphere mapping », mais avec quelques modifications :

- en place d'utiliser les coordonnées de caméra pour les calculs, ils ont utilisé les coordonnées monde ;

- ils ont évité les transformations de matrices ;

- ils ont fait en sorte que les polygones les plus imposants restent toujours au centre.

Même si le rendu n'est pas parfait, cela fonctionne plutôt bien avec leurs scènes.

V-C-3 - Implémentation

Comme il n'y a plus de transformation entre l'espace de coordonnées monde vers l'espace de coordonnées caméra, le code est simple :

ReflPos = normalize(WorldPos.xyz - CameraPos.xyz);
ReflUV = normalize(ReflPos.xy) * (ReflPos.z * 0.5 + 0.5);

Afin d'atténuer la netteté, le studio de développement utilise des tampons de 512 x 512 pixels pour cette technique. De plus, les calculs peuvent être effectués dans le pixel shader, car ils sont rapides.

Toutefois, il est à noter que cette technique nécessite une connaissance de l'environnement et comme elle repose sur la technique de « sphere mapping », elle aura toujours quelques défauts.

VI - Derniers points sur les graphismes sur mobiles

Il est possible d'avoir des ressources haute définition, mais la capacité de stockage des mobiles est limitée à deux gigaoctets sur Android et iOS. La limite est sûrement due à l’utilisation d'architecture 32 bits, mais cela devrait changer dans le futur. La principale utilisation de cet espace est pour les textures.

Vous pouvez convertir les textures ATC à la volée sur les plateformes Android et ainsi n'avoir plus que trois formats (PVR, DXT, ETC1) sur votre mobile au lieu de quatre. Pour la conversion, vous pouvez utiliser un rapide jeu sur les bits.

Il est aussi possible d'utiliser intensivement le « detail mapping » et ainsi stocker 20 textures 128 x 128 dans 200 kilo-octets.

Finalement, il est aussi possible d'utiliser une compression « Run-Length Encoding » (RLE). C'est simple et cela utilise le cache.

Les ressources sont stockées décompressées sur le disque à l'installation. C'est aussi le cas pour les fichiers Android OBB, sauf si vous utilisez une compression maison. Utilisez les tailles de blocs RLE, en faisant correspondre chaque taille de bloc pour chaque texture de format.

Si cela ne suffit pas, il est possible d'utiliser un fichier OBB additionnel et ainsi avoir deux gigaoctets en plus.

VII - Questions/réponses

War Drum Studios ne parle pas de Windows 8, car les pilotes sont complètement différents et n'ont pas les mêmes problèmes.

Navigation

Retrouvez les autres conférences et le compte rendu de l'événement.