Partilhar via


Entrada MR 213: Comandos de movimento

Nota

Os tutoriais Mixed Reality Academy foram concebidos com o HoloLens (1.ª geração) e Mixed Reality Headsets Envolventes em mente. Como tal, consideramos importante deixar estes tutoriais em vigor para os programadores que ainda estão à procura de orientação no desenvolvimento desses dispositivos. Estes tutoriais não serão atualizados com os conjuntos de ferramentas ou interações mais recentes que estão a ser utilizados para HoloLens 2. Serão mantidas para continuarem a trabalhar nos dispositivos suportados. Foi publicada uma nova série de tutoriais para HoloLens 2.

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

No MR Input 213, vamos explorar os eventos de entrada do controlador de movimento criando uma experiência de pintura espacial simples. Com esta aplicação, os utilizadores podem pintar num espaço tridimensional com vários tipos de pincéis e cores.

Tópicos abordados neste tutorial

Tópico MixedReality21311 MixedReality213 Topic2 MixedReality213 Topic3
Visualização do controlador Eventos de entrada do controlador Controlador personalizado e IU
Saiba como compor modelos de comando de movimento no modo de jogo e runtime do Unity. Compreenda os diferentes tipos de eventos de botões e as respetivas aplicações. Saiba como sobrepor elementos da IU na parte superior do controlador ou personalizá-los completamente.

Suporte de dispositivos

Curso HoloLens Headsets envolventes
Entrada MR 213: Comandos de movimento ✔️

Antes de começar

Pré-requisitos

Veja a lista de verificação de instalação para auscultadores envolventes nesta página.

Ficheiros de projeto

Nota

Se quiser ver o código fonte antes de transferir, este estará disponível no GitHub.

Configuração do Unity

Objetivos

  • Otimizar o Unity para desenvolvimento de Windows Mixed Reality
  • Configurar a Câmara Mixed Reality
  • Ambiente de configuração

Instruções

  • Inicie o Unity.

  • Selecione Abrir.

  • Navegue para o seu Ambiente de Trabalho e localize a pasta mestra MixedReality213 que ansiou anteriormente.

  • Clique em Selecionar Pasta.

  • Assim que o Unity concluir o carregamento de ficheiros do projeto, poderá ver o editor do Unity.

  • No Unity, selecione Definições de Compilação de Ficheiros>.

    MR213_BuildSettings

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

  • Definir Dispositivo de Destino como Qualquer dispositivo

  • Definir o Tipo de Compilação como D3D

  • Definir o SDK como Instalado Mais Recente

  • Verificar Projetos C# do Unity

    • Isto permite-lhe modificar ficheiros de script no projeto do Visual Studio sem reconstruir o projeto do Unity.
  • Clique em Definições do Leitor.

  • No painel Inspetor , desloque-se para baixo até à parte inferior

  • Nas Definições XR, verifique a Realidade Virtual Suportada

  • Em SDKs de Realidade Virtual, selecione Windows Mixed Reality

    MR213_XRSettings

  • Feche a janela Definições de Compilação .

Estrutura do projeto

Este tutorial utiliza Mixed Reality Toolkit – Unity. Pode encontrar as versões nesta página.

ProjectStructure

Cenas concluídas para referência

  • Encontrará duas cenas do Unity concluídas na pasta Cenas .
    • MixedReality213: Cena concluída com pincel único
    • MixedReality213Advanced: cenário concluído para design avançado com vários pincéis

Configuração de Nova Cena para o tutorial

  • No Unity, clique em Arquivar > Nova Cena

  • Eliminar Câmara Principal e Luz Direcional

  • No painel Projeto, pesquise e arraste as seguintes prefabs para o painel Hierarquia :

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

    Câmara e Ambiente

  • Existem duas pré-tarefas de câmara no Mixed Reality Toolkit:

    • MixedRealityCamera.prefab: Apenas câmara
    • MixedRealityCameraParent.prefab: Câmara + Teletransporte + Limite
    • Neste tutorial, vamos utilizar a funcionalidade MixedRealityCamera sem teletransporte. Por este motivo, adicionámos uma prefab ambiente simples que contém um piso básico para fazer com que o utilizador se sinta de castigo.
    • Para saber mais sobre a teletransporte com MixedRealityCameraParent, veja Advanced design - Teleportation and locomotion (Design avançado – Teleportação e locomoção)

