Realidad mixta y Azure (305): Funciones y almacenamientoMR and Azure 305: Functions and storage


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.The Mixed Reality Academy tutorials were designed with HoloLens (1st gen) and Mixed Reality Immersive Headsets in mind. Por lo tanto, creemos que es importante conservar estos tutoriales para los desarrolladores que sigan buscando instrucciones sobre el desarrollo para esos dispositivos.As such, we feel it is important to leave these tutorials in place for developers who are still looking for guidance in developing for those devices. Estos tutoriales no se actualizarán con los conjuntos de herramientas o las interacciones más recientes que se usan para HoloLens 2.These tutorials will not be updated with the latest toolsets or interactions being used for HoloLens 2. Se mantendrán para que sigan funcionando en los dispositivos compatibles.They will be maintained to continue working on the supported devices. Habrá una nueva serie de tutoriales que se publicarán en el futuro que mostrarán cómo desarrollar para HoloLens 2.There will be a new series of tutorials that will be posted in the future that will demonstrate how to develop for HoloLens 2. Este aviso se actualizará con un vínculo a esos tutoriales cuando se publiquen.This notice will be updated with a link to those tutorials when they are posted.


Inicio del producto final

En este curso, aprenderá a crear y usar Azure Functions y almacenar datos con un recurso Azure Storage, dentro de una aplicación de realidad mixta.In this course, you will learn how to create and use Azure Functions and store data with an Azure Storage resource, within a mixed reality application.

Azure Functions es un servicio de Microsoft, que permite a los desarrolladores ejecutar pequeños fragmentos de código, "funciones", en Azure.Azure Functions is a Microsoft service, which allows developers to run small pieces of code, 'functions', in Azure. Esto proporciona una manera de delegar el trabajo en la nube, en lugar de la aplicación local, que puede tener muchas ventajas.This provides a way to delegate work to the cloud, rather than your local application, which can have many benefits. Azure Functions admite varios lenguajes de desarrollo, incluidos C # , F # , Node.js, Java y php.Azure Functions supports several development languages, including C#, F#, Node.js, Java, and PHP. Para obtener más información, visite el artículo Azure Functions.For more information, visit the Azure Functions article.

Azure Storage es un servicio en la nube de Microsoft, que permite a los desarrolladores almacenar datos, con el seguro de que estará altamente disponible, seguro, duradero, escalable y redundante.Azure Storage is a Microsoft cloud service, which allows developers to store data, with the insurance that it will be highly available, secure, durable, scalable, and redundant. Esto significa que Microsoft administrará todo el mantenimiento y los problemas críticos.This means Microsoft will handle all maintenance, and critical problems for you. Para obtener más información, visite el artículo Azure Storage.For more information, visit the Azure Storage article.

Una vez finalizado este curso, tendrá una aplicación de auriculares con un casco de realidad mixta que podrá hacer lo siguiente:Having completed this course, you will have a mixed reality immersive headset application which will be able to do the following:

  1. Permite al usuario mirarse en una escena.Allow the user to gaze around a scene.
  2. Desencadenar la generación de objetos cuando el usuario mira en un "botón" 3D.Trigger the spawning of objects when the user gazes at a 3D 'button'.
  3. Los objetos generados serán elegidos por una función de Azure.The spawned objects will be chosen by an Azure Function.
  4. A medida que se genera cada objeto, la aplicación almacenará el tipo de objeto en un archivo de Azure, que se encuentra en Azure Storage.As each object is spawned, the application will store the object type in an Azure File, located in Azure Storage.
  5. Tras la carga por segunda vez, los datos del archivo de Azure se recuperarán y se usarán para reproducir las acciones de generación de la instancia anterior de la aplicación.Upon loading a second time, the Azure File data will be retrieved, and used to replay the spawning actions from the previous instance of the application.

En su aplicación, depende del modo en que va a integrar los resultados con el diseño.In your application, it is up to you as to how you will integrate the results with your design. Este curso está diseñado para enseñarle a integrar un servicio de Azure con su proyecto de Unity.This course is designed to teach you how to integrate an Azure Service with your Unity Project. Es su trabajo usar el conocimiento que obtiene de este curso para mejorar su aplicación de realidad mixta.It is your job to use the knowledge you gain from this course to enhance your mixed reality Application.

Compatibilidad con dispositivosDevice support

CursoCourse HoloLensHoloLens Cascos envolventesImmersive headsets
Realidad mixta y Azure (305): Funciones y almacenamientoMR and Azure 305: Functions and storage ✔️✔️ ✔️✔️

Nota

Aunque este curso se centra principalmente en los auriculares de Windows Mixed Reality inmersivo (VR), también puede aplicar lo que aprenda en este curso a Microsoft HoloLens.While this course primarily focuses on Windows Mixed Reality immersive (VR) headsets, you can also apply what you learn in this course to Microsoft HoloLens. A medida que siga con el curso, verá notas sobre cualquier cambio que deba usar para admitir HoloLens.As you follow along with the course, you will see notes on any changes you might need to employ to support HoloLens.

PrerrequisitosPrerequisites

Nota

Este tutorial está diseñado para desarrolladores que tienen experiencia básica con Unity y C#.This tutorial is designed for developers who have basic experience with Unity and C#. Tenga en cuenta también que los requisitos previos y las instrucciones escritas dentro de este documento representan lo que se ha probado y comprobado en el momento de la escritura (2018 de mayo).Please also be aware that the prerequisites and written instructions within this document represent what has been tested and verified at the time of writing (May 2018). Puede usar el software más reciente, como se indica en el artículo instalar las herramientas , aunque no se debe suponer que la información de este curso se ajusta perfectamente a lo que encontrará en el software más reciente que el que se indica a continuación.You are free to use the latest software, as listed within the install the tools article, though it should not be assumed that the information in this course will perfectly match what you'll find in newer software than what's listed below.

Se recomienda el siguiente hardware y software para este curso:We recommend the following hardware and software for this course:

Antes de empezarBefore you start

Para evitar que se produzcan problemas al compilar este proyecto, se recomienda encarecidamente que cree el proyecto mencionado en este tutorial en una carpeta raíz o cerca de la raíz (las rutas de acceso de carpeta largas pueden producir problemas en tiempo de compilación).To avoid encountering issues building this project, it is strongly suggested that you create the project mentioned in this tutorial in a root or near-root folder (long folder paths can cause issues at build-time).

Capítulo 1: Azure portalChapter 1 - The Azure Portal

