Ponteiros — MRTK2

Ponteiro

Este artigo explica como configurar e responder à entrada do Ponteiro na prática. Para compreender melhor como controlar múltiplos ponteiros a um nível elevado, veja Arquitetura do Ponteiro.

Os ponteiros são automaticamente instânciados no runtime quando é detetado um novo controlador. Pode anexar mais do que um ponteiro a um controlador. Por exemplo, com o perfil de ponteiro predefinido, Windows Mixed Reality controladores obtêm uma linha e um ponteiro parabólico para a seleção e teletransporte normais, respetivamente.

Configuração do ponteiro

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

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

  • Máscaras de Camada de Raycast a Apontar – esta é uma matriz priorizada de LayerMasks para determinar quais os GameObjects possíveis com que um determinado Ponteiro pode interagir e a ordem de interação a tentar. Isto pode ser útil para garantir que os Ponteiros interagem primeiro com os elementos da IU antes de outros objetos de cena. Exemplo de Perfil de Ponteiro

Configuração de opções de ponteiro

A configuração predefinida do Perfil de Ponteiro do MRTK inclui as seguintes classes de ponteiro e pré-fabricados associados fora da caixa. A lista de ponteiros disponíveis para o sistema no runtime é definida em Opções de Ponteiro no perfil ponteiro. Os programadores podem utilizar esta lista para reconfigurar ponteiros existentes, adicionar novos Ponteiros ou eliminar 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 o qual um ponteiro é válido.

    • Por exemplo, o PokePointer é responsável por "espetar" objetos com um dedo e está, por predefinição, marcado como apenas suportando o tipo de controlador manual articulado. Os ponteiros só são instanciados quando um controlador fica disponível e, em particular, o Tipo de Controlador define os controladores com os quais esta pré-base de ponteiro pode ser criada.
  • Handness - permite que um ponteiro seja instanciado apenas para uma mão específica (esquerda/direita)

Nota

Definir a propriedade Entrega de uma entrada de Ponteiro para Nenhuma irá efetivamente desativá-la do sistema como alternativa à remoção desse Ponteiro da lista.

  • Prefab do Ponteiro – este recurso pré-fabricado será instanciado quando um controlador que corresponde ao tipo de controlador especificado e à entrega começar a ser monitorizado.

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

Nota

O MRTK fornece um conjunto de prefabs de ponteiro em Recursos/MRTK/SDK/Features/UX/Prefabs/Pointers. Uma nova pré-base personalizada pode ser criada 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 Olhar é configurável diretamente através da GazeCursorPrefab propriedade no MixedRealityInputSystemProfile editor. Para configurar o cursor utilizado para outros ponteiros, tem de alterar a pré-base utilizada no CursorPrefab campo do correspondente BaseControllerPointer. Para alterar o cursor programaticamente, modifique a BaseCursor propriedade no comportamento correspondente IMixedRealityPointer .

Propriedade Prefab do Cursor

Veja os nossos prefabs de cursor em Recursos/MRTK/SDK/Features/UX/Prefabs/Cursors para obter implementações de comportamento do cursor. Em particular, o DefaultGazeCursor oferece uma implementação robusta da alteração do gráfico do cursor com base no estado contextual.

Classes de ponteiro predefinidas

As classes seguintes são os ponteiros mrtk desaprotedidos disponíveis e definidos no Perfil de Ponteiro de MRTK predefinido descrito acima. Cada prefab de ponteiro fornecido em Recursos/MRTK/SDK/Features/UX/Prefabs/Pointers contém um dos componentes de ponteiro anexados.

Ponteiros Predefinidos do MRTK

Ponteiros distantes

LinePointer

O LinePointer, uma classe de ponteiro base, desenha uma linha da origem da entrada (ou seja, o controlador) na direção do ponteiro e suporta um único raio fundido nesta direção. Geralmente, as classes subordinadas, como os ShellHandRayPointer ponteiros de teletransporte, são instanciadas e utilizadas (que também desenham linhas para indicar onde a teletransporte vai acabar) em vez desta 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.

Linha de Ponteiro do MRTK
CurvePointer

O CurvePointer expande a classe LinePointer ao permitir moldes de raios de vários passos ao longo de uma curva. Esta classe de ponteiro de base é útil para instâncias curvas, como ponteiros de teletransporte em que a linha se dobra consistentemente numa parábola.

ShellHandRayPointer

A implementação do ShellHandRayPointer, que se estende a partir de LinePointer, é utilizada como a predefinição para o Perfil de Ponteiro do MRTK. A prefab DefaultControllerPointer implementa a ShellHandRayPointer classe.

GGVPointer

Também conhecido como o ponteiro Olhar/Gesto/Voz (GGV), o GGVPointer alimenta o aspeto do HoloLens em estilo 1 e toca nas interações, principalmente através da interação Olhar e Toque no Ar ou Olhar 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 a entrada Unity Touch (ou seja, ecrã tátil). Estas são "interações distantes" porque o ato de tocar no ecrã vai lançar um raio da câmara para uma localização potencialmente distante na cena.

