Aller au contenu

Pixel Art en ombres et lumières

Vous êtes vous déjà demandé ce qui faisait la richesse des couleurs d'une image, ou au contraire ce qui vous donnait l'impression qu'elle était plate ou vide ?

En réfléchissant au problème, je suis arrivé à des conclusions quelque peu inattendues et intéressantes sur l'expression des ombres et lumières dans le Pixel Art.

Ombres et lumières

Pour qu'une image donne une impression de profondeur et de réalisme, elle se doit de rendre des effets d'ombre et de lumière.

Ces ombres et lumières apparaissent sous forme de dégradés plus ou moins marqués en fonction des zones. Sur un véritable dessin ou une photo, il y aurait une "infinité" de variantes de couleurs sur ces dégradés. Dans mon exemple ci-dessous, en pixel art, il m'a paru préférable de ne conserver au maximum que 6 variantes d'une même couleur pour garder un effet "jeu vidéo à l'ancienne", et surtout pour fonctionner dans un espace discret, plutôt que continu.

Comparaison entre couleurs plates et variations de teinte/luminance
L'image de droite comporte une variation de saturation et de luminosité, contrairement à celle de gauche

Comme on peut le voir, l'image de gauche parait franchement "plate", aucun volume n'est exprimé, et elle semble un peu vide.

Dans la seconde, on constate bien les variantes (sur le violet des cheveux par exemple), et on a un peu plus l'impression d'avoir une expression de la troisième dimension et de la lumière.