Para usar el servicio Azure Storage, debe crear y configurar una cuenta de almacenamiento en el Azure portal.To use the Azure Storage Service, you will need to create and configure a Storage Account in the Azure portal.

  1. Inicie sesión en el portal de Azure.Log in to the Azure Portal.

    Nota

    Si aún no tiene una cuenta de Azure, tendrá que crear una.If you do not already have an Azure account, you will need to create one. Si sigue este tutorial en una situación de aula o de laboratorio, pregunte al instructor o a uno de los Proctors para obtener ayuda para configurar la nueva cuenta.If you are following this tutorial in a classroom or lab situation, ask your instructor or one of the proctors for help setting up your new account.

  2. Una vez que haya iniciado sesión, haga clic en nuevo en la esquina superior izquierda, busque la cuenta de almacenamiento y haga clic en entrar.Once you are logged in, click on New in the top left corner, and search for Storage account, and click Enter.

    búsqueda de Azure Storage

    Nota

    Es posible que la palabra nuevo se haya reemplazado por crear un recurso, en portales más recientes.The word New may have been replaced with Create a resource, in newer portals.

  3. La nueva página proporcionará una descripción del servicio de cuenta de Azure Storage .The new page will provide a description of the Azure Storage account service. En la parte inferior izquierda de este mensaje, seleccione el botón crear para crear una asociación con este servicio.At the bottom left of this prompt, select the Create button, to create an association with this service.

    crear servicio

  4. Una vez que haya hecho clic en crear:Once you have clicked on Create:

    1. Inserte un nombre para la cuenta. tenga en cuenta que este campo solo acepta números y letras minúsculas.Insert a Name for your account, be aware this field only accepts numbers, and lowercase letters.

    2. En modelo de implementación, seleccione Resource Manager.For Deployment model, select Resource manager.

    3. En tipo de cuenta, seleccione almacenamiento (uso general V1).For Account kind, select Storage (general purpose v1).

    4. Determine la Ubicación del grupo de recursos (si va a crear un nuevo grupo de recursos).Determine the Location for your resource group (if you are creating a new Resource Group). Idealmente, la ubicación estará en la región donde se ejecutará la aplicación.The location would ideally be in the region where the application would run. Algunos recursos de Azure solo están disponibles en determinadas regiones.Some Azure assets are only available in certain regions.

    5. En replicación , seleccione almacenamiento con redundancia geográfica con acceso de lectura (RA-grs).For Replication select Read-access-geo-redundant storage (RA-GRS).

    6. En Rendimiento, seleccione Estándar.For Performance, select Standard.

    7. Deje la transferencia segura requerida como deshabilitada.Leave Secure transfer required as Disabled.

    8. Seleccione una opción en Suscripción.Select a Subscription.

    9. Elija un grupo de recursos o cree uno nuevo.Choose a Resource Group or create a new one. Un grupo de recursos proporciona una manera de supervisar, controlar el acceso, aprovisionar y administrar la facturación de una colección de recursos de Azure.A resource group provides a way to monitor, control access, provision and manage billing for a collection of Azure assets. Se recomienda mantener todos los servicios de Azure asociados a un único proyecto (por ejemplo, estos laboratorios) en un grupo de recursos común).It is recommended to keep all the Azure services associated with a single project (e.g. such as these labs) under a common resource group).

      Si desea leer más información sobre los grupos de recursos de Azure, visite el artículo sobre el grupo de recursos.If you wish to read more about Azure Resource Groups, please visit the resource group article.

    10. También deberá confirmar que ha comprendido los términos y condiciones que se aplican a este servicio.You will also need to confirm that you have understood the Terms and Conditions applied to this Service.

    11. Seleccione Crear.Select Create.

      información del servicio de entrada

  5. Una vez que haya hecho clic en crear, tendrá que esperar a que se cree el servicio, lo que puede tardar un minuto.Once you have clicked on Create, you will have to wait for the service to be created, this might take a minute.

  6. Una vez que se crea la instancia de servicio, aparecerá una notificación en el portal.A notification will appear in the portal once the Service instance is created.

    nueva notificación en Azure portal

  7. Haga clic en las notificaciones para explorar la nueva instancia de servicio.Click on the notifications to explore your new Service instance.

    ir al recurso

  8. Haga clic en el botón ir a recurso de la notificación para explorar la nueva instancia de servicio.Click the Go to resource button in the notification to explore your new Service instance. Se le dirigirá a la nueva instancia de servicio de la cuenta de almacenamiento .You will be taken to your new Storage account service instance.

    Claves de acceso

  9. Haga clic en claves de acceso para mostrar los puntos de conexión de este servicio en la nube.Click Access keys, to reveal the endpoints for this cloud service. Use el Bloc de notas o similar para copiar una de las claves para usarla más adelante.Use Notepad or similar, to copy one of your keys for use later. Además, tenga en cuenta el valor de la cadena de conexión , ya que se usará en la clase AzureServices , que se creará más adelante.Also, note the Connection string value, as it will be used in the AzureServices class, which you will create later.

    copiar cadena de conexión

Capítulo 2: configuración de una función de AzureChapter 2 - Setting up an Azure Function

Ahora escribirá una función de Azure en el servicio de Azure.You will now write an Azure Function in the Azure Service.

Puede usar una función de Azure para hacer prácticamente todo lo que haría con una función clásica en el código, la diferencia es que cualquier aplicación que tenga credenciales para acceder a la cuenta de Azure puede tener acceso a esta función.You can use an Azure Function to do nearly anything that you would do with a classic function in your code, the difference being that this function can be accessed by any application that has credentials to access your Azure Account.

Para crear una función de Azure:To create an Azure Function:

  1. En Azure portal, haga clic en nuevo en la esquina superior izquierda y busque function App y haga clic en entrar.From your Azure Portal, click on New in the top left corner, and search for Function App, and click Enter.

    creación de una aplicación de función

    Nota

    Es posible que la palabra nuevo se haya reemplazado por crear un recurso, en portales más recientes.The word New may have been replaced with Create a resource, in newer portals.

  2. La nueva página proporcionará una descripción del servicio Azure function App .The new page will provide a description of the Azure Function App service. En la parte inferior izquierda de este mensaje, seleccione el botón crear para crear una asociación con este servicio.At the bottom left of this prompt, select the Create button, to create an association with this service.

    información de la aplicación de función

  3. Una vez que haya hecho clic en crear:Once you have clicked on Create:

    1. Proporcione un nombre de aplicación.Provide an App name. Aquí solo se pueden usar letras y números (en mayúsculas o minúsculas).Only letters and numbers can be used here (either upper or lower case is allowed).

    2. Seleccione su suscripción preferida.Select your preferred Subscription.

    3. Elija un grupo de recursos o cree uno nuevo.Choose a Resource Group or create a new one. Un grupo de recursos proporciona una manera de supervisar, controlar el acceso, aprovisionar y administrar la facturación de una colección de recursos de Azure.A resource group provides a way to monitor, control access, provision and manage billing for a collection of Azure assets. Se recomienda mantener todos los servicios de Azure asociados a un único proyecto (por ejemplo, estos laboratorios) en un grupo de recursos común).It is recommended to keep all the Azure services associated with a single project (e.g. such as these labs) under a common resource group).

      Si desea leer más información sobre los grupos de recursos de Azure, visite el artículo sobre el grupo de recursos.If you wish to read more about Azure Resource Groups, please visit the resource group article.

    4. Para este ejercicio, seleccione Windows como el sistema operativo elegido.For this exercise, select Windows as the chosen OS.

    5. Seleccione plan de consumo para el plan de hospedaje.Select Consumption Plan for the Hosting Plan.

    6. Determine la Ubicación del grupo de recursos (si va a crear un nuevo grupo de recursos).Determine the Location for your resource group (if you are creating a new Resource Group). Idealmente, la ubicación estará en la región donde se ejecutará la aplicación.The location would ideally be in the region where the application would run. Algunos recursos de Azure solo están disponibles en determinadas regiones.Some Azure assets are only available in certain regions. Para obtener un rendimiento óptimo, seleccione la misma región que la cuenta de almacenamiento.For optimal performance, select the same region as the storage account.

    7. En almacenamiento, seleccione usar existente y, a continuación, use el menú desplegable para buscar el almacenamiento creado anteriormente.For Storage, select Use existing, and then using the dropdown menu, find your previously created storage.

    8. Deje Application Insights desactivado para este ejercicio.Leave Application Insights off for this exercise.

      detalles de la aplicación de función de entrada

  4. Haga clic en el botón Crear.Click the Create button.

  5. Una vez que haya hecho clic en crear, tendrá que esperar a que se cree el servicio, lo que puede tardar un minuto.Once you have clicked on Create, you will have to wait for the service to be created, this might take a minute.

  6. Una vez que se crea la instancia de servicio, aparecerá una notificación en el portal.A notification will appear in the portal once the Service instance is created.

    nueva notificación de Azure portal

  7. Haga clic en las notificaciones para explorar la nueva instancia de servicio.Click on the notifications to explore your new Service instance.

    vaya a la aplicación de función de recursos

  8. Haga clic en el botón ir a recurso de la notificación para explorar la nueva instancia de servicio.Click the Go to resource button in the notification to explore your new Service instance. Se le dirigirá a la nueva instancia de servicio de function App .You will be taken to your new Function App service instance.

  9. En el panel de function App , mantenga el mouse sobre las funciones, que se encuentran dentro del panel de la izquierda y, a continuación, haga clic en el símbolo + (más) .On the Function App dashboard, hover your mouse over Functions, found within the panel on the left, and then click the + (plus) symbol.

    crear nueva función

  10. En la página siguiente, asegúrese de que se ha seleccionado webhook + API y, para elegir un idioma, seleccione CSharp, ya que este será el idioma usado para este tutorial.On the next page, ensure Webhook + API is selected, and for Choose a language, select CSharp, as this will be the language used for this tutorial. Por último, haga clic en el botón crear esta función .Lastly, click the Create this function button.

    seleccionar CSharp de webhook

  11. Debe ir a la página de códigos (Run. CSX); si no es así, haga clic en la función recién creada en la lista de funciones dentro del panel de la izquierda.You should be taken to the code page (run.csx), if not though, click on the newly created Function in the Functions list within the panel on the left.

    abrir nueva función

  12. Copie el código siguiente en la función.Copy the following code into your function. Esta función simplemente devolverá un entero aleatorio entre 0 y 2 cuando se llame a.This function will simply return a random integer between 0 and 2 when called. No se preocupe por el código existente, no dude en pegarlo encima de la parte superior.Do not worry about the existing code, feel free to paste over the top of it.

        using System.Net;
        using System.Threading.Tasks;
    
        public static int Run(CustomObject req, TraceWriter log)
        {
            Random rnd = new Random();
            int randomInt = rnd.Next(0, 3);
            return randomInt;
        }
    
        public class CustomObject
        {
            public String name {get; set;}
        }
    
  13. Seleccione Guardar.Select Save.

  14. El resultado debería ser similar a la imagen siguiente.The result should look like the image below.

  15. Haga clic en obtener la dirección URL de la función y tome nota del punto de conexión mostrado.Click on Get function URL and take note of the endpoint displayed. Tendrá que insertarlo en la clase AzureServices que creará más adelante en este curso.You will need to insert it into the AzureServices class that you will create later in this course.

    Obtener extremo de función

    Insertar extremo de función

