Réalité mixte - Partage - Cours 250 : HoloLens et casques immersifsMR Sharing 250: HoloLens and immersive headsets

Notes

Les tutoriels Mixed Reality Academy ont été conçus pour les appareils HoloLens (1re génération) et les casques immersifs de réalité mixte.The Mixed Reality Academy tutorials were designed with HoloLens (1st gen) and Mixed Reality Immersive Headsets in mind. Nous estimons qu’il est important de laisser ces tutoriels à la disposition des développeurs qui recherchent encore des conseils pour développer des applications sur ces appareils.As such, we feel it is important to leave these tutorials in place for developers who are still looking for guidance in developing for those devices. Notez que ces tutoriels ne sont pas mis à jour avec les derniers ensembles d’outils ou interactions utilisés pour HoloLens 2.These tutorials will not be updated with the latest toolsets or interactions being used for HoloLens 2. Ils sont fournis dans le but de fonctionner sur les appareils pris en charge.They will be maintained to continue working on the supported devices. Une nouvelle série de tutoriels a été publiée pour HoloLens 2.A new series of tutorials has been posted for HoloLens 2.

Avec la flexibilité de plateforme Windows universelle (UWP), il est facile de créer une application qui s’étend sur plusieurs appareils.With the flexibility of Universal Windows Platform (UWP), it is easy to create an application that spans multiple devices. Grâce à cette flexibilité, nous pouvons créer des expériences qui tirent parti des avantages de chaque appareil.With this flexibility, we can create experiences that leverage the strengths of each device. Ce didacticiel couvre une expérience partagée de base qui s’exécute à la fois sur HoloLens et sur les casques immersifs de la réalité mixte Windows.This tutorial will cover a basic shared experience that runs on both HoloLens and Windows Mixed Reality immersive headsets. Ce contenu a été fourni à l’origine lors de la Conférence Microsoft Build 2017 à Seattle, WA.This content was originally delivered at the Microsoft Build 2017 conference in Seattle, WA.

Dans ce didacticiel, nous allons :In this tutorial, we will:

  • Configurer un réseau à l’aide de UNET.Setup a network using UNET.
  • Partager des hologrammes sur des appareils de réalité mixte.Share holograms across mixed reality devices.
  • Établissez une vue différente de l’application en fonction de l’appareil de réalité mixte utilisé.Establish a different view of the application depending on which mixed reality device is being used.
  • Créez une expérience partagée dans laquelle les utilisateurs de HoloLens guident les utilisateurs immersifs à travers des puzzles simples.Create a shared experience where HoloLens users guide immersive headsets users through some simple puzzles.

Prise en charge des appareilsDevice support

CoursCourse HoloLensHoloLens Casques immersifsImmersive headsets
Réalité mixte - Partage - Cours 250 : HoloLens et casques immersifsMR Sharing 250: HoloLens and immersive headsets ✔️✔️ ✔️✔️

Avant de commencerBefore you start

PrérequisPrerequisites

Fichiers projetProject files

Notes

Si vous souhaitez examiner le code source avant le téléchargement, il est disponible sur GitHub.If you want to look through the source code before downloading, it's available on GitHub.

Chapitre 1-Holo WorldChapter 1 - Holo World

ObjectifsObjectives

Assurez-vous que l’environnement de développement est prêt à l’emploi avec un projet simple.Make sure the development environment is ready to go with a simple project.

Ce que nous allons créerWhat we will build

Application qui affiche un hologramme sur HoloLens ou sur un casque immersif Windows Mixed Reality.An application that shows a hologram on either HoloLens or a Windows Mixed Reality immersive headset.

ÉtapesSteps

  • Ouvrez Unity.Open Unity.
    • Sélectionnez Ouvrir .Select Open .
    • Accédez à l’emplacement où vous avez extrait les fichiers projet.Navigate to where you extracted the project files.
    • Cliquez sur Sélectionner un dossier .Click Select Folder .
    • Il faut un peu pour Unity pour traiter le projet la première fois.It will take a little while for Unity to process the project the first time.
  • Vérifiez que la réalité mixte est activée dans Unity.Check that Mixed Reality is enabled in Unity.
    • Ouvrez la boîte de dialogue Paramètres de build ( Ctrl + Maj + B ou fichier > paramètres de Build... ).Open the build settings dialog ( Control+Shift+B or File > Build Settings... ).
    • Sélectionnez plateforme Windows universelle puis cliquez sur changer de plateforme .Select Universal Windows Platform then click Switch Platform .
    • Sélectionnez modifier les paramètres du lecteur> .Select Edit>Player Settings .
    • Dans le volet de l' inspecteur situé sur le côté droit, développez paramètres XR .In the Inspector panel on the right hand side, expand XR Settings .
    • Cochez la case la réalité virtuelle est prise en charge .Check the Virtual Reality Supported box.
    • Windows Mixed Reality doit être le kit de développement logiciel (SDK) de realisation virtuelle.Windows Mixed Reality should be the Virtual Reality SDK.
  • Créer une scène.Create a scene.
    • Dans la hiérarchie , cliquez avec le bouton droit sur caméra principale , sélectionnez supprimer .In the Hierarchy right click Main Camera select Delete .
    • À partir de HoloToolkit > d’entrée > Prefabs faire glisser MixedRealityCameraParent vers la hiérarchie .From HoloToolkit > Input > Prefabs drag MixedRealityCameraParent to the Hierarchy .
  • Ajouter des hologrammes à la scèneAdd Holograms to the scene
    • À partir de AppPrefabs , faites glisser skybox vers la vue scène .From AppPrefabs drag Skybox to the Scene View .
    • Dans AppPrefabs , faites glisser les gestionnaires vers la hiérarchie .From AppPrefabs drag Managers to the Hierarchy .
    • Dans AppPrefabs , faites glisser l' îlot vers la hiérarchie .From AppPrefabs drag Island to the Hierarchy .
  • Enregistrer et générerSave And build
    • Save ( Control + S ou file > Save Scene )Save (either Control+S or File > Save Scene )
    • Étant donné qu’il s’agit d’une nouvelle scène, vous devez la nommer.Since this is a new scene, you'll need to name it. Le nom n’a pas d’importance, mais nous utilisons SharedMixedReality.Name doesn't matter, but we use SharedMixedReality.
  • Exporter vers Visual StudioExport To Visual Studio
    • Ouvrez le menu Générer ( Ctrl + Maj + B ou fichier > paramètres de build ).Open the build menu ( Control+Shift+B or File > Build Settings )
    • Cliquez sur Ajouter des scènes ouvertes.Click Add Open Scenes.
    • Vérifier les projets Unity C#Check Unity C# Projects
    • Cliquez sur Générer .Click Build .
    • Dans la fenêtre de l’Explorateur de fichiers qui s’affiche, créez un nouveau dossier nommé app .In the file explorer window that appears, create a New Folder named App .
    • Cliquez sur le dossier de l' application .Single click the App folder.
    • Appuyez sur Sélectionner un dossier.Press Select Folder.
    • Attendre la fin de la générationWait for the build to complete
    • Dans la fenêtre de l’Explorateur de fichiers qui s’affiche, accédez au dossier de l' application .In the file explorer window that appears, navigate into the App folder.
    • Double-cliquez sur SharedMixedReality. sln pour lancer Visual StudioDouble-click SharedMixedReality.sln to launch Visual Studio
  • Générer à partir de Visual StudioBuild From Visual Studio
    • À l’aide de la barre d’outils supérieure, remplacez cible par Release et x86 .Using the top toolbar change target to Release and x86 .
    • Cliquez sur la flèche en regard de ordinateur local , puis sélectionnez l' appareil à déployer dans HoloLensClick the arrow next to Local Machine and select Device to deploy to HoloLens
    • Cliquez sur la flèche en regard de périphérique , puis sélectionnez ordinateur local à déployer pour le casque de la réalité mixte.Click the arrow next to Device and select Local Machine to deploy for the mixed reality headset.
    • Cliquez sur Déboguer->exécuter sans débogage ou sur CTRL + F5 pour démarrer l’application.Click Debug->Start Without Debugging or Control+F5 to start the application.

