Observação

Os tutoriais misturados do Academia de realidade foram projetados com o HoloLens (1º gen) e com o fone de cabeça de imersão de realidade misturada.The Mixed Reality Academy tutorials were designed with HoloLens (1st gen) and Mixed Reality Immersive Headsets in mind. Como tal, achamos que é importante deixar esses tutoriais em vigor para os desenvolvedores que ainda estão procurando orientação no desenvolvimento para esses dispositivos.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. Esses tutoriais não serão atualizados com os conjuntos de ferramentas e as interações mais recentes usados para o HoloLens 2.These tutorials will not be updated with the latest toolsets or interactions being used for HoloLens 2. Eles serão mantidos para continuar a trabalhar nos dispositivos com suporte.They will be maintained to continue working on the supported devices. Uma nova série de tutoriais foi postada para o HoloLens 2.A new series of tutorials has been posted for HoloLens 2.


Sr Sharing 250: os headsets de HoloLens e de imersãoMR Sharing 250: HoloLens and immersive headsets

Com a flexibilidade do Plataforma Universal do Windows (UWP), é fácil criar um aplicativo que abranja vários dispositivos.With the flexibility of Universal Windows Platform (UWP), it is easy to create an application that spans multiple devices. Com essa flexibilidade, podemos criar experiências que aproveitam os pontos fortes de cada dispositivo.With this flexibility, we can create experiences that leverage the strengths of each device. Este tutorial abordará uma experiência compartilhada básica que é executada em headsets de uso de realidade mista do HoloLens e do Windows.This tutorial will cover a basic shared experience that runs on both HoloLens and Windows Mixed Reality immersive headsets. Este conteúdo foi originalmente entregue na conferência do Microsoft Build 2017 em Seattle, WA.This content was originally delivered at the Microsoft Build 2017 conference in Seattle, WA.

Neste tutorial, iremos:In this tutorial, we will:

  • Configure uma rede usando o UNET.Setup a network using UNET.
  • Compartilhe hologramas entre dispositivos de realidade misturada.Share holograms across mixed reality devices.
  • Estabeleça uma exibição diferente do aplicativo dependendo de qual dispositivo de realidade misturada está sendo usado.Establish a different view of the application depending on which mixed reality device is being used.
  • Crie uma experiência compartilhada em que os usuários do HoloLens guiam os usuários do headset com um quebra-cabeças simples.Create a shared experience where HoloLens users guide immersive headsets users through some simple puzzles.

Suporte a dispositivosDevice support

CourseCourse HoloLensHoloLens Headsets imersivosImmersive headsets
Sr Sharing 250: os headsets de HoloLens e de imersãoMR Sharing 250: HoloLens and immersive headsets ✔️✔️ ✔️✔️

Antes de começarBefore you start

Pré-requisitosPrerequisites

Arquivos de projetoProject files

Observação

Se você quiser examinar o código-fonte antes de baixá-lo, ele estará disponível no GitHub.If you want to look through the source code before downloading, it's available on GitHub.

Capítulo 1 – holo WorldChapter 1 - Holo World

ObjetivosObjectives

Verifique se o ambiente de desenvolvimento está pronto para ser usado com um projeto simples.Make sure the development environment is ready to go with a simple project.

O que iremos criarWhat we will build

Um aplicativo que mostra um holograma sobre o HoloLens ou um headset de imersão de realidade mista do Windows.An application that shows a hologram on either HoloLens or a Windows Mixed Reality immersive headset.

