Entrada do MR 213: controladores de movimentos

Observação

Os tutoriais do Mixed Reality Academy foram projetados com o HoloLens (1ª geração) e os headsets imersivos de realidade misturada em mente. Dessa forma, achamos que é importante continuar disponibilizando esses tutoriais para os desenvolvedores que ainda buscam obter diretrizes para o desenvolvimento visando esses dispositivos. Esses tutoriais não serão atualizados com os conjuntos de ferramentas mais recentes nem com as interações usadas para o HoloLens 2. Eles serão mantidos para continuar funcionando nos dispositivos compatíveis. Uma nova série de tutoriais foi postada para o HoloLens 2.

Os controladores de movimento no mundo da realidade misturada adicionam outro nível de interatividade. Com os controladores de movimento, podemos interagir diretamente com objetos de maneira mais natural, semelhante às nossas interações físicas na vida real, aumentando a imersão e o prazer em sua experiência de aplicativo.

No MR Input 213, exploraremos os eventos de entrada do controlador de movimento criando uma experiência de pintura espacial simples. Com esse aplicativo, os usuários podem pintar em espaço tridimensional com vários tipos de pincéis e cores.

Tópicos abordados neste tutorial

MixedReality213 Topic1 MixedReality213 Topic2 MixedReality213 Topic3
Visualização do controlador Eventos de entrada do controlador Controlador personalizado e interface do usuário
Saiba como renderizar modelos de controlador de movimento no modo de jogo e no runtime do Unity. Entenda diferentes tipos de eventos de botão e seus aplicativos. Saiba como sobrepor elementos da interface do usuário sobre o controlador ou personalizá-lo totalmente.

Suporte a dispositivos

Curso HoloLens Headsets imersivos
Entrada do MR 213: controladores de movimentos ✔️

Antes de começar

Pré-requisitos

Confira a lista de verificação de instalação para headsets imersivos nesta página.

Arquivos de projeto

  • Baixe os arquivos exigidos pelo projeto e extraia os arquivos para a Área de Trabalho.

Observação

Se você quiser examinar o código-fonte antes de baixar, ele estará disponível no GitHub.

Configuração do Unity

Objetivos

  • Otimizar o Unity para desenvolvimento de Windows Mixed Reality
  • Configurar a câmera Realidade Misturada
  • Ambiente de configuração

Instruções

  • Inicie o Unity.

  • Selecione Abrir.

  • Navegue até a Área de Trabalho e localize a pasta master MixedReality213 que você desarquivou anteriormente.

  • Clique em Selecionar Pasta.

  • Depois que o Unity terminar de carregar arquivos de projeto, você poderá ver o editor do Unity.

  • No Unity, selecione Configurações de Build de Arquivo>.

    MR213_BuildSettings

  • Selecione Plataforma Universal do Windows na lista Plataforma e clique no botão Alternar Plataforma.

  • Definir o dispositivo de destino como qualquer dispositivo

  • Defina o Tipo de Build como D3D

  • Definir o SDK como o mais recente instalado

  • Verificar projetos C# do Unity

    • Isso permite modificar arquivos de script no projeto do Visual Studio sem recompilar o projeto do Unity.
  • Clique em Configurações do Player.

  • No painel Inspetor , role para baixo até a parte inferior

  • Em Configurações de XR, marcar realidade virtual com suporte

  • Em SDKs de Realidade Virtual, selecione Windows Mixed Reality

    MR213_XRSettings

  • Feche a janela Configurações de Build .

Estrutura do projeto

Este tutorial usa Realidade Misturada Toolkit – Unity. Você pode encontrar as versões nesta página.

ProjectStructure

Cenas concluídas para sua referência

  • Você encontrará duas cenas concluídas do Unity na pasta Cenas .
    • MixedReality213: Cena concluída com pincel único
    • MixedReality213Avançado: cena concluída para design avançado com vários pincéis

Configuração de nova cena para o tutorial

  • No Unity, clique em Arquivo > Nova Cena

  • Excluir Câmera Principal e Luz Direcional

  • No painel Projeto, pesquise e arraste os seguintes pré-fabricados para o painel Hierarquia :

    • Assets/HoloToolkit/Input/Prefabs/MixedRealityCamera
    • Ativos/AppPrefabs/Ambiente

    Câmera e ambiente

  • Há dois pré-fabricados de câmera no kit de ferramentas Realidade Misturada:

    • MixedRealityCamera.prefab: somente câmera
    • MixedRealityCameraParent.prefab: Camera + Teleportation + Boundary
    • Neste tutorial, usaremos MixedRealityCamera sem recurso de teletransporte. Por isso, adicionamos um pré-fabricado ambiente simples que contém um piso básico para fazer com que o usuário se sinta aterrado.
    • Para saber mais sobre o teletransporte com MixedRealityCameraParent, confira Design avançado – Teletransporte e locomoção