MousePointer

O MousePointer dá um ecrã ao raycast mundial para interações distantes, mas para o rato em vez do toque.

Ponteiro do rato

Nota

O suporte do rato não está disponível por predefinição no MRTK, mas pode ser ativado ao adicionar um novo Fornecedor de Dados de Entrada do tipo MouseDeviceManager ao perfil de entrada mrTK e atribuir o MixedRealityMouseInputProfile ao fornecedor de dados.

Ponteiros próximos

PokePointer

O PokePointer é utilizado para interagir com objetos de jogo que suportam "interação quase tátil". que são GameObjects que têm um script anexado NearInteractionTouchable . No caso do UnityUI, este ponteiro procura NearInteractionTouchableUnityUIs. O PokePointer utiliza um SphereCast para determinar o elemento tátil mais próximo e é utilizado para ligar elementos como os botões premidos.

Ao configurar o GameObject com o NearInteractionTouchable componente, certifique-se de que configura o parâmetro localForward para apontar para fora da frente do botão ou de outro objeto que deve ser tornado tátil. Certifique-se também de que os limites do touchable correspondem aos limites do objeto tátil.

Propriedades úteis do Ponteiro do Poke:

  • TouchableDistance: distância máxima com a qual uma superfície tátil pode ser interagida
  • Elementos visuais: objeto de jogo utilizado para compor o elemento visual de ponta do dedo (o anel no dedo, por predefinição).
  • Linha: linha opcional a desenhar da ponta dos dedos para a superfície de entrada ativa.
  • Máscaras de Camada de Poke – uma matriz priorizada de LayerMasks para determinar quais os GameObjects possíveis com que o ponteiro pode interagir e a ordem de interação a tentar. Tenha em atenção que um GameObject também tem de ter um NearInteractionTouchable componente para interagir com um ponteiro de toque.
Ponteiro de Sugestão
SpherePointer

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

Agarrar Ponteiro

Propriedades úteis do Ponteiro do Sphere:

  • Sphere Cast Radius: o raio da esfera utilizada para consultar objetos agarráveis.
  • Perto da Margem do Objeto: a distância na parte superior do Sphere Cast Radius para consultar para detetar se um objeto está perto do ponteiro. Total Near Object detection radius is Sphere Cast Radius + Near Object Margin
  • Ângulo do Setor de Objetos Próximo: o ângulo em torno do eixo para a frente do ponteiro para consultar objetos próximos. Faz com que a IsNearObject consulta funcione como um cone. Esta opção está definida como 66 graus por predefinição para corresponder ao comportamento do Hololens 2

Ponteiro do Sphere modificado para apenas consultar objetos na direção para a frente

  • Near Object Smoothing Factor: Smoothing factor for Near Object detection (Quase Fator de Suavidade do Objeto: Fator de suavidade para a deteção de Objetos Próximos). Se for detetado um objeto no Raio de Objeto Próximo, o raio consultado torna-se, em seguida, Próximo do Raio do Objeto * (1 + Fator de Alisamento de Objeto Próximo) para reduzir a sensibilidade e dificultar a saída do intervalo de deteção por parte de um objeto.
  • Grab Layer Masks - uma matriz priorizada de LayerMasks para determinar quais os GameObjects possíveis com que o ponteiro pode interagir e a ordem de interação a tentar. Tenha em atenção que um GameObject também tem de ter um NearInteractionGrabbable para interagir com um SpherePointer.

    Nota

    A camada de Sensibilização Espacial está desativada na pré-fabricada do GrabPointer predefinida fornecida pelo MRTK. Isto é feito para reduzir o impacto no desempenho de fazer uma consulta sobreposta de esferas com a malha espacial. Pode ativar esta opção ao modificar a pré-base do GrabPointer.

  • Ignore Colliders Not in FOV - Whether to ignore colliders that may be near the pointer, but not actually in the visual FOV. Isto pode impedir a captura acidental e permitirá que os raios das mãos se ativem quando estiver perto de um agarrável, mas não o conseguir ver. O Visual FOV é definido através de um cone em vez do frustum típico por motivos de desempenho. Este cone é centrado e orientado da mesma forma que o frustum da câmara com um raio igual a meia altura de apresentação (ou FOV vertical).
Ponteiro do Sphere

Ponteiros de teletransporte

  • TeleportPointer irá gerar um pedido de teletransporte quando a ação for efetuada (ou seja, o botão teleportar é premido) para mover o utilizador.
  • ParabolicTeleportPointer irá gerar um pedido de teletransporte quando a ação for efetuada (ou seja, o botão teleportar é premido) com um raycast de linha parabólica para mover o utilizador.
Ponteiro Parabólico

Suporte de ponteiro para plataformas de realidade mista

