Ponteiros — MRTK2
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.
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.
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
.
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 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.
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.
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.
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.
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
- 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).
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.
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.
- O sistema de entrada MRTK reconhece que ocorreu um evento de entrada
- 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
- O sistema de entrada determina que GameObject está em foco para o ponteiro que acionou o evento
- 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
- 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.
- Exemplo: os componentes que implementam a interface
- 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.
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.
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.
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.