EtapasSteps

  • Abra o Unity.Open Unity.
    • Selecione abrir.Select Open.
    • Navegue até onde você extraiu os arquivos de projeto.Navigate to where you extracted the project files.
    • Clique em Selecionar Pasta.Click Select Folder.
    • Levará algum tempo para que o Unity processe o projeto pela primeira vez.It will take a little while for Unity to process the project the first time.
  • Verifique se a realidade misturada está habilitada no Unity.Check that Mixed Reality is enabled in Unity.
    • Abra a caixa de diálogo Configurações de compilação (Control + Shift + B ou arquivo > configurações de Build... ).Open the build settings dialog (Control+Shift+B or File > Build Settings...).
    • Selecione plataforma universal do Windows , em seguida, clique em alternar plataforma.Select Universal Windows Platform then click Switch Platform.
    • Selecione Editar configurações do Player > .Select Edit>Player Settings.
    • No painel Inspetor no lado direito, expanda Configurações de XR.In the Inspector panel on the right hand side, expand XR Settings.
    • Verifique a caixa suporte à realidade virtual .Check the Virtual Reality Supported box.
    • A realidade mista do Windows deve ser o SDK da realidade virtual.Windows Mixed Reality should be the Virtual Reality SDK.
  • Crie uma cena.Create a scene.
    • Na hierarquia , clique na câmera principal selecionar excluir.In the Hierarchy right click Main Camera select Delete.
    • Em HoloToolkit > entrada > pré-fabricados arraste MixedRealityCameraParent para a hierarquia.From HoloToolkit > Input > Prefabs drag MixedRealityCameraParent to the Hierarchy.
  • Adicionar hologramas à cenaAdd Holograms to the scene
    • Em AppPrefabs , arraste Skybox para a exibição cena.From AppPrefabs drag Skybox to the Scene View.
    • De AppPrefabs , arraste os gerentes para a hierarquia.From AppPrefabs drag Managers to the Hierarchy.
    • Da ilha de arrastar AppPrefabs para a hierarquia.From AppPrefabs drag Island to the Hierarchy.
  • Salvar e compilarSave And build
    • Salvar ( controle + S ou arquivo > salvar cena)Save (either Control+S or File > Save Scene)
    • Como essa é uma nova cena, você precisará nomeá-la.Since this is a new scene, you'll need to name it. O nome não é importante, mas usamos SharedMixedReality.Name doesn't matter, but we use SharedMixedReality.
  • Exportar para o Visual StudioExport To Visual Studio
    • Abra o menu Compilar (Control + Shift + B ou arquivos > configurações de Build)Open the build menu (Control+Shift+B or File > Build Settings)
    • Clique em Adicionar abrir cenas.Click Add Open Scenes.
    • Verificar projetos C# do UnityCheck Unity C# Projects
    • Clique em Compilar.Click Build.
    • Na janela Explorador de arquivos que aparece, crie uma nova pasta chamada aplicativo.In the file explorer window that appears, create a New Folder named App.
    • Clique uma vez na pasta do aplicativo .Single click the App folder.
    • Pressione Selecionar pasta.Press Select Folder.
    • Aguarde a conclusão da compilaçãoWait for the build to complete
    • Na janela Explorador de arquivos que aparece, navegue até a pasta do aplicativo .In the file explorer window that appears, navigate into the App folder.
    • Clique duas vezes em SharedMixedReality. sln para iniciar o Visual StudioDouble-click SharedMixedReality.sln to launch Visual Studio
  • Compilar a partir do Visual StudioBuild From Visual Studio
    • Usando o destino de alteração da barra de ferramentas superior para liberar e x86.Using the top toolbar change target to Release and x86.
    • Clique na seta ao lado de computador local e selecione dispositivo para implantar no HoloLensClick the arrow next to Local Machine and select Device to deploy to HoloLens
    • Clique na seta ao lado de dispositivo e selecione computador local para implantar para o headset de realidade misturada.Click the arrow next to Device and select Local Machine to deploy for the mixed reality headset.
    • Clique em depurar-> iniciar sem Depurar ou controlar + F5 para iniciar o aplicativo.Click Debug->Start Without Debugging or Control+F5 to start the application.

Aprofundando-se no códigoDigging into the code

No painel projeto, navegue até Assets\HoloToolkit\Input\Scripts\Utilities e clique duas vezes em MixedRealityCameraManager.cs para abri-lo.In the project panel, navigate to Assets\HoloToolkit\Input\Scripts\Utilities and double click MixedRealityCameraManager.cs to open it.

Visão geral: MixedRealityCameraManager.cs é um script simples que ajusta as configurações de nível de qualidade e de segundo plano com base no dispositivo.Overview: MixedRealityCameraManager.cs is a simple script that adjusts quality level and background settings based on the device. A chave aqui é HolographicSettings. IsDisplayOpaque, que permite que um script detecte se o dispositivo é um HoloLens (IsDisplayOpaque retorna false) ou um headset de imersão (IsDisplayOpaque retorna 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).

Aproveite seu progressoEnjoy your progress

Neste ponto, o aplicativo apenas renderizará um holograma.At this point the application will just render a hologram. Adicionaremos interação com o holograma posteriormente.We will add interaction to the hologram later. Ambos os dispositivos processarão o holograma da mesma forma.Both devices will render the hologram the same. O headset de imersão também renderizará uma fundo azul céu e nuvens.The immersive headset will also render a blue sky and clouds background.

Capítulo 2-interaçãoChapter 2 - Interaction

ObjetivosObjectives

Mostre como tratar a entrada para um aplicativo do Windows Mixed Reality.Show how to handle input for a Windows Mixed Reality application.

O que iremos criarWhat we will build

Criando o aplicativo no capítulo 1, adicionaremos funcionalidade para permitir que o usuário pegue o holograma e coloque-o em uma superfície do mundo real no HoloLens ou em uma tabela virtual em um headset de imersão.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.

Atualizador de entrada: No HoloLens, o gesto de seleção é o toque de ar.Input Refresher: On HoloLens the select gesture is the air tap. Em headsets de imersão, usaremos o botão a no controlador Xbox.On immersive headsets, we will use the A button on the Xbox controller. Para obter mais informações, confira a visão geral do modelo de interação.For more information check out the interaction model overview.