Examen du codeDigging into the code

Dans le panneau projet, accédez à Assets\HoloToolkit\Input\Scripts\Utilities et double-cliquez sur MixedRealityCameraManager.cs pour l’ouvrir.In the project panel, navigate to Assets\HoloToolkit\Input\Scripts\Utilities and double click MixedRealityCameraManager.cs to open it.

Vue d’ensemble : MixedRealityCameraManager.cs est un script simple qui ajuste le niveau de qualité et les paramètres d’arrière-plan en fonction de l’appareil.Overview: MixedRealityCameraManager.cs is a simple script that adjusts quality level and background settings based on the device. La clé ici est HolographicSettings. IsDisplayOpaque, qui permet à un script de détecter si l’appareil est un HoloLens (IsDisplayOpaque retourne la valeur false) ou un casque immersif (IsDisplayOpaque retourne la valeur true).Key here is HolographicSettings.IsDisplayOpaque, which allows a script to detect if the device is a HoloLens (IsDisplayOpaque returns false) or an immersive headset (IsDisplayOpaque returns true).

Profitez de votre progressionEnjoy your progress

À ce stade, l’application affichera simplement un hologramme.At this point the application will just render a hologram. Nous ajouterons l’interaction à l’hologramme ultérieurement.We will add interaction to the hologram later. Les deux appareils affichent l’hologramme de la même façon.Both devices will render the hologram the same. Le casque immersif affiche également un arrière-plan bleu ciel et Clouds.The immersive headset will also render a blue sky and clouds background.

Chapitre 2-interactionChapter 2 - Interaction

ObjectifsObjectives

Montrez comment gérer les entrées pour une application Windows Mixed Reality.Show how to handle input for a Windows Mixed Reality application.

Ce que nous allons créerWhat we will build

En s’appuyant sur l’application du chapitre 1, nous ajouterons des fonctionnalités pour permettre à l’utilisateur de sélectionner l’hologramme et de le placer sur une surface dans le monde réel dans HoloLens ou sur une table virtuelle dans un casque immersif.Building on the application from chapter 1, we will add functionality to allow the user to pick up the hologram and place it on a real world surface in HoloLens or on a virtual table in an immersive headset.

Actualisateur d’entrée : Sur HoloLens, le geste de sélection est le robinet d’air .Input Refresher: On HoloLens the select gesture is the air tap . Sur les casques immersifs, nous allons utiliser le bouton A sur le contrôleur Xbox.On immersive headsets, we will use the A button on the Xbox controller. Pour plus d’informations, consultez vue d’ensemble du modèle d’interaction.For more information check out the interaction model overview.

ÉtapesSteps

  • Ajouter un gestionnaire d’entréeAdd Input manager
    • À partir de HoloToolkit > d’entrée > Prefabs faire glisser InputManager vers la hiérarchie en tant qu’enfant de managers .From HoloToolkit > Input > Prefabs drag InputManager to Hierarchy as a child of Managers .
    • À partir de HoloToolkit > entrée > curseur de > Prefabs , faites glisser Cursor vers Hierarchy .From HoloToolkit > Input > Prefabs > Cursor drag Cursor to Hierarchy .
  • Ajouter un mappage spatialAdd Spatial Mapping
    • À partir de HoloToolkit > SpatialMapping > Prefabs faites glisser SpatialMapping vers la hiérarchie .From HoloToolkit > SpatialMapping > Prefabs drag SpatialMapping to Hierarchy .
  • Ajouter des PlaySpace virtuelsAdd Virtual Playspace
    • Dans hiérarchie , développez MixedRealityCameraParent sélectionner une limiteIn Hierarchy expand MixedRealityCameraParent select Boundary
    • Dans le panneau inspecteur , cochez la case pour activer la limiteIn Inspector panel check the box to enable Boundary
    • Dans AppPrefabs , faites glisser VRRoom vers la hiérarchie .From AppPrefabs drag VRRoom to Hierarchy .
  • Ajouter WorldAnchorManagerAdd WorldAnchorManager
    • Dans hiérarchie , sélectionnez gestionnaires .In Hierarchy , Select Managers .
    • Dans Inspector , cliquez sur Ajouter un composant .In Inspector , click Add Component .
    • Tapez World Anchor Manager .Type World Anchor Manager .
    • Sélectionnez World Anchor Manager pour l’ajouter.Select World Anchor Manager to add it.
  • Ajouter TapToPlace à l’îlotAdd TapToPlace to the Island
    • Dans hiérarchie , développez îlot .In Hierarchy , expand Island .
    • Sélectionnez MixedRealityLand .Select MixedRealityLand .
    • Dans Inspector , cliquez sur Ajouter un composant .In Inspector , click Add Component .
    • Tapez TAP pour la placer et sélectionnez-le.Type Tap To Place and select it.
    • Cochez Placer le parent sur TAP .Check Place Parent On Tap .
    • Définissez décalage de placement sur (0, 0,1, 0) .Set Placement Offset to (0, 0.1, 0) .
  • Enregistrer et générer comme avantSave and Build as before