A tabela seguinte detalha os tipos de ponteiro que são normalmente utilizados para as plataformas comuns no MRTK. NOTA: é possível adicionar diferentes tipos de ponteiro a estas plataformas. Por exemplo, pode adicionar um ponteiro de Poke ou ponteiro do Sphere ao VR. Além disso, os dispositivos VR com um gamepad podem utilizar 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 através de código

Interfaces de eventos de ponteiro

Os MonoBehaviours que implementam uma ou mais das seguintes interfaces 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 Processador
Antes da Alteração do Foco/Alteração do Foco Gerado tanto no objeto do jogo a perder o foco como no que o ganha sempre que um ponteiro muda de foco. IMixedRealityFocusChangedHandler
Enter/Saída do Foco Gerado sobre o objeto de jogo ganhando foco quando o primeiro ponteiro entra no mesmo e no que está a perder o foco quando o último ponteiro o deixa. IMixedRealityFocusHandler
Ponteiro Para Baixo/Arrastado/Para Cima/Clicado Elevado ao ponteiro do relatório, prima, arraste e solte. IMixedRealityPointerHandler
Touch Started/Updated/Completed Gerado por ponteiros com suporte tátil, como PokePointer comunicar a atividade tátil. IMixedRealityTouchHandler

Nota

IMixedRealityFocusChangedHandler e IMixedRealityFocusHandler devem ser processados nos objetos em que são gerados. É possível receber eventos de foco globalmente, mas, ao contrário de outros eventos de entrada, o processador global de eventos não bloqueia a receção de eventos com base no foco (o evento será recebido tanto pelo processador global como por um objeto correspondente em foco).

Eventos de entrada do ponteiro em ação

Os eventos de entrada do ponteiro são reconhecidos e processados pelo sistema de entrada MRTK de forma semelhante aos eventos de entrada regulares. A diferença é que os eventos de entrada do ponteiro são processados apenas pelo GameObject em foco pelo ponteiro que acionou o evento de entrada, bem como por todos os processadores de entrada globais. Os eventos de entrada regulares são processados 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 aciona a função de interface relevante para o evento de entrada para todos os processadores de entrada globais registados
  3. O sistema de entrada determina que GameObject está em foco para o ponteiro que acionou o evento
    1. O sistema de entrada utiliza o Sistema de Eventos do Unity para acionar 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 utilizado, o processo terminará e nenhum gameObjects mais receberá chamadas de retorno.
      • Exemplo: os componentes que implementam a interface IMixedRealityFocusHandler serão procurados por ganhos do GameObject ou perderão o foco
      • Nota: o Sistema de Eventos do Unity irá surgir para procurar o GameObject principal se não forem encontrados componentes que correspondam à interface pretendida no GameObject atual.
  4. Se não forem registados processadores de entrada globais e não for encontrado nenhum GameObject com um componente/interface correspondente, o sistema de entrada chamará cada processador de entrada registado de contingência

Exemplo

Segue-se um script de exemplo que altera a cor do compositor 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 ao percorrer as origens de entrada disponíveis (ou seja, controladores e entradas disponíveis) para descobrir que ponteiros estão ligados às mesmas.

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 programadores podem subscrever o evento FocusProviders PrimaryPointerChanged para serem notificados quando o ponteiro principal em foco for alterado. Isto pode ser extremamente útil para identificar se o utilizador está atualmente a interagir com uma cena através do olhar ou de um raio de mão ou de outra origem 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 utilizar o PrimaryPointerChangedHandler para eventos para responder a um novo ponteiro principal.

Exemplo de Ponteiro Principal

Resultado do ponteiro

A propriedade ponteiro Result contém o resultado atual da consulta de cena utilizada para determinar o objeto com foco. Para um ponteiro de raycast, como os criados por predefinição para controladores de movimento, entrada de olhar e raios de mão, conterá a localização e o normal do ataque 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 utilizar o ponteiro Result para gerar um objeto na localização de acesso.

Resultado do Ponteiro

Desativar ponteiros

Para ativar e desativar os ponteiros (por exemplo, para desativar o raio da mão), defina o PointerBehavior para um determinado tipo de ponteiro através 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 através do editor

Para eventos de ponteiro processados pelo IMixedRealityPointerHandler, o MRTK fornece maior comodidade na forma do componente, o que permite que os PointerHandler eventos de ponteiro sejam processados diretamente através de Eventos do Unity.

Processador de Ponteiro

Extensão do ponteiro

Os ponteiros distantes têm definições que limitam a distância de raycast e interagem com outros objetos na cena. Por predefinição, este valor está definido como 10 metros. Este valor foi escolhido para permanecer consistente com o comportamento da shell do HoloLens.

Isto pode ser alterado ao atualizar os DefaultControllerPointer campos do componente do ShellHandRayPointer pré-fabricado:

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

Extensão do Ponteiro Predefinida – controla o comprimento do raio/linha do ponteiro que será composto quando o ponteiro não estiver a interagir com nada.

Ver também