Ponteiros — MRTK2

Ponteiro

Este artigo explica como configurar e responder à entrada de ponteiro na prática. Para entender melhor como controlar vários ponteiros em um alto nível, consulte Arquitetura do ponteiro.

Os ponteiros são instânciados automaticamente em runtime quando um novo controlador é detectado. Mais de um ponteiro pode ser anexado a um controlador. Por exemplo, com o perfil de ponteiro padrão, Windows Mixed Reality controladores obtêm uma linha e um ponteiro parabólico para seleção e teletransporte normais, respectivamente.

Configuração do ponteiro

Os ponteiros são configurados como parte do Sistema de Entrada no MRTK por meio de um MixedRealityPointerProfile. Esse tipo de perfil é atribuído a um MixedRealityInputSystemProfile no inspetor de configuração do MRTK. O perfil Ponteiro determina o cursor, os tipos de Ponteiros disponíveis em runtime e como esses ponteiros se comunicam entre si para decidir qual deles está ativo.

  • Extensão de Apontamento – define a distância máxima para a qual um Ponteiro pode interagir com um GameObject.

  • Apontando máscaras de camada raycast – essa é uma matriz priorizada de LayerMasks para determinar com quais possíveis GameObjects qualquer Ponteiro pode interagir e a ordem de interação para tentar. Isso pode ser útil para garantir que ponteiros interajam primeiro com elementos da interface do usuário antes de outros objetos de cena. Exemplo de perfil de ponteiro

Configuração de opções de ponteiro

A configuração padrão do Perfil de Ponteiro do MRTK inclui as seguintes classes de ponteiro e pré-fabricados associados prontos para uso. A lista de ponteiros disponíveis para o sistema em runtime é definida em Opções de Ponteiro no perfil Ponteiro. Os desenvolvedores podem utilizar essa lista para reconfigurar ponteiros existentes, adicionar novos ponteiros ou excluir um.

Exemplo de perfil de opções de ponteiro

Cada entrada de Ponteiro é definida pelo seguinte conjunto de dados:

  • Tipo de Controlador – o conjunto de controladores para os quais um ponteiro é válido.

    • Por exemplo, o PokePointer é responsável por "cutucar" objetos com um dedo e é, por padrão, marcado como suporte apenas ao tipo de controlador de mão articulado. Os ponteiros são instanciados apenas quando um controlador fica disponível e, em particular, o Tipo de Controlador define com quais controladores esse pré-fabricado ponteiro pode ser criado.
  • Handedness - permite que um ponteiro seja instanciado apenas para uma mão específica (esquerda/direita)

Observação

Definir a propriedade Handedness de uma entrada Pointer como None efetivamente a desabilitará do sistema como uma alternativa para remover esse Ponteiro da lista.

  • Pré-fabricado de ponteiro – esse ativo pré-fabricado será instanciado quando um controlador que corresponde ao tipo de controlador especificado e a entrega começar a ser rastreado.

É possível ter vários ponteiros associados a um controlador. Por exemplo, em DefaultHoloLens2InputSystemProfile (Assets/MRTK/SDK/Profiles/HoloLens2/), o controlador de mão articulado está associado ao PokePointer, GrabPointer e DefaultControllerPointer (ou seja, raios de mão).

Observação

O MRTK fornece um conjunto de pré-fabricados de ponteiro em Ativos/MRTK/SDK/Recursos/UX/Pré-fabricados/Ponteiros. Um novo pré-fabricado personalizado pode ser criado desde que contenha um dos scripts de ponteiro em Assets/MRTK/SDK/Features/UX/Scripts/Pointers ou qualquer outro script que implemente IMixedRealityPointer.

Configuração do cursor

O cursor De foco é configurável diretamente por meio da GazeCursorPrefab propriedade no MixedRealityInputSystemProfile no Editor. Para configurar o cursor usado para outros ponteiros, você precisa alterar o pré-fabricado usado no CursorPrefab campo do correspondente BaseControllerPointer. Para alterar o cursor programaticamente, modifique a BaseCursor propriedade no comportamento correspondente IMixedRealityPointer .

Propriedade Pré-fabricado do cursor

Consulte nossos pré-fabricados de cursor em Assets/MRTK/SDK/Features/UX/Prefabs/Cursors para obter exemplos de implementações do comportamento do cursor. Em particular, o DefaultGazeCursor fornece uma implementação robusta de alteração do gráfico do cursor com base no estado contextual.