Configuração do Skybox

  • Clique em Configurações de Iluminação da > Janela >

  • Clique no círculo no lado direito do campo Material do Skybox

  • Digite 'cinza' e selecione SkyboxGray (Assets/AppPrefabs/Support/Materials/SkyboxGray.mat)

    Configurando skybox

  • Marque a opção Skybox para poder ver o skybox de gradiente cinza atribuído

    Alternar opção skybox

  • A cena com MixedRealityCamera, Environment e skybox cinza terá esta aparência.

    Ambiente MixedReality213

  • Clique em Arquivo > Salvar Cena como

  • Salve sua cena na pasta Cenas com qualquer nome

Capítulo 1 – Visualização do controlador

Objetivos

  • Saiba como renderizar modelos de controlador de movimento no modo de jogo do Unity e em runtime.

Windows Mixed Reality fornece um modelo de controlador animado para visualização do controlador. Há várias abordagens que você pode adotar para visualização do controlador em seu aplicativo:

  • Padrão – Usando o controlador padrão sem modificação
  • Híbrido – usando o controlador padrão, mas personalizando alguns de seus elementos ou sobrepondo componentes da interface do usuário
  • Substituição – Usando seu próprio modelo 3D personalizado para o controlador

Neste capítulo, aprenderemos sobre os exemplos dessas personalizações de controlador.

Instruções

  • No painel Projeto , digite MotionControllers na caixa de pesquisa . Você também pode encontrá-lo em Ativos/HoloToolkit/Input/Prefabs/.
  • Arraste a pré-fabricado MotionControllers para o painel Hierarquia .
  • Clique na pré-fabricado MotionControllers no painel Hierarquia .

Pré-fabricado MotionControllers

O prefab MotionControllers tem um script MotionControllerVisualizer que fornece os slots para modelos de controlador alternativos. Se você atribuir seus próprios modelos 3D personalizados, como uma mão ou uma espada e marcar "Sempre usar modelo alternativo à esquerda/direita", você os verá em vez do modelo padrão. Usaremos esse slot no Capítulo 4 para substituir o modelo do controlador por um pincel.

MR213_ControllerVisualizer

Instruções

  • No painel Inspetor , clique duas vezes em MotionControllerVisualizer script para ver o código no Visual Studio

Script MotionControllerVisualizer

As classes MotionControllerVisualizer e MotionControllerInfo fornecem os meios para acessar & modificar os modelos de controlador padrão. MotionControllerVisualizer assina o evento InteractionSourceDetected do Unity e cria uma instância automática dos modelos de controlador quando eles são encontrados.

protected override void Awake()
{
    ...
    InteractionManager.InteractionSourceDetected += InteractionManager_InteractionSourceDetected;
    InteractionManager.InteractionSourceLost += InteractionManager_InteractionSourceLost;
    ...
}

Os modelos de controlador são entregues de acordo com a especificação glTF. Esse formato foi criado para fornecer um formato comum, ao mesmo tempo em que aprimora o processo por trás da transmissão e descompactação de ativos 3D. Nesse caso, precisamos recuperar e carregar os modelos de controlador em runtime, pois queremos tornar a experiência do usuário o mais perfeita possível e não é garantido qual versão dos controladores de movimento o usuário pode estar usando. Este curso, por meio do kit de ferramentas Realidade Misturada, usa uma versão do projeto UnityGLTF do Grupo Khronos.

Depois que o controlador for entregue, os scripts poderão usar MotionControllerInfo para encontrar as transformações de elementos de controlador específicos para que possam se posicionar corretamente.

Em um capítulo posterior, aprenderemos a usar esses scripts para anexar elementos de interface do usuário aos controladores.

Em alguns scripts, você encontrará blocos de código com #if ! UNITY_EDITOR ou UNITY_WSA. Esses blocos de código são executados somente no runtime da UWP quando você implanta no Windows. Isso ocorre porque o conjunto de APIs usado pelo editor do Unity e o runtime do aplicativo UWP são diferentes.

  • Salve a cena e clique no botão Reproduzir .

Você poderá ver a cena com controladores de movimento em seu fone de ouvido. Você pode ver animações detalhadas para cliques de botão, movimento de polegar e realce de toque do touchpad.

