Journal Galeries de shaders GLSL et fond d'écran animé pour Android

Posté par  . Licence CC By‑SA.
Étiquettes :
11
13
mai
2013

Dans le cadre de l'apprentissage d'OpenGL, j'ai découvert récemment les sites de galeries de shaders GLSL, qui pourraient être le nouvel eldorado du hobbyiste passionné d'effet graphique.

Grâce à la norme OpenGL ES 2 dont il fait partie, le langage GLSL permet en quelques lignes de réaliser des effets graphiques visuellement plaisants et potentiellement novateurs.Pour en profiter, le seul prérequis est un navigateur et une configuration supportant WebGL, car WebGL est basé sur OpenGL ES 2.

Voici deux exemples : https://www.shadertoy.com/ et http://glsl.heroku.com/ . Ces sites incitent à l'expérimentation en proposant une rétroaction immédiate sur les modifications du code. Les messages d'erreurs sont parfois abscons car la compilation de GLSL est prise en charge directement par le driver du système graphique. Ces sites vont potentiellement produire de grandes logithèques de shader, et il me semble important de standardiser leur format pour faciliter leur réutilisation, ainsi que d'indiquer leur licence (beaucoup de shaders sont non triviaux).

OpenGL ES 2 est également la norme supportée sur la plupart des appareils Android actuels. Je me suis donc lancé dans un fond d'écran animé paramétrable pour essayer d'utiliser certains de ces shaders sur mon téléphone. Le résultat est encore perfectible, mais cela fonctionne sur le principe. J'ai complété l'appli par une interface primitive sur la galerie de glsl.heroku.com.

J'ai publié ce projet en fin de semaine dernière sur Google Play, et le code est public sur github. Vous trouverez également une video de présentation sur Youtube.

N'hésitez pas à me faire part de vos suggestions dans les commentaires. Le projet est encore assez instable, en particulier lorsque la galerie et le fond d'écran sont simultanément actifs. Je n'ai testé que sous Android 4.1, mais il est possible que cela fonctionne en 2.3. Mes souhaits pour la prochaine version serait d'améliorer la stabilité et la compatibilité avec les shaders (les drivers linux/android ne se comportent exactement comme ceux sous Windows pour les variables non initialisées par exemple).

Les liens :

http://www.youtube.com/watch?v=kZQEvfYftIc

https://play.google.com/store/apps/details?id=com.softwaresemantics.diyglsllwp

