[C#] Webcam dans Unity et multi Caméras

Tous les tutoriaux unity, de la communauté ou d'ailleurs.
Avatar de l’utilisateur
Iwa
Messages : 1089
Inscription : 25 Avr 2012 16:20
Contact :

[C#] Webcam dans Unity et multi Caméras

Messagepar Iwa » 17 Mars 2016 16:57

Bonjour à tous,

Un petit "tuto" sur ce que je fais en ce moment et qui pourrait servir à d'autres, ou même à moi quand je serais sénile ou pas réveillée...

Dans une application, je devais faire une UI 2D avec un rendu de webcam et par dessus de la 3D :

Image

- Sur le côté gauche j'ai donc une partie d'UI qui est toujours au DESSUS de tout
- En blanc j'ai de la 3D
- Derrière ma 3D, j'ai l'image de ma webcam qui est toujours au DESSOUS de tout

Comment faire? A l'aide de Dragonic, j'ai percé le mystère.

On peut avoir plusieurs Canvas d'UI! Et ça je l'ignorais jusque là. Donc c'est une super nouvelle. Il suffit de savoir manipuler les caméras dans leur depth et le tour est presque joué!

Donc prenons la partie UI de gauche, toujours au dessus :

Une fois votre UI créer, il faut faire quelques modifications de settings :

Rappel : de base, votre UI à pour Layer UI

Pour que votre UI ne soit pas rendue toujours au dessus de tout, il va d'abord falloir changer les settings de base de votre Canvas

Image

Le Render Mode est le plus important des settings : il ne faut surtout PAS être en Screen Space - Overlay. Vous pouvez choisir Screen Space - Camera ou World Space. Pour des raisons particulières je n'ai pas le choix, je dois être en World Space.

Avec ce changement de render mode, il faut préciser la caméra qui regarde cette UI. Vous devez donc créer un Caméra qui ne regardera QUE cette ui.

Image

Avec ces settings là, on dit que la Caméra ne voit que le Layer UI, elle a comme Depth 10, ce qui signifie qu'elle est rendu APRES les caméras de Depth entre 0 et 9. De plus elle est en Clear Flags Depth only.

Donc votre première Caméra est bien préparée, elle ne voit que votre UI (ma partie gauche en bleu vert donc).



Ensuite, on s'occupe de la Webcam :

Pour rendre une webcam il y a plusieurs solutions. La plus simple à mon goût pour s'éviter les complications de calculs bourrins et c'est ce qui est proposé par pas mal de gens quand on pose la question à google : utiliser une RawImage, soit un élément d'UI particulier.

L'idée est de récupérer la texture de la webcam et la fixée sur une Raw Image. Pour cela, il y a pleins de scripts sur le net. Voici le mien :

Code : Tout sélectionner

using UnityEngine;
using UnityEngine.UI;
using System.Collections;

public class WebCamView : MonoBehaviour
   {
      //la raw image sur laquel je vais rendre ma texture de webcam
      [SerializeField] private RawImage planeToRenderTexture;
      
      //la webcam que je choisi
      private WebCamDevice device;
      
      //la texture de ma webcam activée
      private WebCamTexture mCameraTexture = null;

      public void Start()
      {
#if UNITY_EDITOR
         //pour récupérer la texture de ma webcam, Unity à une fonction toute faite.
         // Les deux gros chiffres c'est la witdth et la height que je souhaite
         //Pourquoi si gros? Ca se met tout seul au max à priori
         mCameraTexture = new WebCamTexture (10000,10000);
#else
         //je cherche la caméra de derrière. Vous n'y êtes pas obligés!
         //la caméra 0 est la caméra arrière de votre device
         device = WebCamTexture.devices[0];
         
         int width = (int)Screen.width/2;
         int height = (int)Screen.height/2;

         //si je ne suis pas sur l'éditeur de Unity, je prends ma caméra de derrière que j'ai trouvé
         //j'ai pris une résolution moindre pour éviter la latence.
         mCameraTexture = new WebCamTexture (device.name,width,height);
#endif

         OnCameraDisplay ();
      }

      public void OnCameraDisplay ()
      {
         //je connais la texture qui contiendra l'image de ma webcam
         // il est tant que je l'applique à ma Raw Image
         planeToRenderTexture.texture = mCameraTexture;

         //on lance la webcam
         mCameraTexture.Play ();
      
      }
   }


Super! J'assigne ma variable planeToRenderTexture avec la RawImage que j'ai créé. On lance! Et la sous nos zyeux z'ébahient, on voit l'image de la webcam, et notre UI!



Oui mais t'avais parlé de 3D à un moment nan?

En effet, et ça normalement, vous savez le faire depuis toujours. Il vous faut un objet 3D (une cube, une sphère, un bonhomme, whatever) à rendre par une super Caméra. Évidemment cette caméra ne dois voir QUE la 3D, il faut donc faire une nouvelle Caméra avec ces paramètres ci :

Image

On a donc les paramètres suivants : Clear Flags à Depth Only, la Depth à 1 et le Culling Mask est Mixed car on voit TOUT sauf l'UI.

Il ne reste plus qu'à faire "Play" et trilalilalou.... Ben, et ma 3D? Je la vois pas! C'est un scandale!

Et oui, on ne voit rien de plus qu'avant soit notre menu à gauche avec notre webcam.




Récapitulons l'ordre de rendu de nos Caméras :

- PanoramicCamera : depth à 1
- UICamera : depth à 10 (est rendu après les caméras 0 à 9)

C'est bien sûr! La caméra PanoramicCamera est dessinée d'abord PUIS plus tard la caméra UICamera! Hors notre RawImage prend quasi tout l'écran sauf le bandeau gauche. Donc rien n'est vide dans notre UI. Donc ce qui se passe derrière nous est invisible!

Et si on fait l'inverse au niveau des depths? Et bien on ne corrige rien, on verra bien la 3D au dessus. Mais elle sera au dessus de TOUT! Donc c'est hyper moche.

La solution c'est d'utiliser 3 Caméras pour arriver à nos fins. Il nous faut une caméra qui rend la webcam uniquement et qu'on dessinera en tout premier, puis on dessinera la 3D, puis enfin on dessinera notre bandeau gauche.

On va donc modifier un peu notre UI en créant un nouveau Canvas. Ce Canvas est très similaire à celui de l'UI. Il aura simplement une Caméra spéciale pour lui tout seul et on le place dans un Layer particulier appeler Webcam.

Une fois le Canvas créé, on y déplace notre RawImage d'avant et on à plus qu'à créer la Caméra spéciale webcam comme suit :

Image

La différence avec la caméra UI? La depth est à 0 et le culling mask ne voit que le layer Webcam.

Du coup par rapport à avant on à ceci :

- WebcamRenderCam : depth à 0, ne voit que le layer Webcam
- PanoramicCamera : depth à 1, voit tout SAUT le layer Webcam et le layer UI
- UICamera : depth à 10, ne voit que le layer UI

On dessine donc bien dans l'ordre : la webcam, la 3D, le menu de gauche!

:taré1: Super! Trop cool!!! Regarde Gérard ce que j'ai réussi à faire (Gérard c'est votre voisin de bureau)!!! Allez un p'tit café, une pause! J'ai trop bien bossé! ....

Hep, hep, hep! T'as pas l'impression que Gérard a grandit et minci d'un coup?

:rougefaché: Han! Mais... Tu nous as menti! Comment tu nous a embobiné, ton truc il marche pas c'est nul! En plus Bruce Willis il meurt à la fin c'est ça ?!

Je vous rassure! La cause de l’amincissement soudain de Gérard est toute simple : on prend notre rendu de webcam et on le plaque bêtement sur notre RawImage. C'est pas bien malin en y réfléchissant! On passe à côté du ratio de l'image.

Première chose c'est d'ajouter à notre RawImage un component AspectRatioFitter! Ce component permet de conserver un ratio sur notre image et de lui offrir des capacités intéressantes pour étirer l'image pour remplir le parent ou autre. En l'occurrence, notre rendu de webcam prend les 3/4 de l'écran et on veut que ces 3/4 d'écran soit REMPLI (pas de bords noirs). On créé un parent à RawImage à la bonne taille (soit 3/4 d'écran) et on met la propriété Aspect Mode de l'aspactRatioFitter de RawImage à Envelope Parent.

Okay, mais ça suffit pas, on vient juste d'ajouter un outil, maintenant il faut s'en servir.

Donc pour corriger le problème google est notre ami et voici le lien qui m'a aidé et que j'ai repris en grande partie : http://answers.unity3d.com/questions/773464/webcamtexture-correct-resolution-and-ratio.html#answer-1148424

Un gentil monsieur nous offre donc la chance de modifier le code légèrement, pour que ce soit bien plus beau, moins tordu! Et voici l'adaptation que j'en ai faite :

Code : Tout sélectionner

using UnityEngine;
using UnityEngine.UI;
using System.Collections;

public class WebCamView : MonoBehaviour
   {
      [SerializeField] private RawImage planeToRenderTexture;
      
      private WebCamDevice device;
      private WebCamTexture mCameraTexture = null;

      //UPDATE : le component qu'on vient d'ajouter
      private AspectRatioFitter rawImageARF;

      // Image rotation
      Vector3 rotationVector = new Vector3(0f, 0f, 0f);

      // Image uvRect
      Rect defaultRect = new Rect(0f, 0f, 1f, 1f);
      Rect fixedRect = new Rect(0f, 1f, 1f, -1f);

      // Image Parent's scale
      Vector3 defaultScale = new Vector3(1f, 1f, 1f);
      Vector3 fixedScale = new Vector3(-1f, 1f, 1f);

      internal bool Visible { set { planeToRenderTexture.gameObject.SetActive(value);} }

      public void Start()
      {
#if UNITY_EDITOR
         //pour récupérer la texture de ma webcam, Unity à une fonction toute faite.
         // Les deux gros chiffres c'est la witdth et la height que je souhaite
         //Pourquoi si gros? Ca se met tout seul au max à priori
         mCameraTexture = new WebCamTexture (10000,10000);
#else
         //je cherche la caméra de derrière. Vous n'y êtes pas obligés!
         //la caméra 0 est la caméra arrière de votre device
         device = WebCamTexture.devices[0];
         
         int width = (int)Screen.width/2;
         int height = (int)Screen.height/2;

         //si je ne suis pas sur l'éditeur de Unity, je prends ma caméra de derrière que j'ai trouvé
         //j'ai pris une résolution moindre pour éviter la latence.
         mCameraTexture = new WebCamTexture (device.name,width,height);
#endif

         
         //On rempli nos paramètres fraichement créés
         rawImageARF = planeToRenderTexture.GetComponent<AspectRatioFitter>();
         OnCameraDisplay ();
      }

      public void OnCameraDisplay ()
      {
         planeToRenderTexture.texture = mCameraTexture;

         mCameraTexture.Play ();
         
         //On change le ratio de notre RawImage pour collé au ratio de la webcam
         SetWebCamRatio();
         
      }
      
      //UPDATE : à chaque update on vérifie si on doit ou nous mettre à jour le ratio!
      private void Update()
      {
         if (mCameraTexture!=null &&  mCameraTexture.width < 100 )
         {
            //Debug.Log("Still waiting another frame for correct info...");
            return;
         }

         if(mCameraTexture!=null && mCameraTexture.isPlaying && planeToRenderTexture!=null && planeToRenderTexture.gameObject.activeInHierarchy )
         {
            SetWebCamRatio();
         }
      }

      //UPDATE : cette partie est commentée en anglais, ça se comprend bien.
      //  Le principe est de récupérer le ratio de l'image et l'appliquer au ratiofitter et à la raw image
      private void SetWebCamRatio()
      {
         // from http://answers.unity3d.com/questions/773464/webcamtexture-correct-resolution-and-ratio.html#answer-1148424

      // Rotate image to show correct orientation
         rotationVector.z = -mCameraTexture.videoRotationAngle;
         planeToRenderTexture.rectTransform.localEulerAngles = rotationVector;

         // Set AspectRatioFitter's ratio
         float videoRatio =
            (float)mCameraTexture.width / (float)mCameraTexture.height;
         rawImageARF.aspectRatio = videoRatio;

         // Unflip if vertically flipped

         planeToRenderTexture.uvRect =
            mCameraTexture.videoVerticallyMirrored ? fixedRect : defaultRect;

         // Mirror front-facing camera's image horizontally to look more natural
         planeToRenderTexture.transform.parent.localScale =
            device.isFrontFacing ? fixedScale : defaultScale;

      }

   }


Et maintenant vous pouvez appuyer sur "Play"! Gérard à retrouver ces formes d'avant! Ne lui dites pas pour autant qu'il à grossit ;).

Voilà, j'espère que ça vous aura aidé. C'est un peu long mais le but était de découpé en parties. Si vous avez des questions n'hésitez pas non plus ;). (Et non, Bruce Willis n'est même pas mort, vous avez vu!!)

