Ponteiros — MRTK2

Pointer

Este artigo explica como configurar e responder à entrada ponteiro na prática. Para entender melhor como controlar vários ponteiros em um alto nível, consulte a 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, os controladores Windows Mixed Reality 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 inspetor de configuração do MRTK. O perfil Ponteiro determina o cursor, os tipos de Ponteiros disponíveis no 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 do Raycast – esta é uma matriz priorizada de LayerMasks para determinar com quais possíveis GameObjects qualquer ponteiro determinado pode interagir e a ordem de interação a ser tentada. Isso pode ser útil para garantir que os Ponteiros interajam primeiro com elementos da interface do usuário antes de outros objetos de cena. Pointer Profile Example

Configuração de opções de ponteiro

A configuração padrão do Perfil do Ponteiro 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.

Pointer Options Profile Example

Cada entrada 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ó são instanciados quando um controlador fica disponível e, em particular, o Tipo de Controlador define com quais controladores esse pré-fabricado de 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 de pré-fabricado será instanciado quando um controlador que corresponde ao tipo de controlador especificado e à 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, Ao GrabPointer e ao DefaultControllerPointer (ou seja, raios manuais).

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 Gaze é configurável diretamente por meio da GazeCursorPrefab propriedade no MixedRealityInputSystemProfile Editor. Para configurar o cursor usado para outros ponteiros, você precisa alterar o CursorPrefab pré-fabricado usado no campo do correspondente BaseControllerPointer. Para alterar o cursor programaticamente, modifique a BaseCursor propriedade no comportamento correspondente IMixedRealityPointer .

Cursor Prefab Property

Consulte nossos pré-fabricados de cursor em Ativos/MRTK/SDK/Recursos/UX/Prefabs/Cursores 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 mrtk prontos para uso disponíveis e definidos no perfil de ponteiro mrtk padrão descrito acima. Cada pré-fabricado de ponteiro fornecido em Assets/MRTK/SDK/Features/UX/Prefabs/Pointers contém um dos componentes de ponteiro anexados.

MRTK Default Pointers

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. Geralmente, as classes filhos, como os ShellHandRayPointer ponteiros de teletransporte, são instanciadas e utilizadas (que também desenham linhas para indicar onde o teletransporte acabará) em vez dessa classe, que fornece principalmente funcionalidades comuns.

Para controladores de movimento como em 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.

MRTK Pointer Line
CurvePointer

O 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 parábola.

ShellHandRayPointer

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

GGVPointer

Também conhecido como ponteiro GGV (Olhar/Gesto/Voz), o GGVPointer alimenta HoloLens interações de toque e aparência de 1 estilo, principalmente por meio da interação Gaze e Air Tap ou Gaze e seleção de voz. A posição e a direção do ponteiro GGV são controladas pela posição e rotação da cabeça.

TouchPointer

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

MousePointer

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

Mouse pointer

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 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 sensível ao toque mais próximo e é usado para alimentar coisas como os botões pressí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áveis.

Propriedades úteis do Ponteiro poke:

  • TouchableDistance: distância máxima com a qual uma superfície sensível ao toque pode ser interagida
  • Visuais: objeto game 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 Poke – uma matriz priorizada de LayerMasks para determinar com quais possíveis GameObjects o ponteiro pode interagir e a ordem de interação a ser tentada. Observe que um GameObject também deve ter um NearInteractionTouchable componente para interagir com um ponteiro de cutucada.
Poke Pointer
SpherePointer

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

Grab Pointer

Propriedades úteis do Ponteiro do Sphere:

  • Sphere Cast Radius: o raio da esfera usada para consultar objetos que podem ser capturados.
  • Margem de objeto próximo: a distância na parte superior do Raio de Conversão do Sphere para consultar se um objeto está próximo ao ponteiro. Raio total de detecção de objeto próximo é Sphere Cast Radius + Near Object Margin
  • Ângulo próximo do setor de objetos: o ângulo ao redor do eixo dianteiro do ponteiro para consultar objetos próximos. Faz a IsNearObject função de consulta como um cone. Isso é definido como 66 graus por padrão para corresponder ao comportamento do Hololens 2

Sphere pointer modified to only query for objects in the forward direction

  • Fator de suavização de objeto próximo: fator de suavização para detecção de objeto próximo. Se um objeto for detectado no Raio do Objeto Próximo, o raio consultado se tornará o Raio do Objeto Próximo * (1 + Fator de Suavização de Objeto Próximo) para reduzir a sensibilidade e dificultar a saída do intervalo de detecção de um objeto.
  • 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 a ser tentada. 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 de sobreposição de esfera com a malha espacial. Você pode habilitar isso modificando o prefab do 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 manuais 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).
Sphere Pointer

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.
Pointer Parabolic

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 para VR. Além disso, dispositivos VR com um gamepad poderiam 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 pointer

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

Evento Descrição Manipulador
Antes da alteração do foco/foco alterado Gerado em ambos os objetos do jogo perdendo o foco e aquele ganhando-o sempre que um ponteiro muda de foco. IMixedRealityFocusChangedHandler
Focus Enter/Exit Gerado no objeto do jogo ganhando foco quando o primeiro ponteiro entra nele e no que perde o foco quando o último ponteiro o deixa. IMixedRealityFocusHandler
Ponteiro para baixo / Arrastado / Para cima / Clicado Gerado para o relatório, pressione, arraste e solte. IMixedRealityPointerHandler
Touch Started/Updated/Completed Gerados por ponteiros com reconhecimento de toque gostam PokePointer de 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 por 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 somente pelo GameObject em foco pelo ponteiro que disparou o evento de entrada, bem como por qualquer manipulador de entrada global. 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 será encerrado e nenhum GameObjects adicional receberá retornos de chamada.
      • Exemplo: componentes que implementam a interface IMixedRealityFocusHandler serão pesquisados para obter ganhos do GameObject ou perder o foco
      • 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 tira 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 nas 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 principal em foco for alterado. Isso pode ser extremamente útil para identificar se o usuário está interagindo com uma cena por meio de um olhar 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 os PrimaryPointerChangedHandler eventos para responder a um novo ponteiro primário.

Primary Pointer Example

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á o local 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.

Pointer Result

Desabilitar ponteiros

Para habilitar e desabilitar ponteiros (por exemplo, para desabilitar o raio manual), 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);
}

Veja PointerUtils e TurnPointersOnOff para obter mais exemplos.

Interações de ponteiro por meio do editor

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

Pointer Handler

Extensão do ponteiro

Ponteiros distantes têm configurações que limitam o quão longe 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 HoloLens.

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

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

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

Veja também