Examen du codeDigging into the code

Script 1-GamepadInput.csScript 1 - GamepadInput.cs

Dans le panneau projet, accédez à Assets\HoloToolkit\Input\Scripts\InputSources et double-cliquez sur GamepadInput.cs pour l’ouvrir.In the project panel navigate to Assets\HoloToolkit\Input\Scripts\InputSources and double click GamepadInput.cs to open it. À partir du même chemin d’accès dans le panneau projet, double-cliquez sur InteractionSourceInputSource.cs .From the same path in the project panel, also double click InteractionSourceInputSource.cs .

Notez que les deux scripts ont une classe de base commune, BaseInputSource.Note that both scripts have a common base class, BaseInputSource.

BaseInputSource conserve une référence à un InputManager, qui permet à un script de déclencher des événements.BaseInputSource keeps a reference to an InputManager, which allows a script to trigger events. Dans ce cas, l’événement InputClicked est pertinent.In this case, the InputClicked event is relevant. Il est important de se souvenir quand nous obtenons le script 2, TapToPlace.This will be important to remember when we get to script 2, TapToPlace. Dans le cas de GamePadInput, nous interrogeons le bouton A sur le contrôleur à enfoncer, puis nous déclencherons l’événement InputClicked.In the case of GamePadInput, we poll for the A button on the controller to be pressed, then we raise the InputClicked event. Dans le cas de InteractionSourceInputSource, l’événement InputClicked est déclenché en réponse au TappedEvent.In the case of InteractionSourceInputSource, we raise the InputClicked event in response to the TappedEvent.

Script 2-TapToPlace.csScript 2 - TapToPlace.cs

Dans le panneau projet, accédez à Assets\HoloToolkit\SpatialMapping\Scripts et double-cliquez sur TapToPlace.cs pour l’ouvrir.In the project panel navigate to Assets\HoloToolkit\SpatialMapping\Scripts and double click TapToPlace.cs to open it.

La première chose que de nombreux développeurs souhaitent implémenter lors de la création d’une application holographique est le déplacement d’hologrammes avec entrée de mouvement.The first thing many developers want to implement when creating a Holographic application is moving Holograms with gesture input. C’est pourquoi nous avons fait en sorte de formuler des commentaires sur ce script.As such, we've endeavored to thoroughly comment this script. Quelques points méritent une mise en évidence pour ce didacticiel.A few things are worth highlighting for this tutorial.

Tout d’abord, Notez que TapToPlace implémente IInputClickHandler.First, note that TapToPlace implements IInputClickHandler. IInputClickHandler expose les fonctions qui gèrent l’événement InputClicked déclenché par GamePadInput.cs ou InteractionSourceInputSource.cs.IInputClickHandler exposes the functions that handle the InputClicked event raised by GamePadInput.cs or InteractionSourceInputSource.cs. OnInputClicked est appelé lorsqu’un BaseInputSource détecte un clic alors que l’objet avec TapToPlace est actif.OnInputClicked is called when a BaseInputSource detects a click while the object with TapToPlace is in focus. L’activation de la pression sur HoloLens ou sur le bouton A sur le contrôleur Xbox déclenche l’événement.Either airtapping on HoloLens or pressing the A button on the Xbox controller will trigger the event.

Deuxièmement, le code doit être exécuté dans Update pour voir si une surface est recherchée afin que nous puissions placer l’objet de jeu sur une surface, par exemple une table.Second is the code be executed in update to see if a surface is being looked at so we can place the game object on a surface, like a table. Le casque immersif n’a pas de concept de surfaces réelles, donc l’objet qui représente la table Top (Vroom > TableThingy > cube) a été marqué avec la couche physique SpatialMapping, de sorte que la mise à jour de Ray est en conflit avec la table virtuelle Top.The immersive headset doesn't have a concept of real surfaces, so the object that represents the table top (Vroom > TableThingy > Cube) has been marked with the SpatialMapping physics layer, so the ray cast in Update will collide with the virtual table top.

Profitez de votre progressionEnjoy your progress

Cette fois, vous pouvez sélectionner l’îlot pour le déplacer.This time you can select the island to move it. Sur HoloLens, vous pouvez déplacer l’îlot vers une surface réelle.On HoloLens you can move the island to a real surface. Dans le casque immersif, vous pouvez déplacer l’îlot vers la table virtuelle que nous avons ajoutée.In the immersive headset you can move the island to the virtual table we added.

Chapitre 3-partageChapter 3 - Sharing

ObjectifsObjectives

Assurez-vous que le réseau est correctement configuré et comment les ancres spatiales sont partagées entre les appareils.Ensure that the network is correctly configured and detail how spatial anchors are shared between devices.

Ce que nous allons créerWhat we will build

