Correction gamma et pourquoi c'est important

Si vous êtes un développeur de jeux, vous avez probablement entendu parler des termes gamma et correction gamma. Vous pouvez ou non savoir ce qu’ils veulent dire, mais ils ne doivent pas être écartés à la légère..

Les développeurs de jeux ont tendance à ignorer le gamma car ses effets sont suffisamment subtils pour être corrigés approximativement en ajustant les intensités lumineuses, spéculaires, etc., mais pour obtenir une qualité d'image réelle avec un éclairage réaliste, il est important de comprendre la valeur gamma et les étapes à suivre. contourner sa présence en imagerie numérique, afin de recevoir la meilleure qualité possible. L’application de la correction gamma appropriée est l’un des moyens les plus simples d’améliorer radicalement l’apparence de vos graphiques 3D en temps réel..

Introduction: Comment fonctionnent les moniteurs

Les moniteurs CRT utilisés à l'origine pour les écrans d'ordinateur ont une propriété curieuse: la réponse des couleurs sur leurs écrans est non linéaire en ce qui concerne les valeurs brutes transmises de la carte graphique. 

Non-linéaire, dans ce sens, signifie que l’augmentation de l’un de vos composants de couleur selon un rapport constant (par exemple, si un composant rouge d’une couleur devient deux fois plus élevé) n’entraînera pas une augmentation de l’intensité de la lumière émise par le moniteur de même rapport (c’est-à-dire que la lumière rouge émise par l’écran sera ne pas être deux fois plus haut).

La réponse des couleurs d’un moniteur CRT est en réalité une exponentiel une fonction. (Comme dans toute physique, ceci est bien plus complexe que ce que nous décrivons, mais pour simplifier, nous nous en tiendrons à cette hypothèse.) C'est la fonction EmittedLight (C), où C est une valeur de composante de couleur (rouge, verte ou bleue) allant de 0 (pas de lumière) à 1 (intensité lumineuse maximale), est C élevé à un certain pouvoir γ

Ce nombre, γ, est appelé le exposant gamma ou juste gamma. Les valeurs gamma typiques vont de 2,0 à 2,4 et, s’il s’agit de gamma au sens général, il est convenu que la valeur choisie est 2,2, à titre de compromis, et de nombreux nouveaux moniteurs sont utilisés. conçu avoir la valeur gamma de précisément 2,2

Dans un scénario commun de gamma = 2,2, voici comment le moniteur affiche les intensités de couleur de votre jeu (courbe verte). La ligne rouge en pointillé montre comment un moniteur linéaire afficherait les mêmes intensités.

En pratique, cela signifie que le noir et le blanc seront affichés sans distorsion sur l'écran (parce que zéro élevé à n'importe quelle puissance est zéro, et 1 à n'importe quelle puissance est un), mais toutes les valeurs entre les deux seront faussées sans aucun moyen fiable de percevoir cela se passe juste en regardant. 

Par exemple, si vous affichez une couleur supposée deux fois plus sombre que le noir, c'est-à-dire, RVB (0.5, 0.5, 0.5)-il sera effectivement indiqué comme moins de quatre fois plus sombre, étant donné la valeur gamma commune de 2,2, puisque 0,5 élevé à 2,2 est autour de 0,22. Clairement, ce n’est pas ce que vous voulez, et ce n’est pas le cas uniquement avec les moniteurs CRT: les LCD, bien que involontairement ayant cette propriété, sont conçus pour être compatibles avec leurs homologues plus anciens, et affichent ainsi vos valeurs de couleur étirées comme ceci.

De plus, étant donné que les composants rouge, vert et bleu sont traités indépendamment, les nuances de couleur souhaitées des images peuvent être facilement modifiées, car les intensités des trois composants couleur ne seront pas uniformément redimensionnées. Que se passera-t-il lorsque vous afficherez la valeur de couleur RVB (1, 0,5, 0,5)? La composante rouge restera à 1, mais les autres diminueront de moitié, ce qui changera complètement le ton de votre couleur..

La deuxième couleur a été obtenue à partir de la première en appliquant l’échelle non linéaire utilisée par les moniteurs. Remarquez comment cette transformation a affecté non seulement la luminosité de la couleur, mais également sa saturation..