Bonne aprèm à vous.

EDIT : ATTENTION : SI VOUS AVEZ DES LUMIÈRES DANS VOTRE SCÈNE VEILLEZ A BIEN RETIRER LES LAYERS CONCERNANT NOTRE UI! :)
Dernière édition par Iwa le 10 Mai 2016 15:26, édité 8 fois.
"N'est stupide que la stupidité Monsieur..." - Forest Gump
... sauf si tu lis pas ça :)

Si tu as tout ce qu'il te faut, merci de penser à basculer ton sujet en [RESOLU] en éditant ton tout premier post ;)

Avatar de l’utilisateur
axel
Messages : 1827
Inscription : 26 Avr 2012 09:10
Localisation : Lille - Dunkerque
Contact :

Re: [C#] Webcam

Messagepar axel » 17 Mars 2016 17:07

Cool, merci pour ce tuto. :-D

Avatar de l’utilisateur
Max
Bricoleur
Bricoleur
Messages : 5578
Inscription : 30 Juil 2011 13:57

Re: [C#] Webcam dans Unity et multi Caméras

Messagepar Max » 17 Mars 2016 17:10

Excellent :super:

et il manquerait plus que cela que Bruce Willis soit mort
____________________________________________________________________________

Avatar de l’utilisateur
Vosne
Messages : 85
Inscription : 05 Août 2014 16:21
Localisation : Paris
Contact :

Re: [C#] Webcam dans Unity et multi Caméras

Messagepar Vosne » 17 Mars 2016 17:29

Bravo Iwa, ça fait plaisir de voir un si beau résumé ! merci :merci: :-D
Image

Avatar de l’utilisateur
Franck
Bricoleur
Bricoleur
Messages : 2841
Inscription : 08 Jan 2011 18:43
Localisation : Tours

Re: [C#] Webcam dans Unity et multi Caméras

Messagepar Franck » 18 Mars 2016 08:56

Merci! :)
Dés fois j'bug, dés fois j'bug pas.

Avatar de l’utilisateur
simonj
Messages : 212
Inscription : 29 Nov 2015 20:47

Re: [C#] Webcam dans Unity et multi Caméras

Messagepar simonj » 18 Mars 2016 12:18

Bien expliqué, bien documenté... Nice :super:

Avatar de l’utilisateur
Iwa
Messages : 1089
Inscription : 25 Avr 2012 16:20
Contact :

Re: [C#] Webcam dans Unity et multi Caméras

Messagepar Iwa » 29 Mars 2016 15:42

Salut à tous,

je suis en train de changer un peu le script ;) je vous expliquerait ça mieux, quand mes tests seront terminés ^^.

En attendant merci à tous pour les retours.

Bonne journée en attendant.
"N'est stupide que la stupidité Monsieur..." - Forest Gump
... sauf si tu lis pas ça :)

Si tu as tout ce qu'il te faut, merci de penser à basculer ton sujet en [RESOLU] en éditant ton tout premier post ;)

Avatar de l’utilisateur
E3DStef
Administrateur
Administrateur
Messages : 960
Inscription : 14 Juil 2013 18:30

Re: [C#] Webcam dans Unity et multi Caméras

Messagepar E3DStef » 31 Mars 2016 08:33

Chouette initiative, merci pour ce partage !!!

Je l'ai mis dans les news du site, bref maintenant Iwa tu es une star ;-)

@Modos : n'hésitez pas à faire de mm :-)

Bonne fin de semaine à tous
Le Savoir n'est Précieux que s'il est Partagé

Si besoin urgent de me contacter, faites moi un mail sur : franceunity3d@gmail.com

Avatar de l’utilisateur
Iwa
Messages : 1089
Inscription : 25 Avr 2012 16:20
Contact :

Re: [C#] Webcam dans Unity et multi Caméras

Messagepar Iwa » 01 Avr 2016 10:07

Ahah merci Stef :). Faut que je le mette à jour, je me suis rendue compte de pas mal de choses, il y a des petites erreurs. Donc ceux qui veulent l'utiliser, si vous avez des soucis c'est pas forcément étonnant. Je ferais une V2 ;)
"N'est stupide que la stupidité Monsieur..." - Forest Gump
... sauf si tu lis pas ça :)

Si tu as tout ce qu'il te faut, merci de penser à basculer ton sujet en [RESOLU] en éditant ton tout premier post ;)

Avatar de l’utilisateur
E3DStef
Administrateur
Administrateur
Messages : 960
Inscription : 14 Juil 2013 18:30

Re: [C#] Webcam dans Unity et multi Caméras

Messagepar E3DStef » 07 Avr 2016 22:26

Avec plaisir Iwa ;-)

N'hésites pas à MAJ ton post (penses à l'indiquer dans le titre) et à répondre aux derniers com pour générer un rafraichissement des dates (comme cela on verra bien ta MAJ).

A+

Stef
Le Savoir n'est Précieux que s'il est Partagé

Si besoin urgent de me contacter, faites moi un mail sur : franceunity3d@gmail.com


Revenir vers « Tutoriaux »

Qui est en ligne ?

Utilisateurs parcourant ce forum : Aucun utilisateur inscrit et 1 invité