Entrada de realidad mixta (213): Controladores de movimiento

Nota

Los tutoriales de Mixed Reality Academy se han diseñado teniendo en cuenta HoloLens (1.ª generación) y los cascos envolventes de realidad mixta. Por lo tanto, creemos que es importante conservar estos tutoriales para los desarrolladores que sigan buscando instrucciones sobre el desarrollo para esos dispositivos. Estos tutoriales no se actualizarán con los conjuntos de herramientas o las interacciones más recientes que se usan para HoloLens 2. Se mantendrán para que sigan funcionando en los dispositivos compatibles. Se ha publicado una nueva serie de tutoriales para HoloLens 2.

Los controladores de movimiento en el mundo de la realidad mixta agregan otro nivel de interactividad. Con los controladores de movimiento, podemos interactuar directamente con objetos de una manera más natural, similar a nuestras interacciones físicas en la vida real, aumentando la inmersión y el placer en tu experiencia de la aplicación.

En MR Input 213, exploraremos los eventos de entrada del controlador de movimiento mediante la creación de una experiencia de pintura espacial sencilla. Con esta aplicación, los usuarios pueden pintar en un espacio tridimensional con varios tipos de pinceles y colores.

Temas tratados en este tutorial

MixedReality213 Topic1 MixedReality213 Topic2 MixedReality213 Topic3
Visualización del controlador Eventos de entrada del controlador Controlador personalizado y interfaz de usuario
Obtenga información sobre cómo representar modelos de controlador de movimiento en el modo de juego y el tiempo de ejecución de Unity. Comprender diferentes tipos de eventos de botón y sus aplicaciones. Obtenga información sobre cómo superponer elementos de la interfaz de usuario sobre el controlador o personalizarlos completamente.

Compatibilidad con dispositivos

Curso HoloLens Cascos envolventes
Entrada de realidad mixta (213): Controladores de movimiento ✔️

Antes de empezar

Requisitos previos

Consulte la lista de comprobación de instalación para cascos envolventes en esta página.

Archivos de proyecto

Nota

Si desea consultar el código fuente antes de descargarlo, está disponible en GitHub.

Configuración de Unity

Objetivos

  • Optimización de Unity para el desarrollo de Windows Mixed Reality
  • Configurar cámara Mixed Reality
  • Configura el entorno

Instrucciones

  • Inicie Unity.

  • Seleccione Open (Abrir).

  • Vaya al escritorio y busque la carpeta MixedReality213-master que ha desarchivado anteriormente.

  • Haga clic en Seleccionar carpeta.

  • Una vez que Unity termine de cargar archivos de proyecto, podrá ver el editor de Unity.

  • En Unity, seleccione Configuración de compilación de archivos>.

    MR213_BuildSettings

  • Seleccione Plataforma universal de Windows en la lista Plataforma y haga clic en el botón Cambiar plataforma.

  • Establecer el dispositivo de destino en cualquier dispositivo

  • Establezca Build Type (Tipo de compilación) en D3D.

  • Establecer el SDK en Instalado más reciente

  • Comprobación de proyectos de C# de Unity

    • Esto le permite modificar archivos de script en el proyecto de Visual Studio sin volver a generar el proyecto de Unity.
  • Haga clic en Configuración del reproductor.

  • En el panel Inspector , desplácese hacia abajo hasta la parte inferior.

  • En XR Settings (Configuración de XR), compruebe Virtual Reality Supported (Realidad virtual admitida).

  • En SDK de realidad virtual, seleccione Windows Mixed Reality

    MR213_XRSettings

  • Cierre la ventana Configuración de compilación .

Estructura del proyecto

En este tutorial se usa Mixed Reality Toolkit - Unity. Puede encontrar las versiones en esta página.

ProjectStructure

Escenas completadas para la referencia

  • Encontrará dos escenas de Unity completadas en la carpeta Escenas .
    • MixedReality213: escena completada con un solo pincel
    • MixedReality213Avanced: escena completada para el diseño avanzado con varios pinceles

Nueva configuración de escena para el tutorial

  • En Unity, haga clic en Archivo > nueva escena.

  • Eliminar cámara principal y luz direccional

  • En el panel Proyecto, busque y arrastre los siguientes objetos prefabricados al panel Jerarquía :

    • Assets/HoloToolkit/Input/Prefabs/MixedRealityCamera
    • Assets/AppPrefabs/Environment

    Cámara y entorno

  • Hay dos objetos prefabricados de cámara en Mixed Reality Toolkit:

    • MixedRealityCamera.prefab: solo cámara
    • MixedRealityCameraParent.prefab: Cámara + Teletransportación + Límite
    • En este tutorial, usaremos MixedRealityCamera sin la característica de teletransporte. Por este motivo, hemos agregado un sencillo objeto prefabricado environment que contiene un piso básico para que el usuario se sienta bien.
    • Para obtener más información sobre la teletransportación con MixedRealityCameraParent, consulte Diseño avanzado: Teletransportación y locomoción.

