Solucionadores: MRTK3

Principal del solucionador

Los solucionadores son componentes que facilitan los medios para calcular la posición y la orientación de un objeto según un algoritmo predefinido. Ejemplo: colocación de un objeto en la superficie con la que se interseca el raycast de mirada del usuario.

El sistema de solucionadores define de manera determinista un orden de operaciones para estos cálculos de transformación, ya que no hay ninguna manera confiable de especificar a Unity el orden de actualización de los componentes.

Los solucionadores ofrecen una variedad de comportamientos para adjuntar objetos a otros objetos o sistemas. Otro ejemplo sería un objeto con etiquetas continuas que mantiene el puntero delante del usuario (en función de la cámara). También se puede adjuntar un solucionador a un controlador y un objeto para que el objeto etiquete el controlador de manera continua. Todos los solucionadores se pueden apilar de manera segura, por ejemplo, un comportamiento de etiquetas continuas + magnetismo de superficie + impulso.

Cómo se usa

El sistema de solucionadores consta de tres categorías de scripts:

  • Solver: Clase básica abstracta de la que derivan todos los solucionadores. Ofrece seguimiento del estado, parámetros de suavizado e implementación, integración automática del sistema de solucionadores y orden de actualización.
  • SolverHandler: Establece el objeto de referencia con el que se realiza el seguimiento (por ejemplo, la transformación de la cámara principal, el haz de mano, etc.), controla la recopilación de componentes de los solucionadores y ejecuta la actualización en el orden correcto.

La tercera categoría es el solucionador mismo. Los siguientes solucionadores brindan los bloques de creación para el comportamiento básico:

  • Orbital: Se bloquea en una posición y desplazamiento especificados con respecto al objeto referenciado.
  • ConstantViewSize: Escala para mantener un tamaño constante con respecto a la vista del objeto referenciado.
  • RadialView: Mantiene el objeto dentro de una proyección cónica de vista por el objeto referenciado.
  • Follow: Mantiene el objeto dentro de un conjunto de límites del objeto referenciado definidos por el usuario.
  • InBetween: Mantiene un objeto entre dos objetos a los que se hace un seguimiento.
  • SurfaceMagnetism: Proyecta rayos en las superficies del mundo y alinea el objeto con esa superficie.
  • DirectionalIndicator: Establece la posición y la orientación de un objeto como indicador direccional. Desde el punto de la referencia del destino de seguimiento de SolverHandler, este indicador se orientará hacia el directionalTarget señalado.
  • Momentum: Aplica aceleración, velocidad o fricción para simular el impulso y la elasticidad de un objeto que es movido por otros solucionadores o componentes.
  • HandConstraint: Restringe el objeto para que siga las manos en una región que no cruza GameObject con las manos. Esto resulta útil en contenido interactivo restringido a mano, como menús, etc. Este solucionador está pensado para funcionar con XRNode.
  • HandConstraintPalmUp: Proviene de HandConstraint, pero incluye lógica para probar si la palma está orientada hacia el usuario antes de la activación. Este solucionador solo funciona con controladores XRNode y se comportará igual que su clase base con otros tipos de controladores.
  • Overlap: se superpone al objeto de seguimiento.

Para usar el sistema de solucionadores, agregue uno de los componentes enumerados anteriormente a un elemento GameObject. Dado que todos los solucionadores requieren una clase SolverHandler, Unity creará una automáticamente.

Nota:

Puede encontrar ejemplos de cómo usar el sistema de solucionadores en el archivo SolverExamples.scene.

Procedimiento para cambiar la referencia de seguimiento

La propiedad Tipo de destino de seguimiento del componente SolverHandler define el punto de referencia que todos los solucionadores usarán para calcular sus algoritmos. Por ejemplo, un tipo de valor de Head con un componente simple SurfaceMagnetism dará como resultado una proyección de rayo desde la cabeza y en la dirección de la mirada del usuario para resolver qué superficie alcanza. Los valores potenciales para la propiedad TrackedTargetType son:

  • *Head: El punto de referencia es la transformación de la cámara principal
  • ControllerRay: El punto de referencia es la transformación LinePointer en un controlador (es decir, el origen del puntero en un controlador de movimiento o controlador de mano) que apunta en la dirección del rayo de línea
    • Use la propiedad TrackedHandedness para seleccionar la preferencia de diestro o zurdo (es decir, izquierda, derecha o ambas)
  • HandJoint: El punto de referencia es la transformación de una articulación específica de la mano
    • Use la propiedad TrackedHandedness para seleccionar la preferencia de diestro o zurdo (es decir, izquierda, derecha o ambas)
    • Use la propiedad TrackedHandJoint para determinar la transformación de la articulación que se usará.
  • CustomOverride: Punto de referencia de la TransformOverride asignada.