EtapasSteps

  • Adicionar Gerenciador de entradaAdd Input manager
    • Em HoloToolkit > entrada > pré-fabricados arraste InputManager para hierarquia como um filho de gerentes.From HoloToolkit > Input > Prefabs drag InputManager to Hierarchy as a child of Managers.
    • From HoloToolkit > entrada > pré-fabricados > cursor arrastar cursor para hierarquia.From HoloToolkit > Input > Prefabs > Cursor drag Cursor to Hierarchy.
  • Adicionar mapeamento espacialAdd Spatial Mapping
    • Em HoloToolkit > SpatialMapping > pré-fabricados arraste SpatialMapping para hierarquia.From HoloToolkit > SpatialMapping > Prefabs drag SpatialMapping to Hierarchy.
  • Adicionar Playspace virtualAdd Virtual Playspace
    • Em hierarquia , expanda MixedRealityCameraParent selecionar limiteIn Hierarchy expand MixedRealityCameraParent select Boundary
    • No painel Inspetor , marque a caixa para habilitar o limiteIn Inspector panel check the box to enable Boundary
    • Em AppPrefabs , arraste VRRoom para hierarquia.From AppPrefabs drag VRRoom to Hierarchy.
  • Adicionar WorldAnchorManagerAdd WorldAnchorManager
    • Em hierarquia, selecione gerentes.In Hierarchy, Select Managers.
    • No Inspetor, clique em Adicionar componente.In Inspector, click Add Component.
    • Digite gerente de âncora mundial.Type World Anchor Manager.
    • Selecione gerente de âncora mundial para adicioná-lo.Select World Anchor Manager to add it.
  • Adicionar TapToPlace à ilhaAdd TapToPlace to the Island
    • Em hierarquia, expanda ilha.In Hierarchy, expand Island.
    • Selecione MixedRealityLand.Select MixedRealityLand.
    • No Inspetor, clique em Adicionar componente.In Inspector, click Add Component.
    • Digite toque para inserir e selecione-o.Type Tap To Place and select it.
    • Verifique o pai ao tocar.Check Place Parent On Tap.
    • Defina deslocamento de posicionamento como (0, 0,1, 0) .Set Placement Offset to (0, 0.1, 0).
  • Salvar e compilar como antesSave and Build as before

Aprofundando-se no códigoDigging into the code

Script 1-GamepadInput.csScript 1 - GamepadInput.cs

No painel projeto, navegue até Assets\HoloToolkit\Input\Scripts\InputSources e clique duas vezes em GamepadInput.cs para abri-lo.In the project panel navigate to Assets\HoloToolkit\Input\Scripts\InputSources and double click GamepadInput.cs to open it. No mesmo caminho no painel de projeto, também clique duas vezes em InteractionSourceInputSource.cs.From the same path in the project panel, also double click InteractionSourceInputSource.cs.

Observe que ambos os scripts têm uma classe base comum, BaseInputSource.Note that both scripts have a common base class, BaseInputSource.

BaseInputSource mantém uma referência a um InputManager, que permite que um script dispare eventos.BaseInputSource keeps a reference to an InputManager, which allows a script to trigger events. Nesse caso, o evento InputClicked é relevante.In this case, the InputClicked event is relevant. Será importante lembrar-se de quando chegarmos ao script 2, TapToPlace.This will be important to remember when we get to script 2, TapToPlace. No caso do GamePadInput, pesquisamos um botão no controlador a ser pressionado e, em seguida, geramos o evento InputClicked.In the case of GamePadInput, we poll for the A button on the controller to be pressed, then we raise the InputClicked event. No caso do InteractionSourceInputSource, geramos o evento InputClicked em resposta ao TappedEvent.In the case of InteractionSourceInputSource, we raise the InputClicked event in response to the TappedEvent.

Script 2-TapToPlace.csScript 2 - TapToPlace.cs

No painel projeto, navegue até Assets\HoloToolkit\SpatialMapping\Scripts e clique duas vezes em TapToPlace.cs para abri-lo.In the project panel navigate to Assets\HoloToolkit\SpatialMapping\Scripts and double click TapToPlace.cs to open it.

A primeira coisa que muitos desenvolvedores desejam implementar ao criar um aplicativo Holographic está movendo hologramas com entrada de gestos.The first thing many developers want to implement when creating a Holographic application is moving Holograms with gesture input. Assim, fizemos um comentário completo sobre esse script.As such, we've endeavored to thoroughly comment this script. Algumas coisas valem a pena destacar este tutorial.A few things are worth highlighting for this tutorial.

Primeiro, observe que TapToPlace implementa IInputClickHandler.First, note that TapToPlace implements IInputClickHandler. IInputClickHandler expõe as funções que manipulam o evento InputClicked gerado por GamePadInput.cs ou InteractionSourceInputSource.cs.IInputClickHandler exposes the functions that handle the InputClicked event raised by GamePadInput.cs or InteractionSourceInputSource.cs. OnInputClicked é chamado quando um BaseInputSource detecta um clique enquanto o objeto com TapToPlace está em foco.OnInputClicked is called when a BaseInputSource detects a click while the object with TapToPlace is in focus. Ao tocar no HoloLens ou pressionar o botão a no controlador Xbox, o evento será disparado.Either airtapping on HoloLens or pressing the A button on the Xbox controller will trigger the event.

O segundo é que o código seja executado na atualização para ver se uma superfície está sendo examinada para que possamos posicionar o objeto de jogo em uma superfície, como uma tabela.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. O headset de imersão não tem um conceito de superfícies reais, portanto, o objeto que representa a tabela superior (Vroom > TableThingy > Cube) foi marcado com a camada física SpatialMapping, portanto, o Ray Cast na atualização irá colidir com a tabela virtual superior.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.

Aproveite seu progressoEnjoy your progress

Desta vez, você pode selecionar a ilha para movê-la.This time you can select the island to move it. No HoloLens, você pode mover a ilha para uma superfície real.On HoloLens you can move the island to a real surface. No headset de imersão, você pode mover a ilha para a tabela virtual que adicionamos.In the immersive headset you can move the island to the virtual table we added.