Nous allons convertir notre projet en projet multijoueur.We will convert our project to a multiplayer project. Nous allons ajouter l’interface utilisateur et la logique pour héberger ou joindre des sessions.We will add UI and logic to host or join sessions. Les utilisateurs de HoloLens s’afficheront dans la session avec des clouds sur leurs têtes, et les utilisateurs de casque immersif présenteront des clouds proches de l’emplacement où se trouve l’ancre.HoloLens users will see each other in the session with clouds over their heads, and immersive headset users have clouds near to where the anchor is. Les utilisateurs des casques immersifs verront les utilisateurs HoloLens par rapport à l’origine de la scène.Users in the immersive headsets will see the HoloLens users relative to the origin of the scene. Les utilisateurs de HoloLens verront tous l’hologramme de l’île au même endroit.HoloLens users will all see the hologram of the island in the same place. Il est important de noter que les utilisateurs des casques immersifs ne seront pas sur l’île au cours de ce chapitre, mais ils se comportent de la même façon que HoloLens, avec une vue d’ensemble des oiseaux de l’île.It is key to note that the users in the immersive headsets will not be on the island during this chapter, but will behave very similarly to HoloLens, with a birds eye view of the island.

ÉtapesSteps

  • Supprimer l’îlot et VRRoomRemove Island and VRRoom
    • Dans hiérarchie , cliquez avec le bouton droit sur îlot sélectionner supprimerIn Hierarchy right-click Island select Delete
    • Dans hiérarchie , cliquez avec le bouton droit sur VRRoom sélectionner supprimerIn Hierarchy right-click VRRoom select Delete
  • Ajouter UslandAdd Usland
    • Dans AppPrefabs , faites glisser Usland vers la hiérarchie .From AppPrefabs drag Usland to Hierarchy .
  • Dans AppPrefabs , faites glisser chacun des éléments suivants vers la hiérarchie :From AppPrefabs drag each of the following to Hierarchy :
    • UNETSharingStageUNETSharingStage
    • UNetAnchorRootUNetAnchorRoot
    • UIContainerUIContainer
    • DebugPanelButtonDebugPanelButton
  • Enregistrer et générer comme avantSave and Build as before

Examen du codeDigging into the code

Dans le panneau projet, accédez à Assets\AppPrefabs\Support\SharingWithUnet\Scripts et double-cliquez sur UnetAnchorManager.cs .In the project panel, navigate to Assets\AppPrefabs\Support\SharingWithUnet\Scripts and double-click on UnetAnchorManager.cs . La possibilité pour un HoloLens de partager des informations de suivi avec un autre HoloLens de telle sorte que les deux appareils puissent partager le même espace est presque magique.The ability for one HoloLens to share tracking information with another HoloLens such that both devices can share the same space is near magical. La puissance de la réalité mixte est active lorsque deux personnes ou plus peuvent collaborer à l’aide des mêmes données numériques.The power of mixed reality comes alive when two or more people can collaborate using the same digital data.

Voici quelques éléments à souligner dans ce script :A few things to point out in this script:

Dans la fonction Start, notez la vérification de IsDisplayOpaque .In the start function, notice the check for IsDisplayOpaque . Dans ce cas, nous supposons que le point d’ancrage est établi.In this case, we pretend that the Anchor is established. Cela est dû au fait que les casques immersifs n’exposent pas un moyen d’importer ou d’exporter des ancres.This is because the immersive headsets do not expose a way to import or export anchors. Toutefois, si nous exécutons un HoloLens, ce script implémente des ancres de partage entre les appareils.If we are running on a HoloLens, however, this script implements sharing anchors between the devices. L’appareil qui démarre la session crée une ancre pour l’exportation.The device that starts the session will create an anchor for exporting. L’appareil qui rejoint une session demande l’ancre à partir de l’appareil qui a démarré la session.The device that joins a session will request the anchor from the device that started the session.

ExportExporting:

Lorsqu’un utilisateur crée une session, NetworkDiscoveryWithAnchors appelle la fonction UNETAnchorManagers CreateAnchor.When a user creates a session, NetworkDiscoveryWithAnchors will call UNETAnchorManagers CreateAnchor function. Nous allons suivre CreateAnchor Flow.Let's follow CreateAnchor flow.

Nous commençons par la maintenance, en effaçant toutes les données que nous avons pu collecter pour les ancres précédentes.We start by doing some housekeeping, clearing out any data we may have collected for previous anchors. Nous vérifions ensuite s’il y a une ancre mise en cache à charger.Then we check if there is a cached anchor to load. Les données d’ancrage ont tendance à avoir une taille comprise entre 5 et 20 Mo. par conséquent, la réutilisation des ancres mises en cache peut économiser sur la quantité de données que nous devons transférer sur le réseau.The anchor data tends to be between 5 and 20 MB, so reusing cached anchors can save on the amount of data we need to transfer over the network. Nous verrons comment cela fonctionne un peu plus tard.We'll see how this works a bit later. Même si nous réutilisons le point d’ancrage, nous devons recevoir les données d’ancrage au cas où un nouveau client se connecte sans le point d’ancrage.Even if we are reusing the anchor, we need to get the anchor data ready in case a new client joins that doesn't have the anchor.

En ce qui concerne l’obtention des données d’ancrage, la classe WorldAnchorTransferBatch expose les fonctionnalités permettant de préparer les données d’ancrage pour les envoyer à un autre périphérique ou une autre application, ainsi que les fonctionnalités permettant d’importer les données d’ancrage.Speaking of getting the anchor data ready, the WorldAnchorTransferBatch class exposes the functionality to prepare anchor data for sending to another device or application and the functionality to import the anchor data. Étant donné que nous sommes dans le chemin d’exportation, nous allons ajouter notre point d’ancrage au WorldAnchorTransferBatch et appeler la fonction ExportAsync.Since we're on the export path, we will add our anchor to the WorldAnchorTransferBatch and call the ExportAsync function. ExportAsync appellera ensuite le rappel WriteBuffer lors de la génération de données pour l’exportation.ExportAsync will then call the WriteBuffer callback as it generates data for export. Lorsque toutes les données ont été exportées, ExportComplete est appelé.When all of the data has been exported ExportComplete will be called. Dans WriteBuffer, nous ajoutons le segment de données à une liste que nous conservons pour l’exportation.In WriteBuffer we add the chunk of data to a list we keep for exporting. Dans ExportComplete, nous allons convertir la liste en tableau.In ExportComplete we convert the list to an array. La variable AnchorName est également définie, ce qui déclenche la demande de l’ancre à d’autres appareils, le cas échéant.The AnchorName variable is also set, which will trigger other devices to request the anchor if they don't have it.