Nota

Para los tipos ControllerRay y HandJoint, el controlador del solucionador intentará proporcionar primero la transformación de mano o de controlador izquierdo y, luego, la derecha si la primera no está disponible o a menos que la propiedad TrackedHandedness especifique lo contrario.

Importante

La mayoría de los solucionadores usan el vector hacia delante del destino de transformación con seguimiento proporcionado por SolverHandler. Cuando se usa un tipo de destino con seguimiento de HandJoint, el vector hacia delante de la articulación de la mano puede apuntar a través de los dedos y no a través de la palma. Esto depende de la plataforma que suministra los datos de la articulación de la mano. En el caso de la simulación de entrada y Windows Mixed Reality, es el vector ascendente el que apunta hacia arriba a través de la palma (es decir, el vector verde hacia arriba, el vector azul hacia delante).

Para solucionar este problema, actualice la propiedad Rotación adicional en SolverHandler a <90, 0, 0>. Esto garantizará que el vector que va hacia delante y que se ha suministrado a los solucionadores apunte a través de la palma y hacia fuera de la mano.

Como alternativa, use el tipo de destino con seguimiento Controller Ray (Rayo del controlador) para obtener un comportamiento similar para apuntar con las manos.

Procedimiento para encadenar solucionadores

Es posible agregar varios componentes Solver al mismo elemento GameObject, con lo que sus algoritmos se encadenan. El componente SolverHandler controla la actualización de todos los solucionadores en el mismo GameObject. De manera predeterminada, las SolverHandler llamadas GetComponents<Solver>() al Inicio, devolverán los solucionadores en el orden en que aparecen en el inspector.

Además, al establecer la propiedad Updated Linked Transform en "true", se indicará que Solver tiene que guardar su posición, orientación y escala calculadas en una variable intermedia accesible para todos los solucionadores (es decir, GoalPosition). Cuando se establece en false (falso), Solver actualizará la transformación de GameObject directamente. Al guardar las propiedades de la transformación en una ubicación intermediaria, otros Solucionadores pueden realizar sus cálculos a partir de la variable intermediaria. Esto se debe a que Unity no permite que las actualizaciones de gameObject.transform se apilen dentro del mismo fotograma.

Nota:

Para modificar el orden de ejecución de los solucionadores, los desarrolladores pueden establecer la propiedad SolverHandler.Solvers directamente.

Procedimiento para crear un nuevo solucionador

Todos los solucionadores deben heredar de la clase base abstracta, Solver. Los requisitos principales de una Extensión de solucionador implican invalidar el método SolverUpdate. En este método, los desarrolladores deben actualizar las propiedades heredadas GoalPosition, GoalRotation y GoalScale a los valores deseados. Además, es importante aprovechar SolverHandler.TransformTarget como el fotograma de referencia que quiera el consumidor.

El código que se indica a continuación ofrece un ejemplo de un nuevo Componente de solucionador denominado InFront que coloca el objeto adjunto 2 metros delante de SolverHandler.TransformTarget. Si el consumidor establece el valor de SolverHandler.TrackedTargetType como Head, luego el elemento SolverHandler.TransformTarget será la transformación de la cámara y, por tanto, este Solucionador situará el elemento GameObject adjunto a 2 metros de la mirada de los usuarios en cada fotograma.

/// <summary>
/// InFront solver positions an object 2m in front of the tracked transform target
/// </summary>
public class InFront : Solver
{
    ...

    public override void SolverUpdate()
    {
        if (SolverHandler != null && SolverHandler.TransformTarget != null)
        {
            var target = SolverHandler.TransformTarget;
            GoalPosition = target.position + target.forward * 2.0f;
        }
    }
}

Guías de implementación de solucionadores

Propiedades comunes de los solucionadores

Cada componente del solucionador tiene un conjunto básico de propiedades idénticas que controlan el comportamiento principal del Solucionador.

Si Smoothing está habilitado, el Solucionador actualizará gradualmente la transformación de GameObject con el tiempo a los valores calculados. La velocidad de este cambio viene determinada por la propiedad LerpTime de cada componente de transformación. Por ejemplo, un valor MoveLerpTime mayor generará incrementos más lentos en el movimiento entre fotogramas.