Classes de ponteiro padrão

As classes a seguir são os ponteiros do MRTK prontos para uso disponíveis e definidos no perfil de ponteiro padrão do MRTK descrito acima. Cada pré-fabricado de ponteiro fornecido em Ativos/MRTK/SDK/Features/UX/Prefabs/Pointers contém um dos componentes de ponteiro anexados.

Ponteiros padrão do MRTK

Ponteiros distantes

LinePointer

LinePointer, uma classe de ponteiro base, desenha uma linha da origem da entrada (ou seja, o controlador) na direção do ponteiro e dá suporte a uma conversão de raio único nessa direção. Em geral, classes filho, como o ShellHandRayPointer e os ponteiros de teletransporte, são instanciadas e utilizadas (que também desenham linhas para indicar onde o teletransporte acabará em) em vez dessa classe, que fornece principalmente funcionalidade comum.

Para controladores de movimento como no Oculus, Vive e Windows Mixed Reality, a rotação corresponderá à rotação do controlador. Para outros controladores, como HoloLens 2 mãos articuladas, a rotação corresponde à pose de apontamento fornecida pelo sistema da mão.

Linha de ponteiro do MRTK
CurvePointer

CurvePointer estende a classe LinePointer permitindo conversões de raios de várias etapas ao longo de uma curva. Essa classe de ponteiro base é útil para instâncias curvas, como ponteiros de teletransporte, em que a linha se curva consistentemente em uma parabola.

ShellHandRayPointer

A implementação de ShellHandRayPointer, que se estende de , é usada como o padrão para o Perfil de LinePointerPonteiro do MRTK. O pré-fabricado DefaultControllerPointer implementa a ShellHandRayPointer classe .

GGVPointer

Também conhecido como o ponteiro GGV (Foco/Gesto/Voz ), o GGVPointer alimenta a interação de olhar e toque no estilo holoLens 1, principalmente por meio da interação gaze e air tap ou foco e voz selecionar interação. A posição e a direção do ponteiro GGV são orientadas pela posição e rotação da cabeça.

TouchPointer

O TouchPointer é responsável por trabalhar com entrada touch do Unity (ou seja, tela touch). Essas são "interações distantes" porque o ato de tocar a tela converterá um raio da câmera em um local potencialmente distante na cena.

MousePointer

O MousePointer alimenta uma tela para o raycast do mundo para interações distantes, mas para o mouse em vez de toque.

Ponteiro do mouse

Observação

O suporte ao mouse não está disponível por padrão no MRTK, mas pode ser habilitado adicionando um novo Provedor de Dados de Entrada do tipo MouseDeviceManager ao perfil de entrada do MRTK e atribuindo o MixedRealityMouseInputProfile ao provedor de dados.

Ponteiros próximos

PokePointer

O PokePointer é usado para interagir com objetos de jogo que dão suporte a "interação quase tocável". que são GameObjects que têm um script anexado NearInteractionTouchable . No caso do UnityUI, esse ponteiro procura NearInteractionTouchableUnityUIs. O PokePointer usa um SphereCast para determinar o elemento tocável mais próximo e é usado para ligar itens como os botões pressionáveis.

Ao configurar o GameObject com o NearInteractionTouchable componente , configure o parâmetro localForward para apontar para fora da frente do botão ou outro objeto que deve ser tocável. Verifique também se os limites do touchable correspondem aos limites do objeto tocável.

Propriedades úteis do Poke Pointer:

  • TouchableDistance: distância máxima com a qual uma superfície tocável pode ser interagida
  • Visuais: objeto de jogo usado para renderizar o visual da ponta do dedo (o anel no dedo, por padrão).
  • Linha: linha opcional a ser desenhada da ponta do dedo para a superfície de entrada ativa.
  • Máscaras de Camada de Cutucar – uma matriz priorizada de LayerMasks para determinar com quais Possíveis GameObjects o ponteiro pode interagir e a ordem de interação para tentar. Observe que um GameObject também deve ter um NearInteractionTouchable componente para interagir com um ponteiro de cutucada.
Ponteiro de Cutucar
SpherePointer

