Photos Facebook 3D à l'intérieur: Shaders Parallax

image

Au cours des derniers mois, Facebook a inondé les photos 3D . Si vous n’avez pas pu les voir, je vais vous expliquer: les photos 3D sont des images à l’intérieur du message qui modifient l’angle en douceur lors du défilement de la page ou lorsque vous déplacez la souris dessus.

Quelques mois avant l'apparition de cette fonctionnalité, Facebook a testé une fonctionnalité similaire avec des modèles 3D. Bien que vous puissiez facilement comprendre comment Facebook peut rendre des modèles 3D et les faire pivoter en fonction de la position de la souris, avec des photos 3D, la situation peut ne pas être aussi intuitive.

La technique utilisée par Facebook pour créer une tridimensionnalité d'images bidimensionnelles est parfois appelée décalage de carte d'élévation . Il utilise un phénomène optique appelé parallaxe .

Exemple de photo Facebook 3D (GIF)

Qu'est-ce que la parallaxe


Si vous avez joué à Super Mario, vous savez exactement ce qu'est la parallaxe. Bien que Mario fonctionne à la même vitesse, il semble que les objets distants en arrière-plan se déplacent plus lentement (voir ci-dessous).


Cet effet crée l'illusion que certains éléments, tels que les montagnes et les nuages, sont situés plus loin. Il est efficace car notre cerveau utilise la parallaxe (ainsi que d'autres indices visuels) pour estimer la distance aux objets distants.

Comment le cerveau évalue-t-il la distance?
On suppose que le cerveau humain utilise plusieurs mécanismes pour estimer la distance. À courte et moyenne portée, les distances sont calculées en comparant les différences de position de l'objet visible avec l'œil droit et l'œil gauche. C'est ce qu'on appelle la vision stéréoscopique et est répandu dans la nature.

Cependant, pour des objets suffisamment éloignés, une vision stéréoscopique ne suffit pas. Les montagnes, les nuages ​​et les étoiles diffèrent trop peu pour que différents yeux remarquent une différence significative. Par conséquent, la parallaxe relative entre en jeu. Les objets en arrière-plan se déplacent moins que les objets en avant-plan. C'est leur mouvement relatif qui vous permet de définir la distance relative.

Dans la perception de la distance, de nombreux autres mécanismes sont utilisés. Le plus célèbre d'entre eux est la brume atmosphérique, qui donne aux objets éloignés une teinte bleue. Dans d'autres mondes, la plupart de ces indices atmosphériques n'existent pas, il est donc difficile d'évaluer l'échelle des objets sur d'autres planètes et la lune. L'utilisateur YouTube Alex McCulgan explique cela sur sa chaîne Astrum , montrant à quel point il est difficile de déterminer la taille des objets lunaires montrés dans la vidéo.


La parallaxe comme décalage


Si vous connaissez l'algèbre linéaire, vous savez probablement à quel point les mathématiques des rotations 3D peuvent être compliquées et non triviales. Par conséquent, il existe un moyen beaucoup plus simple de comprendre la parallaxe, qui ne nécessite que des décalages.

Imaginons que nous regardions un cube (voir ci-dessous). Si nous sommes précisément alignés avec son centre, les faces avant et arrière ressembleront à deux carrés de tailles différentes pour nos yeux. Telle est la perspective .


Cependant, que se passe-t-il si nous déplaçons la caméra vers le bas ou soulevons le cube? En appliquant les mêmes principes, nous pouvons voir que les faces avant et arrière ont changé par rapport à leur position précédente. Plus intéressant encore, ils se sont déplacés les uns par rapport aux autres. La face arrière, qui est plus éloignée de nous, comme si elle bougeait moins.


Si nous voulons calculer les positions réelles de ces sommets du cube dans notre portée projetée, alors nous devrons sérieusement prendre la trigonométrie. Cependant, ce n'est pas vraiment nécessaire. Si le mouvement de la caméra est suffisamment petit, nous pouvons approximer le déplacement des sommets en les déplaçant proportionnellement à leur distance.

La seule chose que nous devons déterminer est l'échelle. Si nous déplaçons X mètres vers la droite, il devrait sembler que l'objet Y mètres se soit déplacé de Z mètres. Si X reste petit, la parallaxe devient la tâche d' interpolation linéaire plutôt que de trigonométrie. Essentiellement, cela signifie que nous pouvons simuler de petites rotations 3D en décalant les pixels en fonction de leur distance par rapport à la caméra.