Maintenant que nous avons vu les effets de cette propriété du moniteur sur les données de couleur transmises au moniteur, nous pouvons voir les étapes pour les combattre..

Qu'est-ce que la correction gamma??

La correction gamma consiste à annuler le travail malheureux du moniteur. La correction gamma d’une image élève essentiellement son intensité de couleur à 1 / gamma, de sorte que lorsque le moniteur augmente à son tour la valeur de gamma, ceux-ci s'annulent, et le résultat est la couleur que nous avions initialement l'intention de montrer. 

(Rappelez-vous que UNE élevé à B, et ensuite élevé à C, est le même que UNE élevé à B × C, et c’est pourquoi ces opérations s’annulent, comme gamma × (1 / gamma) est 1.) 

Étant donné que l'utilisateur moyen ne calibre pas son moniteur pour obtenir une réponse linéaire, de nombreuses images rencontrées sont corrigées afin de ne jamais ressentir la différence. En règle générale, la plupart des fichiers image sur Internet sont distribués dans ce que l’on appelle le espace de couleur sRGB-cela signifie que les valeurs de couleur d'origine prévues sont grossièrement élevé au pouvoir de 1 / 2.2 avant de les mettre dans des fichiers (bien que des équations plus complexes aient lieu dans la réalité). Cela garantit que tous les utilisateurs avec des écrans conventionnels voient les vraies couleurs. Les scanneurs, les appareils photo et de nombreux périphériques d'imagerie numérique prennent tous cela en compte et corrigent leur sortie pour vous lors de l'enregistrement dans des formats d'image conventionnels.

Cette image montre la cartographie des intensités de couleurs envoyées au moniteur par la carte graphique et les intensités affichées par le moniteur..

Regardez l'image ci-dessus. Si nous ne tenons pas compte du gamma, la courbe sera exponentielle (courbe verte inférieure). Si nous effectuons une correction gamma, la réponse réelle sera linéaire, comme il se doit. À des fins de comparaison, l'image montre également l'aspect du graphique lorsque nous effectuons une correction gamma, mais le moniteur a en réalité une réponse linéaire. Dans ce cas, les intensités seront déformées de la manière opposée, et nous pouvons voir que lorsqu'un moniteur non linéaire les déforme à son tour, cela s'annule et nous aboutissons à une ligne droite..

Quand dois-je m'inquiéter?

Jusqu'à présent, nous avons expliqué la théorie à la base de ces phénomènes: les moniteurs sont non linéaires et la plupart des images sont corrigées pour donner une apparence correcte à ces moniteurs, mais quel semble être le problème? Pourquoi devrais-je, un développeur de jeux 3D en herbe, me préoccuper de la correction gamma et faire autre chose? juste connaissance à propos de ça?

La réponse est simple: tant que les images sont créées pour être affichées, le problème n'existe même pas. Cependant, dès que vous souhaitez qu'un programme modifie ces images (redimensionnez-les, utilisez-les comme textures, vous le nommez), vous devez veiller à ce que le programme sache que les valeurs sont pas vrai et sont juste corrigés afin qu'ils l'air réel sur un moniteur.

En particulier, cela se produit dans un moteur de rendu lorsqu'il prend en entrée des cartes de texture, telles que des surfaces diffuses. Il les opère en supposant que leurs valeurs de couleur représentent avec précision les intensités lumineuses; c'est-à-dire en supposant correspondance linéaire avec des phénomènes réels qu'ils représentent.

Mais c’est une erreur fondamentale: si vous voulez additionner les valeurs de couleur et qu’elles sont corrigées des gamma (élevé à 1 / gamma) vous obtenez les mauvaises valeurs. Il ne faut pas un génie des mathématiques pour se rendre compte que UNE élevé à 1 / gamma plus B élevé à 1 / gamma n'est pas égal (A + B) élevé à 1 / gamma. Le problème se produit également lorsqu'un moteur de rendu génère certaines valeurs, telles que des contributions de lumière: des sommes deux contributions de lumière mais ne sait pas que le résultat sera élevé au gamma lorsqu’il est affiché à l’écran, il a produit faux valeurs.

Et c’est précisément là que le problème se pose: lorsqu'un moteur de rendu suppose que les couleurs obtenues correspondent linéairement aux phénomènes de la vie réelle, ou suppose que les couleurs qu’il produit en sortie correspondent linéairement aux intensités lumineuses de l’écran lorsqu’elles ont gagné. t, c’est une erreur assez grave qui peut affecter l’aspect des images produites.