Configuración de Skybox

  • Haga clic en Configuración de iluminación > de la ventana>.

  • Haga clic en el círculo del lado derecho del campo Material de Skybox.

  • Escriba "gris" y seleccione SkyboxGray (Assets/AppPrefabs/Support/Materials/SkyboxGray.mat)

    Establecer skybox

  • Active la opción Skybox para poder ver el skybox degradado gris asignado

    Alternar la opción skybox

  • La escena con MixedRealityCamera, Environment y skybox gris tendrá este aspecto.

    Entorno mixedReality213

  • Haga clic en Guardar escena como archivo > .

  • Guarde la escena en la carpeta Escenas con cualquier nombre.

Capítulo 1: Visualización del controlador

Objetivos

  • Obtenga información sobre cómo representar modelos de controlador de movimiento en el modo de juego de Unity y en tiempo de ejecución.

Windows Mixed Reality proporciona un modelo de controlador animado para la visualización del controlador. Hay varios enfoques que puede adoptar para la visualización del controlador en la aplicación:

  • Valor predeterminado: uso del controlador predeterminado sin modificaciones
  • Híbrido: usar el controlador predeterminado, pero personalizar algunos de sus elementos o superponer componentes de la interfaz de usuario
  • Reemplazo: uso de su propio modelo 3D personalizado para el controlador

En este capítulo, veremos los ejemplos de estas personalizaciones de controlador.

Instrucciones

  • En el panel Proyecto , escriba MotionControllers en el cuadro de búsqueda . También puede encontrarlo en Activos/HoloToolkit/Input/Prefabs/.
  • Arrastre el objeto prefabricado MotionControllers al panel Jerarquía .
  • Haga clic en el objeto prefabricado MotionControllers en el panel Jerarquía .

Objeto prefabricado MotionControllers

El objeto prefabricado MotionControllers tiene un script MotionControllerVisualizer que proporciona las ranuras para los modelos de controlador alternativos. Si asigna sus propios modelos 3D personalizados, como una mano o una espada, y comprueba "Usar siempre el modelo alternativo de izquierda o derecha", los verá en lugar del modelo predeterminado. Usaremos esta ranura en el capítulo 4 para reemplazar el modelo de controlador por un pincel.

MR213_ControllerVisualizer

Instrucciones

  • En el panel Inspector , haga doble clic en MotionControllerVisualizer script para ver el código en Visual Studio.

Script MotionControllerVisualizer

Las clases MotionControllerVisualizer y MotionControllerInfo proporcionan los medios para acceder a & modificar los modelos de controlador predeterminados. MotionControllerVisualizer se suscribe al evento InteractionSourceDetected de Unity y crea automáticamente instancias de los modelos de controlador cuando se encuentran.

protected override void Awake()
{
    ...
    InteractionManager.InteractionSourceDetected += InteractionManager_InteractionSourceDetected;
    InteractionManager.InteractionSourceLost += InteractionManager_InteractionSourceLost;
    ...
}

Los modelos de controlador se entregan según la especificación glTF. Este formato se ha creado para proporcionar un formato común, al tiempo que mejora el proceso detrás de la transmisión y desempaquetación de recursos 3D. En este caso, es necesario recuperar y cargar los modelos de controlador en tiempo de ejecución, ya que queremos que la experiencia del usuario sea lo más fluida posible y no se garantiza qué versión de los controladores de movimiento podría usar el usuario. En este curso, a través del kit de herramientas de Mixed Reality, se usa una versión del proyecto UnityGLTF del grupo Khronos.

Una vez entregado el controlador, los scripts pueden usar MotionControllerInfo para buscar las transformaciones de elementos de controlador específicos para que puedan colocarse correctamente.

En un capítulo posterior, aprenderemos a usar estos scripts para adjuntar elementos de interfaz de usuario a los controladores.

En algunos scripts, encontrará bloques de código con #if ! UNITY_EDITOR o UNITY_WSA. Estos bloques de código solo se ejecutan en el entorno de ejecución de UWP cuando se implementa en Windows. Esto se debe a que el conjunto de API que usa el editor de Unity y el tiempo de ejecución de la aplicación para UWP son diferentes.

  • Guarde la escena y haga clic en el botón Reproducir .

Podrá ver la escena con controladores de movimiento en los auriculares. Puede ver animaciones detalladas para los clics de botón, el movimiento del stick digital y el resaltado táctil del panel táctil.