Générer des cartes de profondeur


En principe, ce que Facebook fait n'est pas trop différent de ce qui se passe dans Super Mario. Pour une image donnée, certains pixels sont décalés dans la direction du mouvement en fonction de la distance à la caméra. Pour créer une photo 3D de Facebook, vous n'avez besoin que de la photo elle-même et d'une carte indiquant la distance de chaque pixel par rapport à la caméra. Une telle carte a le nom attendu - «carte de profondeur» . Elle est également appelée carte de hauteur, selon le contexte.

Prendre une photo est assez simple, mais générer la bonne carte de profondeur est une tâche beaucoup plus difficile. Les appareils modernes utilisent diverses techniques. Utilisez le plus souvent deux caméras; chacun prend une photo du même sujet, mais avec une perspective légèrement différente. Le même principe est utilisé en vision stéréoscopique , que les gens utilisent pour évaluer la profondeur à de courtes et moyennes distances. L'image ci-dessous montre comment l'iPhone 7 peut créer des cartes de profondeur à partir de deux images très proches.


Les détails de la mise en œuvre d'une telle reconstruction sont décrits dans l'article Instant 3D Photography , présenté par Peter Hedman et Johannes Kopf au SIGGRAPH2018.

Après avoir créé une carte de profondeur de haute qualité, la simulation de la tridimensionnalité devient une tâche presque triviale. La véritable limite de cette technique est que même si vous pouvez recréer un modèle 3D approximatif, il manque des informations sur la façon de rendre les pièces invisibles dans la photo d'origine. Pour le moment, ce problème ne peut pas être résolu, et par conséquent, tous les mouvements visibles sur les photographies 3D sont plutôt insignifiants.

Nous nous sommes familiarisés avec le concept des photographies 3D et avons brièvement expliqué comment les smartphones modernes peuvent les créer. Dans la deuxième partie, nous apprendrons comment les mêmes techniques peuvent être utilisées pour implémenter des photos 3D dans Unity à l'aide de shaders.


Partie 2. Shaders de parallaxe et cartes de profondeur


Modèle de shader


Si nous voulons recréer des photos 3D de Facebook à l'aide d'un shader, nous devons d'abord décider exactement ce que nous allons faire. Étant donné que cet effet fonctionne mieux avec des images 2D, il serait logique d'implémenter une solution compatible avec les sprites Unity. Nous allons créer un shader qui peut être utilisé avec Sprite Renderer .

Bien qu'un tel shader puisse être créé à partir de zéro, il est souvent préférable de commencer avec un modèle prêt à l'emploi. Il est préférable de commencer à avancer en copiant le shader diffus existant des sprites, que Unity utilise par défaut pour tous les sprites. Malheureusement, le moteur n'est pas fourni avec un fichier shader que vous pouvez modifier vous-même.

Pour l'obtenir, vous devez aller dans l' archive de téléchargement Unity et télécharger le package Built in shaders (voir ci-dessous) pour la version du moteur que vous utilisez.


Après avoir extrait le package, vous pouvez afficher le code source de tous les shaders fournis avec Unity. Nous sommes intéressés par le fichier Sprites-Diffuse.shader , qui est utilisé par défaut pour tous les sprites créés.

Les images


Le deuxième aspect qui doit être officialisé est les données dont nous disposons. Imaginez que nous ayons à la fois l'image que nous voulons animer et sa carte de profondeur. Ce dernier sera une image en noir et blanc, dans laquelle les pixels en noir et blanc indiquent à quelle distance ou à quelle distance ils sont de la caméra.

Les images utilisées dans ce tutoriel sont tirées du projet Pickle cat de Dennis Hotson , et c'est sans aucun doute la meilleure que vous verrez aujourd'hui.


La carte d'altitude associée à cette image reflète la distance entre le museau du chat et la caméra.


Il est facile de voir comment de bons résultats peuvent être obtenus avec une carte de profondeur aussi simple. Cela signifie qu'il est facile de créer vos propres cartes de profondeur pour les images existantes.

Les propriétés


Maintenant que nous avons toutes les ressources, nous pouvons commencer à écrire le code du shader de parallaxe. Si nous importons l'image principale en tant que sprite, Unity la transmettra automatiquement au shader via la propriété _MainTex . Cependant, nous devons mettre la carte de profondeur à la disposition du shader. Cela peut être implémenté à l'aide d'une nouvelle propriété de shader appelée _HeightTex . J'ai intentionnellement décidé de ne pas l'appeler _DepthTex afin de ne pas le confondre avec la texture de profondeur (il s'agit d'un concept Unity similaire utilisé pour rendre la carte de profondeur de la scène).