Si vous ne corrigez aucune des erreurs, ne vous assurez pas que les couleurs de la texture en entrée introduites dans le rendu sont linéaires, ni que l'image de sortie du rendu sera linéaire par rapport à l'écran, ces images seront annulées. d’autres, dans une certaine mesure, un peu comme la façon dont ils annulent l’affichage lorsqu’ils affichent des fichiers JPEG précorrigés dans un navigateur Web. Cependant, dès que vous incluez des calculs intermédiaires qui supposent des correspondances linéaires, votre calcul sera faux.


(une) Ne pas corriger les textures et ne pas corriger l'image finale, (b) ne pas corriger les textures mais corriger l'image finale, (c) corriger les textures mais pas l'image finale, (ré) corriger les textures et l'image finale.

Rappelez-vous ce que nous avons dit à propos de la modification des tons de couleur plus tôt - ce fait peut (parfois) vous aider à détecter la non-linéarité. La règle générale est la suivante: si, lorsque vous appliquez des réglages linéaires aux paramètres (par exemple, en doublant la luminosité des lumières de la scène), l’image obtenue change non seulement de luminosité, mais également de nuances de couleur (par exemple, une zone partant d’un teinte orange rougeâtre vers le jaune), cela signifie qu’un processus intermédiaire non linéaire a très probablement lieu.

Cela peut se produire avec des cartes de texture extraites de différentes sources: Internet, un appareil photo numérique enregistrant au format sRGB JPEG, un scanner ou une texture peinte sur un moniteur non calibré explicitement ou non explicitement. corrigé par la suite. Toute mathématique effectuée sur ces cartes de texture sera fausse et s'écartera légèrement des valeurs théoriquement correctes. Ceci est visible avec le filtrage de texture et les mipmaps: puisque le filtrage suppose des réponses linéaires lors de la moyenne des valeurs de couleur, vous verrez des erreurs prononcées: les textures plus petites (distantes) apparaîtront nettement plus sombres que les plus grandes (c'est-à-dire, lorsqu'elles sont plus proches de vous): En effet, quand ils sont distants, l'algorithme de filtrage calcule la moyenne de davantage d'échantillons et leur non-linéarité affecte davantage le résultat..

L’éclairage souffrira également d’un gamma inapproprié: apport de lumière aux surfaces somme dans le monde réel, et donc dans un moteur de rendu, mais la somme n’est pas une opération fidèle si le résultat est asymétrique. Si vous utilisez des shaders de fragments complexes effectuant un éclairage sophistiqué, tel que la diffusion sous la surface ou le HDR, les erreurs deviennent de plus en plus prononcées, jusqu'au point réellement Je me demande ce qui ne va pas dans l’image, par opposition à un sentiment inconfortable de "peut-être un peu mauvais éclairage, mais c’est probablement juste moi", ce qui peut aussi arriver souvent. Le fait d’obscurcir les textures ou d’éclaircir les images finales avec un facteur constant ou linéaire ne tue pas l’effet, car il s’agit également d’opérations linéaires, et vous avez besoin d’une opération non linéaire pour lutter contre la courbe de réponse exponentielle inhérente se produisant sur le moniteur..

Comment je le répare?

Maintenant, espérons-le, vous êtes parfaitement au courant de ce que sont les corrections gamma et gamma et de la raison pour laquelle il s'agit d'un si gros problème lorsque vous créez des graphiques 3D en temps réel. Mais, bien sûr, il doit y avoir un moyen de résoudre ces problèmes? 

La réponse est oui, et fixer le gamma est une opération assez simple qui ne nécessite aucune modification du code, à part l’ajout de quelques lignes de code, sans compter les ajustements de paramètres, d’intensité et de couleurs supplémentaires que vous devrez effectuer pour obtenir le bon éclairage si vous avez réglé vos scènes pour bien paraître sur des moniteurs non linéaires sans les corriger. 

Il existe trois étapes de base pour rester linéaire le plus longtemps possible et effectuer la correction au bon moment:

1. Assurez-vous que les couleurs de votre texture sont justes