O SpherePointer usa UnityEngine.Physics.OverlapSphere para identificar o objeto mais NearInteractionGrabbable próximo para interação, o que é útil para entrada "agarrável", como o ManipulationHandler. Semelhante ao PokePointer/NearInteractionTouchable par funcional, para poder interagir com o Ponteiro do Sphere, o objeto de jogo deve conter um componente que seja o NearInteractionGrabbable script.

Ponteiro de Captura

Propriedades úteis do Ponteiro do Sphere:

  • Raio de Conversão de Esfera: o raio para a esfera usada para consultar objetos que podem ser capturados.
  • Margem de objeto próxima: a distância na parte superior do Raio de Conversão de Esfera para consultar se um objeto está próximo ao ponteiro. O raio total de detecção de objeto próximo é Raio de Conversão de Esfera + Margem de Objeto Próximo
  • Ângulo do setor de objetos próximo: o ângulo ao redor do eixo de avanço do ponteiro para consultar objetos próximos. Faz com que a IsNearObject consulta funcione como um cone. Isso é definido como 66 graus por padrão para corresponder ao comportamento do Hololens 2

Ponteiro de esfera modificado apenas para consultar objetos na direção para a frente

  • Fator de suavização de objeto próximo: fator de suavização para detecção de objetos próximos. Se um objeto for detectado no Raio do Objeto Próximo, o raio consultado se tornará Raio do Objeto Próximo * (1 + Fator de Suavização de Objeto Próximo) para reduzir a sensibilidade e tornar mais difícil para um objeto sair do intervalo de detecção.
  • Capturar Máscaras de Camada – uma matriz priorizada de LayerMasks para determinar com quais Possíveis GameObjects o ponteiro pode interagir e a ordem de interação para tentar. Observe que um GameObject também deve ter um NearInteractionGrabbable para interagir com um SpherePointer.

    Observação

    A camada de Reconhecimento Espacial está desabilitada no pré-fabricado padrão do GrabPointer fornecido pelo MRTK. Isso é feito para reduzir o impacto no desempenho de fazer uma consulta sobreposta de esfera com a malha espacial. Você pode habilitar isso modificando o pré-fabricado GrabPointer.

  • Ignorar Colisores Não em FOV - Se deve ignorar colisores que podem estar perto do ponteiro, mas não realmente no FOV visual. Isso pode evitar capturas acidentais e permitirá que os raios de mão ativem quando você pode estar perto de um agarrável, mas não pode vê-lo. O Visual FOV é definido por meio de um cone em vez do frusto típico por motivos de desempenho. Esse cone é centralizado e orientado da mesma forma que o frusto da câmera com um raio igual a meia altura de exibição (ou FOV vertical).
Ponteiro sphere

Ponteiros de teletransporte

  • TeleportPointer gerará uma solicitação de teletransporte quando a ação for tomada (ou seja, o botão de teletransporte é pressionado) para mover o usuário.
  • ParabolicTeleportPointer gerará uma solicitação de teletransporte quando a ação for tomada (ou seja, o botão de teletransporte é pressionado) com um raycast de linha parabólica para mover o usuário.
Ponteiro Parabólico

Suporte de ponteiro para plataformas de realidade misturada

A tabela a seguir detalha os tipos de ponteiro que normalmente são usados para as plataformas comuns no MRTK. OBSERVAÇÃO: é possível adicionar diferentes tipos de ponteiro a essas plataformas. Por exemplo, você pode adicionar um ponteiro Poke ou ponteiro Sphere a VR. Além disso, dispositivos VR com um gamepad podem usar o ponteiro GGV.

Ponteiro OpenVR Windows Mixed Reality HoloLens 1 HoloLens 2
ShellHandRayPointer Válido Válido Válido
TeleportPointer Válido Válido
GGVPointer Válido
SpherePointer Válido
PokePointer Válido

Interações de ponteiro por meio de código

Interfaces de evento de ponteiro

MonoBehaviours que implementam uma ou mais das interfaces a seguir e são atribuídos a um GameObject com um Collider receberão eventos de interações de ponteiro, conforme definido pela interface associada.