Configuração do Skybox

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

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

  • Escreva "cinzento" e selecione SkyboxGray (Assets/AppPrefabs/Support/Materials/SkyboxGray.mat)

    Definir skybox

  • Selecione a opção Skybox para ver o skybox de gradação cinzento atribuído

    Ativar/desativar o skybox

  • A cena com MixedRealityCamera, Ambiente e skybox cinzento terá este aspeto.

    Ambiente MixedReality213

  • Clique em Cena guardar ficheiro > como

  • Guardar a cena na pasta Cenas com qualquer nome

Capítulo 1 - Visualização do controlador

Objetivos

  • Saiba como compor modelos de comando de movimento no modo de jogo do Unity e no runtime.

Windows Mixed Reality fornece um modelo de controlador animado para a visualização do controlador. Existem várias abordagens que pode adotar para a visualização do controlador na sua aplicação:

  • Predefinição – utilizar o controlador predefinido sem modificação
  • Híbrido – utilizar o controlador predefinido, mas personalizar alguns dos respetivos elementos ou sobrepor componentes da IU
  • Substituição – utilizar o seu próprio modelo 3D personalizado para o controlador

Neste capítulo, vamos saber mais sobre os exemplos destas personalizações do controlador.

Instruções

  • No painel Projeto , escreva MotionControllers na caixa de pesquisa . Também pode encontrá-lo em Assets/HoloToolkit/Input/Prefabs/.
  • Arraste a prefab MotionControllers para o painel Hierarquia .
  • Clique na prefab MotionControllers no painel Hierarquia .

Pré-criação de MotionControllers

O motionControllers prefab tem um script MotionControllerVisualizer que fornece os blocos para modelos de controlador alternativos. Se atribuir os seus próprios modelos 3D personalizados, como uma mão ou uma espada, e verificar "Utilizar Sempre Modelo Alternativo à Esquerda/Direita", irá vê-los em vez do modelo predefinido. Vamos utilizar este bloco no Capítulo 4 para substituir o modelo do controlador por um pincel.

MR213_ControllerVisualizer

Instruções

  • No painel Inspetor , faça duplo clique em MotionControllerVisualizer script para ver o código no Visual Studio

Script MotionControllerVisualizer

As classes MotionControllerVisualizer e MotionControllerInfo fornecem os meios para aceder & modificar os modelos de controlador predefinidos. MotionControllerVisualizer subscreve o evento InteractionSourceDetected do Unity e instancia automaticamente os modelos de controlador quando são encontrados.

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

Os modelos de controlador são fornecidos de acordo com a especificação glTF. Este formato foi criado para fornecer um formato comum, ao mesmo tempo que melhora o processo subjacente à transmissão e desempacotamento de recursos 3D. Neste caso, precisamos de obter e carregar os modelos de controlador no runtime, pois queremos tornar a experiência do utilizador o mais perfeita possível e não é garantido qual a versão dos controladores de movimento que o utilizador poderá estar a utilizar. Este curso, através do Mixed Reality Toolkit, utiliza uma versão do projeto UnityGLTF do Grupo Khronos.

Depois de o controlador ser entregue, os scripts podem utilizar MotionControllerInfo para encontrar as transformações para elementos específicos do controlador para que possam posicionar-se corretamente.

Num capítulo posterior, vamos aprender a utilizar estes scripts para anexar elementos de IU aos controladores.

Em alguns scripts, encontrará blocos de código com #if ! UNITY_EDITOR ou UNITY_WSA. Estes blocos de código são executados apenas no runtime UWP quando implementa no Windows. Isto deve-se ao facto de o conjunto de APIs utilizado pelo editor do Unity e o runtime da aplicação UWP serem diferentes.

  • Guarde a cena e clique no botão reproduzir .