Dans certains cas, le point d’ancrage n’exportera pas ou créera donc un petit nombre de données que nous réessaierons.In some cases the anchor won't export or will create so little data that we will try again. Ici, nous appelons simplement CreateAnchor.Here we just call CreateAnchor again.

Une fonction finale dans le chemin d’exportation est AnchorFoundRemotely.A final function in the export path is AnchorFoundRemotely. Lorsqu’un autre appareil trouve le point d’ancrage, cet appareil indique à l’ordinateur hôte, et l’hôte l’utilise comme signal indiquant que l’ancre est une « bonne ancre » et peut être mise en cache.When another device finds the anchor, that device will tell the host, and the host will use that as a signal that the anchor is a "good anchor" and can be cached.

DestinationImporting:

Lorsqu’un HoloLens rejoint une session, il doit importer une ancre.When a HoloLens joins a session, it needs to import an anchor. Dans la fonction de mise à jour de UNETAnchorManager, le AnchorName est interrogé.In UNETAnchorManager's Update function, the AnchorName is polled. Lorsque le nom d’ancrage change, le processus d’importation commence.When the anchor name changes, the import process begins. Tout d’abord, nous essayons de charger l’ancre avec le nom spécifié à partir du magasin d’ancrage local.First, we try to load the anchor with the specified name from the local anchor store. Si nous l’avons déjà, nous pouvons l’utiliser sans télécharger à nouveau les données.If we already have it, we can use it without downloading the data again. Si ce n’est pas le cas, nous appelons WaitForAnchor, ce qui va lancer le téléchargement.If we don't have it, then we call WaitForAnchor which will initiate the download.

Une fois le téléchargement terminé, NetworkTransmitter_dataReadyEvent est appelée.When the download is completed, NetworkTransmitter_dataReadyEvent is called. Cela indique à la boucle de mise à jour d’appeler ImportAsync avec les données téléchargées.This will signal the Update loop to call ImportAsync with the downloaded data. ImportAsync appellera ImportComplete lorsque le processus d’importation est terminé.ImportAsync will call ImportComplete when the import process is complete. Si l’importation réussit, le point d’ancrage est enregistré dans la Banque de lecteurs locale.If the import is successful, the anchor will be saved in the local player store. PlayerController.cs effectue en fait l’appel à AnchorFoundRemotely pour permettre à l’hôte de savoir qu’une bonne ancre a été établie.PlayerController.cs actually makes the call to AnchorFoundRemotely to let the host know that a good anchor has been established.

Profitez de votre progressionEnjoy your progress

Cette fois, un utilisateur disposant d’un HoloLens hébergera une session à l’aide du bouton Démarrer la session dans l’interface utilisateur.This time a user with a HoloLens will host a session using the start session button in the UI. D’autres utilisateurs, à la fois sur HoloLens ou sur un casque immersif, sélectionnent la session, puis sélectionnent le bouton rejoindre la session dans l’interface utilisateur.Other users, both on HoloLens or an immersive headset, will select the session and then select the join session button in the UI. Si vous avez plusieurs personnes avec des appareils HoloLens, elles auront des clouds rouges sur leurs têtes.If you have multiple people with HoloLens devices, they will have red clouds over their heads. Il y aura également un Cloud bleu pour chaque casque immersif, mais les clouds bleus ne seront pas au-dessus des casques, car les casques n’essaient pas de trouver les mêmes espaces de coordonnées universelles que les appareils HoloLens.There will also be a blue cloud for each immersive headset, but the blue clouds will not be above the headsets, as the headsets are not trying to find the same world coordinate space as the HoloLens devices.

Ce point dans le projet est une application de partage contenue. Il n’en fait pas beaucoup et peut servir de base.This point in the project is a contained sharing application; it doesn't do very much, and could act as a baseline. Dans les chapitres suivants, nous allons commencer à créer une expérience que les gens pourront apprécier.In the next chapters, we will start building an experience for people to enjoy. Pour obtenir des conseils supplémentaires sur la conception de l’expérience partagée, rendez-vous ici.To get further guidance on shared experience design, go here.

Chapitre 4-immersion et téléportageChapter 4 - Immersion and teleporting

ObjectifsObjectives

Traitez l’expérience de chaque type d’appareil de réalité mixte.Cater the experience to each type of mixed reality device.

Ce que nous allons créerWhat we will build

Nous mettrons à jour l’application pour placer les utilisateurs du casque immersif sur l’île avec une vue immersive.We will update the application to put immersive headset users on the island with an immersive view. Les utilisateurs de HoloLens auront toujours la vue d’ensemble de l’île.HoloLens users will still have the bird's eye view of the island. Les utilisateurs de chaque type d’appareil peuvent voir d’autres utilisateurs tels qu’ils apparaissent dans le monde.Users of each device type can see other users as they appear in the world. Par exemple, les utilisateurs de casque immersif peuvent voir les autres avatars sur d’autres chemins d’accès sur l’île, et les utilisateurs HoloLens en tant que Clouds géants au-dessus de l’île.For instance, immersive headset users can see the other avatars on other paths on the island, and they see the HoloLens users as giant clouds above the island. Les utilisateurs du casque immersif verront également le curseur du point de regard de l’utilisateur HoloLens si l’utilisateur HoloLens regarde l’île.Immersive headset users will also see the cursor of the HoloLens user's gaze ray if the HoloLens user is looking at the island. Les utilisateurs de HoloLens verront un avatar sur l’île pour représenter chaque utilisateur de casque immersif.HoloLens users will see an avatar on the island to represent each immersive headset user.