MR213_Controller visualización predeterminada

Capítulo 2: Adjuntar elementos de interfaz de usuario al controlador

Objetivos

  • Más información sobre los elementos de los controladores de movimiento
  • Obtenga información sobre cómo adjuntar objetos a partes específicas de los controladores

En este capítulo, aprenderá a agregar elementos de interfaz de usuario al controlador al que el usuario puede acceder y manipular fácilmente en cualquier momento. También aprenderá a agregar una interfaz de usuario de selector de colores simple mediante la entrada del panel táctil.

Instrucciones

  • En el panel Proyecto , busque el script MotionControllerInfo .
  • En el resultado de la búsqueda, haga doble clic en MotionControllerInfo script para ver el código en Visual Studio.

Script MotionControllerInfo

El primer paso consiste en elegir a qué elemento del controlador desea que se conecte la interfaz de usuario. Estos elementos se definen en ControllerElementEnum en MotionControllerInfo.cs.

MR213 MotionControllerElements

  • Página principal
  • Menú
  • Agarran
  • Stick
  • Select
  • Panel táctil
  • Posición de apuntamiento : este elemento representa la punta del controlador que apunta hacia delante.

Instrucciones

  • En el panel Proyecto , busque El script AttachToController .
  • En el resultado de la búsqueda, haga doble clic en AttachToController script para ver el código en Visual Studio.

Script AttachToController

El script AttachToController proporciona una manera sencilla de adjuntar cualquier objeto a un controlador especificado y a un elemento.

En AttachElementToController(),

  • Comprobar la entrega mediante MotionControllerInfo.Handedness
  • Obtener un elemento específico del controlador mediante MotionControllerInfo.TryGetElement()
  • Después de recuperar la transformación del elemento del modelo de controlador, primario el objeto bajo él y establezca la posición local del objeto & rotación en cero.
public MotionControllerInfo.ControllerElementEnum Element { get { return element; } }

private void AttachElementToController(MotionControllerInfo newController)
{
     if (!IsAttached && newController.Handedness == handedness)
     {
          if (!newController.TryGetElement(element, out elementTransform))
          {
               Debug.LogError("Unable to find element of type " + element + " under controller " + newController.ControllerParent.name + "; not attaching.");
               return;
          }

          controller = newController;

          SetChildrenActive(true);

          // Parent ourselves under the element and set our offsets
          transform.parent = elementTransform;
          transform.localPosition = positionOffset;
          transform.localEulerAngles = rotationOffset;
          if (setScaleOnAttach)
          {
               transform.localScale = scale;
          }

          // Announce that we're attached
          OnAttachToController();
          IsAttached = true;
     }
}

La manera más sencilla de usar el script AttachToController es heredar de él, como hemos hecho en el caso de ColorPickerWheel. Simplemente invalide las funciones OnAttachToController y OnDetachFromController para realizar la configuración o el desglose cuando el controlador se detecta o se desconecta.

Instrucciones

  • En el panel Proyecto , escriba el cuadro de búsqueda ColorPickerWheel. También puede encontrarlo en Activos/AppPrefabs/.
  • Arrastre el objeto prefabricado ColorPickerWheel al panel Jerarquía .
  • Haga clic en el objeto prefabricado ColorPickerWheel en el panel Jerarquía .
  • En el panel Inspector , haga doble clic en ColorPickerWheel Script para ver el código en Visual Studio.

ColorPickerWheel prefab

Script ColorPickerWheel

Dado que ColorPickerWheel hereda AttachToController, muestra La entrega y el elemento en el panel Inspector . Vamos a adjuntar la interfaz de usuario al elemento Touchpad en el controlador izquierdo.

Script ColorPickerWheel

ColorPickerWheel invalida OnAttachToController y OnDetachFromController para suscribirse al evento de entrada que se usará en el siguiente capítulo para la selección de colores con entrada táctil.

public class ColorPickerWheel : AttachToController, IPointerTarget
{
    protected override void OnAttachToController()
    {
        // Subscribe to input now that we're parented under the controller
        InteractionManager.InteractionSourceUpdated += InteractionSourceUpdated;
    }

    protected override void OnDetachFromController()
    {
        Visible = false;

        // Unsubscribe from input now that we've detached from the controller
        InteractionManager.InteractionSourceUpdated -= InteractionSourceUpdated;
    }
    ...
}
  • Guarde la escena y haga clic en el botón Reproducir .

Método alternativo para adjuntar objetos a los controladores