Capítulo 3 – compartilhandoChapter 3 - Sharing

ObjetivosObjectives

Verifique se a rede está configurada corretamente e detalhe como as âncoras espaciais são compartilhadas entre os dispositivos.Ensure that the network is correctly configured and detail how spatial anchors are shared between devices.

O que iremos criarWhat we will build

Converteremos nosso projeto em um projeto de vários participantes.We will convert our project to a multiplayer project. Adicionaremos a interface do usuário e a lógica para hospedar ou ingressar em sessões.We will add UI and logic to host or join sessions. Os usuários do HoloLens verão um ao outro na sessão com nuvens em seus cabeçotes e os usuários do headset de imersão têm nuvens perto de onde está a âncora.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. Os usuários em headsets de imersão verão os usuários do HoloLens em relação à origem da cena.Users in the immersive headsets will see the HoloLens users relative to the origin of the scene. Os usuários do HoloLens verão o holograma da ilha no mesmo local.HoloLens users will all see the hologram of the island in the same place. É importante observar que os usuários nos headsets de imersão não estarão na ilha durante este capítulo, mas se comportarão de forma semelhante ao HoloLens, com uma visão de olho da ilha.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.

EtapasSteps

  • Remover ilha e VRRoomRemove Island and VRRoom
    • Em hierarquia , clique com o botão direito do mouse em ilha selecionar excluirIn Hierarchy right-click Island select Delete
    • Em hierarquia , clique com o botão direito do mouse em VRRoom selecionar excluirIn Hierarchy right-click VRRoom select Delete
  • Adicionar UslandAdd Usland
    • Em AppPrefabs , arraste Usland para hierarquia.From AppPrefabs drag Usland to Hierarchy.
  • Em AppPrefabs , arraste cada um dos seguintes para hierarquia:From AppPrefabs drag each of the following to Hierarchy:
    • UNETSharingStageUNETSharingStage
    • UNetAnchorRootUNetAnchorRoot
    • UIContainerUIContainer
    • DebugPanelButtonDebugPanelButton
  • Salvar e compilar como antesSave and Build as before

Aprofundando-se no códigoDigging into the code

No painel projeto, navegue até Assets\AppPrefabs\Support\SharingWithUnet\Scripts e clique duas vezes em UnetAnchorManager.cs.In the project panel, navigate to Assets\AppPrefabs\Support\SharingWithUnet\Scripts and double-click on UnetAnchorManager.cs. A capacidade de um HoloLens compartilhar informações de rastreamento com outro HoloLens, de modo que ambos os dispositivos possam compartilhar o mesmo espaço é quase mágico.The ability for one HoloLens to share tracking information with another HoloLens such that both devices can share the same space is near magical. O poder da realidade misturada vem ativo quando duas ou mais pessoas podem colaborar usando os mesmos dados digitais.The power of mixed reality comes alive when two or more people can collaborate using the same digital data.

Algumas coisas para destacar esse script:A few things to point out in this script:

Na função iniciar, observe a verificação de IsDisplayOpaque.In the start function, notice the check for IsDisplayOpaque. Nesse caso, vamos fingir que a âncora é estabelecida.In this case, we pretend that the Anchor is established. Isso ocorre porque os headsets de imersão não expõem uma maneira de importar ou exportar âncoras.This is because the immersive headsets do not expose a way to import or export anchors. No entanto, se estivermos executando em um HoloLens, esse script implementará âncoras de compartilhamento entre os dispositivos.If we are running on a HoloLens, however, this script implements sharing anchors between the devices. O dispositivo que inicia a sessão criará uma âncora para exportação.The device that starts the session will create an anchor for exporting. O dispositivo que ingressa em uma sessão solicitará a âncora do dispositivo que iniciou a sessão.The device that joins a session will request the anchor from the device that started the session.

ExportarExporting:

Quando um usuário cria uma sessão, NetworkDiscoveryWithAnchors chamará a função createanchor UNETAnchorManagers.When a user creates a session, NetworkDiscoveryWithAnchors will call UNETAnchorManagers CreateAnchor function. Vamos seguir o fluxo de createanchor.Let's follow CreateAnchor flow.

Começamos fazendo algumas realizações, limpando todos os dados que poderemos ter coletado para âncoras anteriores.We start by doing some housekeeping, clearing out any data we may have collected for previous anchors. Em seguida, verificamos se há uma âncora em cache a ser carregada.Then we check if there is a cached anchor to load. Os dados de âncora tendem a estar entre 5 e 20 MB, portanto, reutilizar âncoras em cache pode economizar na quantidade de dados que precisamos transferir pela rede.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. Veremos como isso funciona um pouco mais tarde.We'll see how this works a bit later. Mesmo que estejamos reutilizando a âncora, precisamos obter os dados de âncora prontos caso um novo cliente ingresse que não tenha a âncora.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.