Entrée mise à jour pour l’appareil immersif :Updated Input for the Immersive device:

  • Les boutons du pare-chocs gauche et du pare-chocs droit sur le contrôleur Xbox font pivoter le lecteurThe left bumper and right bumper buttons on the Xbox controller rotate the player
  • Le maintien du bouton Y sur le contrôleur Xbox active un curseur de téléopération.Holding the Y button on the Xbox controller will enable a teleport cursor. Si le curseur a un indicateur de flèche en rotation lorsque vous relâchez le bouton Y, vous serez téléporté à l’emplacement du curseur.If the cursor has a spinning arrow indicator when you release the Y button, you will be teleported to the cursor's location.

ÉtapesSteps

  • Ajouter MixedRealityTeleport à MixedRealityCameraParentAdd MixedRealityTeleport to MixedRealityCameraParent
    • Dans hiérarchie , sélectionnez Usland .In Hierarchy , select Usland .
    • Dans Inspector , activez le contrôle de niveau .In Inspector , enable Level Control .
    • Dans hiérarchie , sélectionnez MixedRealityCameraParent .In Hierarchy , select MixedRealityCameraParent .
    • Dans Inspector , cliquez sur Ajouter un composant .In Inspector , click Add Component .
    • Tapez Mixed realre telela et sélectionnez-la.Type Mixed Reality Teleport and select it.

Examen du codeDigging into the code

Les utilisateurs du casque immersif sont attachés à leurs PC avec un câble, mais notre îlot est plus grand que le câble est long.Immersive headset users will be tethered to their PCs with a cable, but our island is larger than the cable is long. Pour compenser, nous avons besoin de la possibilité de déplacer l’appareil photo indépendamment du mouvement de l’utilisateur.To compensate, we need the ability to move the camera independently of the user's motion. Pour plus d’informations sur la conception de votre application de réalité mixte (en particulier automotion et locomotion), consultez la page Comfort .Please see the comfort page for more information about designing your mixed reality application (in particular self motion and locomotion).

Pour pouvoir décrire ce processus, il est utile de définir deux termes.In order to describe this process it will be useful to define two terms. Tout d’abord, la poupée est l’objet qui déplace l’appareil photo indépendamment de l’utilisateur.First, dolly will be the object that moves the camera independently from the user. Un objet de jeu enfant de la poupée est l' appareil photo principal .A child game object of the dolly will be the main camera . La caméra principale est attachée à la tête de l’utilisateur.The main camera is attached to the user's head.

Dans le panneau projet, accédez à Assets\AppPrefabs\Support\Scripts\GameLogic et double-cliquez sur MixedRealityTeleport.cs .In the project panel, navigate to Assets\AppPrefabs\Support\Scripts\GameLogic and double-click on MixedRealityTeleport.cs .

MixedRealityTeleport a deux tâches.MixedRealityTeleport has two jobs. Tout d’abord, elle gère la rotation à l’aide des champignons.First, it handles rotation using the bumpers. Dans la fonction de mise à jour, nous interrogeons « ButtonUp » sur LeftBumper et RightBumper.In the update function we poll for 'ButtonUp' on LeftBumper and RightBumper. GetButtonUp retourne uniquement la valeur true sur la première image. un bouton est activé après avoir été enfoncé.GetButtonUp only returns true on the first frame a button is up after having been down. Si l’un des deux boutons a été déclenché, nous savons que l’utilisateur doit faire pivoter.If either button had been raised, then we know the user needs to rotate.

Lorsque nous faisons pivoter, nous faisons un fondu et un fondu dans à l’aide d’un script simple appelé « contrôle de fondu ».When we rotate we do a fade out and fade in using a simple script called 'fade control'. Nous faisons cela pour empêcher l’utilisateur de voir un mouvement non naturel qui pourrait entraîner une gêne.We do this to prevent the user from seeing an unnatural movement which could lead to discomfort. L’effet d’atténuation et de sortie est relativement simple.The fade in and out effect is fairly simple. Nous avons un blocage noir à l’avant de la caméra principale .We have a black quad hanging in front of the main camera . En cas de fondu, nous transmettons la valeur alpha de 0 à 1.When fading out we transition the alpha value from 0 to 1. Cela provoque progressivement le rendu des pixels noirs du quad et leur masquage.This gradually causes the black pixels of the quad to render and obscure anything behind them. Lors du fondu, nous transférons la valeur alpha à zéro.When fading back in we transition the alpha value back to zero.

Lorsque nous calculons la rotation, Notez que nous allons faire pivoter notre poupée , mais en calculant la rotation autour de la caméra principale .When we calculate the rotation, note that we are rotating our dolly but calculating the rotation around the main camera . Ce point est important, car plus la caméra principale est éloignée de 0, 0, moins la précision d’une rotation autour de la poupée deviendra du point de vue de l’utilisateur.This is important as the farther the main camera is away from 0,0,0, the less accurate a rotation around the dolly would become from the point of view of the user. En fait, si vous ne faites pas pivoter la position de la caméra, l’utilisateur se déplacera sur un arc autour du chariot plutôt que sur la rotation.In fact, if you do not rotate around the camera position, the user will move on an arc around the dolly rather than rotating.

La deuxième tâche pour MixedRealityTeleport consiste à gérer le déplacement de la poupée .The second job for MixedRealityTeleport is to handle moving the dolly . Cette opération s’effectue dans SetWorldPosition.This is done in SetWorldPosition. SetWorldPosition prend la position universelle souhaitée, c’est-à-dire la position à laquelle l’utilisateur veut percieve qu’il habite.SetWorldPosition takes the desired world position, the position where the user wants to percieve that they inhabit. Nous devons placer notre poupée à cette position, moins la position locale de la caméra principale , car ce décalage sera ajouté à chaque cadre.We need to put our dolly at that position minus the local position of the main camera , as that offset will be added each frame.

Un deuxième script appelle SetWorldPosition.A second script calls SetWorldPosition. Examinons ce script.Let's look at that script. Dans le panneau projet, accédez à Assets\AppPrefabs\Support\Scripts\GameLogic et double-cliquez sur TeleportScript.cs .In the project panel, navigate to Assets\AppPrefabs\Support\Scripts\GameLogic and double-click on TeleportScript.cs .