Si MaintainScale está habilitado, el Solucionador usará la escala local predeterminada de GameObject.

Orbital

La clase Orbital es un componente de etiquetas continuas que se comporta como los planetas en un sistema solar. Este solucionador garantizará que los GameObject adjuntos orbiten alrededor de la transformación a la que se hace el seguimiento. Por lo tanto, si Tracked Target Type (Tipo de destino con seguimiento) de SolverHandler está establecido en Head, el GameObject orbitará alrededor de la cabeza del usuario con la aplicación de un desplazamiento fijo.

Los desarrolladores pueden modificar este desplazamiento fijo para mantener los menús u otros componentes de la escena en el nivel ocular, de la cintura, etc., en torno a un usuario. Para ello, modifique las propiedades Local Offset (Desplazamiento local) y World Offset (Desplazamiento del mundo). La propiedad Orientation Type (Tipo de orientación) determina la rotación que se aplica al objeto si debe mantener su rotación original o estar siempre frente a la cámara o frente a cualquier transformación que impulse su posición.

RadialView

RadialView es otro componente de etiquetas continuas que mantiene una parte determinada de un GameObject dentro del tronco de la vista del usuario.

Las propiedades Min & Max View Degrees determinan la cantidad de una parte de GameObject siempre debe estar en vista.

Las propiedades Min & Max Distance determinan la distancia que debe mantener el GameObject del usuario. Por ejemplo, si se avanza hacia el elemento GameObject con un valor de Min Distance (Distancia mínima) de 1 metro, el elemento GameObject se alejará para asegurarse de que nunca esté a menos de 1 metro del usuario.

Por lo general, RadialView se usa junto con Tracked Target Type (Tipo de destino con seguimiento) establecido en Head, de modo que el componente siga la mirada del usuario. Sin embargo, este componente puede funcionar para mantenerse en la "vista" de cualquier Tracked Target Type (Tipo de destino con seguimiento).

Seguir

La clase Follow coloca un elemento delante del destino al que se hace el seguimiento en relación con su eje de avance local. El elemento se puede restringir libremente (también conocido como etiquetado) para que no siga hasta que el destino del que se realiza el seguimiento se mueva más allá de los límites definidos por el usuario.

Funciona de forma similar al solucionador RadialView, con controles adicionales para administrar Max Horizontal & Vertical View Degrees y mecanismos para modificar la Orientación del objeto.

InBetween

La clase InBetween mantendrá el GameObject adjunto entre dos transformaciones. El elemento SolverHandlerTracked Target Type (Tipo de destino con seguimiento) propio de GameObject y la propiedad Second Tracked Target Type (Segundo tipo de destino con seguimiento) del componente InBetween definen estos dos puntos de conexión de transformación. Por lo general, ambos tipos se establecerán en CustomOverride y los valores SolverHandler.TransformOverride y InBetween.SecondTransformOverride se establecerán en los dos puntos de conexión con seguimiento.

El componente InBetween creará otro componente SolverHandler en el tiempo de ejecución según las propiedades Second Tracked Target Type (Segundo tipo de destino con seguimiento) y Second Transform Override (Segunda invalidación de transformación).

PartwayOffset define dónde se colocará el objeto , a lo largo de la línea entre dos transformaciones; esto es, 0.5 corresponde a la mitad, 1.0 a la primera transformación y 0.0 a la segunda transformación.

SurfaceMagnetism

SurfaceMagnetism funciona mediante la aplicación de un raycast frente a un LayerMask establecido de superficies y colocando el elemento GameObject en ese punto de contacto.

Surface Normal Offset (Desplazamiento normal de la superficie) colocará el GameObject a una distancia establecida en metros de distancia de la superficie en la dirección de la normal en el punto de impacto en la superficie.

Por el contrario, Surface Ray Offset (Desplazamiento del rayo en la superficie) colocará el Objeto GameObject a una distancia establecida en metros de la superficie, pero en la dirección opuesta del raycast aplicado. Por lo tanto, si el raycast es la mirada del usuario, el GameObject se acercará a lo largo de la línea desde el punto de impacto en la superficie hasta la cámara.

Orientation Mode (Modo de orientación) determina el tipo de rotación que se aplicará en relación con la normal en la superficie.

  • None: No se aplica ninguna rotación.
  • TrackedTarget: El objeto se enfrentará a la transformación con seguimiento que controla el raycast.
  • SurfaceNormal: El objeto se alineará en función de la normal en el punto de impacto en la superficie.
  • Blended: El objeto se alineará en función de la normal en el punto de impacto en la superficie, y en función de la orientación de la transformación con seguimiento.