Se recomienda que los scripts hereden de AttachToController e invaliden OnAttachToController. Sin embargo, es posible que esto no siempre sea posible. Una alternativa es usarla como un componente independiente. Esto puede ser útil cuando desea adjuntar un objeto prefabricado existente a un controlador sin refactorizar los scripts. Basta con que la clase espere a que IsAttached se establezca en true antes de realizar cualquier configuración. La manera más sencilla de hacerlo es usar una corrutina para "Start".

private IEnumerator Start() {
    AttachToController attach = gameObject.GetComponent<AttachToController>();

    while (!attach.IsAttached) {
        yield return null;
    }

    // Perform setup here
}

Capítulo 3: Trabajar con la entrada del panel táctil

Objetivos

  • Obtenga información sobre cómo obtener eventos de datos de entrada del panel táctil
  • Obtenga información sobre cómo usar la información de posición del eje del panel táctil para la experiencia de la aplicación.

Instrucciones

  • En el panel Jerarquía, haga clic en ColorPickerWheel.
  • En el panel Inspector, en Animator, haga doble clic en ColorPickerWheelController.
  • Podrá ver la pestaña Animator abierta.

Mostrar u ocultar la interfaz de usuario con el controlador de animación de Unity

Para mostrar y ocultar la interfaz de usuario de ColorPickerWheel con animación, usamos el sistema de animación de Unity. Establecer la propiedad Visible de ColorPickerWheel en desencadenadores true o false Mostrar y ocultar desencadenadores de animación. Los parámetros Show y Hide se definen en el controlador de animación ColorPickerWheelController .

Controlador de animación de Unity

Instrucciones

  • En el panel Jerarquía , seleccione ColorPickerWheel prefab.
  • En el panel Inspector , haga doble clic en ColorPickerWheel script para ver el código en Visual Studio.

Script ColorPickerWheel

ColorPickerWheel se suscribe al evento InteractionSourceUpdated de Unity para escuchar eventos de panel táctil.

En InteractionSourceUpdated(), el script comprueba primero para asegurarse de que:

  • es realmente un evento de panel táctil (obj.state.touchpadTouched)
  • se origina en el controlador izquierdo (obj.state.source).mano a mano)

Si ambos son true, la posición del panel táctil (obj.state).touchpadPosition) se asigna a selectorPosition.

private void InteractionSourceUpdated(InteractionSourceUpdatedEventArgs obj)
{
    if (obj.state.source.handedness == handedness && obj.state.touchpadTouched)
    {
        Visible = true;
        selectorPosition = obj.state.touchpadPosition;
    }
}

En Update(), en función de la propiedad visible , desencadena los desencadenadores de animación Mostrar y ocultar en el componente del animador del selector de colores.

if (visible != visibleLastFrame)
{
    if (visible)
    {
        animator.SetTrigger("Show");
    }
    else
    {
        animator.SetTrigger("Hide");
    }
}

En Update(), selectorPosition se usa para convertir un rayo en el colisionador de malla de la rueda de color, que devuelve una posición UV. Esta posición se puede usar para buscar la coordenada de píxeles y el valor de color de la textura de la rueda de color. Este valor es accesible para otros scripts a través de la propiedad SelectedColor .

Raycasting de la rueda del selector de colores

...
    // Clamp selector position to a radius of 1
    Vector3 localPosition = new Vector3(selectorPosition.x * inputScale, 0.15f, selectorPosition.y * inputScale);
    if (localPosition.magnitude > 1)
    {
        localPosition = localPosition.normalized;
    }
    selectorTransform.localPosition = localPosition;

    // Raycast the wheel mesh and get its UV coordinates
    Vector3 raycastStart = selectorTransform.position + selectorTransform.up * 0.15f;
    RaycastHit hit;
    Debug.DrawLine(raycastStart, raycastStart - (selectorTransform.up * 0.25f));

    if (Physics.Raycast(raycastStart, -selectorTransform.up, out hit, 0.25f, 1 << colorWheelObject.layer, QueryTriggerInteraction.Ignore))
    {
        // Get pixel from the color wheel texture using UV coordinates
        Vector2 uv = hit.textureCoord;
        int pixelX = Mathf.FloorToInt(colorWheelTexture.width * uv.x);
        int pixelY = Mathf.FloorToInt(colorWheelTexture.height * uv.y);
        selectedColor = colorWheelTexture.GetPixel(pixelX, pixelY);
        selectedColor.a = 1f;
    }
    // Set the selector's color and blend it with white to make it visible on top of the wheel
    selectorRenderer.material.color = Color.Lerp (selectedColor, Color.white, 0.5f);
}

Capítulo 4: Invalidación del modelo de controlador

Objetivos

  • Obtenga información sobre cómo invalidar el modelo de controlador con un modelo 3D personalizado.