Falando em colocar os dados de ancoragem prontos, a classe WorldAnchorTransferBatch expõe a funcionalidade para preparar dados âncora para enviar para outro dispositivo ou aplicativo e a funcionalidade para importar os dados de âncora.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. Como estamos no caminho de exportação, adicionaremos nossa âncora ao WorldAnchorTransferBatch e chamarei a função ExportAsync.Since we're on the export path, we will add our anchor to the WorldAnchorTransferBatch and call the ExportAsync function. Em seguida, ExportAsync chamará o retorno de chamada WriteBuffer, pois ele gera dados para exportação.ExportAsync will then call the WriteBuffer callback as it generates data for export. Quando todos os dados forem exportados, ExportComplete será chamado.When all of the data has been exported ExportComplete will be called. No WriteBuffer, adicionamos a parte dos dados a uma lista que mantemos para a exportação.In WriteBuffer we add the chunk of data to a list we keep for exporting. No ExportComplete, convertemos a lista em uma matriz.In ExportComplete we convert the list to an array. A variável anchorName também é definida, o que disparará outros dispositivos para solicitar a âncora se eles não o tiverem.The AnchorName variable is also set, which will trigger other devices to request the anchor if they don't have it.

Em alguns casos, a âncora não será exportada ou criará poucos dados que tentaremos novamente.In some cases the anchor won't export or will create so little data that we will try again. Aqui, basta chamar createanchor novamente.Here we just call CreateAnchor again.

Uma função final no caminho de exportação é AnchorFoundRemotely.A final function in the export path is AnchorFoundRemotely. Quando outro dispositivo encontrar a âncora, esse dispositivo dirá o host, e o host usará isso como um sinal de que a âncora é uma "boa âncora" e pode ser armazenada em 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.

ImportarImporting:

Quando um HoloLens ingressa em uma sessão, ele precisa importar uma âncora.When a HoloLens joins a session, it needs to import an anchor. Na função Update do UNETAnchorManager, o ancoraname é sondado.In UNETAnchorManager's Update function, the AnchorName is polled. Quando o nome da âncora é alterado, o processo de importação é iniciado.When the anchor name changes, the import process begins. Primeiro, tentamos carregar a âncora com o nome especificado do repositório de âncora local.First, we try to load the anchor with the specified name from the local anchor store. Se já o tiver, podemos usá-lo sem baixar os dados novamente.If we already have it, we can use it without downloading the data again. Se não tivermos, chamamos o WaitForAnchor, que iniciará o download.If we don't have it, then we call WaitForAnchor which will initiate the download.

Quando o download for concluído, NetworkTransmitter_dataReadyEvent será chamado.When the download is completed, NetworkTransmitter_dataReadyEvent is called. Isso sinalizará o loop de atualização para chamar ImportAsync com os dados baixados.This will signal the Update loop to call ImportAsync with the downloaded data. ImportAsync chamará ImportComplete quando o processo de importação for concluído.ImportAsync will call ImportComplete when the import process is complete. Se a importação for bem-sucedida, a âncora será salva no repositório local do Player.If the import is successful, the anchor will be saved in the local player store. PlayerController.cs realmente faz a chamada para AnchorFoundRemotely para permitir que o host saiba que uma boa âncora foi estabelecida.PlayerController.cs actually makes the call to AnchorFoundRemotely to let the host know that a good anchor has been established.

Aproveite seu progressoEnjoy your progress

Desta vez, um usuário com um HoloLens hospedará uma sessão usando o botão iniciar sessão na interface do usuário.This time a user with a HoloLens will host a session using the start session button in the UI. Outros usuários, tanto no HoloLens quanto em um headset de imersão, selecionarão a sessão e, em seguida, selecionarão o botão de sessão de junção na interface do usuário.Other users, both on HoloLens or an immersive headset, will select the session and then select the join session button in the UI. Se você tiver várias pessoas com dispositivos de HoloLens, elas terão nuvens vermelhas sobre suas cabeças.If you have multiple people with HoloLens devices, they will have red clouds over their heads. Também haverá uma nuvem azul para cada headset de imersão, mas as nuvens azuis não estarão acima dos headsets, pois os headsets não estão tentando encontrar o mesmo espaço de coordenadas do mundo que os dispositivos 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.

Esse ponto no projeto é um aplicativo de compartilhamento independente; Ele não faz muita coisa e pode agir como uma linha de base.This point in the project is a contained sharing application; it doesn't do very much, and could act as a baseline. Nos próximos capítulos, começaremos a criar uma experiência para as pessoas gostarem.In the next chapters, we will start building an experience for people to enjoy. Para obter mais orientações sobre o design de experiência compartilhada, acesse aqui.To get further guidance on shared experience design, go here.

Capítulo 4-imersão e teleportabilidadeChapter 4 - Immersion and teleporting

ObjetivosObjectives

Atenda à experiência de cada tipo de dispositivo de realidade misturada.Cater the experience to each type of mixed reality device.

O que iremos criarWhat we will build

Atualizaremos o aplicativo para colocar os usuários de headsets imersivas na ilha com uma exibição imersiva.We will update the application to put immersive headset users on the island with an immersive view. Os usuários do HoloLens ainda terão a visão panorâmica da ilha.HoloLens users will still have the bird's eye view of the island. Os usuários de cada tipo de dispositivo podem ver outros usuários como aparecem no mundo.Users of each device type can see other users as they appear in the world. Por exemplo, os usuários de headsets de imersão podem ver os outros avatars em outros caminhos na ilha e eles veem os usuários do HoloLens como nuvens Giant acima da ilha.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. Os usuários do headset de imersão também verão o cursor do olhar Ray do usuário do HoloLens se o usuário do HoloLens estiver olhando para a ilha.Immersive headset users will also see the cursor of the HoloLens user's gaze ray if the HoloLens user is looking at the island. Os usuários do HoloLens verão um avatar na ilha para representar cada usuário do headset de imersão.HoloLens users will see an avatar on the island to represent each immersive headset user.