Poderá ver a cena com comandos de movimento nos auscultadores. Pode ver animações detalhadas para cliques de botões, movimento de manípulo e realce do toque do touchpad.

MR213_Controller Visualização Predefinida

Capítulo 2 – Anexar elementos da IU ao controlador

Objetivos

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

Neste capítulo, irá aprender a adicionar elementos de interface de utilizador ao controlador aos quais o utilizador pode aceder e manipular facilmente em qualquer altura. Também irá aprender a adicionar uma IU do seletor de cores simples com a entrada do touchpad.

Instruções

  • No painel Projeto , procure script MotionControllerInfo .
  • No resultado da pesquisa, faça duplo clique no script MotionControllerInfo para ver o código no Visual Studio.

Script MotionControllerInfo

O primeiro passo é escolher o elemento do controlador ao qual pretende anexar a IU. Estes elementos são definidos em ControllerElementEnum em MotionControllerInfo.cs.

MR213 MotionControllerElements

  • Base
  • Menu
  • Compreender
  • Manípulo
  • Selecionar
  • Touchpad
  • Pose a apontar – este elemento representa a ponta do controlador que aponta para a direção para a frente.

Instruções

  • No painel Projeto , procure script AttachToController .
  • No resultado da pesquisa, faça duplo clique no script AttachToController para ver o código no Visual Studio.

Script AttachToController

O script AttachToController fornece uma forma simples de anexar quaisquer objetos a um elemento e entrega de controladores especificados.

Em AttachElementToController(),

  • Verificar a entrega com MotionControllerInfo.Handedness
  • Obter um elemento específico do controlador com MotionControllerInfo.TryGetElement()
  • Depois de obter a transformação do elemento do modelo de controlador, coloque o objeto principal por baixo do mesmo e defina 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 forma mais simples de utilizar o script AttachToController é herdar do mesmo, como fizemos no caso do ColorPickerWheel. Basta substituir as funções OnAttachToController e OnDetachFromController para efetuar a configuração/divisão quando o controlador for detetado/desligado.

Instruções

  • No painel Projeto , escreva na caixa de pesquisa ColorPickerWheel. Também pode encontrá-lo em Ativos/AppPrefabs/.
  • Arraste ColorPickerWheel prefab para o painel Hierarquia .
  • Clique na prefab ColorPickerWheel no painel Hierarquia .
  • No painel Inspetor , faça duplo clique em ColorPickerWheel Script para ver o código no Visual Studio.

Pré-fabricado ColorPickerWheel

Script ColorPickerWheel

Uma vez que ColorPickerWheel herda AttachToController, mostra Handedness e Element no painel Inspetor . Vamos anexar a IU ao elemento Touchpad no controlador esquerdo.

Script ColorPickerWheel

ColorPickerWheel substitui OnAttachToController e OnDetachFromController para subscrever o evento de entrada que será utilizado no próximo capítulo para seleção de cores com entrada do 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;
    }
    ...
}
  • Guarde a cena e clique no botão reproduzir .

Método alternativo para anexar objetos aos controladores

Recomendamos que os scripts herdem de AttachToController e substituam OnAttachToController. No entanto, isto pode nem sempre ser possível. Uma alternativa é utilizá-lo como um componente autónomo. Isto pode ser útil quando quer anexar uma pré-base existente a um controlador sem refatorizar os scripts. Basta que a sua turma aguarde que IsAttached seja definido como verdadeiro antes de efetuar qualquer configuração. A forma mais simples de o fazer é utilizando um coroutine para "Iniciar".

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

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

    // Perform setup here
}

Capítulo 3 - Trabalhar com a entrada do touchpad

Objetivos

  • Saiba como obter eventos de dados de entrada do touchpad
  • Saiba como utilizar as informações de posição do eixo do touchpad para a sua experiência de aplicação

Instruções

  • No painel Hierarquia , clique em ColorPickerWheel
  • No painel Inspetor , em Animator, faça duplo clique em ColorPickerWheelController
  • Poderá ver o separador Animator aberto

Mostrar/ocultar a IU com o controlador de Animação do Unity

