Controladores, ponteiros e foco — MRTK2

Controladores, ponteiros e foco são conceitos de nível superior que se baseiam na base estabelecida pelo sistema de entrada principal. Em conjunto, fornecem uma grande parte do mecanismo para interagir com objetos na cena.

Controladores

Os controladores são representações de um controlador físico (6 graus de liberdade, mão articulada, etc.). São criados por gestores de dispositivos e são responsáveis por comunicar com o sistema subjacente correspondente e traduzir esses dados em dados e eventos em forma de MRTK.a

Por exemplo, na plataforma Windows Mixed Reality, o WindowsMixedRealityArticulatedHand é um controlador responsável por interagir com as APIs de controlo manual do Windows subjacentes para obter informações sobre as articulações, pose e outras propriedades da mão. É responsável por transformar estes dados em eventos MRTK relevantes (por exemplo, ao chamar RaisePoseInputChanged ou RaiseHandJointsUpdated) e ao atualizar o seu próprio estado interno para que as consultas devolvam TryGetJointPose dados corretos.

Geralmente, o ciclo de vida de um controlador envolverá:

  1. Um controlador é criado por um gestor de dispositivos após a deteção de uma nova origem (por exemplo, o gestor de dispositivos deteta e começa a controlar uma mão).

  2. No ciclo Update() do controlador, chama para o sistema de API subjacente.

  3. No mesmo ciclo de atualização, gera alterações de eventos de entrada ao chamar diretamente para o próprio sistema de entrada principal (por exemplo, elevando HandMeshUpdated ou HandJointsUpdated).

Ponteiros e foco

Os ponteiros são utilizados para interagir com objetos de jogo. Esta secção descreve como os ponteiros são criados, como são atualizados e como determinam os objetos que estão em foco. Também abrangerá os diferentes tipos de ponteiros que existem e os cenários em que estão ativos.

Categorias de ponteiro

Geralmente, os ponteiros enquadram-se numa das seguintes categorias:

  • Ponteiros distantes

    Estes tipos de ponteiros são utilizados para interagir com objetos que estão longe do utilizador (longe é definido como simplesmente "não perto"). Geralmente, estes tipos de ponteiros lançam linhas que podem ir longe no mundo e permitem que o utilizador interaja e manipule objetos que não estão imediatamente ao seu lado.

  • Ponteiros próximos

    Estes tipos de ponteiros são utilizados para interagir com objetos suficientemente próximos do utilizador para agarrar, tocar e manipular. Geralmente, estes tipos de ponteiros interagem com objetos ao procurar objetos nas proximidades (seja através de raycasting a pequenas distâncias, fazendo castings esféricos à procura de objetos nas proximidades ou enumerando listas de objetos considerados agarráveis/táteis).

  • Ponteiros de teletransporte

    Estes tipos de ponteiros ligam-se ao sistema de teletransporte para processar a movimentação do utilizador para a localização direcionada pelo ponteiro.

Mediação do ponteiro

Uma vez que um único controlador pode ter vários ponteiros (por exemplo, a mão articulada pode ter ponteiros de interação próximos e distantes), existe um componente responsável pela mediação do ponteiro que deve estar ativo.

Por exemplo, à medida que a mão do utilizador se aproxima de um botão premido, o ShellHandRayPointer deve parar de ser apresentado e o PokePointer deve ser interativado.

Isto é processado pelo , que é responsável por DefaultPointerMediatordeterminar que ponteiros estão ativos, com base no estado de todos os ponteiros. Uma das principais coisas que isto faz é desativar ponteiros distantes quando um ponteiro próximo está próximo de um objeto (veja DefaultPointerMediator).

É possível fornecer uma implementação alternativa do mediador de ponteiro ao alterar a PointerMediator propriedade no perfil de ponteiro.

Como desativar ponteiros

Uma vez que o mediador de ponteiro executa cada frame, acaba por controlar o estado ativo/inativo de todos os ponteiros. Por conseguinte, se definir a propriedade IsInteractionEnabled de um ponteiro no código, esta será substituída pelo mediador de ponteiros em cada frame. Em vez disso, pode especificar o para controlar se os PointerBehavior ponteiros devem estar ativados ou desligados. Tenha em atenção que isto só funcionará se estiver a utilizar a predefinição FocusProvider e DefaultPointerMediator no MRTK.

Exemplo: Desativar raios de mão no MRTK

O código seguinte irá desativar os raios de mão no MRTK:

// Turn off all hand rays
PointerUtils.SetHandRayPointerBehavior(PointerBehavior.AlwaysOff);

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

O código seguinte irá devolver os raios manufator ao comportamento predefinido no MRTK:

PointerUtils.SetHandRayPointerBehavior(PointerBehavior.Default);

O código seguinte irá forçar a ativação dos raios de mão, independentemente de estarem perto de um agarrável:

// Turn off all hand rays
PointerUtils.SetHandRayPointerBehavior(PointerBehavior.AlwaysOn);

Veja PointerUtils e TurnPointersOnOff para obter mais exemplos.

FocusProvider

O FocusProvider é o cavalo de trabalho que é responsável por iterar sobre a lista de todos os ponteiros e descobrir qual é o objeto focado para cada ponteiro.

Em cada Update() chamada, isto irá:

  1. Atualize todos os ponteiros, ao raycasting e ao fazer a deteção de impacto conforme configurado pelo próprio ponteiro (por exemplo, o ponteiro da esfera pode especificar o raycastMode SphereOverlap, pelo que o FocusProvider fará uma colisão baseada na esfera)

  2. Atualize o objeto focado numa base por ponteiro (ou seja, se um objeto ganhar foco, também acionaria eventos nesses objetos, se um objeto perdesse o foco, acionaria a perda de foco, etc.).

Configuração do ponteiro e ciclo de vida

Os ponteiros podem ser configurados na secção Ponteiros do perfil do sistema de entrada.

Geralmente, a duração de um ponteiro é a seguinte:

  1. Um gestor de dispositivos irá detetar a presença de um controlador. Em seguida, este gestor de dispositivos irá criar o conjunto de ponteiros associados ao controlador através de uma chamada para RequestPointers.

  2. O FocusProvider, no ciclo Update(), iterará todos os ponteiros válidos e fará o raycast associado ou a lógica de deteção de acesso. Isto é utilizado para determinar o objeto que está focado por cada ponteiro específico.

    • Uma vez que é possível ter várias origens de entrada ativas ao mesmo tempo (por exemplo, duas mãos ativas presentes), também é possível ter vários objetos que têm o foco ao mesmo tempo.
  3. O gestor de dispositivos, ao descobrir que uma origem do controlador foi perdida, irá derrubar os ponteiros associados ao controlador perdido.