padrão de visualização MR213_Controller

Capítulo 2 – Anexando elementos de interface do usuário ao controlador

Objetivos

  • Saiba mais sobre os elementos dos controladores de movimento
  • Saiba como anexar objetos a partes específicas dos controladores

Neste capítulo, você aprenderá a adicionar elementos de interface do usuário ao controlador que o usuário pode acessar e manipular facilmente a qualquer momento. Você também aprenderá a adicionar uma interface do usuário do seletor de cores simples usando a entrada touchpad.

Instruções

  • No painel Projeto , pesquise MotionControllerInfo script.
  • No resultado da pesquisa, clique duas vezes em MotionControllerInfo script para ver o código no Visual Studio.

Script MotionControllerInfo

A primeira etapa é escolher a qual elemento do controlador você deseja que a interface do usuário anexe. Esses elementos são definidos em ControllerElementEnum em MotionControllerInfo.cs.

MR213 MotionControllerElements

  • Início
  • Menu
  • Agarrar
  • Manípulo
  • Selecionar
  • Touchpad
  • Pose apontando – esse elemento representa a ponta do controlador apontando para a direção para a frente.

Instruções

  • No painel Projeto , pesquise o script AttachToController .
  • No resultado da pesquisa, clique duas vezes em AnexarToController script para ver o código no Visual Studio.

Script AttachToController

O script AttachToController fornece uma maneira simples de anexar objetos a um elemento e uma entrega do controlador especificados.

Em AttachElementToController(),

  • Verificar a entrega usando MotionControllerInfo.Handedness
  • Obter elemento específico do controlador usando MotionControllerInfo.TryGetElement()
  • Depois de recuperar a transformação do elemento do modelo de controlador, pai do objeto sob ele e definir a posição local do objeto & rotação como zero.
public MotionControllerInfo.ControllerElementEnum Element { get { return element; } }

private void AttachElementToController(MotionControllerInfo newController)
{
     if (!IsAttached && newController.Handedness == handedness)
     {
          if (!newController.TryGetElement(element, out elementTransform))
          {
               Debug.LogError("Unable to find element of type " + element + " under controller " + newController.ControllerParent.name + "; not attaching.");
               return;
          }

          controller = newController;

          SetChildrenActive(true);

          // Parent ourselves under the element and set our offsets
          transform.parent = elementTransform;
          transform.localPosition = positionOffset;
          transform.localEulerAngles = rotationOffset;
          if (setScaleOnAttach)
          {
               transform.localScale = scale;
          }

          // Announce that we're attached
          OnAttachToController();
          IsAttached = true;
     }
}

A maneira mais simples de usar o script AttachToController é herdar dele, como fizemos no caso de ColorPickerWheel. Basta substituir as funções OnAttachToController e OnDetachFromController para executar sua instalação/detalhamento quando o controlador for detectado/desconectado.

Instruções

  • No painel Projeto , digite na caixa de pesquisa ColorPickerWheel. Você também pode encontrá-lo em Ativos/AppPrefabs/.
  • Arraste a pré-fabricado ColorPickerWheel para o painel Hierarquia .
  • Clique na pré-fabricado ColorPickerWheel no painel Hierarquia .
  • No painel Inspetor , clique duas vezes em ColorPickerWheel Script para ver o código no Visual Studio.

Pré-fabricado ColorPickerWheel

Script ColorPickerWheel

Como ColorPickerWheel herda AttachToController, ele mostra Handedness e Element no painel Inspetor . Anexaremos a interface do usuário ao elemento Touchpad no controlador esquerdo.

Script ColorPickerWheel

ColorPickerWheel substitui OnAttachToController e OnDetachFromController para assinar o evento de entrada que será usado no próximo capítulo para seleção de cores com entrada touchpad.

public class ColorPickerWheel : AttachToController, IPointerTarget
{
    protected override void OnAttachToController()
    {
        // Subscribe to input now that we're parented under the controller
        InteractionManager.InteractionSourceUpdated += InteractionSourceUpdated;
    }

    protected override void OnDetachFromController()
    {
        Visible = false;

        // Unsubscribe from input now that we've detached from the controller
        InteractionManager.InteractionSourceUpdated -= InteractionSourceUpdated;
    }
    ...
}
  • Salve a cena e clique no botão Reproduzir .

Método alternativo para anexar objetos aos controladores