Evento Descrição Manipulador
Antes de o foco ser alterado/o foco foi alterado Gerado no objeto de jogo perdendo o foco e aquele ganhando-o sempre que um ponteiro muda de foco. IMixedRealityFocusChangedHandler
Insira/Saia do Foco Gerado no objeto de jogo ganhando foco quando o primeiro ponteiro o insere e no que está perdendo o foco quando o último ponteiro o deixa. IMixedRealityFocusHandler
Ponteiro para baixo/Arrastado/Para Cima/Clicado Gerado para o ponteiro de relatório pressione, arraste e solte. IMixedRealityPointerHandler
Touch Started / Updated / Completed Gerado por ponteiros com reconhecimento de toque, como PokePointer relatar a atividade de toque. IMixedRealityTouchHandler

Observação

IMixedRealityFocusChangedHandler e IMixedRealityFocusHandler devem ser tratados nos objetos em que são gerados. É possível receber eventos de foco globalmente, mas, ao contrário de outros eventos de entrada, o manipulador de eventos global não bloqueará o recebimento de eventos com base no foco (o evento será recebido pelo manipulador global e um objeto correspondente em foco).

Eventos de entrada de ponteiro em ação

Os eventos de entrada de ponteiro são reconhecidos e tratados pelo sistema de entrada MRTK de maneira semelhante aos eventos de entrada regulares. A diferença é que os eventos de entrada de ponteiro são tratados apenas pelo GameObject em foco pelo ponteiro que disparou o evento de entrada, bem como por qualquer manipulador de entrada global. Os eventos de entrada regulares são tratados por GameObjects em foco para todos os ponteiros ativos.

  1. O sistema de entrada MRTK reconhece que ocorreu um evento de entrada
  2. O sistema de entrada MRTK dispara a função de interface relevante para o evento de entrada para todos os manipuladores de entrada globais registrados
  3. O sistema de entrada determina qual GameObject está em foco para o ponteiro que disparou o evento
    1. O sistema de entrada utiliza o Sistema de Eventos do Unity para disparar a função de interface relevante para todos os componentes correspondentes no GameObject focado
    2. Se em algum momento um evento de entrada tiver sido marcado como usado, o processo terminará e nenhum GameObjects receberá retornos de chamada.
      • Exemplo: Os componentes que implementam a interface IMixedRealityFocusHandler serão pesquisados para obter ganhos ou perder o foco do GameObject
      • Observação: o Sistema de Eventos do Unity será gerado para pesquisar o GameObject pai se nenhum componente correspondente à interface desejada for encontrado no GameObject atual..
  4. Se nenhum manipulador de entrada global for registrado e nenhum GameObject for encontrado com um componente/interface correspondente, o sistema de entrada chamará cada manipulador de entrada registrado de fallback

Exemplo

Abaixo está um script de exemplo que altera a cor do renderizador anexado quando um ponteiro usa ou deixa o foco ou quando um ponteiro seleciona o objeto.

public class ColorTap : MonoBehaviour, IMixedRealityFocusHandler, IMixedRealityPointerHandler
{
    private Color color_IdleState = Color.cyan;
    private Color color_OnHover = Color.white;
    private Color color_OnSelect = Color.blue;
    private Material material;

    private void Awake()
    {
        material = GetComponent<Renderer>().material;
    }

    void IMixedRealityFocusHandler.OnFocusEnter(FocusEventData eventData)
    {
        material.color = color_OnHover;
    }

    void IMixedRealityFocusHandler.OnFocusExit(FocusEventData eventData)
    {
        material.color = color_IdleState;
    }

    void IMixedRealityPointerHandler.OnPointerDown(
         MixedRealityPointerEventData eventData) { }

    void IMixedRealityPointerHandler.OnPointerDragged(
         MixedRealityPointerEventData eventData) { }

    void IMixedRealityPointerHandler.OnPointerClicked(MixedRealityPointerEventData eventData)
    {
        material.color = color_OnSelect;
    }
}

Ponteiros de consulta

É possível reunir todos os ponteiros atualmente ativos fazendo loop pelas fontes de entrada disponíveis (ou seja, controladores e entradas disponíveis) para descobrir quais ponteiros estão anexados a eles.

var pointers = new HashSet<IMixedRealityPointer>();

// Find all valid pointers
foreach (var inputSource in CoreServices.InputSystem.DetectedInputSources)
{
    foreach (var pointer in inputSource.Pointers)
    {
        if (pointer.IsInteractionEnabled && !pointers.Contains(pointer))
        {
            pointers.Add(pointer);
        }
    }
}

Ponteiro principal