Para mostrar e ocultar a IU colorPickerWheel com animação, estamos a utilizar o sistema de animação do Unity. Definir a propriedade Visível de ColorPickerWheel como acionadores verdadeiros ou falsos Mostrar e Ocultar acionadores 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 prefab
  • No painel Inspetor , faça duplo clique em ColorPickerWheel script para ver o código no Visual Studio

Script ColorPickerWheel

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

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

  • é, na verdade, um evento do touchpad (obj.state.touchpadTouched)
  • tem origem no controlador esquerdo (obj.state.source.mão de mão)

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 , aciona acionadores Mostrar e Ocultar animações no componente de animador do selecionador de cores

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

Em Update(), selectorPosition é utilizado para lançar um raio no colisor de malha da roda de cores, que devolve uma posição UV. Esta posição pode então ser utilizada para encontrar a coordenada de píxel e o valor de cor da textura da roda de cor. Este valor é acessível a outros scripts através da propriedade SelectedColor .

Raycasting de Roda do Selecionador 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 – Substituir o modelo de controlador

Objetivos

  • Saiba como substituir o modelo de 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 Comando Alternativo à Direita .
  • Escreva "BrushController" e selecione a pré-fab no resultado. Pode encontrá-la em Assets/AppPrefabs/BrushController.
  • Verificar utilizar sempre o modelo alternativo à direita

MR213_BrushToolOverrideSlot

A prefab BrushController não tem de ser incluída no painel Hierarquia . No entanto, para dar saída dos componentes subordinados:

  • No painel Projeto , escreva BrushController e arraste BrushController prefab para o painel Hierarquia .

MR213_BrushTool_Prefab2

Encontrará o componente Sugestão em BrushController. Vamos utilizar a sua transformação para iniciar/parar linhas de desenho.

  • Elimine o BrushController do painel Hierarquia .
  • Guarde a cena e clique no botão reproduzir . Poderá ver que o modelo do pincel substituiu o comando de movimento do lado direito.

Capítulo 5 - Pintar com Selecionar entrada

Objetivos

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

Instruções

  • Pesquise brushController prefab no painel Projeto .
  • No painel Inspetor , faça duplo clique em BrushController Script para ver o código no Visual Studio

Script BrushController

BrushController subscreve os eventos InteractionSourcePressed e InteractionSourceReleased do InteractionManager. Quando o evento InteractionSourcePressed é acionado, a propriedade Desenhar do pincel é definida como verdadeira; quando o evento InteractionSourceReleased é acionado , a propriedade Desenhar do pincel é definida como falsa.

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;
    }
}

Enquanto Desenhar está definido como verdadeiro, o pincel irá gerar pontos num LineRenderer do Unity instanciado. Uma referência a esta pré-fab é mantida no campo Prefab de Traço 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 utilizar a cor atualmente selecionada da IU da roda do selecionador de cores, BrushController tem de ter uma referência ao objeto ColorPickerWheel . Uma vez que a prefab BrushController é instanciada no runtime como um controlador de substituição, todas as referências aos objetos na cena terão de ser definidas no runtime. Neste caso, utilizamos 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;
    ...
}
  • Guarde a cena e clique no botão reproduzir . Poderá desenhar as linhas e pintar com o botão selecionar no comando direito.

Capítulo 6 – Desova de objetos com Selecionar entrada

Objetivos

  • Saiba como utilizar eventos de entrada do botão Selecionar e Agarrar
  • Saiba como instanciar objetos

Instruções

  • No painel Projeto , escreva ObjectSpawner na caixa de pesquisa. Também pode encontrá-lo em Ativos/AppPrefabs/

  • Arraste a prefab ObjectSpawner para o painel Hierarquia .

  • Clique em ObjectSpawner no painel Hierarquia .

  • ObjectSpawner tem um campo denominado Origem da Cor.

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

    Inspetor de Desova de Objetos

  • Clique na prefab ObjectSpawner no painel Hierarquia .

  • No painel Inspetor , faça duplo clique em ObjectSpawner Script para ver o código no Visual Studio.

Script ObjectSpawner