Capítulo 3: configuración del proyecto de UnityChapter 3 - Setting up the Unity project

Lo siguiente es una configuración típica para desarrollar con la realidad mixta y, como tal, es una buena plantilla para otros proyectos.The following is a typical set up for developing with Mixed Reality, and as such, is a good template for other projects.

Configure y pruebe sus auriculares de la realidad mixta.Set up and test your mixed reality immersive headset.

Nota

No necesitará controladores de movimiento para este curso.You will not require Motion Controllers for this course. Si necesita ayuda para configurar el casco inmersivo, visite el artículo sobre laconfiguración de la realidad mixta.If you need support setting up the immersive headset, please visit the mixed reality set up article.

  1. Abra Unity y haga clic en nuevo.Open Unity and click New.

    Crear nuevo proyecto de Unity

  2. Ahora tendrá que proporcionar un nombre de proyecto de Unity.You will now need to provide a Unity Project name. Inserte MR_Azure_Functions.Insert MR_Azure_Functions. Asegúrese de que el tipo de proyecto está establecido en 3D.Make sure the project type is set to 3D. Establezca la Ubicación en algún lugar adecuado para usted (Recuerde que, más cerca de los directorios raíz es mejor).Set the Location to somewhere appropriate for you (remember, closer to root directories is better). A continuación, haga clic en crear proyecto.Then, click Create project.

    Asignar un nombre al nuevo proyecto de Unity

  3. Con Unity abierto, merece la pena comprobar que el Editor de scripts predeterminado está establecido en Visual Studio.With Unity open, it is worth checking the default Script Editor is set to Visual Studio. Vaya a Editar > preferencias y, a continuación, en la nueva ventana, vaya a herramientas externas.Go to Edit > Preferences and then from the new window, navigate to External Tools. Cambie el Editor de script externo a Visual Studio 2017.Change External Script Editor to Visual Studio 2017. Cierre la ventana preferencias .Close the Preferences window.

    establecer Visual Studio como editor de scripts

  4. A continuación, vaya File a > configuración de compilación de archivos y cambie la plataforma a plataforma universal de Windows, haciendo clic en el botón cambiar plataforma .Next, go to File > Build Settings and switch the platform to Universal Windows Platform, by clicking on the Switch Platform button.

    cambiar la plataforma a UWP

  5. Vaya a File > configuración de compilación de archivos y asegúrese de que:Go to File > Build Settings and make sure that:

    1. El dispositivo de destino se establece en cualquier dispositivo.Target Device is set to Any Device.

      Para Microsoft HoloLens, establezca el dispositivo de destino en hololens.For Microsoft HoloLens, set Target Device to HoloLens.

    2. El tipo de compilación se establece en D3DBuild Type is set to D3D

    3. SDK está establecido en la versión más reciente instaladaSDK is set to Latest installed

    4. La versión de Visual Studio está establecida en la más reciente instaladaVisual Studio Version is set to Latest installed

    5. Compilar y ejecutar está establecido en equipo localBuild and Run is set to Local Machine

    6. Guarde la escena y agréguela a la compilación.Save the scene and add it to the build.

      1. Para ello, seleccione Agregar escenas abiertas.Do this by selecting Add Open Scenes. Aparecerá una ventana de guardar.A save window will appear.

        agregar escenas abiertas

      2. Cree una nueva carpeta para este, y en cualquier momento, en el futuro, seleccione el botón nueva carpeta para crear una nueva carpeta, asígnele el nombre Scenes.Create a new folder for this, and any future, scene, then select the New folder button, to create a new folder, name it Scenes.

        crear carpeta de escenas

      3. Abra la carpeta Scenes recién creada y, a continuación, en el campo nombre de archivo: , escriba FunctionsScene y, a continuación, presione Guardar.Open your newly created Scenes folder, and then in the File name: text field, type FunctionsScene, then press Save.

        Escena de Save Functions

  6. El resto de la configuración, en la configuración de compilación, debe dejarse como predeterminada por ahora.The remaining settings, in Build Settings, should be left as default for now.

    Dejar la configuración de compilación predeterminada

  7. En la ventana configuración de compilación , haga clic en el botón Configuración del reproductor ; se abrirá el panel relacionado en el espacio donde se encuentra el Inspector .In the Build Settings window, click on the Player Settings button, this will open the related panel in the space where the Inspector is located.

    configuración del reproductor en el inspector

  8. En este panel, deben comprobarse algunas opciones de configuración:In this panel, a few settings need to be verified:

    1. En la pestaña otros valores :In the Other Settings tab:

      1. La versión de scripting en tiempo de ejecución debe ser Experimental (.net 4,6 equivalente), lo que desencadenará una necesidad de reiniciar el editor.Scripting Runtime Version should be Experimental (.NET 4.6 Equivalent), which will trigger a need to restart the Editor.
      2. El back-end de scripting debe ser .netScripting Backend should be .NET
      3. El nivel de compatibilidad de API debe ser .net 4,6API Compatibility Level should be .NET 4.6
    2. En la pestaña configuración de publicación , en capacidades, seleccione:Within the Publishing Settings tab, under Capabilities, check:

      • InternetClientInternetClient

        establecer capacidades

    3. Más abajo en el panel, en la configuración de XR (se encuentra debajo de configuración de publicación), tick Virtual Reality compatible, asegúrese de que se agrega el SDK de Windows Mixed Reality .Further down the panel, in XR Settings (found below Publishing Settings), tick Virtual Reality Supported, make sure the Windows Mixed Reality SDK is added.

      establecer la configuración de XR

  9. De nuevo en la configuración de compilación , los proyectos de C# de Unity ya no están atenuados; Marque la casilla situada junto a este.Back in Build Settings Unity C# Projects is no longer greyed out; tick the checkbox next to this.

    proyectos de c# de tick

  10. Cierre la ventana Build Settings (Configuración de compilación).Close the Build Settings window.

  11. Guarde la escena y el proyecto (archivo > Guardar escena/archivo > Guardar proyecto).Save your Scene and Project (FILE > SAVE SCENE / FILE > SAVE PROJECT).

Capítulo 4: configuración de la cámara principalChapter 4 - Setup Main Camera

Importante