Ce script est un peu plus impliqué dans MixedRealityTeleport.This script is a little more involved than MixedRealityTeleport. Le script vérifie que le bouton Y du contrôleur Xbox est maintenu enfoncé.The script is checking for the Y Button on the Xbox controller to be held down. Lorsque le bouton est maintenu enfoncé, un curseur de téléverrouillage est rendu et le script convertit un rayon à partir de la position de regard de l’utilisateur.While the button is held down a teleport cursor is rendered and the script casts a ray from the user's gaze position. Si ce rayon entre en conflit avec une surface qui est plus ou moins pointée vers le haut, la surface sera considérée comme une bonne surface de téléchargement et l’animation sur le curseur de télétentative sera activée.If that ray collides with a surface that is more or less pointing up, the surface will be considered a good surface to teleport to, and the animation on the teleport cursor will be enabled. Si le rayon n’entre pas en conflit avec une surface qui pointe vers le haut, l’animation sur le curseur est désactivée.If the ray does not collide with a surface more or less pointing up, then the animation on the cursor will be disabled. Lorsque le bouton Y est relâché et que le point calculé du rayon est une position valide, le script appelle SetWorldPosition avec la position de l’intersection entre le rayon et le rayon.When the Y button is released and the calculated point of the ray is a valid position, the script calls SetWorldPosition with the position the ray intersected.

Profitez de votre progressionEnjoy your progress

Cette fois, vous devez rechercher un ami.This time you'll need to find a friend.

Une fois encore, un utilisateur avec HoloLens hébergera une session.Once again, a user with the HoloLens will host a session. D’autres utilisateurs vont rejoindre la session.Other users will join the session. L’application place les trois premiers utilisateurs à joindre à partir d’un casque immersif sur l’un des trois tracés sur l’îlot.The application will place the first three users to join from an immersive headset on one of the three paths on the island. N’hésitez pas à explorer l’île dans cette section.Feel free to explore the island in this section.

Détails à noter :Details to notice:

  1. Vous pouvez voir les visages dans les Clouds, ce qui permet à un utilisateur immersif de voir la direction qu’un utilisateur HoloLens recherche.You can see faces in the clouds, which helps an immersed user see which direction a HoloLens user is looking.
  2. Les avatars sur l’îlot ont des cou qui pivotent.The avatars on the island have necks that rotate. Ils ne suivent pas ce que fait l’utilisateur en réalité (nous n’avons pas ces informations), mais il offre une expérience intéressante.They won't follow what the user is doing is real reality (we don't have that information) but it makes for a nice experience.
  3. Si l’utilisateur HoloLens examine l’île, les utilisateurs immergés peuvent voir leur curseur.If the HoloLens user is looking at the Island, the immersed users can see their cursor.
  4. Les clouds qui représentent les utilisateurs HoloLens convertient des ombres.The clouds that represent the HoloLens users cast shadows.

Chapitre 5-finalisationChapter 5 - Finale

ObjectifsObjectives

Créez une expérience interactive collaborative entre les deux types d’appareils.Create a collaborative interactive experience between the two device types.

Ce que nous allons créerWhat we will build

En s’appuyant sur le chapitre 4, lorsqu’un utilisateur avec un casque immersif est proche d’un puzzle sur l’île, les utilisateurs de HoloLens reçoivent une info-bulle avec un indice sur le puzzle.Building on chapter 4, when a user with an immersive headset gets near a puzzle on the island, the HoloLens users will get a tool tip with a clue to the puzzle. Une fois que tous les utilisateurs du casque immersif ont passé leurs puzzles et dans le panneau « Ready » dans la salle de fusée, le fusée démarre.Once all of the immersive headset users get past their puzzles and onto the "ready pad" in the rocket room, the rocket will launch.

ÉtapesSteps

  • Dans hiérarchie , sélectionnez Usland .In Hierarchy , select Usland .
  • Dans l' inspecteur , dans contrôle de niveau , activez la case à cocher Activer la collaboration .In Inspector , in Level Control , check Enable Collaboration .

Examen du codeDigging into the code

Nous allons maintenant examiner LevelControl.cs.Now let us look at LevelControl.cs. Ce script est le cœur de la logique de jeu et gère l’état du jeu.This script is the core of the game logic and maintains the game state. Dans la mesure où il s’agit d’un jeu multijoueur utilisant UNET, nous devons comprendre la façon dont les données circulent, au moins suffisamment bien pour modifier ce didacticiel.Since this is a multiplayer game using UNET we need to understand how data flows, at least well enough to modify this tutorial. Pour une vue d’ensemble plus complète de UNET, reportez-vous à la documentation d’Unity.For a more complete overview of UNET, please refer to Unity's documentation.

Dans le panneau projet, accédez à Assets\AppPrefabs\Support\Scripts\GameLogic et double-cliquez sur LevelControl.cs .In the project panel, navigate to Assets\AppPrefabs\Support\Scripts\GameLogic and double-click on LevelControl.cs .

Voyons comment un casque immersif indique qu’ils sont prêts pour le lancement de fusée.Let us understand how an immersive headset indicates that they are ready for the rocket launch. La préparation au lancement de fusée est communiquée par la définition de l’un des trois bools dans une liste de bools qui correspondent aux trois tracés sur l’îlot.Rocket Launch readiness is communicated by setting one of three bools in a list of bools that correspond to the three paths on the island. La valeur booléenne d’un chemin d’accès est définie lorsque l’utilisateur affecté au chemin d’accès se trouve au-dessus du pavé brun dans la salle de fusée.A path's bool will be set when the user assigned to the path is on top of the brown pad inside the rocket room. OK, maintenant aux détails.Okay, now to the details.

