Punteros: MRTK2
En este artículo se explica cómo configurar y responder a la entrada de puntero en la práctica. Para comprender mejor cómo controlar varios punteros en un nivel alto, consulte Arquitectura de puntero.
Los punteros se crean automáticamente en tiempo de ejecución cuando se detecta un nuevo controlador. Se puede conectar más de un puntero a un controlador. Por ejemplo, con el perfil de puntero predeterminado, Windows Mixed Reality controladores obtienen una línea y un puntero parabólico para la selección normal y la teletransportación respectivamente.
Los punteros se configuran como parte del sistema de entrada en MRTK a través de .MixedRealityPointerProfile
Este tipo de perfil se asigna a en MixedRealityInputSystemProfile
el inspector de configuración de MRTK. El perfil de puntero determina el cursor, los tipos de punteros disponibles en tiempo de ejecución y cómo esos punteros se comunican entre sí para decidir cuál está activo.
Extensión apuntadora : define la distancia máxima para la que un puntero puede interactuar con un GameObject.
Apuntando máscaras de capa de Raycast : se trata de una matriz prioritaria de LayerMasks para determinar con qué posibles GameObjects cualquier puntero determinado puede interactuar con y el orden de interacción que se va a intentar. Esto puede ser útil para garantizar que los punteros interactúen primero con los elementos de la interfaz de usuario antes que otros objetos de escena.
La configuración predeterminada del perfil de puntero de MRTK incluye las siguientes clases de puntero y los objetos prefabricados asociados de fábrica. La lista de punteros disponibles para el sistema en tiempo de ejecución se define en Opciones de puntero en el perfil de puntero. Los desarrolladores pueden usar esta lista para volver a configurar punteros existentes, agregar nuevos punteros o eliminar uno.
Cada entrada de puntero se define mediante el siguiente conjunto de datos:
Tipo de controlador : conjunto de controladores para los que un puntero es válido.
- Por ejemplo, el PokePointer es responsable de "pegar" objetos con un dedo, y está marcado de forma predeterminada como solo compatible con el tipo de controlador de mano articulado. Solo se crean instancias de punteros cuando un controlador está disponible y, en particular, el tipo de controlador define con qué controladores se puede crear este objeto prefabricado de puntero.
Mano a mano : permite que solo se cree una instancia de un puntero para una mano específica (izquierda/derecha)
Nota
Si se establece la propiedad Handedness de una entrada pointer en None , se deshabilitará eficazmente desde el sistema como alternativa a quitar ese puntero de la lista.
- Puntero Prefabricado : se creará una instancia de este recurso prefabricado cuando un controlador coincida con el tipo de controlador especificado y se inicie el seguimiento de la entrega.
Es posible tener varios punteros asociados a un controlador. Por ejemplo, en DefaultHoloLens2InputSystemProfile
(Assets/MRTK/SDK/Profiles/HoloLens2/) el controlador de mano articulado está asociado con PokePointer, GrabPointer y DefaultControllerPointer (es decir, rayos de mano).
Nota
MRTK proporciona un conjunto de objetos prefabricados de puntero en Assets/MRTK/SDK/Features/UX/Prefabs/Pointers. Se puede crear un nuevo objeto prefabricado personalizado siempre que contenga uno de los scripts de puntero en Assets/MRTK/SDK/Features/UX/Scripts/Pointers o cualquier otro script que implemente IMixedRealityPointer
.
El cursor de mirada se puede configurar directamente a través de la GazeCursorPrefab
propiedad en el MixedRealityInputSystemProfile
elemento del editor. Para configurar el cursor usado para otros punteros, debe cambiar el objeto prefabricado usado en el CursorPrefab
campo de la correspondiente BaseControllerPointer
. Para cambiar el cursor mediante programación, modifique la BaseCursor
propiedad en el comportamiento correspondiente IMixedRealityPointer
.
Consulte nuestros objetos prefabricados de cursor en Assets/MRTK/SDK/Features/UX/Prefabs/Cursors para ver implementaciones de comportamiento del cursor. En concreto, DefaultGazeCursor proporciona una implementación sólida de cómo cambiar el gráfico del cursor en función del estado contextual.
Las siguientes clases son los punteros de MRTK estándar disponibles y definidos en el perfil de puntero de MRTK predeterminado descrito anteriormente. Cada objeto prefabricado de puntero proporcionado en Assets/MRTK/SDK/Features/UX/Prefabs/Pointers contiene uno de los componentes de puntero adjuntos.
LinePointer, una clase de puntero base, dibuja una línea del origen de la entrada (es decir, el controlador) en la dirección del puntero y admite una sola conversión de rayos en esta dirección. Por lo general, se crean instancias de clases secundarias como los ShellHandRayPointer
punteros de teletransporte y se usan (que también dibujan líneas para indicar dónde terminará la teletransportación) en lugar de esta clase que proporciona principalmente funcionalidad común.
En el caso de los controladores de movimiento como en Els, Vive y Windows Mixed Reality, la rotación coincidirá con la rotación del controlador. Para otros controladores como HoloLens 2 manos articuladas, la rotación coincide con la posición apuntada proporcionada por el sistema de la mano.
CurvePointer extiende la clase LinePointer permitiendo conversiones de rayos de varios pasos a lo largo de una curva. Esta clase de puntero base es útil para instancias curvadas, como punteros de teletransportación donde la línea se dobla de forma coherente en una parabola.
La implementación de ShellHandRayPointer, que se extiende desde , se usa como valor predeterminado para el perfil de LinePointer
puntero de MRTK. El objeto prefabricado DefaultControllerPointer implementa la ShellHandRayPointer
clase .
También conocido como el puntero Mirada/Gesto/Voz (GGV), el GGVPointer potencia la apariencia de HoloLens de 1 estilo y pulsa las interacciones, principalmente a través de La mirada y pulsación de aire o mirada y la interacción De selección de voz. La posición y la dirección del puntero GGV están controladas por la posición y la rotación de la cabeza.
TouchPointer es responsable de trabajar con la entrada touch de Unity (es decir, pantalla táctil). Estas son "interacciones lejanas" porque el acto de tocar la pantalla convertirá un rayo de la cámara a una ubicación potencialmente lejana en la escena.
El MousePointer alimenta una pantalla al raycast mundial para interacciones lejanas, pero para el mouse en lugar de tocar.
Nota
La compatibilidad con el mouse no está disponible de forma predeterminada en MRTK, pero se puede habilitar agregando un nuevo proveedor de datos de entrada de tipo MouseDeviceManager
al perfil de entrada de MRTK y asignando el MixedRealityMouseInputProfile
al proveedor de datos.
El PokePointer se usa para interactuar con objetos de juego que admiten "interacción cercana táctil". que son GameObjects que tienen un script adjunto NearInteractionTouchable
. En el caso de UnityUI, este puntero busca NearInteractionTouchableUnityUIs. El PokePointer usa un SphereCast para determinar el elemento táctil más cercano y se usa para encender elementos como los botones presionables.
Al configurar GameObject con el NearInteractionTouchable
componente , asegúrese de configurar el parámetro localForward para que apunte fuera de la parte delantera del botón u otro objeto que se debe hacer táctil. Asegúrese también de que los límites del objeto táctil coincidan con los límites del objeto táctil.
Propiedades útiles de Poke Pointer:
- TouchableDistance: distancia máxima en la que se puede interactuar con una superficie táctil
- Objetos visuales: objeto game usado para representar el objeto visual de punta del dedo (el anillo en el dedo, de forma predeterminada).
- Línea: línea opcional para dibujar de la punta del dedo a la superficie de entrada activa.
- Máscaras de capa poke : una matriz prioritaria de LayerMasks para determinar con qué posibles GameObjects el puntero puede interactuar con y el orden de interacción que se va a intentar. Ten en cuenta que un GameObject también debe tener un
NearInteractionTouchable
componente para interactuar con un puntero poke.
SpherePointer usa UnityEngine.Physics.OverlapSphere para identificar el objeto más NearInteractionGrabbable
cercano para la interacción, lo que resulta útil para la ManipulationHandler
entrada "agarrable" como . De forma similar al PokePointer
/NearInteractionTouchable
par funcional, para poder interactuar con el puntero sphere, el objeto de juego debe contener un componente que sea el NearInteractionGrabbable
script.
Propiedades útiles del puntero de esfera:
- Radio de conversión de esfera: radio de la esfera utilizada para consultar objetos que se pueden agarrar.
- Margen de objeto cercano: distancia sobre el radio de conversión de esfera que se va a consultar para detectar si un objeto está cerca del puntero. El radio total de detección de objetos cercanos es Radio de conversión de esfera + Margen de objeto cercano
- Ángulo del sector del objeto cercano: ángulo alrededor del eje hacia delante del puntero para consultar objetos cercanos. Hace que la
IsNearObject
consulta funcione como un cono. Esto se establece en 66 grados de forma predeterminada para que coincida con el comportamiento de Hololens 2.
- Factor de suavizado de objetos cercanos: factor de suavizado para la detección de objetos cercanos. Si se detecta un objeto en el radio de objeto cercano, el radio consultado se convierte en Near Object Radius * (1 + Near Object Smoothing Factor) para reducir la sensibilidad y hacer que un objeto deje el intervalo de detección.
- Capturar máscaras de capa : una matriz prioritaria de LayerMasks para determinar con qué posibles GameObjects el puntero puede interactuar y el orden de interacción que se va a intentar. Tenga en cuenta que un GameObject también debe tener un
NearInteractionGrabbable
objeto para interactuar con un SpherePointer.Nota
La capa de reconocimiento espacial está deshabilitada en el objeto prefabricado de GrabPointer predeterminado proporcionado por MRTK. Esto se hace para reducir el impacto en el rendimiento de realizar una consulta de superposición de esfera con la malla espacial. Para habilitarlo, modifique el objeto prefabricado GrabPointer.
- Omitir colisionadores no en FOV : si se omiten los colisionadores que pueden estar cerca del puntero, pero no realmente en el FOV visual. Esto puede evitar agarres accidentales, y permitirá que los rayos de mano se activen cuando pueda estar cerca de un agarrable, pero no puede verlo. El FOV visual se define a través de un cono en lugar del frustum típico por motivos de rendimiento. Este cono está centrado y orientado al mismo que el frustum de la cámara con un radio igual a la mitad de la altura de la pantalla (o FOV vertical).
TeleportPointer
generará una solicitud de teletransporte cuando se realiza una acción (es decir, se presiona el botón de teletransporte) para mover el usuario.ParabolicTeleportPointer
generará una solicitud de teletransporte cuando se realiza una acción (es decir, se presiona el botón de teletransporte) con un raycast de línea parabólica para mover al usuario.
En la tabla siguiente se detallan los tipos de puntero que se usan normalmente para las plataformas comunes de MRTK. NOTA: Es posible agregar diferentes tipos de puntero a estas plataformas. Por ejemplo, podrías agregar un puntero Poke o un puntero sphere a VR. Además, los dispositivos VR con un controlador para juegos podrían usar el puntero GGV.
Puntero | 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 |
MonoBehaviours que implementan una o varias de las siguientes interfaces y se asignan a un GameObject con un Collider
recibirá eventos de interacciones de puntero según lo definido por la interfaz asociada.
Evento | Descripción | Controlador |
---|---|---|
Antes de cambiar el foco o cambiar el foco | Se genera tanto en el objeto de juego que pierde el foco como en el que lo obtiene cada vez que un puntero cambia el foco. | IMixedRealityFocusChangedHandler |
Entrada y salida del foco | Elevado en el objeto de juego que obtiene el foco cuando el primer puntero entra en él y en el que pierde el foco cuando el último puntero lo deja. | IMixedRealityFocusHandler |
Puntero hacia abajo / Arrastrado / Arriba / Clic | Se genera para informar de la presión del puntero, arrastre y suelte. | IMixedRealityPointerHandler |
Touch Started/Updated/Completed | Se genera mediante punteros táctiles como PokePointer para informar de la actividad táctil. |
IMixedRealityTouchHandler |
Nota
IMixedRealityFocusChangedHandler
y IMixedRealityFocusHandler
deben controlarse en los objetos en los que se generan. Es posible recibir eventos de foco globalmente, pero, a diferencia de otros eventos de entrada, el controlador de eventos globales no bloqueará la recepción de eventos en función del foco (el controlador global recibirá el evento y un objeto correspondiente en el foco).
El sistema de entrada de MRTK reconoce y controla los eventos de entrada de puntero de forma similar a los eventos de entrada normales. La diferencia es que los eventos de entrada de puntero solo se controlan mediante gameObject en el foco por el puntero que desencadenó el evento de entrada, así como cualquier controlador de entrada global. Los eventos de entrada normales se controlan mediante GameObjects en el foco para todos los punteros activos.
- El sistema de entrada de MRTK reconoce que se ha producido un evento de entrada.
- El sistema de entrada MRTK activa la función de interfaz pertinente para el evento de entrada en todos los controladores de entrada globales registrados.
- El sistema de entrada determina qué GameObject está en el foco del puntero que desencadenó el evento.
- El sistema de entrada utiliza el sistema de eventos de Unity para activar la función de interfaz pertinente para todos los componentes coincidentes en el GameObject centrado
- Si en cualquier momento se ha marcado como usado un evento de entrada, el proceso finalizará y ningún gameObjects recibirá devoluciones de llamada.
- Ejemplo: Los componentes que implementan la interfaz
IMixedRealityFocusHandler
se buscarán ganancias o pérdida de foco de GameObject - Nota: El sistema de eventos de Unity se propagará hasta buscar en gameObject primario si no se encuentra ningún componente que coincida con la interfaz deseada en el gameObject actual.
- Ejemplo: Los componentes que implementan la interfaz
- Si no hay controladores de entrada globales registrados y no se encuentra GameObject con un componente o interfaz coincidente, el sistema de entrada llamará a cada controlador de entrada registrado de reserva.
A continuación se muestra un script de ejemplo que cambia el color del representador adjunto cuando un puntero toma o deja el foco o cuando un puntero selecciona el 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;
}
}
Es posible recopilar todos los punteros activos actualmente mediante el bucle de los orígenes de entrada disponibles (es decir, controladores y entradas disponibles) para detectar qué punteros están asociados a ellos.
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);
}
}
}
Los desarrolladores pueden suscribirse al evento FocusProviders PrimaryPointerChanged para recibir notificaciones cuando el puntero principal en el foco ha cambiado. Esto puede ser extremadamente útil para identificar si el usuario está interactuando actualmente con una escena a través de una mirada o un rayo de mano u otro origen 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);
}
La PrimaryPointerExample
escena (Assets/MRTK/Examples/Demos/Input/Scenes/PrimaryPointer) muestra cómo usar para que los PrimaryPointerChangedHandler
eventos respondan a un nuevo puntero principal.
La propiedad de puntero Result
contiene el resultado actual de la consulta de escena utilizada para determinar el objeto con foco. Para un puntero de raycast, como los creados de forma predeterminada para los controladores de movimiento, la entrada de mirada y los rayos de mano, contendrá la ubicación y la normalidad del golpe de 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);
}
La PointerResultExample
escena (Assets/MRTK/Examples/Demos/Input/Scenes/PointerResult/PointerResultExample.unity) muestra cómo usar el puntero Result
para generar un objeto en la ubicación de posicionamiento.
Para activar y deshabilitar punteros (por ejemplo, para deshabilitar el rayo de mano), establezca para PointerBehavior
un tipo de puntero determinado a travé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);
}
Consulte PointerUtils
y TurnPointersOnOff
para obtener más ejemplos.
En el caso de los eventos de puntero controlados por IMixedRealityPointerHandler
, MRTK proporciona mayor comodidad en forma de PointerHandler
componente, lo que permite controlar los eventos de puntero directamente a través de eventos de Unity.
Los punteros lejanos tienen configuraciones que limitan hasta dónde se van a hacer raycast e interactuar con otros objetos de la escena. De forma predeterminada, este valor se establece en 10 metros. Este valor se eligió para mantener la coherencia con el comportamiento del shell de HoloLens.
Esto se puede cambiar actualizando los DefaultControllerPointer
campos del ShellHandRayPointer
componente prefabricado:
Extensión del puntero : controla la distancia máxima con la que interactuarán los punteros.
Extensión de puntero predeterminada : controla la longitud del rayo o línea de puntero que se representará cuando el puntero no interactúe con nada.