Si desea omitir los componentes de configuración de Unity de este curso y continuar directamente en el código, no dude en Descargar este. unitypackage Toolse importarlo en el proyecto como un paquete personalizado.If you wish to skip the Unity Set up components of this course, and continue straight into code, feel free to download this .unitypackage, and import it into your project as a Custom Package. También contendrá los archivos DLL del siguiente capítulo.This will also contain the DLLs from the next Chapter. Después de la importación, continúe en el capítulo 7.After import, continue from Chapter 7.

  1. En el Panel jerarquía, encontrará un objeto denominado cámara principal, este objeto representa el punto de vista "principal" una vez que está "dentro" de la aplicación.In the Hierarchy Panel, you will find an object called Main Camera, this object represents your "head" point of view once you are "inside" your application.

  2. Con el panel de Unity delante de usted, seleccione la cámara principal GameObject.With the Unity Dashboard in front of you, select the Main Camera GameObject. Observará que el panel Inspector (generalmente situado a la derecha, dentro del panel) mostrará los distintos componentes de ese GameObject, con la transformación en la parte superior, la cámara y otros componentes.You will notice that the Inspector Panel (generally found to the right, within the Dashboard) will show the various components of that GameObject, with Transform at the top, followed by Camera, and some other components. Tendrá que restablecer la transformación de la cámara principal, de modo que esté colocada correctamente.You will need to reset the Transform of the Main Camera, so it is positioned correctly.

  3. Para ello, seleccione el icono de engranaje situado junto al componente de transformación de la cámara y seleccione restablecer.To do this, select the Gear icon next to the Camera's Transform component, and select Reset.

    restablecer transformación

  4. A continuación, actualice el componente de transformación para que tenga el siguiente aspecto:Then update the Transform component to look like:

    TRANSFORMACIÓN: POSICIÓNTRANSFORM - POSITION
    XX SY ZZ
    00 11 00
    TRANSFORMACIÓN-GIROTRANSFORM - ROTATION
    XX SY ZZ
    00 00 00
    TRANSFORMACIÓN DE ESCALATRANSFORM - SCALE
    XX SY ZZ
    11 11 11

    establecer transformación de cámara

Capítulo 5: configuración de la escena de UnityChapter 5 - Setting up the Unity scene

  1. Haga clic con el botón secundario en un área vacía del Panel de jerarquías, en objeto 3D, agregar un plano.Right-click in an empty area of the Hierarchy Panel, under 3D Object, add a Plane.

    crear nuevo plano

  2. Con el objeto de plano seleccionado, cambie los siguientes parámetros en el panel del inspector:With the Plane object selected, change the following parameters in the Inspector Panel:

    TRANSFORMACIÓN: POSICIÓNTRANSFORM - POSITION
    XX SY ZZ
    00 00 44
    TRANSFORMACIÓN DE ESCALATRANSFORM - SCALE
    XX SY ZZ
    1010 11 1010

    establecer la posición y la escala del plano

    vista de escena de plano

  3. Haga clic con el botón secundario en un área vacía del Panel jerarquía, en objeto 3D, agregar un cubo.Right-click in an empty area of the Hierarchy Panel, under 3D Object, add a Cube.

    1. Cambie el nombre del cubo a GazeButton (con el cubo seleccionado, presione ' F2 ').Rename the Cube to GazeButton (with the Cube selected, press 'F2').

    2. Cambie los parámetros siguientes en el panel Inspector:Change the following parameters in the Inspector Panel:

      TRANSFORMACIÓN: POSICIÓNTRANSFORM - POSITION
      XX SY ZZ
      00 33 55

      establecer transformación de botón de mira

      vista de escena de botón de mira

    3. Haga clic en el botón desplegable etiqueta y haga clic en Agregar etiqueta para abrir el panel Etiquetas & capas.Click on the Tag drop-down button and click on Add Tag to open the Tags & Layers Pane.

      Agregar nueva etiqueta

      seleccionar más

    4. Seleccione el botón + (más) y, en el campo nuevo nombre de etiqueta , escriba GazeButton y presione Guardar.Select the + (plus) button, and in the New Tag Name field, enter GazeButton, and press Save.

      nombre nueva etiqueta

    5. Haga clic en el objeto GazeButton en el Panel jerarquía y, en el panel Inspector, asigne la etiqueta GazeButton recién creada.Click on the GazeButton object in the Hierarchy Panel, and in the Inspector Panel, assign the newly created GazeButton tag.

      asignar botón de mira la nueva etiqueta

  4. Haga clic con el botón derecho en el objeto GazeButton , en el Panel jerarquía, y agregue un GameObject vacío (que se agregará como un objeto secundario ).Right-click on the GazeButton object, in the Hierarchy Panel, and add an Empty GameObject (which will be added as a child object).

  5. Seleccione el nuevo objeto y cambie su nombre a ShapeSpawnPoint.Select the new object and rename it ShapeSpawnPoint.

    1. Cambie los parámetros siguientes en el panel Inspector:Change the following parameters in the Inspector Panel:

      TRANSFORMACIÓN: POSICIÓNTRANSFORM - POSITION
      XX SY ZZ
      00 -1-1 00

      transformación actualizar punto de generación de forma

      vista de escena de punto de generación de formas

  6. A continuación, creará un objeto de texto 3D para proporcionar comentarios sobre el estado del servicio de Azure.Next you will create a 3D Text object to provide feedback on the status of the Azure service.

    Vuelva a hacer clic con el botón derecho en GazeButton en el panel jerarquía y agregue un objeto 3D de > texto 3D de objeto como elemento secundario.Right click on the GazeButton in the Hierarchy Panel again and add a 3D Object > 3D Text object as a child.

    crear nuevo objeto de texto 3D

  7. Cambie el nombre del objeto de texto 3D a AzureStatusText.Rename the 3D Text object to AzureStatusText.

  8. Cambie la transformación del objeto AzureStatusText de la siguiente manera:Change the AzureStatusText object Transform as follows:

    TRANSFORMACIÓN: POSICIÓNTRANSFORM - POSITION
    XX SY ZZ
    00 00 -0,6-0.6
    TRANSFORMACIÓN DE ESCALATRANSFORM - SCALE
    XX SY ZZ
    0,10.1 0,10.1 0,10.1

    Nota

    No se preocupe si parece estar fuera del centro, ya que se solucionará cuando se actualice el componente de malla de texto siguiente.Do not worry if it appears to be off-centre, as this will be fixed when the below Text Mesh component is updated.

  9. Cambie el componente de malla de texto para que coincida con el siguiente:Change the Text Mesh component to match the below:

    establecer componente de malla de texto

    Sugerencia

    El color seleccionado aquí es color Hex: 000000FF, aunque no dude en elegir el suyo propio, solo tiene que asegurarse de que es legible.The selected color here is Hex color: 000000FF, though feel free to choose your own, just ensure it is readable.

  10. La estructura del panel de jerarquías debería tener ahora el siguiente aspecto:Your Hierarchy Panel structure should now look like this:

    Malla de texto en la jerarquía

  11. La escena debe tener ahora el siguiente aspecto:Your scene should now look like this:

    Malla de texto en la vista de escenas

Capítulo 6: importar Azure Storage para UnityChapter 6 - Import Azure Storage for Unity

Usará Azure Storage para Unity (que a su vez usa el SDK de .net para Azure).You will be using Azure Storage for Unity (which itself leverages the .Net SDK for Azure). Puede leer más sobre esto en el artículo Azure Storage para Unity.You can read more about this at the Azure Storage for Unity article.

Actualmente hay un problema conocido en Unity que requiere que los complementos se vuelvan a configurar después de la importación.There is currently a known issue in Unity which requires plugins to be reconfigured after import. Estos pasos (4-7 en esta sección) ya no serán necesarios una vez resuelto el error.These steps (4 - 7 in this section) will no longer be required after the bug has been resolved.