Nous allons commencer par la fonction Update ().We will start in the Update() function. Vous noterez qu’il y a une fonction « triche ».You will note that there is a 'cheat' function. Nous l’avons utilisé en développement pour tester l’ordre de lancement et de réinitialisation des fusées.We used this in development to test the rocket launch and reset sequence. Elle ne fonctionnera pas dans l’expérience multi-utilisateur.It won't work in the multi user experience. J’espère que lorsque vous internalrez l’inversion suivante, vous pouvez le faire fonctionner.Hopefully by the time you internalize the following infromation you can make it work. Une fois que nous avons vérifié que nous devrions faire une triche, nous vérifions si le joueur local est plongé.After we check to see if we should cheat, we check to see if the local player is immersed. Nous souhaitons nous concentrer sur la façon dont nous sommes à l’objectif.We want to focus on how we find that we're at the goal. À l’intérieur de la vérification if (immergée), un appel à CheckGoal est masqué derrière le EnableCollaboration bool.Inside of the if (Immersed) check, there is a call to CheckGoal hiding behind the EnableCollaboration bool. Cela correspond à la case à cocher que vous avez sélectionnée lors de l’exécution des étapes de ce chapitre.This corresponds to the checkbox you checked while completing the steps for this chapter. Dans EnableCollaboration, nous voyons un appel à CheckGoal ().Inside of EnableCollaboration we see a call to CheckGoal().

CheckGoal effectue certaines opérations mathématiques pour voir si nous sommes plus ou moins debout sur le boîtier.CheckGoal does some math to see if we are more or less standing on the pad. Dans ce cas, nous déboguons. log « arrivé à l’objectif », puis nous appelons « SendAtGoalMessage () ».When we are, we Debug.Log "Arrived at goal" and then we call 'SendAtGoalMessage()'. Dans SendAtGoalMessage, nous appelons playerController. SendAtGoal.In SendAtGoalMessage we call playerController.SendAtGoal. Pour gagner du temps, voici le code :To save you some time, here's the code:

private void CmdSendAtGoal(int GoalIndex)
{
    levelState.SetGoalIndex(GoalIndex);
}
public void SendAtGoal(int GoalIndex)
{
    if (isLocalPlayer)
    {
        Debug.Log("sending at goal " + GoalIndex);
        CmdSendAtGoal(GoalIndex);
    }
}

Notez que SendAtGoalMessage appelle CmdSendAtGoal, qui appelle levelState. SetGoalIndex, qui est de nouveau dans LevelControl.cs.Note that SendAtGoalMessage calls CmdSendAtGoal, which calls levelState.SetGoalIndex, which is back in LevelControl.cs. À première vue, cela semble étrange.At first glance this seems strange. Pourquoi ne pas simplement appeler SetGoalIndex au lieu d’effectuer un routage dans le contrôleur de lecteur ?Why not just call SetGoalIndex rather than this strange routing through the player controller? Cela est dû au fait que nous nous conformons au modèle de données utilisé par UNET pour maintenir la synchronisation des données. Pour empêcher la triche et le blocage, UNET nécessite que chaque objet dispose d’un utilisateur habilité à modifier les variables synchronisées.The reason is that we are conforming to the data model UNET uses to keep data in sync. To prevent cheating and thrashing, UNET requires that each object has a user who has authority to change the synchronized variables. En outre, seul l’hôte (l’utilisateur qui a démarré la session) peut modifier directement les données.Further, only the host (the user that started the session) can change data directly. Les utilisateurs qui ne sont pas l’hôte, mais qui ont une autorité, doivent envoyer une « commande » à l’hôte qui modifiera la variable.Users who are not the host, but have authority, need to send a 'command' to the host which will change the variable. Par défaut, l’hôte a autorité sur tous les objets, à l’exception de l’objet généré pour représenter l’utilisateur.By default the host has authority over all objects, except for the object spawned to represent the user. Dans notre cas, cet objet contient le script playercontroller.In our case this object has the playercontroller script. Il existe un moyen de demander une autorité pour un objet, puis d’apporter des modifications, mais nous choisissons de tirer parti du fait que le contrôleur de lecteur dispose d’une autorité autonome et de commandes de routage via le contrôleur de lecteur.There is a way to request authority for an object and then make changes, but we choose to leverage the fact that the player controller has self authority and route commands through the player controller.

Autrement dit, lorsque nous nous sommes trouvés dans notre objectif, le joueur doit indiquer à l’hôte, et l’hôte va dire à tous les autres utilisateurs.Said another way, when we've found ourselves at our goal, the player needs to tell the host, and the host will tell everyone else.

De retour dans LevelControl.cs, consultez SetGoalIndex.Back in LevelControl.cs look at SetGoalIndex. Ici, nous définissons la valeur d’une valeur dans un SyncList (AtGoal).Here we are setting the value of a value in a synclist (AtGoal). N’oubliez pas que nous sommes dans le contexte de l’hôte pendant que nous faisons cela.Remember that we are in the context of the host while we do this. À l’instar d’une commande, un RPC est un problème que l’hôte peut émettre et qui entraînent l’exécution de code par tous les clients.Similar to a command, an RPC is something the host can issue that will cause all clients to run some code. Ici, nous appelons « RpcCheckAllGoals ».Here we call 'RpcCheckAllGoals'. Chaque client vérifie individuellement si les trois AtGoals sont définis et, le cas échéant, lance la fusée.Each client will individually check to see if all three AtGoals are set, and if so, launch the rocket.

Profitez de votre progressionEnjoy your progress

En s’appuyant sur le chapitre précédent, nous allons démarrer la session comme auparavant.Building on the previous chapter, we will start the session as before. Cette fois, lorsque les utilisateurs du casque immersif obtiennent la « porte » sur leur chemin d’accès, une info-bulle s’affiche pour que seuls les utilisateurs HoloLens puissent voir.This time as the users in the immersive headset get to the "door" on their path, a tooltip will appear that only the HoloLens users can see. Les utilisateurs de HoloLens sont responsables de la communication de cet indice aux utilisateurs du casque immersif.The HoloLens users are responsible for communicating this clue to the users in the immersive headset. La fusée démarre sur espace une fois que chaque avatar a effectué un pas à pas sur son panneau brun correspondant à l’intérieur des Volcano.The rocket will launch to space once each avatar has stepped on its corresponding brown pad inside the volcano. La scène sera réinitialisée après 60 secondes pour vous permettre de le faire à nouveau.The scene will reset after 60 seconds so you can do it again.

Voir aussiSee also