MR213_BrushToolOverride

Instrucciones

  • Haga clic en MotionControllers en el panel Jerarquía .
  • Haga clic en el círculo del lado derecho del campo Controlador derecho alternativo .
  • Escriba "BrushController" y seleccione el objeto prefabricado en el resultado. Puede encontrarlo en Activos/AppPrefabs/BrushController.
  • Comprobar usar siempre el modelo correcto alternativo

MR213_BrushToolOverrideSlot

El objeto prefabricado BrushController no tiene que incluirse en el panel Jerarquía . Sin embargo, para comprobar sus componentes secundarios:

  • En el panel Proyecto , escriba BrushController y arrastre el objeto prefabricado BrushController al panel Jerarquía .

MR213_BrushTool_Prefab2

Encontrará el componente Tip en BrushController. Usaremos su transformación para iniciar o detener líneas de dibujo.

  • Elimine BrushController en el panel Jerarquía .
  • Guarde la escena y haga clic en el botón Reproducir . Podrá ver que el modelo de pincel ha reemplazado al controlador de movimiento derecho.

Capítulo 5: Pintar con la entrada Select

Objetivos

  • Aprenda a usar el evento Seleccionar botón para iniciar y detener un dibujo de línea

Instrucciones

  • Busque el objeto prefabricado BrushController en el panel Proyecto .
  • En el panel Inspector , haga doble clic en BrushController Script para ver el código en Visual Studio.

Script brushController

BrushController se suscribe a los eventos InteractionSourcePressed e InteractionSourceReleased de InteractionManager. Cuando se desencadena el evento InteractionSourcePressed , la propiedad Draw del pincel se establece en true; cuando se desencadena el evento InteractionSourceReleased , la propiedad Draw del pincel se establece en false.

private void InteractionSourcePressed(InteractionSourcePressedEventArgs obj)
{
    if (obj.state.source.handedness == InteractionSourceHandedness.Right && obj.pressType == InteractionSourcePressType.Select)
    {
        Draw = true;
    }
}

private void InteractionSourceReleased(InteractionSourceReleasedEventArgs obj)
{
    if (obj.state.source.handedness == InteractionSourceHandedness.Right && obj.pressType == InteractionSourcePressType.Select)
    {
        Draw = false;
    }
}

Mientras Draw se establece en true, el pincel generará puntos en una instancia de Unity LineRenderer. Una referencia a este objeto prefabricado se mantiene en el campo Prefabricado de trazo del pincel.

private IEnumerator DrawOverTime()
{
    // Get the position of the tip
    Vector3 lastPointPosition = tip.position;

    ...

    // Create a new brush stroke
    GameObject newStroke = Instantiate(strokePrefab);
    LineRenderer line = newStroke.GetComponent<LineRenderer>();
    newStroke.transform.position = startPosition;
    line.SetPosition(0, tip.position);
    float initialWidth = line.widthMultiplier;

    // Generate points in an instantiated Unity LineRenderer
    while (draw)
    {
        // Move the last point to the draw point position
        line.SetPosition(line.positionCount - 1, tip.position);
        line.material.color = colorPicker.SelectedColor;
        brushRenderer.material.color = colorPicker.SelectedColor;
        lastPointAddedTime = Time.unscaledTime;
        // Adjust the width between 1x and 2x width based on strength of trigger pull
        line.widthMultiplier = Mathf.Lerp(initialWidth, initialWidth * 2, width);

        if (Vector3.Distance(lastPointPosition, tip.position) > minPositionDelta || Time.unscaledTime > lastPointAddedTime + maxTimeDelta)
        {
            // Spawn a new point
            lastPointAddedTime = Time.unscaledTime;
            lastPointPosition = tip.position;
            line.positionCount += 1;
            line.SetPosition(line.positionCount - 1, lastPointPosition);
        }
        yield return null;
    }
}

Para usar el color seleccionado actualmente en la interfaz de usuario de la rueda del selector de colores, BrushController debe tener una referencia al objeto ColorPickerWheel . Dado que se crea una instancia del objeto prefabricado BrushController en tiempo de ejecución como controlador de reemplazo, las referencias a objetos de la escena tendrán que establecerse en tiempo de ejecución. En este caso, usamos GameObject.FindObjectOfType para buscar colorPickerWheel:

private void OnEnable()
{
    // Locate the ColorPickerWheel
    colorPicker = FindObjectOfType<ColorPickerWheel>();

    // Assign currently selected color to the brush’s material color
    brushRenderer.material.color = colorPicker.SelectedColor;
    ...
}
  • Guarde la escena y haga clic en el botón Reproducir . Podrá dibujar las líneas y pintar con el botón seleccionar del controlador derecho.