Para importar el SDK en su propio proyecto, asegúrese de que ha descargado el ". unitypackage Tools" más reciente de github.To import the SDK into your own project, make sure you have downloaded the latest '.unitypackage' from GitHub. A continuación, haga lo siguiente:Then, do the following:

  1. Agregue el archivo . unitypackage Tools a Unity mediante la opción de menú de Assets > Import Package > paquete personalizado de importación de recursos.Add the .unitypackage file to Unity by using the Assets > Import Package > Custom Package menu option.

  2. En el cuadro importar paquete Unity que aparece, puede seleccionar todo en almacenamiento de Complementos > Storage.In the Import Unity Package box that pops up, you can select everything under Plugin > Storage. Desactive todo lo demás, ya que no es necesario para este curso.Uncheck everything else, as it is not needed for this course.

    importar a paquete

  3. Haga clic en el botón importar para agregar los elementos al proyecto.Click the Import button to add the items to your project.

  4. Vaya a la carpeta Storage en Complementos, en la vista proyecto, y seleccione solo los siguientes complementos:Go to the Storage folder under Plugins, in the Project view, and select the following plugins only:

    • Microsoft.Data.EdmMicrosoft.Data.Edm

    • Microsoft.Data.ODataMicrosoft.Data.OData

    • Microsoft.WindowsAzure.StorageMicrosoft.WindowsAzure.Storage

    • Newtonsoft.JsonNewtonsoft.Json

    • System.SpatialSystem.Spatial

      desactive cualquier plataforma

  5. Con estos complementos específicos seleccionados, desactive cualquier plataforma y desactive WSAPlayer y haga clic en aplicar.With these specific plugins selected, uncheck Any Platform and uncheck WSAPlayer then click Apply.

    aplicar dll de plataforma

    Nota

    Estamos marcando estos complementos concretos para usarlos solo en el editor de Unity.We are marking these particular plugins to only be used in the Unity Editor. Esto se debe a que hay diferentes versiones de los mismos complementos en la carpeta WSA que se usarán después de exportar el proyecto desde Unity.This is because there are different versions of the same plugins in the WSA folder that will be used after the project is exported from Unity.

  6. En la carpeta del complemento de almacenamiento , seleccione solo:In the Storage plugin folder, select only:

    • Microsoft.Data.Services.ClientMicrosoft.Data.Services.Client

      establecer no procesar para archivos dll

  7. Active la casilla no procesar en configuración de plataforma y haga clic en aplicar.Check the Don't Process box under Platform Settings and click Apply.

    no aplicar procesamiento

    Nota

    Estamos marcando este complemento como "no procesar" porque el parche de ensamblado de Unity tiene dificultades para procesar este complemento.We are marking this plugin "Don't process" because the Unity assembly patcher has difficulty processing this plugin. El complemento seguirá funcionando aunque no se haya procesado.The plugin will still work even though it is not processed.

Capítulo 7: creación de la clase AzureServicesChapter 7 - Create the AzureServices class

La primera clase que va a crear es la clase AzureServices .The first class you are going to create is the AzureServices class.

La clase AzureServices se encargará de:The AzureServices class will be responsible for:

  • Almacenamiento de las credenciales de la cuenta de Azure.Storing Azure Account credentials.

  • Llamar a la función App de Azure.Calling your Azure App Function.

  • La carga y descarga del archivo de datos en el almacenamiento en la nube de Azure.The upload and download of the data file in your Azure Cloud Storage.

Para crear esta clase:To create this Class:

  1. Haga clic con el botón derecho en la carpeta de recursos , que se encuentra en el panel Proyecto, crear > carpeta.Right-click in the Asset Folder, located in the Project Panel, Create > Folder. Asigne a la carpeta el nombre scripts.Name the folder Scripts.

    crear nueva carpeta

    carpeta de llamadas: scripts

  2. Haga doble clic en la carpeta que acaba de crear para abrirla.Double click on the folder just created, to open it.

  3. Haga clic con el botón derecho en la carpeta, cree un > script de C#.Right-click inside the folder, Create > C# Script. Llame al script AzureServices.Call the script AzureServices.

  4. Haga doble clic en la nueva clase AzureServices para abrirla con Visual Studio.Double click on the new AzureServices class to open it with Visual Studio.

  5. Agregue los siguientes espacios de nombres en la parte superior de AzureServices:Add the following namespaces to the top of the AzureServices:

        using System;
        using System.Threading.Tasks;
        using UnityEngine;
        using Microsoft.WindowsAzure.Storage;
        using Microsoft.WindowsAzure.Storage.File;
        using System.IO;
        using System.Net;
    
  6. Agregue los siguientes campos de inspector dentro de la clase AzureServices :Add the following Inspector Fields inside the AzureServices class:

        /// <summary>
        /// Provides Singleton-like behavior to this class.
        /// </summary>
        public static AzureServices instance;
    
        /// <summary>
        /// Reference Target for AzureStatusText Text Mesh object
        /// </summary>
        public TextMesh azureStatusText;
    
  7. A continuación, agregue las siguientes variables de miembro dentro de la clase AzureServices :Then add the following member variables inside the AzureServices class:

        /// <summary>
        /// Holds the Azure Function endpoint - Insert your Azure Function
        /// Connection String here.
        /// </summary>
    
        private readonly string azureFunctionEndpoint = "--Insert here you AzureFunction Endpoint--";
    
        /// <summary>
        /// Holds the Storage Connection String - Insert your Azure Storage
        /// Connection String here.
        /// </summary>
        private readonly string storageConnectionString = "--Insert here you AzureStorage Connection String--";
    
        /// <summary>
        /// Name of the Cloud Share - Hosts directories.
        /// </summary>
        private const string fileShare = "fileshare";
    
        /// <summary>
        /// Name of a Directory within the Share
        /// </summary>
        private const string storageDirectory = "storagedirectory";
    
        /// <summary>
        /// The Cloud File
        /// </summary>
        private CloudFile shapeIndexCloudFile;
    
        /// <summary>
        /// The Linked Storage Account
        /// </summary>
        private CloudStorageAccount storageAccount;
    
        /// <summary>
        /// The Cloud Client
        /// </summary>
        private CloudFileClient fileClient;
    
        /// <summary>
        /// The Cloud Share - Hosts Directories
        /// </summary>
        private CloudFileShare share;
    
        /// <summary>
        /// The Directory in the share that will host the Cloud file
        /// </summary>
        private CloudFileDirectory dir;
    

    Importante

    Asegúrese de reemplazar los valores de punto de conexión y de cadena de conexión con los valores de Azure Storage, que se encuentran en Azure portal.Make sure you replace the endpoint and connection string values with the values from your Azure storage, found in the Azure Portal

  8. Ahora es necesario agregar el código para los métodos activo () e Inicio () .Code for Awake() and Start() methods now needs to be added. Se llamará a estos métodos cuando se inicialice la clase:These methods will be called when the class initializes:

        private void Awake()
        {
            instance = this;
        }
    
        // Use this for initialization
        private void Start()
        {
            // Set the Status text to loading, whilst attempting connection to Azure.
            azureStatusText.text = "Loading...";
        }
    
        /// <summary>
        /// Call to the Azure Function App to request a Shape.
        /// </summary>
        public async void CallAzureFunctionForNextShape()
        {
    
        }
    

    Importante

    En un capítulo futuro, rellenaremos el código para CallAzureFunctionForNextShape () .We will fill in the code for CallAzureFunctionForNextShape() in a future Chapter.

  9. Elimine el método Update () , ya que esta clase no lo usará.Delete the Update() method since this class will not use it.

  10. Guarde los cambios en Visual Studio y vuelva a Unity.Save your changes in Visual Studio, and then return to Unity.

  11. Haga clic y arrastre la clase AzureServices desde la carpeta scripts hasta el objeto cámara principal en el Panel jerarquía.Click and drag the AzureServices class from the Scripts folder to the Main Camera object in the Hierarchy Panel.

  12. Seleccione la cámara principal, después arrastre el objeto secundario AzureStatusText de debajo del objeto GazeButton y colóquelo en el campo destino de referencia AzureStatusText , en el Inspector, para proporcionar la referencia al script AzureServices .Select the Main Camera, then grab the AzureStatusText child object from beneath the GazeButton object, and place it within the AzureStatusText reference target field, in the Inspector, to provide the reference to the AzureServices script.

    asignar destino de referencia de texto de estado de Azure

Capítulo 8: creación de la clase ShapeFactoryChapter 8 - Create the ShapeFactory class

El siguiente script que se va a crear es la clase ShapeFactory .The next script to create, is the ShapeFactory class. El rol de esta clase es crear una nueva forma, cuando se solicita, y mantener un historial de las formas creadas en una lista de historial de formas.The role of this class is to create a new shape, when requested, and keep a history of the shapes created in a Shape History List. Cada vez que se crea una forma, se actualiza la lista de historial de formas en la clase AzureService y, a continuación, se almacena en el Azure Storage.Every time a shape is created, the Shape History list is updated in the AzureService class, and then stored in your Azure Storage. Cuando se inicia la aplicación, si se encuentra un archivo almacenado en el Azure Storage, se recupera y se vuelve a reproducir la lista de historial de formas , con el objeto de texto 3D que proporciona si la forma generada es de almacenamiento o nueva.When the application starts, if a stored file is found in your Azure Storage, the Shape History list is retrieved and replayed, with the 3D Text object providing whether the generated shape is from storage, or new.