Os desenvolvedores podem assinar o evento FocusProviders PrimaryPointerChanged para serem notificados quando o ponteiro primário em foco for alterado. Isso pode ser extremamente útil para identificar se o usuário está interagindo atualmente com uma cena por meio de um foco ou um raio de mão ou outra fonte de entrada.

private void OnEnable()
{
    var focusProvider = CoreServices.InputSystem?.FocusProvider;
    focusProvider?.SubscribeToPrimaryPointerChanged(OnPrimaryPointerChanged, true);
}

private void OnPrimaryPointerChanged(IMixedRealityPointer oldPointer, IMixedRealityPointer newPointer)
{
    ...
}

private void OnDisable()
{
    var focusProvider = CoreServices.InputSystem?.FocusProvider;
    focusProvider?.UnsubscribeFromPrimaryPointerChanged(OnPrimaryPointerChanged);

    // This flushes out the current primary pointer
    OnPrimaryPointerChanged(null, null);
}

A PrimaryPointerExample cena (Assets/MRTK/Examples/Demos/Input/Scenes/PrimaryPointer) mostra como usar o PrimaryPointerChangedHandler para eventos responderem a um novo ponteiro primário.

Exemplo de ponteiro primário

Resultado do ponteiro

A propriedade pointer Result contém o resultado atual da consulta de cena usada para determinar o objeto com foco. Para um ponteiro raycast, como os criados por padrão para controladores de movimento, a entrada de foco e os raios manuais, ele conterá a localização e o normal da ocorrência do raycast.

private void IMixedRealityPointerHandler.OnPointerClicked(MixedRealityPointerEventData eventData)
{
    var result = eventData.Pointer.Result;
    var spawnPosition = result.Details.Point;
    var spawnRotation = Quaternion.LookRotation(result.Details.Normal);
    Instantiate(MyPrefab, spawnPosition, spawnRotation);
}

A PointerResultExample cena (Assets/MRTK/Examples/Demos/Input/Scenes/PointerResult/PointerResultExample.unity) mostra como usar o ponteiro Result para gerar um objeto no local de ocorrência.

Resultado do ponteiro

Desabilitar ponteiros

Para habilitar e desabilitar ponteiros (por exemplo, para desabilitar o raio da mão), defina o PointerBehavior para um determinado tipo de ponteiro por meio de PointerUtils.

// Disable the hand rays
PointerUtils.SetHandRayPointerBehavior(PointerBehavior.AlwaysOff);

// Disable hand rays for the right hand only
PointerUtils.SetHandRayPointerBehavior(PointerBehavior.AlwaysOff, Handedness.Right);

// Disable the gaze pointer
PointerUtils.SetGazePointerBehavior(PointerBehavior.AlwaysOff);

// Set the behavior to match HoloLens 1
// Note, if on HoloLens 2, you must configure your pointer profile to make the GGV pointer show up for articulated hands.
public void SetHoloLens1()
{
    PointerUtils.SetPokePointerBehavior(PointerBehavior.AlwaysOff, Handedness.Any);
    PointerUtils.SetGrabPointerBehavior(PointerBehavior.AlwaysOff, Handedness.Any);
    PointerUtils.SetRayPointerBehavior(PointerBehavior.AlwaysOff, Handedness.Any);
    PointerUtils.SetGGVBehavior(PointerBehavior.Default);
}

Confira PointerUtils e TurnPointersOnOff para obter mais exemplos.

Interações de ponteiro por meio do editor

Para eventos de ponteiro tratados pelo IMixedRealityPointerHandler, o MRTK fornece mais conveniência na forma do componente, o que permite que eventos PointerHandler de ponteiro sejam tratados diretamente por meio de Eventos do Unity.

Manipulador de ponteiro

Extensão do ponteiro

Ponteiros distantes têm configurações que limitam o quanto eles vão raycast e interagem com outros objetos na cena. Por padrão, esse valor é definido como 10 metros. Esse valor foi escolhido para permanecer consistente com o comportamento do shell do HoloLens.

Isso pode ser alterado atualizando os DefaultControllerPointer campos do ShellHandRayPointer componente do pré-fabricado:

Extensão do Ponteiro – controla a distância máxima com a qual os ponteiros interagirão.

Extensão do Ponteiro Padrão – controla o comprimento do raio/linha do ponteiro que será renderizado quando o ponteiro não estiver interagindo com nada.

Confira também