Recomendamos que seus scripts herdem de AttachToController e substituam OnAttachToController. No entanto, isso pode nem sempre ser possível. Uma alternativa é usá-la como um componente autônomo. Isso pode ser útil quando você deseja anexar um pré-fabricado existente a um controlador sem refatorar seus scripts. Basta fazer com que sua classe aguarde que IsAttached seja definido como true antes de executar qualquer configuração. A maneira mais simples de fazer isso é usando uma corrotina para "Iniciar".

private IEnumerator Start() {
    AttachToController attach = gameObject.GetComponent<AttachToController>();

    while (!attach.IsAttached) {
        yield return null;
    }

    // Perform setup here
}

Capítulo 3 – Trabalhando com entrada touchpad

Objetivos

  • Saiba como obter eventos de dados de entrada do touchpad
  • Saiba como usar informações de posição do eixo touchpad para sua experiência de aplicativo

Instruções

  • No painel Hierarquia , clique em ColorPickerWheel
  • No painel Inspetor , em Animador, clique duas vezes em ColorPickerWheelController
  • Você poderá ver a guia Animador aberta

Mostrando/ocultando a interface do usuário com o controlador de animação do Unity

Para mostrar e ocultar a interface do usuário ColorPickerWheel com animação, estamos usando o sistema de animação do Unity. Definindo a propriedade Visible do ColorPickerWheel como gatilhos verdadeiros ou falsos Mostrar e Ocultar gatilhos de animação. Os parâmetros Mostrar e Ocultar são definidos no controlador de animação ColorPickerWheelController .

Controlador de Animação do Unity

Instruções

  • No painel Hierarquia , selecione ColorPickerWheel pré-fabricado
  • No painel Inspetor , clique duas vezes em ColorPickerWheel script para ver o código no Visual Studio

Script ColorPickerWheel

ColorPickerWheel assina o evento InteractionSourceUpdated do Unity para escutar eventos do touchpad.

Em InteractionSourceUpdated(), o script primeiro verifica para garantir que:

  • é, na verdade, um evento touchpad (obj.state).touchpadTouched)
  • origina-se do controlador esquerdo (obj.state.source.handedness)

Se ambos forem verdadeiros, a posição do touchpad (obj.state.touchpadPosition) é atribuído a selectorPosition.

private void InteractionSourceUpdated(InteractionSourceUpdatedEventArgs obj)
{
    if (obj.state.source.handedness == handedness && obj.state.touchpadTouched)
    {
        Visible = true;
        selectorPosition = obj.state.touchpadPosition;
    }
}

Em Update(), com base na propriedade visível , ela dispara mostrar e ocultar gatilhos de animação no componente do animador do seletor de cores

if (visible != visibleLastFrame)
{
    if (visible)
    {
        animator.SetTrigger("Show");
    }
    else
    {
        animator.SetTrigger("Hide");
    }
}

Em Update(), selectorPosition é usado para converter um raio no colisor de malha da roda colorida, que retorna uma posição UV. Essa posição pode ser usada para localizar a coordenada de pixel e o valor de cor da textura da roda de cor. Esse valor é acessível a outros scripts por meio da propriedade SelectedColor .

Raycasting da roda do seletor de cores

...
    // Clamp selector position to a radius of 1
    Vector3 localPosition = new Vector3(selectorPosition.x * inputScale, 0.15f, selectorPosition.y * inputScale);
    if (localPosition.magnitude > 1)
    {
        localPosition = localPosition.normalized;
    }
    selectorTransform.localPosition = localPosition;

    // Raycast the wheel mesh and get its UV coordinates
    Vector3 raycastStart = selectorTransform.position + selectorTransform.up * 0.15f;
    RaycastHit hit;
    Debug.DrawLine(raycastStart, raycastStart - (selectorTransform.up * 0.25f));

    if (Physics.Raycast(raycastStart, -selectorTransform.up, out hit, 0.25f, 1 << colorWheelObject.layer, QueryTriggerInteraction.Ignore))
    {
        // Get pixel from the color wheel texture using UV coordinates
        Vector2 uv = hit.textureCoord;
        int pixelX = Mathf.FloorToInt(colorWheelTexture.width * uv.x);
        int pixelY = Mathf.FloorToInt(colorWheelTexture.height * uv.y);
        selectedColor = colorWheelTexture.GetPixel(pixelX, pixelY);
        selectedColor.a = 1f;
    }
    // Set the selector's color and blend it with white to make it visible on top of the wheel
    selectorRenderer.material.color = Color.Lerp (selectedColor, Color.white, 0.5f);
}

Capítulo 4 – Substituindo o modelo de controlador

Objetivos

  • Saiba como substituir o modelo do controlador por um modelo 3D personalizado.