Normalement, vous ne devez pas modifier les images source afin qu’elles contiennent des couleurs linéaires; la correction gamma des couleurs pour le moniteur typique dans des champs de couleur de huit bits vous offre la résolution supplémentaire nécessaire dans les zones sombres où l'œil humain est plus sensible aux variations d'intensité. Cependant, vous pouvez vous assurer que les valeurs de couleur sont linéaires avant qu'elles n'atteignent vos shaders.. 

Normalement, dans OpenGL, vous pouvez le faire en passant GL_SRGB8 au lieu de GL_RGB8, et GL_SRGB8_ALPHA8 au lieu de GL_RGBA8, à glTexImage2D (), en spécifiant une texture. Cela garantira que toutes les valeurs lues à partir de cette texture via un échantillonneur de shader seront corrigées de l'espace colorimétrique sRGB en un espace linéaire, c'est précisément ce dont nous avons besoin! Si vous utilisez un moteur de rendu ou de jeu qui charge la texture pour vous, il peut en tenir compte ou vous devrez peut-être le spécifier manuellement. consulter la documentation de la bibliothèque ou demander de l'aide à quelqu'un en cas de doute.

Cependant, veillez à ne pas le faire par erreur avec des images qui, par définition, ne représentent pas les informations de couleur et ont été explicitement peintes dans cet esprit. Les exemples incluent les cartes normales, les reliefs et les reliefs, qui codent tous des données autres que la couleur dans les canaux de couleur d'une texture et ne nécessitent donc probablement pas ce type de précorrection..

Extrait de la démo incluse dans cet article (certains paramètres ont été échangés avec leurs valeurs réelles pour plus de clarté):

glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB8, largeur, hauteur, 0, GL_BGR, GL_UNSIGNED_BYTE, data); 

Cela chargera la texture dans un espace colorimétrique non corrigé. Cependant, si les données du fichier de texture se trouvent dans l’espace colorimétrique sRGB, nous devons modifier le troisième paramètre en GL_SRGB8, cédant:

glTexImage2D (GL_TEXTURE_2D, 0, GL_SRGB8, largeur, hauteur, 0, GL_BGR, GL_UNSIGNED_BYTE, données);

Cela garantira qu'OpenGL corrige les données de texture lorsque nous les recherchons.

2. Assurez-vous que les couleurs de l'image de sortie sont correctes

Vous devez maintenant appliquer une correction de couleur aux images de sortie finales de votre rendu. Assurez-vous de ne pas appliquer de correction à autre chose que le final framebuffer à afficher à l’écran. (Ne touchez pas les tampons intermédiaires qui sont entrés dans d'autres shaders de post-traitement, car ils s'attendent toujours à travailler avec des valeurs linéaires.) 

Cela peut être fait dans OpenGL en spécifiant le tampon de rendu (le tampon de frame final, non-échantillonnable) pour avoir un codage de couleur sRGB en passant GL_SRGB au lieu de GL_RGB en tant que paramètre pour glRenderbufferStorage (). Après cela, vous devez lever le GL_FRAMEBUFFER_SRGB signaler en appelant glEnable. De cette façon, les écritures du shader dans les tampons sRVB seront corrigées afin qu’elles soient affichées directement sur un moniteur typique.. 

Si vous utilisez un moteur ou un framework, celui-ci inclut probablement une sorte d’option permettant de créer un framebuffer sRGB pour vous et de le configurer correctement. Encore une fois, vous pouvez consulter la documentation de la bibliothèque ou demander à quelqu'un de clarifier cela pour vous..

Dans la démo, nous utilisons la bibliothèque GLFW, qui nous offre un moyen simple de demander un tampon de mémoire sRGB. En particulier, nous définissons un indicateur de fenêtre, puis, plus tard, nous indiquons à OpenGL d'activer les opérations du framebuffer dans l'espace sRGB:

glfwWindowHint (GLFW_SRGB_CAPABLE, TRUE);… glEnable (GL_FRAMEBUFFER_SRGB);

3. Corrigez vos réglages d'intensité de lumière et de couleur

S'il ne s'agit pas d'un nouveau projet, il est fort probable qu'un éclairage et un filtrage gamma incorrects vous nuisent. Peut-être avez-vous peaufiné vos couleurs de réflectance diffuse, vos intensités lumineuses et tout ce que vous avez essayé de faire pour compenser les nuisances subtiles que vous a occasionnées la négligence du gamma. 