Pour changer la force de l'effet, nous ajouterons également la propriété _Scale .

 Properties { ... _HeightTex ("Heightmap (R)", 2D) = "gray" {} _Scale ("Scale", Vector) = (0,0,0,0) } 

Ces deux nouvelles propriétés doivent également correspondre à deux variables du même nom qui doivent être ajoutées à la ENDCG CGPROGRAM / ENDCG :

 sampler2D _HeightTex; fixed2 _Scale; 

Maintenant, tout est prêt et nous pouvons commencer à écrire du code qui effectuera le décalage.

La première étape consiste à échantillonner la valeur de la carte de profondeur, ce qui peut être fait en utilisant la fonction tex2D . Puisque _HeightTex est une texture en noir et blanc, nous pouvons simplement prendre son canal rouge et jeter le reste. La valeur résultante mesure la distance dans certaines unités arbitraires du pixel actuel à la caméra.

La valeur de profondeur est comprise entre 0avant 1mais nous allons l'étirer à l'intervalle de 1avant +1. Cela vous permet de fournir une parallaxe positive (couleur blanche) et négative (couleur noire).

Théorie


Pour simuler l'effet de parallaxe à ce stade, nous devons utiliser les informations de profondeur pour décaler les pixels de l'image. Plus le pixel est proche, plus il doit être déplacé. Ce processus est expliqué dans le diagramme ci-dessous. Le pixel rouge de l' image d'origine, conformément aux informations de la carte de profondeur, doit décaler de deux pixels vers la gauche. De même, le pixel bleu doit décaler deux pixels vers la droite.


Bien que cela devrait théoriquement fonctionner, il n'y a pas de moyen facile de l'implémenter dans le shader. Le fait est qu'un shader par son principe ne peut que changer la couleur du pixel actuel . Lors de l'exécution du code de shader, il doit dessiner un pixel spécifique sur l'écran; nous ne pouvons pas simplement déplacer ce pixel vers un autre endroit ou changer la couleur du pixel voisin. Cette restriction de localité fournit un fonctionnement parallèle très efficace des shaders, mais ne nous permet pas de mettre en œuvre toutes sortes d'effets qui seraient triviaux à condition qu'il y ait un accès aléatoire pour l'enregistrement à chaque pixel de l'image.

Si nous voulons être précis, alors nous devons échantillonner la carte de profondeur de tous les pixels voisins pour savoir lequel doit (s'il doit) se déplacer vers la position actuelle. Si plusieurs pixels doivent être au même endroit, alors nous pouvons faire la moyenne de leur influence. Bien qu'un tel système fonctionne et fournisse le meilleur résultat possible, il est extrêmement inefficace et potentiellement des centaines de fois plus lent que le shader diffus original avec lequel nous avons commencé.

La meilleure alternative serait la solution suivante: nous obtenons la profondeur du pixel actuel à partir de la carte de profondeur; puis, si nous devons la déplacer vers la droite , remplacez la couleur actuelle par le pixel à gauche (voir image ci-dessous). Ici, nous supposons que si vous souhaitez déplacer le pixel vers la droite, les pixels voisins à gauche devraient également se déplacer de la même manière.


Il est facile de voir que ce n'est qu'une approximation à faible coût de ce que nous voulions vraiment réaliser. Cependant, il est très efficace car les cartes de profondeur s'avèrent généralement lisses.

Code


En suivant l'algorithme décrit dans la section précédente, nous pouvons implémenter le shader de parallaxe avec un simple décalage des coordonnées UV .

Cela conduit au code suivant:

 void surf (Input IN, inout SurfaceOutput o) { // Displacement fixed height = tex2D(_HeightTex, IN.uv_MainTex).r; fixed2 displacement = _Scale * ((height - 0.5) * 2); fixed4 c = SampleSpriteTexture (IN.uv_MainTex - displacement) * IN.color; ... } 

Cette technique fonctionne bien avec des objets presque plats, comme le montre l'animation ci-dessous.


Mais cela fonctionne vraiment très bien avec les modèles 3D, car il est très facile de rendre la texture de profondeur pour une scène 3D. Ci-dessous, une image rendue en 3D et sa carte de profondeur.


Les résultats finaux sont affichés ici:

Source: https://habr.com/ru/post/fr444706/


All Articles