MR213_BrushToolOverride

Instruções

  • Clique em MotionControllers no painel Hierarquia .
  • Clique no círculo no lado direito do campo Controlador Direito Alternativo .
  • Digite 'BrushController' e selecione o pré-fabricado no resultado. Você pode encontrá-lo em Ativos/AppPrefabs/BrushController.
  • Verificar Sempre Usar Modelo Alternativo à Direita

MR213_BrushToolOverrideSlot

O pré-fabricado BrushController não precisa ser incluído no painel Hierarquia . No entanto, para marcar seus componentes filho:

  • No painel Projeto , digite BrushController e arraste o pré-fabricado BrushController para o painel Hierarquia .

MR213_BrushTool_Prefab2

Você encontrará o componente Dica no BrushController. Usaremos sua transformação para iniciar/parar linhas de desenho.

  • Exclua o BrushController do painel Hierarquia .
  • Salve a cena e clique no botão Reproduzir . Você poderá ver que o modelo de pincel substituiu o controlador de movimento à direita.

Capítulo 5 – Pintando com a entrada Selecionar

Objetivos

  • Saiba como usar o evento do botão Selecionar para iniciar e parar um desenho de linha

Instruções

  • Pesquise o pré-fabricado BrushController no painel Projeto .
  • No painel Inspetor , clique duas vezes em Script BrushController para ver o código no Visual Studio

Script BrushController

BrushController assina os eventos InteractionSourcePressed e InteractionSourceReleased do InteractionManager. Quando o evento InteractionSourcePressed é disparado, a propriedade Draw do pincel é definida como true; quando o evento InteractionSourceReleased é disparado, a propriedade Draw do pincel é definida como false.

private void InteractionSourcePressed(InteractionSourcePressedEventArgs obj)
{
    if (obj.state.source.handedness == InteractionSourceHandedness.Right && obj.pressType == InteractionSourcePressType.Select)
    {
        Draw = true;
    }
}

private void InteractionSourceReleased(InteractionSourceReleasedEventArgs obj)
{
    if (obj.state.source.handedness == InteractionSourceHandedness.Right && obj.pressType == InteractionSourcePressType.Select)
    {
        Draw = false;
    }
}

Embora Draw seja definido como true, o pincel gerará pontos em um LineRenderer do Unity instanciado. Uma referência a esse pré-fabricado é mantida no campo Prefab stroke do pincel.

private IEnumerator DrawOverTime()
{
    // Get the position of the tip
    Vector3 lastPointPosition = tip.position;

    ...

    // Create a new brush stroke
    GameObject newStroke = Instantiate(strokePrefab);
    LineRenderer line = newStroke.GetComponent<LineRenderer>();
    newStroke.transform.position = startPosition;
    line.SetPosition(0, tip.position);
    float initialWidth = line.widthMultiplier;

    // Generate points in an instantiated Unity LineRenderer
    while (draw)
    {
        // Move the last point to the draw point position
        line.SetPosition(line.positionCount - 1, tip.position);
        line.material.color = colorPicker.SelectedColor;
        brushRenderer.material.color = colorPicker.SelectedColor;
        lastPointAddedTime = Time.unscaledTime;
        // Adjust the width between 1x and 2x width based on strength of trigger pull
        line.widthMultiplier = Mathf.Lerp(initialWidth, initialWidth * 2, width);

        if (Vector3.Distance(lastPointPosition, tip.position) > minPositionDelta || Time.unscaledTime > lastPointAddedTime + maxTimeDelta)
        {
            // Spawn a new point
            lastPointAddedTime = Time.unscaledTime;
            lastPointPosition = tip.position;
            line.positionCount += 1;
            line.SetPosition(line.positionCount - 1, lastPointPosition);
        }
        yield return null;
    }
}

Para usar a cor selecionada no momento na interface do usuário do seletor de cores, BrushController precisa ter uma referência ao objeto ColorPickerWheel . Como o pré-fabricado BrushController é instanciado em runtime como um controlador de substituição, todas as referências a objetos na cena precisarão ser definidas em runtime. Nesse caso, usamos GameObject.FindObjectOfType para localizar o ColorPickerWheel:

private void OnEnable()
{
    // Locate the ColorPickerWheel
    colorPicker = FindObjectOfType<ColorPickerWheel>();

    // Assign currently selected color to the brush’s material color
    brushRenderer.material.color = colorPicker.SelectedColor;
    ...
}
  • Salve a cena e clique no botão Reproduzir . Você poderá desenhar as linhas e pintar usando o botão selecionar no controlador direito.