Entrada atualizada para o dispositivo de imersão:Updated Input for the Immersive device:

  • Os botões do amortecedor esquerdo e do amortecedor direito no controlador Xbox giram o PlayerThe left bumper and right bumper buttons on the Xbox controller rotate the player
  • Manter o botão Y no controlador Xbox habilitará um cursor teleport .Holding the Y button on the Xbox controller will enable a teleport cursor. Se o cursor tiver um indicador de seta girando quando você liberar o botão Y, você será teleportado para o local do cursor.If the cursor has a spinning arrow indicator when you release the Y button, you will be teleported to the cursor's location.

EtapasSteps

  • Adicionar MixedRealityTeleport a MixedRealityCameraParentAdd MixedRealityTeleport to MixedRealityCameraParent
    • Em hierarquia, selecione Usland.In Hierarchy, select Usland.
    • No Inspetor, habilite o controle de nível.In Inspector, enable Level Control.
    • Em hierarquia, selecione MixedRealityCameraParent.In Hierarchy, select MixedRealityCameraParent.
    • No Inspetor, clique em Adicionar componente.In Inspector, click Add Component.
    • Digite teleport de realidade misturada e selecione-o.Type Mixed Reality Teleport and select it.

Aprofundando-se no códigoDigging into the code

Os usuários do headset de imersão serão conectados a seus PCs com um cabo, mas nossa ilha é maior do que o cabo é longo.Immersive headset users will be tethered to their PCs with a cable, but our island is larger than the cable is long. Para compensar, precisamos da capacidade de mover a câmera independentemente do movimento do usuário.To compensate, we need the ability to move the camera independently of the user's motion. Consulte a página de conforto para obter mais informações sobre como criar seu aplicativo de realidade misturada (em particular e Locomotion).Please see the comfort page for more information about designing your mixed reality application (in particular self motion and locomotion).

Para descrever esse processo, será útil definir dois termos.In order to describe this process it will be useful to define two terms. Primeiro, Dolly será o objeto que move a câmera independentemente do usuário.First, dolly will be the object that moves the camera independently from the user. Um objeto de jogo filho do Dolly será a câmera principal.A child game object of the dolly will be the main camera. A câmera principal é anexada à cabeça do usuário.The main camera is attached to the user's head.

No painel projeto, navegue até Assets\AppPrefabs\Support\Scripts\GameLogic e clique duas vezes em MixedRealityTeleport.cs.In the project panel, navigate to Assets\AppPrefabs\Support\Scripts\GameLogic and double-click on MixedRealityTeleport.cs.

MixedRealityTeleport tem dois trabalhos.MixedRealityTeleport has two jobs. Primeiro, ele lida com a rotação usando os amortecedores.First, it handles rotation using the bumpers. Na função Update, pesquisamos por ' ButtonUp ' em LeftBumper e RightBumper.In the update function we poll for 'ButtonUp' on LeftBumper and RightBumper. GetButtonUp retorna true no primeiro quadro em que um botão está ativo depois de ter sido desativado.GetButtonUp only returns true on the first frame a button is up after having been down. Se um dos botões tivesse sido gerado, sabemos que o usuário precisa girar.If either button had been raised, then we know the user needs to rotate.

Quando giramos, fazemos um fade out e esmaecemos usando um script simples chamado ' Fade Control '.When we rotate we do a fade out and fade in using a simple script called 'fade control'. Fazemos isso para impedir que o usuário veja um movimento não natural que poderia levar a discomfort.We do this to prevent the user from seeing an unnatural movement which could lead to discomfort. O efeito de fade in e saída é bastante simples.The fade in and out effect is fairly simple. Temos um buraco de cruz preto na frente da câmera principal.We have a black quad hanging in front of the main camera. Ao desbotar, fazemos a transição do valor alfa de 0 para 1.When fading out we transition the alpha value from 0 to 1. Isso gradualmente faz com que os pixels pretos do Quad sejam renderizados e obscurecem qualquer coisa por trás deles.This gradually causes the black pixels of the quad to render and obscure anything behind them. Ao retroceder, fazemos a transição do valor alfa de volta para zero.When fading back in we transition the alpha value back to zero.

Quando calculamos a rotação, observe que estamos girando nosso Dolly , mas calculando a rotação em toda a câmera principal.When we calculate the rotation, note that we are rotating our dolly but calculating the rotation around the main camera. Isso é importante, pois o mais distante da câmera principal está longe de 0, 0, a rotação menos precisa em relação ao Dolly se tornaria do ponto de vista do usuário.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. Na verdade, se você não girar a posição da câmera, o usuário será movido em um arco em volta do Dolly em vez de girar.In fact, if you do not rotate around the camera position, the user will move on an arc around the dolly rather than rotating.

O segundo trabalho para MixedRealityTeleport é manipular a movimentação de Dolly.The second job for MixedRealityTeleport is to handle moving the dolly. Isso é feito em SetWorldPosition.This is done in SetWorldPosition. SetWorldPosition usa a posição do mundo desejada, a posição onde o usuário deseja percieve que estar.SetWorldPosition takes the desired world position, the position where the user wants to percieve that they inhabit. Precisamos colocar nosso Dolly nessa posição menos a posição local da câmera principal, pois esse deslocamento será adicionado a cada quadro.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.