Vous devez revoir ces valeurs et les ajuster pour qu'elles aient une apparence correcte. Cependant, cette fois, vos scènes seront plus naturelles grâce à une illumination représentant plus fidèlement les circonstances du monde réel. Les coins ne sembleront pas trop sombres, vous n'aurez donc pas besoin d'ajouter plus d'intensité à la lumière (ce qui annihilera l'éclairage d'objets plus brillants qui paraîtront artificiellement brillants pour cette quantité de lumière dans la scène).. 

Cela vous rapportera: revisiter vos paramètres pour créer un environnement naturel avec correction gamma contribuera grandement à fournir à vos utilisateurs une expérience et une distribution de la luminosité qui leur ressemble, à la fois habitués et sensibles au fonctionnement de la lumière dans la vie réelle.

Démo

Inclus avec cet article est une petite démo OpenGL 3.3 qui montre une scène simple avec des textures éclairées par deux sources de lumière en mouvement. Il vous permet de basculer entre plusieurs scénarios: ne pas corriger les textures mais corriger l’image finale; corriger les textures en négligeant de corriger l'image finale; corriger les deux (c'est-à-dire tout faire correctement); et ne pas corriger non plus (en faisant une double erreur). 

La démo est écrite en C ++ (avec deux shaders GLSL) et utilise des bibliothèques portables GLFW et GLEW. Elle devrait donc fonctionner sur une grande variété de plates-formes. Le code source est rempli de commentaires pour que vous puissiez explorer et explorer tous les aspects de cette courte application..

La démo en action.

Utilisez le 1 touche de votre clavier pour alterner entre la correction des textures et la non-correction des textures, et 2 clé pour alterner entre la correction du framebuffer et la correction du framebuffer. Pour faire défiler les deux simultanément, appuyez sur 3-Il est utile de voir la différence entre négliger complètement le gamma (deux erreurs qui s’annulent en grande partie) et faire les choses correctement. Lorsque la démo commence, aucune de ces corrections n’est effectuée, alors appuyez sur 3 pour voir les avantages d'une correction gamma appropriée.

J'ai inclus un projet Microsoft Visual C ++ 2013, des versions 64 bits compatibles des bibliothèques GLFW et GLEW et un exécutable Windows 64 bits. Cependant, vous pouvez le compiler assez facilement sur n’importe quelle plate-forme avec le support de GLFW et GLEW: main.cpp et loader.cpp ensemble et les lier contre ces deux bibliothèques. Sous Linux, installer ces bibliothèques via votre gestionnaire de paquets et passer -lglew -lglfw à g++ devrait faire l'affaire. (Veuillez noter que ceci n'a pas été testé sur des systèmes d'exploitation autres que Windows, mais il est supposé fonctionner. Si vous rencontrez des problèmes, merci de me le faire savoir dans les commentaires et je les corrigerai dès que possible.)

Comme vous pouvez le constater lors de l'exécution de la démo, les effets sont assez visibles, même avec un modèle simple et une scène simple comme celle-ci. Bien sûr, dans ce cas simple, vous pourriez peut-être vous permettre d’affiner les paramètres du shader pour que l’image ait l’air agréable de ne pas être corrigée. Cependant, dès que vous commencez à créer de la complexité dans vos scènes, la différence sera simplement trop visible pour compenser de cette façon..

Conclusion

Dans cet article, nous avons abordé des termes tels que gamma, correction gamma, entrées et sorties non linéaires et calcul mathématique non linéaire. Si tout va bien, j'ai réussi à vous convaincre que vous devriez commencer à vous préoccuper de la correction gamma dès maintenant si vous l'aviez négligée jusqu'à présent, et si vous avez été prudent avec le gamma avant de rencontrer cet article, j'espère seulement qu'il vous en donnera de nouveaux. petit élément d'information pour résoudre le problème avec. 

Nous avons surtout appris à résoudre les problèmes qui se posent lorsque vous manipulez des valeurs de couleur incorrectement, en supposant qu'elles sont linéaires, et nous avons passé en revue les pièges et les symptômes courants qui se produisent lorsque vous négligez cet aspect important de l'infographie..

J'espère que vous vous êtes amusés et avez appris quelque chose de nouveau en lisant cet article. Jusqu'à la prochaine fois!