O ObjectSpawner instancia cópias de uma malha primitiva (cubo, esfera, cilindro) para o espaço. Quando é detetada uma InteractionSourcePressed , verifica a entrega e se é um evento InteractionSourcePressType.Grasp ou InteractionSourcePressType.Select .

Para um evento do Grasp , 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 parentado e lançado 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 utiliza o ColorPickerWheel para definir a cor do material do objeto de apresentação. Os objetos gerados recebem uma instância deste material para que estes mantenham a cor.

  • Guarde a cena e clique no botão reproduzir .

Poderá alterar os objetos com o botão Agarrar e gerar objetos com o botão Selecionar.

Criar e implementar aplicações no Portal do Mixed Reality

  • No Unity, selecione Definições de Compilação de Ficheiros>.
  • Clique em Adicionar Cenas Abertas para adicionar a cena atual às Cenas na Compilação.
  • Clique em Compilar.
  • Crie uma Nova Pasta com o nome "Aplicação".
  • Clique apenas na pasta Aplicação .
  • Clique em Selecionar Pasta.
  • Quando o Unity estiver concluído, será apresentada uma janela de Explorador de Ficheiros.
  • Abra a pasta Aplicação .
  • Faça duplo clique no ficheiro YourSceneName.sln Visual Studio Solution.
  • Com a barra de ferramentas superior no Visual Studio, altere o destino de Depuração para Versão e de ARM para X64.
  • Clique na seta pendente junto ao botão Dispositivo e selecione Máquina Local.
  • Clique em Depurar –> Iniciar Sem depuração no menu ou prima Ctrl + F5.

Agora, a aplicação foi criada e instalada no Portal do Mixed Reality. Pode iniciá-la novamente através do menu Iniciar no Portal do Mixed Reality.

Design avançado - Ferramentas de pincel com esquema radial

MixedReality213 Main

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

Instruções

  • No painel Projeto , escreva BrushSelector na caixa de pesquisa . Também pode encontrá-lo em Ativos/AppPrefabs/

  • Arraste a pré-base BrushSelector para o painel Hierarquia .

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

  • Arraste as seguintes pré-tarefas do painel Project para Brushes

    • Recursos/AppPrefabs/BrushFat
    • Recursos/AppPrefabs/BrushThin
    • Recursos/AppPrefabs/Borracha
    • Assets/AppPrefabs/MarkerFat
    • Recursos/AppPrefabs/MarkerThin
    • Recursos/AppPrefabs/Pencil

    Pincéis

  • Clique em MotionControllers prefab no painel Hierarquia .

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

  • No painel Hierarquia , clique em PincelEletor

  • BrushSelector tem um campo chamado ColorPicker

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

    Atribuir ColorPickerWheel ao Seletor de Pincel

  • No painel Hierarquia , em BrushSelector prefab, selecione o objeto Menu .

  • No painel Inspetor , no componente LineObjectCollection , abra a lista pendente Matriz de objetos . Verá 6 blocos vazios.

  • No painel Hierarquia , arraste cada um dos pré-fabricados parentados por baixo de Brushes GameObject para estes blocos por qualquer ordem. (Certifique-se de que está a arrastar os pré-fabricados do local, não os pré-fabricados na pasta do projeto.)

Seletor de Pincel

BrushSelector prefab

Uma vez que BrushSelector herda AttachToController, mostra as opções Handedness e Element no painel Inspetor . Selecionámos Right e Pointing Pose para anexar as ferramentas de pincel ao comando do lado direito com a direção para a frente.

O BrushSelector utiliza dois utilitários:

  • Reticências: utilizada para gerar pontos no espaço ao longo de uma forma de reticências.
  • LineObjectCollection: distribui objetos com os pontos gerados por qualquer classe de Linha (por exemplo, Reticências). Isto é o que vamos utilizar para colocar os nossos pincéis ao longo da forma de Elipse.

Quando combinados, estes utilitários podem ser utilizados para criar um menu radial.

Script LineObjectCollection

LineObjectCollection tem controlos para o tamanho, posição e rotação de objetos distribuídos ao longo da linha. Isto é útil para criar menus radiais como o seletor de pincel. Para criar o aspeto dos pincéis que se aproximam do nada à medida que se aproximam da posição selecionada pelo centro, a curva ObjectScale atinge o pico no centro e os tapers desativados nas margens.