Capítulo 6 – Geração de objetos com a opção Selecionar entrada

Objetivos

  • Saiba como usar eventos de entrada do botão Selecionar e Entender
  • Saiba como instanciar objetos

Instruções

  • No painel Projeto , digite ObjectSpawner na caixa de pesquisa. Você também pode encontrá-lo em Ativos/AppPrefabs/

  • Arraste o pré-fabricado ObjectSpawner para o painel Hierarquia .

  • Clique em ObjetoPawner no painel Hierarquia .

  • ObjectSpawner tem um campo chamado Fonte de Cores.

  • No painel Hierarquia , arraste a referência ColorPickerWheel para esse campo.

    Inspetor do Gerador de Objetos

  • Clique no pré-fabricado ObjectSpawner no painel Hierarquia .

  • No painel Inspetor , clique duas vezes em ObjectSpawner Script para ver o código no Visual Studio.

Script ObjectSpawner

O ObjectSpawner cria uma instância de cópias de uma malha primitiva (cubo, esfera, cilindro) no espaço. Quando um InteractionSourcePressed é detectado, ele verifica a entrega e se é um evento InteractionSourcePressType.Grasp ou InteractionSourcePressType.Select .

Para um evento Grasp , ele incrementa o índice do tipo de malha atual (esfera, cubo, cilindro)

private void InteractionSourcePressed(InteractionSourcePressedEventArgs obj)
{
    // Check handedness, see if it is left controller
    if (obj.state.source.handedness == handedness)
    {
        switch (obj.pressType)
        {
            // If it is Select button event, spawn object
            case InteractionSourcePressType.Select:
                if (state == StateEnum.Idle)
                {
                    // We've pressed the grasp - enter spawning state
                    state = StateEnum.Spawning;
                    SpawnObject();
                }
                break;

            // If it is Grasp button event
            case InteractionSourcePressType.Grasp:

                // Increment the index of current mesh type (sphere, cube, cylinder)
                meshIndex++;
                if (meshIndex >= NumAvailableMeshes)
                {
                    meshIndex = 0;
                }
                break;

            default:
                break;
        }
    }
}

Para um evento Select , em SpawnObject(), um novo objeto é instanciado, não pai e liberado no mundo.

private void SpawnObject()
{
    // Instantiate the spawned object
    GameObject newObject = Instantiate(displayObject.gameObject, spawnParent);
    // Detach the newly spawned object
    newObject.transform.parent = null;
    // Reset the scale transform to 1
    scaleParent.localScale = Vector3.one;
    // Set its material color so its material gets instantiated
    newObject.GetComponent<Renderer>().material.color = colorSource.SelectedColor;
}

O ObjectSpawner usa ColorPickerWheel para definir a cor do material do objeto de exibição. Os objetos gerados recebem uma instância desse material para que eles mantenham sua cor.

  • Salve a cena e clique no botão Reproduzir .

Você poderá alterar os objetos com o botão Agarrar e gerar objetos com o botão Selecionar.

Criar e implantar o aplicativo no Portal do Realidade Misturada

  • No Unity, selecione Configurações de Build de Arquivo>.
  • Clique em Adicionar Cenas Abertas para adicionar a cena atual ao Scenes In Build.
  • Clique em Compilar.
  • Crie uma nova pasta chamada "App".
  • Clique com um único clique na pasta Aplicativo .
  • Clique em Selecionar Pasta.
  • Quando o Unity for concluído, uma janela Explorador de Arquivos será exibida.
  • Abra a pasta Aplicativo .
  • Clique duas vezes no arquivo Solução YourSceneName.sln do Visual Studio.
  • Usando a barra de ferramentas superior no Visual Studio, altere o destino de Depurar para Versão e de ARM para X64.
  • Clique na seta suspensa ao lado do botão Dispositivo e selecione Computador Local.
  • Clique em Depurar –> Iniciar Sem depuração no menu ou pressione Ctrl + F5.

Agora, o aplicativo foi criado e instalado no Portal do Realidade Misturada. Você pode iniciá-lo novamente por meio do menu Iniciar no Portal Realidade Misturada.

Design avançado – Ferramentas de pincel com layout radial

MixedReality213 Main

Neste capítulo, você aprenderá a substituir o modelo de controlador de movimento padrão por uma coleção de ferramentas de pincel personalizada. Para sua referência, você pode encontrar a cena concluída MixedReality213Avançada na pasta Cenas .