Um segundo script chama SetWorldPosition.A second script calls SetWorldPosition. Vamos examinar esse script.Let's look at that script. No painel projeto, navegue até Assets\AppPrefabs\Support\Scripts\GameLogic e clique duas vezes em TeleportScript.cs.In the project panel, navigate to Assets\AppPrefabs\Support\Scripts\GameLogic and double-click on TeleportScript.cs.

Esse script é um pouco mais envolvido do que MixedRealityTeleport.This script is a little more involved than MixedRealityTeleport. O script está verificando se o botão Y no controlador Xbox será mantido.The script is checking for the Y Button on the Xbox controller to be held down. Enquanto o botão é mantido para baixo, um cursor teleport é renderizado e o script converte um Ray a partir da posição de olhar do usuário.While the button is held down a teleport cursor is rendered and the script casts a ray from the user's gaze position. Se esse raio colidir com uma superfície que está mais ou menos apontando para cima, a superfície será considerada uma boa superfície para teleport e a animação no cursor teleport será habilitada.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. Se o raio não colidir com uma superfície mais ou menos apontando para cima, a animação no cursor será desabilitada.If the ray does not collide with a surface more or less pointing up, then the animation on the cursor will be disabled. Quando o botão Y é liberado e o ponto calculado do raio é uma posição válida, o script chama SetWorldPosition com a posição do raio interseccionado.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.

Aproveite seu progressoEnjoy your progress

Desta vez, você precisará encontrar um amigo.This time you'll need to find a friend.

Mais uma vez, um usuário com o HoloLens hospedará uma sessão.Once again, a user with the HoloLens will host a session. Outros usuários ingressarão na sessão.Other users will join the session. O aplicativo fará com que os três primeiros usuários ingressem de um headset de imersão em um dos três caminhos na ilha.The application will place the first three users to join from an immersive headset on one of the three paths on the island. Sinta-se à vontade para explorar a ilha nesta seção.Feel free to explore the island in this section.

Detalhes a serem observados:Details to notice:

  1. Você pode ver os rostos nas nuvens, o que ajuda um usuário imersos a ver qual direção um usuário do HoloLens está olhando.You can see faces in the clouds, which helps an immersed user see which direction a HoloLens user is looking.
  2. Os avatars na ilha têm pescoços que giram.The avatars on the island have necks that rotate. Eles não seguirão o que o usuário está fazendo é realidade real (não temos essas informações), mas isso faz uma boa experiência.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. Se o usuário do HoloLens estiver olhando para a ilha, os usuários do imersos poderão ver o cursor.If the HoloLens user is looking at the Island, the immersed users can see their cursor.
  4. As nuvens que representam os usuários do HoloLens convertem sombras.The clouds that represent the HoloLens users cast shadows.

Capítulo 5 – finalChapter 5 - Finale

ObjetivosObjectives

Crie uma experiência interativa colaborativa entre os dois tipos de dispositivo.Create a collaborative interactive experience between the two device types.

O que iremos criarWhat we will build

Com base no capítulo 4, quando um usuário com um headset de imersão fica perto de um quebra-cabeça na ilha, os usuários do HoloLens terão uma dica de ferramenta com uma pista para o quebra-cabeça.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. Depois que todos os usuários do headset de imersão passarem do quebra-cabeças e para a "área pronta" na sala de Rocket, o Rocket será iniciado.Once all of the immersive headset users get past their puzzles and onto the "ready pad" in the rocket room, the rocket will launch.

EtapasSteps

  • Em hierarquia, selecione Usland.In Hierarchy, select Usland.
  • No Inspetor, em controle de nível, marque habilitar colaboração.In Inspector, in Level Control, check Enable Collaboration.

Aprofundando-se no códigoDigging into the code

Agora vamos examinar LevelControl.cs.Now let us look at LevelControl.cs. Esse script é o núcleo da lógica do jogo e mantém o estado do jogo.This script is the core of the game logic and maintains the game state. Como este é um jogo com vários participantes usando o UNET, precisamos entender como os fluxos de dados, pelo menos, o suficiente para modificar este tutorial.Since this is a multiplayer game using UNET we need to understand how data flows, at least well enough to modify this tutorial. Para obter uma visão geral mais completa do UNET, consulte a documentação do Unity.For a more complete overview of UNET, please refer to Unity's documentation.

No painel projeto, navegue até Assets\AppPrefabs\Support\Scripts\GameLogic e clique duas vezes em LevelControl.cs.In the project panel, navigate to Assets\AppPrefabs\Support\Scripts\GameLogic and double-click on LevelControl.cs.

Vamos entender como um headset de imersão indica que eles estão prontos para o lançamento do Rocket.Let us understand how an immersive headset indicates that they are ready for the rocket launch. O Rocket Launch Readiness é comunicado pela definição de um dos Três BOOLs em uma lista de BOOLs que correspondem aos três caminhos na ilha.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. O bool de um caminho será definido quando o usuário atribuído ao caminho estiver na parte superior do painel marrom dentro da sala de Rocket.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. Bem, agora para os detalhes.Okay, now to the details.