Capítulo 6: Creación de objetos con Seleccionar entrada

Objetivos

  • Obtenga información sobre cómo usar los eventos de entrada de botón Seleccionar y Comprender
  • Obtenga información sobre cómo crear instancias de objetos

Instrucciones

  • En el panel Proyecto , escriba ObjectSpawner en el cuadro de búsqueda. También puede encontrarlo en Activos/AppPrefabs/

  • Arrastre el objeto prefabricado ObjectSpawner al panel Jerarquía .

  • Haga clic en ObjectSpawner en el panel Jerarquía .

  • ObjectSpawner tiene un campo denominado Color Source.

  • En el panel Jerarquía , arrastre la referencia ColorPickerWheel a este campo.

    Inspector del generador de objetos

  • Haga clic en el objeto prefabricado ObjectSpawner en el panel Jerarquía .

  • En el panel Inspector , haga doble clic en ObjectSpawner Script para ver el código en Visual Studio.

Script ObjectSpawner

ObjectSpawner crea una instancia de copias de una malla primitiva (cubo, esfera, cilindro) en el espacio. Cuando se detecta interactionSourcePressed , comprueba la entrega y si se trata de un evento InteractionSourcePressType.Grasp o InteractionSourcePressType.Select .

Para un evento Grasp , incrementa el índice del tipo de malla actual (esfera, cubo, cilindro)

private void InteractionSourcePressed(InteractionSourcePressedEventArgs obj)
{
    // Check handedness, see if it is left controller
    if (obj.state.source.handedness == handedness)
    {
        switch (obj.pressType)
        {
            // If it is Select button event, spawn object
            case InteractionSourcePressType.Select:
                if (state == StateEnum.Idle)
                {
                    // We've pressed the grasp - enter spawning state
                    state = StateEnum.Spawning;
                    SpawnObject();
                }
                break;

            // If it is Grasp button event
            case InteractionSourcePressType.Grasp:

                // Increment the index of current mesh type (sphere, cube, cylinder)
                meshIndex++;
                if (meshIndex >= NumAvailableMeshes)
                {
                    meshIndex = 0;
                }
                break;

            default:
                break;
        }
    }
}

En el caso de un evento Select , en SpawnObject(), se crea una instancia de un nuevo objeto, no primario y se libera en el mundo.

private void SpawnObject()
{
    // Instantiate the spawned object
    GameObject newObject = Instantiate(displayObject.gameObject, spawnParent);
    // Detach the newly spawned object
    newObject.transform.parent = null;
    // Reset the scale transform to 1
    scaleParent.localScale = Vector3.one;
    // Set its material color so its material gets instantiated
    newObject.GetComponent<Renderer>().material.color = colorSource.SelectedColor;
}

ObjectSpawner usa ColorPickerWheel para establecer el color del material del objeto de presentación. A los objetos generados se les asigna una instancia de este material para que conserven su color.

  • Guarde la escena y haga clic en el botón Reproducir .

Podrá cambiar los objetos con el botón Capturar y generar objetos con el botón Seleccionar.

Compilación e implementación de una aplicación en Mixed Reality Portal

  • En Unity, seleccione Configuración de compilación de archivos>.
  • Haga clic en Agregar escenas abiertas para agregar la escena actual a las escenas en compilación.
  • Haga clic en Generar.
  • Cree una nueva carpeta denominada "App".
  • Haga clic en la carpeta Aplicación .
  • Haga clic en Seleccionar carpeta.
  • Cuando haya terminado Unity, aparecerá una ventana de Explorador de archivos.
  • Abra la carpeta Aplicación .
  • Haga doble clic en El archivo de solución yourSceneName.sln de Visual Studio.
  • Con la barra de herramientas superior de Visual Studio, cambie el destino de Depurar a Release y de ARM a X64.
  • Haga clic en la flecha desplegable situada junto al botón Dispositivo y seleccione Equipo local.
  • Haga clic en Depurar-> Iniciar sin depurar en el menú o presione Ctrl + F5.

Ahora la aplicación está compilada e instalada en Mixed Reality Portal. Puede volver a iniciarlo a través del menú Inicio en Mixed Reality Portal.

Diseño avanzado: herramientas de pincel con diseño radial

MixedReality213 Main

En este capítulo, aprenderá a reemplazar el modelo de controlador de movimiento predeterminado por una colección de herramientas de pincel personalizada. Para su referencia, puede encontrar la escena completada MixedReality213Avanced en la carpeta Escenas .