Para crear esta clase:To create this class:

  1. Vaya a la carpeta scripts que creó anteriormente.Go to the Scripts folder you created previously.

  2. Haga clic con el botón derecho en la carpeta, cree un > script de C#.Right-click inside the folder, Create > C# Script. Llame al script ShapeFactory.Call the script ShapeFactory.

  3. Haga doble clic en el nuevo script ShapeFactory para abrirlo con Visual Studio.Double click on the new ShapeFactory script to open it with Visual Studio.

  4. Asegúrese de que la clase ShapeFactory incluye los siguientes espacios de nombres:Ensure the ShapeFactory class includes the following namespaces:

        using System.Collections.Generic;
        using UnityEngine;
    
  5. Agregue las variables que se muestran a continuación a la clase ShapeFactory y reemplace las funciones Start () y Activate () con las siguientes:Add the variables shown below to the ShapeFactory class, and replace the Start() and Awake() functions with those below:

        /// <summary>
        /// Provide this class Singleton-like behaviour
        /// </summary>
        [HideInInspector]
        public static ShapeFactory instance;
    
        /// <summary>
        /// Provides an Inspector exposed reference to ShapeSpawnPoint
        /// </summary>
        [SerializeField]
        public Transform spawnPoint;
    
        /// <summary>
        /// Shape History Index
        /// </summary>
        [HideInInspector]
        public List<int> shapeHistoryList;
    
        /// <summary>
        /// Shapes Enum for selecting required shape
        /// </summary>
        private enum Shapes { Cube, Sphere, Cylinder }
    
        private void Awake()
        {
            instance = this;
        }
    
        private void Start()
        {
            shapeHistoryList = new List<int>();
        }
    
  6. El método CreateShape () genera las formas primitivas, basándose en el parámetro de entero proporcionado.The CreateShape() method generates the primitive shapes, based upon the provided integer parameter. El parámetro booleano se usa para especificar si la forma creada actualmente es de almacenamiento o nueva.The Boolean parameter is used to specify whether the currently created shape is from storage, or new. Coloque el código siguiente en la clase ShapeFactory , debajo de los métodos anteriores:Place the following code in your ShapeFactory class, below the previous methods:

        /// <summary>
        /// Use the Shape Enum to spawn a new Primitive object in the scene
        /// </summary>
        /// <param name="shape">Enumerator Number for Shape</param>
        /// <param name="storageShape">Provides whether this is new or old</param>
        internal void CreateShape(int shape, bool storageSpace)
        {
            Shapes primitive = (Shapes)shape;
            GameObject newObject = null;
            string shapeText = storageSpace == true ? "Storage: " : "New: ";
    
            AzureServices.instance.azureStatusText.text = string.Format("{0}{1}", shapeText, primitive.ToString());
    
            switch (primitive)
            {
                case Shapes.Cube:
                newObject = GameObject.CreatePrimitive(PrimitiveType.Cube);
                break;
    
                case Shapes.Sphere:
                newObject = GameObject.CreatePrimitive(PrimitiveType.Sphere);
                break;
    
                case Shapes.Cylinder:
                newObject = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
                break;
            }
    
            if (newObject != null)
            {
                newObject.transform.position = spawnPoint.position;
    
                newObject.transform.localScale = new Vector3(0.5f, 0.5f, 0.5f);
    
                newObject.AddComponent<Rigidbody>().useGravity = true;
    
                newObject.GetComponent<Renderer>().material.color = UnityEngine.Random.ColorHSV(0f, 1f, 1f, 1f, 0.5f, 1f);
            }
        }
    
  7. Asegúrese de guardar los cambios en Visual Studio antes de volver a Unity.Be sure to save your changes in Visual Studio before returning to Unity.

  8. De nuevo en el editor de Unity, haga clic y arrastre la clase ShapeFactory desde la carpeta scripts hasta el objeto cámara principal en el Panel jerarquía.Back in the Unity Editor, click and drag the ShapeFactory class from the Scripts folder to the Main Camera object in the Hierarchy Panel.

  9. Con la cámara principal seleccionada, observará que en el componente de script ShapeFactory falta la referencia de punto de generación .With the Main Camera selected you will notice the ShapeFactory script component is missing the Spawn Point reference. Para corregirlo, arrastre el objeto ShapeSpawnPoint desde el Panel jerarquía hasta el destino de referencia de punto de generación .To fix it, drag the ShapeSpawnPoint object from the Hierarchy Panel to the Spawn Point reference target.

    establecer destino de referencia de generador de formas

Capítulo 9: creación de la clase fijamenteChapter 9 - Create the Gaze class

El último script que necesita crear es la clase mira .The last script you need to create is the Gaze class.

Esta clase es responsable de crear un Raycast que se proyectará hacia delante desde la cámara principal, para detectar qué objeto está examinando el usuario.This class is responsible for creating a Raycast that will be projected forward from the Main Camera, to detect which object the user is looking at. En este caso, Raycast deberá identificar si el usuario mira el objeto GazeButton en la escena y desencadena un comportamiento.In this case, the Raycast will need to identify if the user is looking at the GazeButton object in the scene and trigger a behavior.

Para crear esta clase:To create this Class:

  1. Vaya a la carpeta scripts que creó anteriormente.Go to the Scripts folder you created previously.

  2. Haga clic con el botón derecho en el panel Proyecto y cree un > script de C#.Right-click in the Project Panel, Create > C# Script. Llame al script fijamente.Call the script Gaze.

  3. Haga doble clic en el nuevo script de miraciones para abrirlo con Visual Studio.Double click on the new Gaze script to open it with Visual Studio.

  4. Asegúrese de que el siguiente espacio de nombres se incluye en la parte superior del script:Ensure the following namespace is included at the top of the script:

        using UnityEngine;
    
  5. Después, agregue las siguientes variables dentro de la clase mirate :Then add the following variables inside the Gaze class:

        /// <summary>
        /// Provides Singleton-like behavior to this class.
        /// </summary>
        public static Gaze instance;
    
        /// <summary>
        /// The Tag which the Gaze will use to interact with objects. Can also be set in editor.
        /// </summary>
        public string InteractibleTag = "GazeButton";
    
        /// <summary>
        /// The layer which will be detected by the Gaze ('~0' equals everything).
        /// </summary>
        public LayerMask LayerMask = ~0;
    
        /// <summary>
        /// The Max Distance the gaze should travel, if it has not hit anything.
        /// </summary>
        public float GazeMaxDistance = 300;
    
        /// <summary>
        /// The size of the cursor, which will be created.
        /// </summary>
        public Vector3 CursorSize = new Vector3(0.05f, 0.05f, 0.05f);
    
        /// <summary>
        /// The color of the cursor - can be set in editor.
        /// </summary>
        public Color CursorColour = Color.HSVToRGB(0.0223f, 0.7922f, 1.000f);
    
        /// <summary>
        /// Provides when the gaze is ready to start working (based upon whether
        /// Azure connects successfully).
        /// </summary>
        internal bool GazeEnabled = false;
    
        /// <summary>
        /// The currently focused object.
        /// </summary>
        internal GameObject FocusedObject { get; private set; }
    
        /// <summary>
        /// The object which was last focused on.
        /// </summary>
        internal GameObject _oldFocusedObject { get; private set; }
    
        /// <summary>
        /// The info taken from the last hit.
        /// </summary>
        internal RaycastHit HitInfo { get; private set; }
    
        /// <summary>
        /// The cursor object.
        /// </summary>
        internal GameObject Cursor { get; private set; }
    
        /// <summary>
        /// Provides whether the raycast has hit something.
        /// </summary>
        internal bool Hit { get; private set; }
    
        /// <summary>
        /// This will store the position which the ray last hit.
        /// </summary>
        internal Vector3 Position { get; private set; }
    
        /// <summary>
        /// This will store the normal, of the ray from its last hit.
        /// </summary>
        internal Vector3 Normal { get; private set; }
    
        /// <summary>
        /// The start point of the gaze ray cast.
        /// </summary>
        private Vector3 _gazeOrigin;
    
        /// <summary>
        /// The direction in which the gaze should be.
        /// </summary>
        private Vector3 _gazeDirection;
    

Importante