Começaremos a usar a função Update ().We will start in the Update() function. Você observará que há uma função ' enganar '.You will note that there is a 'cheat' function. Nós usamos isso em desenvolvimento para testar a sequência de inicialização e redefinição do Rocket.We used this in development to test the rocket launch and reset sequence. Ele não funcionará na experiência de vários usuários.It won't work in the multi user experience. Espero que, no momento em que você internalizar o seguinte inprocedimento, você possa fazê-lo funcionar.Hopefully by the time you internalize the following infromation you can make it work. Depois de verificarmos para ver se devemos enganar, verificamos se o player local é imersos.After we check to see if we should cheat, we check to see if the local player is immersed. Queremos nos concentrar em como descobrimos que estamos no objetivo.We want to focus on how we find that we're at the goal. Dentro da verificação if (imersos), há uma chamada para CheckGoal ocultando por trás do EnableCollaboration bool.Inside of the if (Immersed) check, there is a call to CheckGoal hiding behind the EnableCollaboration bool. Isso corresponde à caixa de seleção selecionada ao concluir as etapas deste capítulo.This corresponds to the checkbox you checked while completing the steps for this chapter. Dentro de EnableCollaboration, vemos uma chamada para CheckGoal ().Inside of EnableCollaboration we see a call to CheckGoal().

CheckGoal faz algumas matemáticas para ver se estamos mais ou menos em pé no painel.CheckGoal does some math to see if we are more or less standing on the pad. Quando estamos, Depuramos. log "chegou ao objetivo" e, em seguida, chamamos ' SendAtGoalMessage () '.When we are, we Debug.Log "Arrived at goal" and then we call 'SendAtGoalMessage()'. Em SendAtGoalMessage, chamamos playerController. SendAtGoal.In SendAtGoalMessage we call playerController.SendAtGoal. Para economizar algum tempo, aqui está o código: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);
    }
}

Observe que SendAtGoalMessage chama CmdSendAtGoal, que chama levelstate. SetGoalIndex, que está de volta em LevelControl.cs.Note that SendAtGoalMessage calls CmdSendAtGoal, which calls levelState.SetGoalIndex, which is back in LevelControl.cs. À primeira vista, isso parece estranho.At first glance this seems strange. Por que não apenas chamar SetGoalIndex em vez desse roteamento estranho por meio do controlador do jogador?Why not just call SetGoalIndex rather than this strange routing through the player controller? O motivo é que estamos em conformidade com o modelo de dados que o UNET usa para manter os dados sincronizados. Para evitar trapaceando e ultrapaginação, o UNET requer que cada objeto tenha um usuário que tenha autoridade para alterar as variáveis sincronizadas.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. Além disso, somente o host (o usuário que iniciou a sessão) pode alterar os dados diretamente.Further, only the host (the user that started the session) can change data directly. Os usuários que não são o host, mas têm autoridade, precisam enviar um ' Command ' para o host que alterará a variável.Users who are not the host, but have authority, need to send a 'command' to the host which will change the variable. Por padrão, o host tem autoridade sobre todos os objetos, exceto pelo objeto gerado para representar o usuário.By default the host has authority over all objects, except for the object spawned to represent the user. Em nosso caso, esse objeto tem o script playercontroller.In our case this object has the playercontroller script. Há uma maneira de solicitar autoridade para um objeto e, em seguida, fazer alterações, mas optamos por aproveitar o fato de que o controlador do Player tem comandos Self Authority e Route por meio do controlador do jogador.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.

Dito outra maneira, quando nos encontramos em nossa meta, o jogador precisa dizer ao host, e o host informará a todos os outros.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 volta ao LevelControl.cs, consulte SetGoalIndex.Back in LevelControl.cs look at SetGoalIndex. Aqui, estamos definindo o valor de um valor em uma synclist (AtGoal).Here we are setting the value of a value in a synclist (AtGoal). Lembre-se de que estamos no contexto do host enquanto fazemos isso.Remember that we are in the context of the host while we do this. Semelhante a um comando, um RPC é algo que o host pode emitir e fará com que todos os clientes executem algum código.Similar to a command, an RPC is something the host can issue that will cause all clients to run some code. Aqui, chamamos ' RpcCheckAllGoals '.Here we call 'RpcCheckAllGoals'. Cada cliente verifica individualmente se todos os três AtGoals estão definidos e, nesse caso, inicia o Rocket.Each client will individually check to see if all three AtGoals are set, and if so, launch the rocket.

Aproveite seu progressoEnjoy your progress

Criando no capítulo anterior, iniciaremos a sessão como antes.Building on the previous chapter, we will start the session as before. Desta vez, à medida que os usuários no headset de imersão chegarem à "porta" em seu caminho, uma dica de ferramenta aparecerá para que apenas os usuários do HoloLens possam ver.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. Os usuários do HoloLens são responsáveis por comunicar essa pista aos usuários no headset de imersão.The HoloLens users are responsible for communicating this clue to the users in the immersive headset. O Rocket será iniciado em espaço depois que cada avatar tiver passado em seu painel marrom correspondente dentro do vulcão.The rocket will launch to space once each avatar has stepped on its corresponding brown pad inside the volcano. A cena será redefinida após 60 segundos para que você possa fazer isso novamente.The scene will reset after 60 seconds so you can do it again.

Consulte tambémSee also