Instrucciones

  • En el panel Proyecto , escriba BrushSelector en el cuadro de búsqueda . También puede encontrarlo en Activos/AppPrefabs/

  • Arrastre el objeto prefabricado BrushSelector al panel Jerarquía .

  • Para la organización, cree un GameObject vacío denominado Brushes

  • Arrastre los siguientes objetos prefabricados desde el panel Proyecto a Pinceles

    • Assets/AppPrefabs/BrushFat
    • Assets/AppPrefabs/BrushThin
    • Assets/AppPrefabs/Eraser
    • Assets/AppPrefabs/MarkerFat
    • Assets/AppPrefabs/MarkerThin
    • Assets/AppPrefabs/Pencil

    Pinceles

  • Haga clic en MotionControllers prefab en el panel Jerarquía .

  • En el panel Inspector, desactive Usar siempre el modelo derecho alternativo en el visualizador del controlador de movimiento.

  • En el panel Jerarquía, haga clic en BrushSelector.

  • BrushSelector tiene un campo denominado ColorPicker

  • En el panel Jerarquía , arrastre el campo ColorPickerWheel a ColorPicker en el panel Inspector .

    Asignar ColorPickerWheel al selector de pinceles

  • En el panel Jerarquía , en Objeto prefabricado BrushSelector , seleccione el objeto Menu .

  • En el panel Inspector , en el componente LineObjectCollection , abra la lista desplegable Matriz de objetos . Verá 6 ranuras vacías.

  • En el panel Jerarquía , arrastre cada uno de los objetos prefabricados primarios debajo del GameObject Brushes a estas ranuras en cualquier orden. (Asegúrese de que está arrastrando los objetos prefabricados desde la escena, no los objetos prefabricados de la carpeta del proyecto).

Selector de pinceles

Objeto prefabricado BrushSelector

Dado que BrushSelector hereda AttachToController, muestra las opciones De entrega y Elemento en el panel Inspector . Seleccionamos La posición derecha y apuntando para adjuntar herramientas de pincel al controlador de mano derecha con dirección hacia delante.

BrushSelector usa dos utilidades:

  • Elipse: se usa para generar puntos en el espacio a lo largo de una forma de elipse.
  • LineObjectCollection: distribuye objetos mediante los puntos generados por cualquier clase Line (por ejemplo, Ellipse). Esto es lo que usaremos para colocar nuestros pinceles a lo largo de la forma elipse.

Cuando se combinan, estas utilidades se pueden usar para crear un menú radial.

Script LineObjectCollection

LineObjectCollection tiene controles para el tamaño, la posición y la rotación de objetos distribuidos a lo largo de su línea. Esto es útil para crear menús radiales como el selector de pinceles. Para crear la apariencia de pinceles que se escalan verticalmente desde nada a medida que se acercan a la posición seleccionada del centro, la curva ObjectScale alcanza los picos en el centro y pulsa en los bordes.

Script BrushSelector

En el caso de BrushSelector, hemos elegido usar la animación de procedimientos. En primer lugar, los modelos de pincel se distribuyen en una elipse mediante el script LineObjectCollection . A continuación, cada pincel es responsable de mantener su posición en la mano del usuario en función de su valor DisplayMode , que cambia en función de la selección. Hemos elegido un enfoque de procedimiento debido a la alta probabilidad de que se interrumpan las transiciones de posición del pincel a medida que el usuario selecciona pinceles. Las animaciones Mecanim pueden controlar las interrupciones correctamente, pero tiende a ser más complicada que una simple operación lerp.

BrushSelector usa una combinación de ambos. Cuando se detecta la entrada del panel táctil, las opciones de pincel se vuelven visibles y se escalan verticalmente a lo largo del menú radial. Después de un período de tiempo de espera (que indica que el usuario ha realizado una selección), las opciones de pincel se vuelven a reducir verticalmente, dejando solo el pincel seleccionado.

Visualización de la entrada del panel táctil

Incluso en los casos en los que el modelo de controlador se ha reemplazado por completo, puede resultar útil mostrar la entrada en las entradas del modelo original. Esto ayuda a fundamentar las acciones del usuario en realidad. Para brushSelector hemos elegido hacer que el panel táctil sea brevemente visible cuando se recibe la entrada. Esto se hizo recuperando el elemento Touchpad del controlador, reemplazando su material por un material personalizado y aplicando un degradado al color del material basado en la última vez que se recibió la entrada del panel táctil.

protected override void OnAttachToController()
{
    // Turn off the default controller's renderers
    controller.SetRenderersVisible(false);

    // Get the touchpad and assign our custom material to it
    Transform touchpad;
    if (controller.TryGetElement(MotionControllerInfo.ControllerElementEnum.Touchpad, out touchpad))
    {
        touchpadRenderer = touchpad.GetComponentInChildren<MeshRenderer>();
        originalTouchpadMaterial = touchpadRenderer.material;
        touchpadRenderer.material = touchpadMaterial;
        touchpadRenderer.enabled = true;
    }

    // Subscribe to input now that we're parented under the controller
    InteractionManager.InteractionSourceUpdated += InteractionSourceUpdated;
}