Algunas de estas variables se podrán editar en el Editor.Some of these variables will be able to be edited in the Editor.

  1. Ahora es necesario agregar el código para los métodos activo () e Inicio () .Code for the Awake() and Start() methods now needs to be added.

        /// <summary>
        /// The method used after initialization of the scene, though before Start().
        /// </summary>
        private void Awake()
        {
            // Set this class to behave similar to singleton
            instance = this;
        }
    
        /// <summary>
        /// Start method used upon initialization.
        /// </summary>
        private void Start()
        {
            FocusedObject = null;
            Cursor = CreateCursor();
        }
    
  2. Agregue el código siguiente, que creará un objeto cursor en el inicio, junto con el método Update () , que ejecutará el método Raycast, junto con el lugar donde se alterna el valor booleano GazeEnabled:Add the following code, which will create a cursor object at start, along with the Update() method, which will run the Raycast method, along with being where the GazeEnabled boolean is toggled:

        /// <summary>
        /// Method to create a cursor object.
        /// </summary>
        /// <returns></returns>
        private GameObject CreateCursor()
        {
            GameObject newCursor = GameObject.CreatePrimitive(PrimitiveType.Sphere);
            newCursor.SetActive(false);
    
            // Remove the collider, so it doesn't block raycast.
            Destroy(newCursor.GetComponent<SphereCollider>());
            newCursor.transform.localScale = CursorSize;
    
            newCursor.GetComponent<MeshRenderer>().material = new Material(Shader.Find("Diffuse"))
            {
                color = CursorColour
            };
    
            newCursor.name = "Cursor";
    
            newCursor.SetActive(true);
    
            return newCursor;
        }
    
        /// <summary>
        /// Called every frame
        /// </summary>
        private void Update()
        {
            if(GazeEnabled == true)
            {
                _gazeOrigin = Camera.main.transform.position;
    
                _gazeDirection = Camera.main.transform.forward;
    
                UpdateRaycast();
            }
        }
    
  3. A continuación, agregue el método UpdateRaycast () , que proyectará un Raycast y detectará el destino de la visita.Next add the UpdateRaycast() method, which will project a Raycast and detect the hit target.

        private void UpdateRaycast()
        {
            // Set the old focused gameobject.
            _oldFocusedObject = FocusedObject;
    
            RaycastHit hitInfo;
    
            // Initialise Raycasting.
            Hit = Physics.Raycast(_gazeOrigin,
                _gazeDirection,
                out hitInfo,
                GazeMaxDistance, LayerMask);
    
            HitInfo = hitInfo;
    
            // Check whether raycast has hit.
            if (Hit == true)
            {
                Position = hitInfo.point;
    
                Normal = hitInfo.normal;
    
                // Check whether the hit has a collider.
                if (hitInfo.collider != null)
                {
                    // Set the focused object with what the user just looked at.
                    FocusedObject = hitInfo.collider.gameObject;
                }
                else
                {
                    // Object looked on is not valid, set focused gameobject to null.
                    FocusedObject = null;
                }
            }
            else
            {
                // No object looked upon, set focused gameobject to null.
                FocusedObject = null;
    
                // Provide default position for cursor.
                Position = _gazeOrigin + (_gazeDirection * GazeMaxDistance);
    
                // Provide a default normal.
                Normal = _gazeDirection;
            }
    
            // Lerp the cursor to the given position, which helps to stabilize the gaze.
            Cursor.transform.position = Vector3.Lerp(Cursor.transform.position, Position, 0.6f);
    
            // Check whether the previous focused object is this same 
            //    object. If so, reset the focused object.
            if (FocusedObject != _oldFocusedObject)
            {
                ResetFocusedObject();
    
                if (FocusedObject != null)
                {
                if (FocusedObject.CompareTag(InteractibleTag.ToString()))
                {
                        // Set the Focused object to green - success!
                        FocusedObject.GetComponent<Renderer>().material.color = Color.green;
    
                        // Start the Azure Function, to provide the next shape!
                        AzureServices.instance.CallAzureFunctionForNextShape();
                    }
                }
            }
        }
    
  4. Por último, agregue el método ResetFocusedObject () , que cambiará el color actual de los objetos GazeButton, lo que indicará si está creando una nueva forma o no.Lastly, add the ResetFocusedObject() method, which will toggle the GazeButton objects current color, indicating whether it is creating a new shape or not.

        /// <summary>
        /// Reset the old focused object, stop the gaze timer, and send data if it
        /// is greater than one.
        /// </summary>
        private void ResetFocusedObject()
        {
            // Ensure the old focused object is not null.
            if (_oldFocusedObject != null)
            {
                if (_oldFocusedObject.CompareTag(InteractibleTag.ToString()))
                {
                    // Set the old focused object to red - its original state.
                    _oldFocusedObject.GetComponent<Renderer>().material.color = Color.red;
                }
            }
        }
    
  5. Guarde los cambios en Visual Studio antes de volver a Unity.Save your changes in Visual Studio before returning to Unity.

  6. Haga clic y arrastre la clase mira desde la carpeta scripts hasta el objeto cámara principal en el Panel jerarquía.Click and drag the Gaze class from the Scripts folder to the Main Camera object in the Hierarchy Panel.

Capítulo 10: completar la clase AzureServicesChapter 10 - Completing the AzureServices class