Script BrushSelector

No caso do BrushSelector, optámos por utilizar animações processuais. Primeiro, os modelos de pincel são distribuídos numa reticência pelo script LineObjectCollection . Em seguida, cada pincel é responsável por manter a sua posição na mão do utilizador com base no respetivo valor DisplayMode , que é alterado com base na seleção. Escolhemos uma abordagem processual devido à elevada probabilidade de as transições de posição do pincel serem interrompidas à medida que o utilizador seleciona pincéis. As animações mecanim podem processar as interrupções corretamente, mas tendem a ser mais complicadas do que uma simples operação Lerp.

BrushSelector utiliza uma combinação de ambos. Quando a entrada do touchpad é detetada, as opções do pincel ficam visíveis e verticalmente ao longo do menu radial. Após um período de tempo limite (que indica que o utilizador fez uma seleção), as opções do pincel voltam a reduzir verticalmente, deixando apenas o pincel selecionado.

Visualizar a entrada do touchpad

Mesmo nos casos em que o modelo do controlador foi completamente substituído, pode ser útil mostrar entradas nas entradas do modelo original. Isto ajuda a basear as ações do utilizador na realidade. Para o BrushSelector , optámos por tornar o touchpad brevemente visível quando a entrada é recebida. Isto foi feito ao obter o elemento Touchpad do controlador, substituindo o respetivo material por um material personalizado e, em seguida, aplicando uma gradação à cor desse material com base na última vez 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 ferramentas de pincel com entrada do touchpad

Quando o seletor de pincel deteta a entrada premida do touchpad, verifica a posição da entrada para determinar se se encontrava à esquerda ou à direita.

Espessura do traço com selectPressedAmount

Em vez do evento InteractionSourcePressType.Select no InteractionSourcePressed(), pode obter o valor analógico da quantidade premida através de selectPressedAmount. Este valor pode ser obtido 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

Borracha é um tipo especial de pincel que substitui a função DrawOverTime() do Pincel base. Enquanto Desenhar é verdadeiro, a borracha verifica se a ponta se cruza com traços de pincel existentes. Se for o caso, são adicionados a uma fila para serem reduzidas e eliminadas.

Design avançado - Teletransportação e locomoção

Se quiser permitir que o utilizador se mova na cena com teletransporte com o thumbstick, utilize MixedRealityCameraParent em vez de MixedRealityCamera. Também tem de adicionar InputManager e DefaultCursor. Uma vez que MixedRealityCameraParent já inclui MotionControllers e Boundary como componentes subordinados, deve remover motionControllers e Environment prefab existentes.

Instruções

  • No painel Hierarquia , elimine MixedRealityCamera, Environment e MotionControllers

  • No painel Projeto, pesquise e arraste as seguintes prefabs para o painel Hierarquia :

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

    Mixed Reality Câmara Principal

  • No painel Hierarquia , clique em Gestor de Entradas

  • No painel Inspetor, desloque-se para baixo até à secção Seletor de Ponteiro Único Simples

  • No painel Hierarquia, arraste DefaultCursor para o campo Cursor

    Atribuir DefaultCursor

  • Guarde a cena e clique no botão reproduzir . Poderá utilizar o manípulo para rodar para a esquerda/direita ou teletransportar.

O fim

E é o fim deste tutorial! Aprendeu:

  • Como trabalhar com modelos de comando de movimento no modo de jogo e runtime do Unity.
  • Como utilizar diferentes tipos de eventos de botão e respetivas aplicações.
  • Como sobrepor elementos da IU na parte superior do controlador ou personalizá-los completamente.

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

Cenas concluídas

  • No painel Projeto do Unity, clique na pasta Cenas .
  • Encontrará duas cenas do Unity MixedReality213 e MixedReality213Advanced.
    • MixedReality213: Cena concluída com pincel único
    • MixedReality213Advanced: Cena concluída com vários pincel com exemplo de quantidade de imprensa do botão selecionar

Ver também