Instruções

  • No painel Projeto , digite BrushSelector na caixa de pesquisa . Você também pode encontrá-lo em Ativos/AppPrefabs/

  • Arraste o pré-fabricado BrushSelector para o painel Hierarquia .

  • Para a organização, crie um GameObject vazio chamado Brushes

  • Arraste os pré-fabricados a seguir do painel Projeto para Pincéis

    • Assets/AppPrefabs/BrushFat
    • Assets/AppPrefabs/BrushThin
    • Assets/AppPrefabs/Eraser
    • Assets/AppPrefabs/MarkerFat
    • Assets/AppPrefabs/MarkerThin
    • Assets/AppPrefabs/Pencil

    Pincéis

  • Clique em MotionControllers pré-fabricado no painel Hierarquia .

  • No painel Inspetor , desmarque Sempre Usar Modelo Alternativo à Direita no Visualizador do Controlador de Movimento

  • No painel Hierarquia , clique em BrushSelector

  • BrushSelector tem um campo chamado ColorPicker

  • No painel Hierarquia , arraste o ColorPickerWheel para o campo ColorPicker no painel Inspetor .

    Atribuir ColorPickerWheel ao Seletor de Pincel

  • No painel Hierarquia , em Pré-fabricado BrushSelector , selecione o objeto Menu .

  • No painel Inspetor , no componente LineObjectCollection , abra a lista suspensa Matriz de objetos . Você verá seis slots vazios.

  • No painel Hierarquia , arraste cada um dos pré-fabricados com pai sob o GameObject Brushes para esses slots em qualquer ordem. (Verifique se você está arrastando os pré-fabricados da cena, não os pré-fabricados na pasta do projeto.)

Seletor de pincel

Pré-fabricado BrushSelector

Como BrushSelector herda AttachToController, ele mostra as opções Handedness e Element no painel Inspetor . Selecionamos Posição Direita e Apontando para anexar ferramentas de pincel ao controlador de mão direita com direção para a frente.

O BrushSelector usa dois utilitários:

  • Elipse: usada para gerar pontos no espaço ao longo de uma forma de elipse.
  • LineObjectCollection: distribui objetos usando os pontos gerados por qualquer classe Line (por exemplo, Ellipse). Isso é o que usaremos para colocar nossos pincéis ao longo da forma de Elipse.

Quando combinados, esses utilitários podem ser usados para criar um menu radial.

Script LineObjectCollection

LineObjectCollection tem controles para o tamanho, posição e rotação de objetos distribuídos ao longo de sua linha. Isso é útil para criar menus radiais como o seletor de pincel. Para criar a aparência de pincéis que são escalados do nada à medida que se aproximam da posição selecionada central, a curva ObjectScale atinge o pico no centro e toca para fora nas bordas.

Script BrushSelector

No caso do BrushSelector, escolhemos usar a animação de procedimento. Primeiro, os modelos de pincel são distribuídos em uma elipse pelo script LineObjectCollection . Em seguida, cada pincel é responsável por manter sua posição na mão do usuário com base em seu valor DisplayMode , que é alterado com base na seleção. Escolhemos uma abordagem de procedimento devido à alta probabilidade de transições de posição do pincel serem interrompidas à medida que o usuário seleciona pincéis. Animações mecanim podem lidar com interrupções normalmente, mas tende a ser mais complicada do que uma simples operação lerp.

BrushSelector usa uma combinação de ambos. Quando a entrada do touchpad é detectada, as opções de pincel ficam visíveis e escalam verticalmente ao longo do menu radial. Após um período de tempo limite (que indica que o usuário fez uma seleção), as opções de pincel reduzem verticalmente novamente, deixando apenas o pincel selecionado.

Visualizando a entrada do touchpad

Mesmo nos casos em que o modelo do controlador foi completamente substituído, pode ser útil mostrar a entrada nas entradas do modelo original. Isso ajuda a fundamentar as ações do usuário na realidade. Para o BrushSelector , escolhemos tornar o touchpad brevemente visível quando a entrada é recebida. Isso foi feito recuperando o elemento Touchpad do controlador, substituindo seu material por um material personalizado e aplicando um gradiente à cor desse material com base na última vez em que a entrada do touchpad foi recebida.

protected override void OnAttachToController()
{
    // Turn off the default controller's renderers
    controller.SetRenderersVisible(false);

    // Get the touchpad and assign our custom material to it
    Transform touchpad;
    if (controller.TryGetElement(MotionControllerInfo.ControllerElementEnum.Touchpad, out touchpad))
    {
        touchpadRenderer = touchpad.GetComponentInChildren<MeshRenderer>();
        originalTouchpadMaterial = touchpadRenderer.material;
        touchpadRenderer.material = touchpadMaterial;
        touchpadRenderer.enabled = true;
    }

    // Subscribe to input now that we're parented under the controller
    InteractionManager.InteractionSourceUpdated += InteractionSourceUpdated;
}