Con los demás scripts en su lugar, ahora es posible completar la clase AzureServices .With the other scripts in place, it is now possible to complete the AzureServices class. Esto se logra mediante:This will be achieved through:

  1. Agregar un nuevo método denominado CreateCloudIdentityAsync () para configurar las variables de autenticación necesarias para comunicarse con Azure.Adding a new method named CreateCloudIdentityAsync(), to set up the authentication variables needed for communicating with Azure.

    Este método también comprobará la existencia de un archivo previamente almacenado que contenga la lista de formas.This method will also check for the existence of a previously stored File containing the Shape List.

    Si se encuentra el archivo, se deshabilitará el usuario y se desencadenará la creación de la forma, según el patrón de formas, tal como se almacena en el archivo de Azure Storage.If the file is found, it will disable the user Gaze, and trigger Shape creation, according to the pattern of shapes, as stored in the Azure Storage file. El usuario puede ver esto, ya que la malla de texto proporcionará la pantalla "almacenamiento" o "nuevo", según el origen de las formas.The user can see this, as the Text Mesh will provide display 'Storage' or 'New', depending on the shapes origin.

    Si no se encuentra ningún archivo, se habilitará la mirada, lo que permite al usuario crear formas al mirar el objeto GazeButton de la escena.If no file is found, it will enable the Gaze, enabling the user to create shapes when looking at the GazeButton object in the scene.

        /// <summary>
        /// Create the references necessary to log into Azure
        /// </summary>
        private async void CreateCloudIdentityAsync()
        {
            // Retrieve storage account information from connection string
            storageAccount = CloudStorageAccount.Parse(storageConnectionString);
    
            // Create a file client for interacting with the file service.
            fileClient = storageAccount.CreateCloudFileClient();
    
            // Create a share for organizing files and directories within the storage account.
            share = fileClient.GetShareReference(fileShare);
    
            await share.CreateIfNotExistsAsync();
    
            // Get a reference to the root directory of the share.
            CloudFileDirectory root = share.GetRootDirectoryReference();
    
            // Create a directory under the root directory
            dir = root.GetDirectoryReference(storageDirectory);
    
            await dir.CreateIfNotExistsAsync();
    
            //Check if the there is a stored text file containing the list
            shapeIndexCloudFile = dir.GetFileReference("TextShapeFile");
    
            if (!await shapeIndexCloudFile.ExistsAsync())
            {
                // File not found, enable gaze for shapes creation
                Gaze.instance.GazeEnabled = true;
    
                azureStatusText.text = "No Shape\nFile!";
            }
            else
            {
                // The file has been found, disable gaze and get the list from the file
                Gaze.instance.GazeEnabled = false;
    
                azureStatusText.text = "Shape File\nFound!";
    
                await ReplicateListFromAzureAsync();
            }
        }
    
  2. El siguiente fragmento de código se encuentra dentro del método Start () ; donde se realizará una llamada al método CreateCloudIdentityAsync () .The next code snippet is from within the Start() method; wherein a call will be made to the CreateCloudIdentityAsync() method. No dude en copiar sobre el método Start () actual, con lo siguiente:Feel free to copy over your current Start() method, with the below:

        private void Start()
        {
            // Disable TLS cert checks only while in Unity Editor (until Unity adds support for TLS)
    #if UNITY_EDITOR
            ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
    #endif
    
            // Set the Status text to loading, whilst attempting connection to Azure.
            azureStatusText.text = "Loading...";
    
            //Creating the references necessary to log into Azure and check if the Storage Directory is empty
            CreateCloudIdentityAsync();
        }
    
  3. Rellene el código para el método CallAzureFunctionForNextShape ().Fill in the code for the method CallAzureFunctionForNextShape(). Usará el function App de Azure creado anteriormente para solicitar un índice de forma.You will use the previously created Azure Function App to request a shape index. Una vez recibida la nueva forma, este método enviará la forma a la clase ShapeFactory para crear la nueva forma en la escena.Once the new shape is received, this method will send the shape to the ShapeFactory class to create the new shape in the scene. Use el código siguiente para completar el cuerpo de CallAzureFunctionForNextShape ().Use the code below to complete the body of CallAzureFunctionForNextShape().

        /// <summary>
        /// Call to the Azure Function App to request a Shape.
        /// </summary>
        public async void CallAzureFunctionForNextShape()
        {
            int azureRandomInt = 0;
    
            // Call Azure function
            HttpWebRequest webRequest = WebRequest.CreateHttp(azureFunctionEndpoint);
    
            WebResponse response = await webRequest.GetResponseAsync();
    
            // Read response as string
            using (Stream stream = response.GetResponseStream())
            {
                StreamReader reader = new StreamReader(stream);
    
                String responseString = reader.ReadToEnd();
    
                //parse result as integer
                Int32.TryParse(responseString, out azureRandomInt);
            }
    
            //add random int from Azure to the ShapeIndexList
            ShapeFactory.instance.shapeHistoryList.Add(azureRandomInt);
    
            ShapeFactory.instance.CreateShape(azureRandomInt, false);
    
            //Save to Azure storage
            await UploadListToAzureAsync();
        }
    
  4. Agregue un método para crear una cadena mediante la concatenación de los enteros almacenados en la lista de historial de formas y guárdelo en el archivo de Azure Storage.Add a method to create a string, by concatenating the integers stored in the shape history list, and saving it in your Azure Storage File.

        /// <summary>
        /// Upload the locally stored List to Azure
        /// </summary>
        private async Task UploadListToAzureAsync()
        {
            // Uploading a local file to the directory created above
            string listToString = string.Join(",", ShapeFactory.instance.shapeHistoryList.ToArray());
    
            await shapeIndexCloudFile.UploadTextAsync(listToString);
        }
    
  5. Agregue un método para recuperar el texto almacenado en el archivo que se encuentra en el archivo de Azure Storage y deserializarlo en una lista.Add a method to retrieve the text stored in the file located in your Azure Storage File and deserialize it into a list.

  6. Una vez completado este proceso, el método vuelve a habilitar la mirada para que el usuario pueda agregar más formas a la escena.Once this process is completed, the method re-enables the gaze so that the user can add more shapes to the scene.

        ///<summary>
        /// Get the List stored in Azure and use the data retrieved to replicate 
        /// a Shape creation pattern
        ///</summary>
        private async Task ReplicateListFromAzureAsync()
        {
            string azureTextFileContent = await shapeIndexCloudFile.DownloadTextAsync();
    
            string[] shapes = azureTextFileContent.Split(new char[] { ',' });
    
            foreach (string shape in shapes)
            {
                int i;
    
                Int32.TryParse(shape.ToString(), out i);
    
                ShapeFactory.instance.shapeHistoryList.Add(i);
    
                ShapeFactory.instance.CreateShape(i, true);
    
                await Task.Delay(500);
            }
    
            Gaze.instance.GazeEnabled = true;
    
            azureStatusText.text = "Load Complete!";
        }
    
  7. Guarde los cambios en Visual Studio antes de volver a Unity.Save your changes in Visual Studio before returning to Unity.

Capítulo 11: compilar la solución UWPChapter 11 - Build the UWP Solution

Para comenzar el proceso de compilación:To begin the Build process:

  1. Vaya a archivos > configuración de compilación.Go to File > Build Settings.

    compilar la aplicación

  2. Haga clic en Generar.Click Build. Unity iniciará una ventana del Explorador de archivos , donde tendrá que crear y seleccionar una carpeta en la que compilar la aplicación.Unity will launch a File Explorer window, where you need to create and then select a folder to build the app into. Cree esa carpeta ahora y asígnele el nombre App.Create that folder now, and name it App. Después, con la carpeta de la aplicación seleccionada, presione Seleccionar carpeta.Then with the App folder selected, press Select Folder.

  3. Unity comenzará a compilar el proyecto en la carpeta de la aplicación .Unity will begin building your project to the App folder.

  4. Una vez que Unity termine de compilar (puede tardar algún tiempo), se abrirá una ventana del Explorador de archivos en la ubicación de la compilación (Compruebe la barra de tareas, ya que es posible que no aparezca siempre por encima de las ventanas, pero le notificará la adición de una nueva ventana).Once Unity has finished building (it might take some time), it will open a File Explorer window at the location of your build (check your task bar, as it may not always appear above your windows, but will notify you of the addition of a new window).

Capítulo 12: implementación de la aplicaciónChapter 12 - Deploying your application

Para implementar la aplicación:To deploy your application:

  1. Navegue hasta la carpeta de la aplicación que se creó en el último capítulo.Navigate to the App folder which was created in the last Chapter. Verá un archivo con el nombre de la aplicación, con la extensión '. sln ', en la que debe hacer doble clic para abrirlo en Visual Studio.You will see a file with your apps name, with the '.sln' extension, which you should double-click, so to open it within Visual Studio.

  2. En la plataforma de la solución, seleccione x86, equipo local.In the Solution Platform, select x86, Local Machine.

  3. En la configuración de soluciones , seleccione depurar.In the Solution Configuration select Debug.

    En el caso de Microsoft HoloLens, es posible que le resulte más fácil establecer esto en el equipo remoto, de modo que no esté anclado al equipo.For the Microsoft HoloLens, you may find it easier to set this to Remote Machine, so that you are not tethered to your computer. Sin embargo, también tendrá que hacer lo siguiente:Though, you will need to also do the following:

    • Conozca la dirección IP de HoloLens, que se encuentra en la red de configuración > & > Opciones avanzadas de Wi-Fi de Internet > Advanced Options; la IPv4 es la dirección que debe usar.Know the IP Address of your HoloLens, which can be found within the Settings > Network & Internet > Wi-Fi > Advanced Options; the IPv4 is the address you should use.
    • Asegurarse de que el modo de desarrollador está activado; se encuentra en configuración > Actualizar & seguridad > para los desarrolladores.Ensure Developer Mode is On; found in Settings > Update & Security > For developers.

    implementar solución

  4. Vaya al menú compilar y haga clic en implementar solución para transferir localmente la aplicación a la máquina.Go to the Build menu and click on Deploy Solution to sideload the application to your machine.

  5. La aplicación debe aparecer ahora en la lista de aplicaciones instaladas, lista para iniciarse y probarse.Your App should now appear in the list of installed apps, ready to be launched and tested!

La aplicación de almacenamiento y Azure Functions finalizadaYour finished Azure Functions and Storage Application

Enhorabuena, ha creado una aplicación de realidad mixta que aprovecha los servicios Azure Functions y Azure Storage.Congratulations, you built a mixed reality app that leverages both the Azure Functions and Azure Storage services. La aplicación podrá dibujar en datos almacenados y proporcionar una acción basada en esos datos.Your app will be able to draw on stored data, and provide an action based on that data.

final del producto final

Ejercicios extraBonus exercises

Ejercicio 1Exercise 1

Cree un segundo punto de generación y grabe el punto de generación a partir del que se creó un objeto.Create a second spawn point and record which spawn point an object was created from. Al cargar el archivo de datos, reproduzca las formas que se van a generar desde la ubicación en la que se crearon originalmente.When you load the data file, replay the shapes being spawned from the location they originally were created.

Ejercicio 2Exercise 2

Cree una manera de reiniciar la aplicación, en lugar de tener que volver a abrirla cada vez.Create a way to restart the app, rather than having to re-open it each time. La carga de escenas es un buen punto de partida.Loading Scenes is a good spot to start. Después de hacerlo, cree una manera de borrar la lista almacenada en Azure Storage, para que se pueda restablecer fácilmente desde la aplicación.After doing that, create a way to clear the stored list in Azure Storage, so that it can be easily reset from your app.