Para forzar que el Objeto GameObject asociado permanezca vertical en cualquier modo distinto de None, habilite Keep Orientation Vertical (Mantener orientación vertical).

Nota:

Use la propiedad Orientation Blend (Combinación de orientación) para controlar el equilibrio entre los factores de rotación Orientation Mode (Modo de orientación) está establecido en Blended. Con un valor de 0,0 la orientación se controlará completamente con el modo TrackedTarget; y con un valor de 1,0, la orientación se controlará completamente con SurfaceNormal.

Superposición

Overlap es un solucionador simple que mantendrá la transformación del objeto en la misma posición y rotación que el destino de SolverHandler's transformación.

Establecimiento de qué superficies se pueden impactar

Al agregar un componente SurfaceMagnetism a un elemento GameObject, es importante tener en cuenta la capa del elemento GameObject y sus elementos secundarios, si es que alguno tiene colisionadores. El componente funciona mediante la aplicación de varios tipos de raycasts para determinar contra qué superficie se va a "imantar". Supongamos que el solucionador GameObject tiene un colisionador en una de las capas enumeradas en la propiedad MagneticSurfaces de SurfaceMagnetism. En ese caso, es probable que el raycast se alcance a sí mismo, lo que da lugar a que el elemento GameObject se adjunte a su propio punto de colisionador. Para evitar este comportamiento extraño, se puede establecer el elemento GameObject principal y todos los elementos secundarios en la capa Ignore Raycast (Omitir raycast) o modificar de forma correcta la matriz LayerMask MagneticSurfaces.

Por el contrario, un elemento GameObject SurfaceMagnetism no colisionará con las superficies de una capa que no aparezca en la propiedad MagneticSurfaces. Se recomienda colocar todas las superficies deseadas en una capa dedicada (es decir, Superficies) y configurar la propiedad MagneticSurfaces solo para esta capa. El uso de default o everything puede dar lugar a que los componentes de la interfaz de usuario o los cursores contribuyan al solucionador.

Por último, los raycasts de SurfaceMagnetism omitirán las superficies más alejadas de la configuración de la propiedad MaxRaycastDistance.

DirectionalIndicator

La clase DirectionalIndicator es un componente de etiquetas continuas que se orienta a sí mismo a la dirección de un punto deseado en el espacio. Se usa normalmente cuando Tracked Target Type de SolverHandler se establece en Head. De este modo, un componente de la experiencia de usuario con el solucionador DirectionalIndicator dirigirá a un usuario a que mire el punto deseado en el espacio. Este punto viene determinado por la propiedad Directional Target.

Si el usuario puede ver el destino direccional, o cualquier fotograma de referencia se establece en SolverHandler, este solucionador deshabilitará todos los componentes Renderer debajo de él. Si no se puede ver, todo se habilitará en el indicador.

El tamaño del indicador se reducirá cuanto más se acerque el usuario a capturar el valor de Directional Target (Destino direccional) en su campo de visión.

  • Min Indicator Scale (Escala mínima del indicador): Escala mínima para el objeto indicador.

  • Max Indicator Scale (Escala máxima del indicador): Escala máxima para el objeto indicador.

  • Factor de escala de visibilidad: Multiplicador para aumentar o disminuir el campo de visión que determina si el punto Destino direccional se puede ver o no.

  • Desplazamiento de vista: Desde el punto de vista del marco de referencia (es decir, posiblemente la cámara) y en la dirección del indicador, esta propiedad define lo lejos que está el objeto desde el centro de la ventanilla.

Escena de ejemplo de DirectionalIndicator (Assets/MRTK/Examples/Demos/Solvers/Scenes/DirectionalIndicatorSolverExample.unity)

Menú Mano con HandConstraint y HandConstraintPalmUp

El comportamiento HandConstraint proporciona un solucionador que restringe el objeto de seguimiento a una región segura para el contenido restringido a mano (como la interfaz de usuario de mano, los menús, etc.). Las regiones seguras se consideran áreas que no se dividen con la mano. También se incluye una clase derivada HandConstraint de llamada HandConstraintPalmUp para mostrar un comportamiento común de activar el objeto con seguimiento del solucionador cuando la palma mira hacia el usuario.

Consulte la documentación Menú de mano para ver los ejemplos de uso del solucionador Hand Constraint para crear menús manuales.