private void Update()
{
    ...
    // Update our touchpad material
    Color glowColor = touchpadColor.Evaluate((Time.unscaledTime - touchpadTouchTime) / touchpadGlowLossTime);
    touchpadMaterial.SetColor("_EmissionColor", glowColor);
    touchpadMaterial.SetColor("_Color", glowColor);
    ...
}

Seleção de ferramenta de pincel com entrada touchpad

Quando o seletor de pincel detecta a entrada pressionada do touchpad, ele verifica a posição da entrada para determinar se ela estava à esquerda ou à direita.

Espessura do traço com selectPressedAmount

Em vez do evento InteractionSourcePressType.Select no InteractionSourcePressed(), você pode obter o valor analógico do valor pressionado por meio de selectPressedAmount. Esse valor pode ser recuperado em InteractionSourceUpdated().

private void InteractionSourceUpdated(InteractionSourceUpdatedEventArgs obj)
{
    if (obj.state.source.handedness == handedness)
    {
        if (obj.state.touchpadPressed)
        {
            // Check which side we clicked
            if (obj.state.touchpadPosition.x < 0)
            {
                currentAction = SwipeEnum.Left;
            }
            else
            {
                currentAction = SwipeEnum.Right;
            }

            // Ping the touchpad material so it gets bright
            touchpadTouchTime = Time.unscaledTime;
        }

        if (activeBrush != null)
        {
            // If the pressed amount is greater than our threshold, draw
            if (obj.state.selectPressedAmount >= selectPressedDrawThreshold)
            {
                activeBrush.Draw = true;
                activeBrush.Width = ProcessSelectPressedAmount(obj.state.selectPressedAmount);
            }
            else
            {
                // Otherwise, stop drawing
                activeBrush.Draw = false;
                selectPressedSmooth = 0f;
            }
        }
    }
}

Script de borracha

Eraser é um tipo especial de pincel que substitui a função DrawOverTime() do Brush base. Embora Draw seja true, a borracha verifica se sua ponta se cruza com quaisquer traços de pincel existentes. Se isso acontecer, eles serão adicionados a uma fila para serem reduzidos e excluídos.

Design avançado – Teletransporte e locomoção

Se você quiser permitir que o usuário se mova pela cena com teletransporte usando o thumbstick, use MixedRealityCameraParent em vez de MixedRealityCamera. Você também precisa adicionar InputManager e DefaultCursor. Como MixedRealityCameraParent já inclui MotionControllers e Boundary como componentes filho, você deve remover motioncontrollers e pré-fabricados de ambiente existentes.

Instruções

  • No painel Hierarquia , exclua MixedRealityCamera, Environment e MotionControllers

  • No painel Projeto, pesquise e arraste os seguintes pré-fabricados para o painel Hierarquia :

    • Assets/AppPrefabs/Input/Prefabs/MixedRealityCameraParent
    • Assets/AppPrefabs/Input/Prefabs/InputManager
    • Assets/AppPrefabs/Input/Prefabs/Cursor/DefaultCursor

    Realidade Misturada Pai da Câmera

  • No painel Hierarquia , clique em Gerenciador de Entradas

  • No painel Inspetor, role para baixo até a seção Seletor de Ponteiro Único Simples

  • No painel Hierarquia, arraste DefaultCursor para o campo Cursor

    Atribuindo DefaultCursor

  • Salve a cena e clique no botão Reproduzir . Você poderá usar o botão para girar para a esquerda/direita ou teletransporte.

Fim

E esse é o fim deste tutorial! Você aprendeu a:

  • Como trabalhar com modelos de controlador de movimento no modo de jogo e no runtime do Unity.
  • Como usar diferentes tipos de eventos de botão e seus aplicativos.
  • Como sobrepor elementos da interface do usuário sobre o controlador ou personalizá-lo totalmente.

Agora você está pronto para começar a criar sua própria experiência imersiva com controladores de movimento!

Cenas concluídas

  • No painel Projeto do Unity, clique na pasta Cenas .
  • Você encontrará duas cenas do Unity MixedReality213 e MixedReality213Avançadas.
    • MixedReality213: Cena concluída com pincel único
    • MixedReality213Avançado: cena concluída com vários pincels com o exemplo de quantidade de pressionamento do botão de seleção

Confira também