Les variantes ont été constituées de manière très basique (en reprenant le modèle HSL déjà évoqué plus tôt) : on conserve ici la même teinte, et on fait varier la luminosité (ce qui semble logique, puisqu'on cherche à exprimer une variation de lumière sur une même surface) et la saturation.

Mais il semble encore manquer quelque chose...

En effet, cette méthode est trop simpliste, et ça se voit. Les effets de lumière paraissent étranges, voire "plats", encore une fois...

Couleurs des ombres et lumières

Il y a deux éléments primordiaux qui n'ont pas été pris en compte jusqu'ici :

  1. La lumière a une couleur. Toute source de lumière tend vers une couleur, le Soleil y compris (en réalité, le Soleil émet une lumière blanche, mais, après être passée dans l’atmosphère, le bleu s'est dispersé dans le ciel, et on voit surtout du jaune). De ce fait, une surface bleue éclairée par une lampe jaune devrait paraitre un peu plus verte dans les zones éclairées, et plus bleue dans les zones d'ombre
  2. Les ombres aussi comportent une couleur. En effet, si vous vous mettez à l'ombre d'un bâtiment orange, votre peau paraitra plus orange. Ce ne sont pas les ombres elles-mêmes qui génèrent la couleur. En réalité, l'élément qui entraine l'ombre reflète aussi une infime partie de la lumière dans sa couleur.

Un bon exemple de ces deux points : la peau parait "rose" du fait de la couleur rouge du sang. Et souvent, les sources de lumière artificielles ont tendance à tendre vers le jaune.

On constatera que les photos et dessins de peau (je ne vous pousse pas à aller regarde du nu, mais c'est le meilleur moyen de le constater) ont tendance à accentuer les rouges dans les ombres, et à accentuer le jaune/orange dans les zones de lumière.

C'est particulièrement visible sur ce dessin et un peu moins sur cette photo

Méthode empirique

Pour simplifier, on pourrait partir du principe que toutes les sources de lumière sont jaunes, et que plus un objet est éclairé, plus il tend vers cette couleur, et plus il est dans l'ombre, plus il tend à refléter sa propre couleur.

C'est un peu comme ça que je le voyais, jusqu'à ce que j'analyse les couleurs utilisées dans divers sprites issus de jeux-vidéo différents (Ragnarok online, Jump Superstars, et divers autres). En prenant divers exemples, je me suis rendu compte que les 6 variantes de couleur avaient tendance à se construire sur le même principe, c'est à dire que les variations de teinte, de saturation et de luminosité entre les variantes d'une même couleur pouvait très souvent être exprimées avec la même formule mathématique.

Variation de saturation
Note : il n'y a aucune correspondance de couleur entre les graphiques, ni avec la couleur affichée
Les variantes de couleurs vont de 0 (la plus sombre) à 5 (la plus claire)

Si on met de côté le drôle d'écart de la couleur 4, on a semble-t-il quelque chose d'assez linéaire. Chaque droite semble avoir une pente équivalente, mais un offset légèrement différent.

Variation de luminance

Ici, on constate que chacune des courbes se découpe en trois parties : une pente normale sur les premiers points, une pente forte au milieu et une pente faible sur la fin. Cela laisse imaginer une équation d'ordre 3 ou plus. Ici encore, les variations entre chaque courbe peuvent probablement s'exprimer par un offset, ou au pire par un facteur (ça reste franchement empirique et approximatif, mais avons-nous réellement besoin de plus de précision ?).

Bref, jusqu'ici, on constate que plus on est dans les ombres, plus la saturation est forte et la luminosité faible. Ca n'a rien de surprenant. Le plus intéressant arrive :

Variation de teinte

Clairement, la variation de de teinte se présente sous forme linéaire. Mais les pentes varient beaucoup. Il y a donc une logique, mais laquelle ?

Elles semblent plus ou moins converger vers un point. Et ce point de convergence est {X=15, Y=75}. En bref, elles tendent toutes vers la couleur "75", qui correspond à un vert un peu jaune !

J'en entend dans le fond me dire que ce n'est pas le cas de la couleur 3, qui diverge (verge !). Sauf que... si !

En réalité, les valeurs que nous manipulons ici sont des angles exprimés en degrés. Si on calcule où semble tendre la couleur 3, on tombe sur 435°, qui équivaut en fait à 75° (rappel : 360° = 0°).

Si on applique cette logique à notre image du début, cela donne :

Comparaison entre simple variation de luminance + saturation et variation luminance + saturation + teinte
L'image de droite comporte une variation de teinte, contrairement à celle de gauche

Je vous l'accorde, la différence ne saute pas aux yeux (elle est surtout visible dans les cheveux et le vêtement. La peau est un peu ratée, ici...). Et pourtant, c'est un élément crucial pour obtenir un effet plus réaliste.

Traduction mathématique

Après quelques recherches et interpolations, j'en viens à cette description du comportement des variations de couleurs sur les sprites de jeu vidéo entre ombre et lumière, que les graphistes les aient calculées ou choisies "au feeling", il semblerait qu'ils ont toujours tendance à suivre la même logique mathématique, qui peut s'exprimer comme suit :

Teinte

y = x + ( 75 - x ) 15

(x = 0) étant la teinte appliquée à la première variante, la plus sombre.

On pourrait très bien faire varier le diviseur pour tendre plus ou moins rapidement vers le vert à 75°.

Saturation

y = 55 - 7,2 x

Une droite relativement simple à calculer (comme la plupart de mes calculs, il s'agit d'une conclusion empirique, bien sûr).

Luminosité

y = 95 + 51,58 x - 18,55 x 2 + 2,92 x 3

Merci à l'outil d'interpolation de WolframAlpha, qui m'a permis d'arriver à un résultat exploitable, que j'ai ensuite simplifié un peu.

Pistes de réflexion

Maintenant que nous avons un moyen mathématique de calculer des variantes de couleur qui donneront un certain réalisme à notre image, que reste-t-il en suspens ?

Tout d'abord, pourquoi le vert 75° ? Ce vert-jaune vers lequel semblent tendre toutes les couleurs dans leurs variantes claires pourrait-il avoir un lien avec l'un des éléments suivants ?

  • La couleur pour laquelle l'oeil humain est optimisé ? Cette couleur se trouve effectivement dans les verts un peu jaune.
  • La couleur de la lumière reçue du Soleil au travers de la couche d'Ozone ?
    J'évoquais plus haut le fait que c'était surtout la lumière jaune qui nous parvenait du Soleil (même si elle est blanche à l'origine). Cependant, il me parait possible que le bleu du ciel ait son influence en renvoyant un peu de lumière bleue sur nous...

Autre question : à partir de quel point la droite d'une teinte devrait diverger ? J'ai deux hypothèses là-dessus, mais aucune preuve concrète pour l'étayer :

  • à 255° : c'est l'opposé au 75° vers lequel on tend. Ainsi, un angle supérieur à 255° se rapprochera plus rapidement du 75° en tournant dans le sens horaire plutôt qu'antihoraire.
  • à 270° : en réalité, les angles utilisés pour définir une teinte vont de 0° à 360°, allant du rouge au jaune, puis au vert, au bleu, au violet, avant de revenir au rouge. Pourtant, le spectre visible (et les-arcs-en-ciel) ne vont pas aussi loin, et s'arrêtent dans les bleus.
    sAlors comment peut-on expliquer le violet ? Il s'agit tout simplement d'un mélange de bleu et de rouge. Un mélange de 2 longueurs d'onde. Dans ce cas, la logique sur la variation de teinte n'est peut-être pas vraiment valable entre 270° et 259°...

EDIT : et je compte réutiliser toute cette logique dans une variante de l'Anime Girl Generator, réalisée en C++/Qt, cette fois-ci.

Des nouvelles sur le sujet d'ici quelques jours.