https://github.com/cyrilmhansen/DIYGlslLwp

  • # charge cpu

    Posté par  . Évalué à 2. Dernière modification le 13 mai 2013 à 10:19.

    merci pour ces liens.

    je suis surpris, firefox me prend un core entier lors de l'affichage d'un élément de la galerie.
    pourtant, le about:support de firefox me dit "WebGL RendererGoogle Inc.—ANGLE (Intel(R) HD Graphics Family)".
    je pensais que cela allait délester le cpu.

    • [^] # Re: charge cpu

      Posté par  . Évalué à 2.

      En effet le support de WebGL n'est pas encore stable pour tout le monde.
      Voici un tableau des versions de navigateurs le supportant : http://caniuse.com/webgl . D'après ce même site, 50% des internautes ont une configuration le supportant au moins en partie.

      Sur mon desktop j'ai une carte nvidia. J'avais l'impression que le support 3d des dernières cartes Intel était OK, mais cela dépend aussi de ta carte.

    • [^] # Re: charge cpu

      Posté par  (site web personnel, Mastodon) . Évalué à 2. Dernière modification le 13 mai 2013 à 15:23.

      Si ça peut te rassurer, Chromium me bouffe deux CPU à 80-90% pour cette démo https://www.shadertoy.com/view/4dl3z7. 6fps. (chromimum 25)

      Et pour Firefox (20), c'est plutôt 1 à 90% et un autre à 70%… Toujours à 6 fps

      carte NVIDIA Corporation—NVS 4200M/PCIe/SSE2. Sous linux bien sûr, avec driver proprio.

      Je pense que cela est dû plutôt au JS ce que l'on voit en temps CPU, vu qu'il y a des animations.

      • [^] # Re: charge cpu

        Posté par  . Évalué à 7.

        J'ai du 35 fps avec les drivers libres et une carte AMD (par contre, je n'ai pas d'image /o\)

        « Rappelez-vous toujours que si la Gestapo avait les moyens de vous faire parler, les politiciens ont, eux, les moyens de vous faire taire. » Coluche

      • [^] # Re: charge cpu

        Posté par  . Évalué à 1.

        Ici 7.5 FPS macbouc air (sous macos /o\ ) avec core i7 Intel HD 3000 et firefox 21, CPU à 4%.

  • # batterie

    Posté par  . Évalué à 2.

    C'est joli tout ça, mais la batterie qui n'a déjà pas une durée bien longue depuis quelques années, elle dure combien avec ce truc qui tourne en permanence ?

    • [^] # Re: batterie

      Posté par  (site web personnel) . Évalué à 4.

      C'est joli tout ça

      Tout est relatif, j'ai regardé la vidéo et je ne sais pas qui peut bien mettre un truc pareil en fond d'écran sans devenir épileptique au bout de deux jours :)

    • [^] # Re: batterie

      Posté par  . Évalué à 3. Dernière modification le 13 mai 2013 à 11:23.

      Un fond d'écran animé Android n'est actif que lorsque le launcher/home est visible. Dès que vous lancez une application, l'animation n'est plus visible et ne consomme plus de ressource. La mémoire peut même être libérée si le système le requiert. Ce qui bouffe l'autonomie sous Android il me semble, ce sont les applis qui bloquent la mise en veille correcte du téléphone, l'accès réseau…

      Néanmoins, je conviens qu'un écran animé consommera toujours plus de ressources qu'une image statique. Personnellement, cela me gène plus au niveau de la réactivité du téléphone qu'au niveau de l'autonomie, mais cela dépend évidemment de l'usage de chacun et des capacités de son matos. Notez que la consommation des téléphones va baisser progressivement avec la finesse de gravure.

  • # Ouch, plantage !

    Posté par  . Évalué à 1.

    Le premier site donné en exemple (http://www.shadertoy.com/) ne me réussit pas… Mon navigateur reste gelé après quelques secondes de chargement (dès la page d'accueil du site).

    Testé aussi bien avec un Firefox 20.0 (avec WebGL activé) qu'un Iceweasel 10.0 (sans support du WebGL à ma connaissance). Côté matos/pilote 3D, si c'est là l'origine commune du plantage, c'est du SandyBridge…

    Par contre ça marche sans soucis avec le second site. J'aime bien cet exemple ci : http://glsl.heroku.com/e#8598.0 , dont le code source est très concis et qui n'est pas trop désagréable à regarder (avec le petit côté intéractif en bonus).

  • # C'est trop limité ;)

    Posté par  (site web personnel) . Évalué à 10.

    Ce qui est bien avec GL c'est que le système de shader est plus complet que cela.

    En GL/GL-ES, tu as deux/trois/quatre stages de shader en plus:

    Vertex Shader -> (Tesselation Control -> Tesselation Evaluation) -> [Geometry shader] -> Fragment shader + Compute shader.

    (Entre parenthèse ce qui est strictement GL 5, entre crochet un stage optionnel et qui est disponible en GL3 ou GLES depuis peu, mais je ne crois pas sur les navigateurs).

    Respectivement le travail de chacun :

    Vertex Shader

    Prend des points en entrée et les transforme pour generer de nouveaux points. Un point c'est une entité arbitraire, donc cela peut être une position, mais cela peut aussi être un poulet, défini par sa couleur, sa taille, ses points de vie. Le but du vertex shader est de transformer cela pour donner un nouveau point arbitraire (cela peut donc être des mesures de température liés à une date)

    Pour être très honette, le viewer sur glsl sandbox utilise (obligatoirement) un Vertex Shader avec 4 points positionnés au quatre coins de l'écran. (Je n'ai pas regardé le code, on peut aussi faire autrement, mais ce serait vicieux ;)

    Controle et Evaluation Tesselation Shader

    Je groupe ces deux shaders car ils sont liés. Ils prennent en entrée des points et vont générer pleins de triangles/lignes. C'est généralement utilisé pour lisser les objets, mais on peut s'en servir de façon détournée (pour faire des cheveux par exemples, en générant pleins de lignes)

    Geometry Shader

    Celui-ci est tordu. Sont but est de prendre une primitive (i.e. un assemblage de points) et de générer une/plusieurs nouvelles primitives. Dans les grandes ligne GL ne connaît que trois primitives (point, ligne, triangle) (c'est encore faux, mais bon, vous lirez la doc pour plus). Un exemple d'utilisation du geometry shader pourrait être de convertir un point en triangles. Exemple vous avez un arbre, représenté par un point contenant une couleur, une position, une taille, un type de feuille et vous aller mettre un tas de triangle à la place.

    Generalement on utilise le géometrie shader pour des cas tordus, d'autant qu'il est lent, donc on le réserve pour des usages bizarres ;)

    Ici il faut faire une pause. Tout ces traitement ont eu lieu sur des points arbitraires (comme je le disais, des poulets), mais maintenant il faut savoir quoi afficher à l'écran. Pour cela il faut connaître la position 3D de vos points. Ainsi nos points qui étaient arbitraire au depart doivent sortir du geometry shader (ou du tesselation si le geometry n'est pas utilisé, ou du vertex shader si ni geometry ni tesselation ne sont activés) avec une position.

    Ainsi on passe d'un point arbitraire (un poulet) à un point positioné dans l'espace avec des attributs arbitraires (i.e.: une position associée à une couleur, une taille, une agressivité et des points de vie).

    A ce moment, la carte graphique va decider des pixels qui sont couverts par notre primitive et pour chacun de ses pixels elle va appeler le fragment shader (i.e.: le seul bout de code disponible dans l’outil presenté dans ce journal)

    Fragment shader

    Sert à donner une couleur et une profondeur à un pixel en fonction des attributs interpolés des points passés en paramètre pour dessiner une primitive.

    Vous l'aurez conclu vous même, sans control sur les points passés en paramètre et sur le type de primitive, le fragment shader ne sert qu'a "donner une couleur à un pixel arbitraire" et c'est super limité !

    Relativisons, on peut faire pleins de choses, mais comparé à ce qui est normalement faisable dans GL, c'est limité.

    Il reste un dernier shader (GL4.3 dernièrement) c'est le Compute shader, qui sert à tout faire, et même le café, sans aucune aide de la part du GPU pour par exemple afficher. C'est moins limité, mais plus lent dans certains cas, donc il faut l'utiliser au bon endroit.

    tl;dr

    C'est limité, GL permet de faire tellement plus de chose. Mais c'est tout de même cool !

    • [^] # Re: C'est trop limité ;)

      Posté par  . Évalué à 2.

      Merci pour la présentation de toute la famille des "shader". L'application pratique à Android contraint néanmoins de se limiter à ce dont dispose OpenGL2 ES, soit les shaders de vertex et de fragment.

      Les galeries fixent en effet en général la géométrie et le vertex shader pour que la surface dessinée par le fragment shader correspondent à la surface du canevas. Le shader travaille donc avec les coordonnées du pixel à calculer principalement, mais aussi avec des variables entière ou flottantes qui peuvent être définies pour image par image : c'est ainsi que sont possibles les animations, on fait varier un paramètre temps (time). Il y a aussi des paramètres pour la taille de l'écran et la position du curseur de souris, ces derniers difficilement exploitables sous Android.

      Je ne me rappelle plus où, mais je suis tombé sur une galerie ou l'on pouvait définir son propre shader de vertex en sus du vertex de fragment. Si c'est utile, c'est simple à ajouter. Dans tous les cas, il y a un besoin de standardiser l'interface des shaders. S'il y a plusieurs shaders ils peuvent se passer des paramètres…

      Une des questions que je me pose, c'est comment rendre le rendu indépendant de la résolution. Actuellement, l'image est zoomée (ie restreinte) lorsque la resolution est plus faible. Pour éviter cela, le fragment shader doit avoir accès à la résolution et faire les adaptations nécessaires dans son propre code, ce qui n'est pas le cas en général sur glsl.heroku.com. Mon appli pourrait modifier à la volée les shaders pour corriger le problème.

      • [^] # Re: C'est trop limité ;)

        Posté par  (site web personnel) . Évalué à 2.

        D'ailleurs, c'est quoi les interfaces des shader présentés plus haut ? Que sont les données 3d d'entrée ?

        gl_FragCoord est utilisé en entré et l_FragColor en sortie. J'ai bien compris que la sortie était la couleur d'un pixel. Mais pour le fragCoord, j'ai rien compris, j'ai cru penser que c'était chaque pixel de l'image, mais on dirait que non.

        "La première sécurité est la liberté"

        • [^] # Re: C'est trop limité ;)

          Posté par  . Évalué à 1.

          gl_FragCoord est un vecteur de dimension 2 représentant les coordonnées du point dont le shader doit calculer la couleur.
          gl_FragColor est un vecteur de dimension 4 représentant la couleur (rgba). La plupart des variables sont en float.

          Ce sont des paramètres implicites. Les autres paramètres sont définis en tête du shader :

          Ex uniform float time;
          uniform vec2 mouse;
          uniform vec2 resolution;

          uniform veut dire que les valeurs sont constantes pour tous les points.

          • [^] # Re: C'est trop limité ;)

            Posté par  (site web personnel) . Évalué à 2.

            Est-ce qu tu peux déclarer une variable uniforme dans une fonction du shader ?

            Quel est l’intérêt du "a" dans rgba quand on est plus dans un espace 3d ?

            "La première sécurité est la liberté"

            • [^] # Re: C'est trop limité ;)

              Posté par  . Évalué à 2. Dernière modification le 15 mai 2013 à 16:25.

              Est-ce qu tu peux déclarer une variable uniforme dans une fonction du shader ?

              Pas que je sache, mais en même temps, vu que la variable est globale et constante, quel serait l'intérêt de la limiter à une fonction ?

              Quel est l’intérêt du "a" dans rgba quand on est plus dans un espace 3d ?
              la a, c'est la composante alpha de la couleur, son intérêt est le même en 3d et en 2d, faire de la transparence.

              • [^] # Re: C'est trop limité ;)

                Posté par  (site web personnel) . Évalué à 2. Dernière modification le 15 mai 2013 à 17:13.

                "Pas que je sache, mais en même temps, vu que la variable est globale et constante, quel serait l'intérêt de la limiter à une fonction ?"

                Faire des calculs genre lui faire calculer 1/ srqt(5) une fois pour toutes sans avoir à faire confiance au compilo du drivers opengl.

                "a" pour faire de la transparence, dans une fenêtre web ?

                "La première sécurité est la liberté"

                • [^] # Re: C'est trop limité ;)

                  Posté par  . Évalué à 2.

                  Faire des calculs genre lui faire calculer 1/ srqt(5) une fois pour toutes sans avoir à faire confiance au compilo du drivers opengl.

                  Ok, ça c'est une constante, généralement tu l'écris de façon littérale dans ton code.
                  Les "uniform" ce sont des variables globales passés depuis ton code cpu vers ton shader, ça ne sert pas à stocker un résultat de calcul dans le shader.

                  "a" pour faire de la transparence, dans une fenêtre web

                  Pour faire de la transparence dans ta scene de rendu, entre deux textures par exemple.

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.