private void Update()
{
    ...
    // Update our touchpad material
    Color glowColor = touchpadColor.Evaluate((Time.unscaledTime - touchpadTouchTime) / touchpadGlowLossTime);
    touchpadMaterial.SetColor("_EmissionColor", glowColor);
    touchpadMaterial.SetColor("_Color", glowColor);
    ...
}

Selección de herramientas de pincel con entrada táctil

Cuando el selector de pincel detecta la entrada presionada del panel táctil, comprueba la posición de la entrada para determinar si estaba a la izquierda o a la derecha.

Grosor del trazo con selectPressedAmount

En lugar del evento InteractionSourcePressType.Select en InteractionSourcePressed(), puede obtener el valor analógico de la cantidad presionada a través de selectPressedAmount. Este valor se puede recuperar en InteractionSourceUpdated().

private void InteractionSourceUpdated(InteractionSourceUpdatedEventArgs obj)
{
    if (obj.state.source.handedness == handedness)
    {
        if (obj.state.touchpadPressed)
        {
            // Check which side we clicked
            if (obj.state.touchpadPosition.x < 0)
            {
                currentAction = SwipeEnum.Left;
            }
            else
            {
                currentAction = SwipeEnum.Right;
            }

            // Ping the touchpad material so it gets bright
            touchpadTouchTime = Time.unscaledTime;
        }

        if (activeBrush != null)
        {
            // If the pressed amount is greater than our threshold, draw
            if (obj.state.selectPressedAmount >= selectPressedDrawThreshold)
            {
                activeBrush.Draw = true;
                activeBrush.Width = ProcessSelectPressedAmount(obj.state.selectPressedAmount);
            }
            else
            {
                // Otherwise, stop drawing
                activeBrush.Draw = false;
                selectPressedSmooth = 0f;
            }
        }
    }
}

Script del borrador

Borrador es un tipo especial de pincel que invalida la función DrawOverTime() del pincel base. Aunque Draw es true, el borrador comprueba si su punta se intersecta con los trazos de pincel existentes. Si es así, se agregan a una cola para reducirse y eliminarse.

Diseño avanzado: teletransporte y locomoción

Si desea permitir que el usuario se mueva por la escena con teletransporte mediante el stick digital, use MixedRealityCameraParent en lugar de MixedRealityCamera. También debe agregar InputManager y DefaultCursor. Dado que MixedRealityCameraParent ya incluye MotionControllers y Boundary como componentes secundarios, debe quitar motionControllers y entorno prefabricados existentes.

Instrucciones

  • En el panel Jerarquía, elimine MixedRealityCamera, Environment y MotionControllers.

  • En el panel Proyecto, busque y arrastre los siguientes objetos prefabricados al panel Jerarquía :

    • Assets/AppPrefabs/Input/Prefabs/MixedRealityCameraParent
    • Assets/AppPrefabs/Input/Prefabs/InputManager
    • Assets/AppPrefabs/Input/Prefabs/Cursor/DefaultCursor

    Mixed Reality cámara primaria

  • En el panel Jerarquía, haga clic en Administrador de entrada.

  • En el panel Inspector, desplácese hacia abajo hasta la sección Simple Single Pointer Selector (Selector de puntero único simple).

  • En el panel Jerarquía , arrastre DefaultCursor al campo Cursor .

    Asignación de DefaultCursor

  • Guarde la escena y haga clic en el botón Reproducir . Podrá usar el stick digital para girar a la izquierda/derecha o a la teletransporte.

Fin

¡Y eso es el final de este tutorial! Ha aprendido:

  • Cómo trabajar con modelos de controlador de movimiento en el modo de juego y el tiempo de ejecución de Unity.
  • Cómo usar diferentes tipos de eventos de botón y sus aplicaciones.
  • Cómo superponer elementos de la interfaz de usuario sobre el controlador o personalizarlos completamente.

Ya está listo para empezar a crear su propia experiencia inmersiva con controladores de movimiento.

Escenas completadas

  • En el panel Proyecto de Unity, haga clic en la carpeta Escenas .
  • Encontrará dos escenas de Unity MixedReality213 y MixedReality213Advanced.
    • MixedReality213: escena completada con un solo pincel
    • MixedReality213Avanced: escena completada con varios pinceles con el ejemplo de cantidad de presión del botón de selección

Consulte también