HoloLens (prima generazione) e Azure 305: Funzioni e archiviazione


Nota

Le esercitazioni di Mixed Reality Academy sono state progettate in base a HoloLens (prima generazione) e ai visori VR immersive di realtà mista. Pertanto, riteniamo importante lasciarle a disposizione degli sviluppatori a cui serve ancora materiale sussidiario per lo sviluppo di questi dispositivi. Queste esercitazioni non verranno aggiornate con i set di strumenti o le interazioni più recenti usati per HoloLens 2. Rimarranno invariate per consentire di continuare a lavorare sui dispositivi supportati. Saranno disponibili nuove serie di esercitazioni che verranno pubblicate in futuro che mostreranno come sviluppare per HoloLens 2. Questo avviso verrà aggiornato con un collegamento a tali esercitazioni quando vengono pubblicati.


prodotto finale -start

In questo corso si apprenderà come creare e usare Funzioni di Azure e archiviare i dati con una risorsa di archiviazione di Azure, all'interno di un'applicazione di realtà mista.

Funzioni di Azure è un servizio Microsoft, che consente agli sviluppatori di eseguire piccole parti di codice, "funzioni", in Azure. In questo modo è possibile delegare il lavoro al cloud, anziché all'applicazione locale, che può avere molti vantaggi. Funzioni di Azure supporta diversi linguaggi di sviluppo, tra cui C#, F#, Node.js, Java e PHP. Per altre informazioni, visitare l'articolo Funzioni di Azure.

Archiviazione di Azure è un servizio cloud Microsoft, che consente agli sviluppatori di archiviare i dati, con l'assicurazione che sarà a disponibilità elevata, sicura, durevole, scalabile e ridondante. Ciò significa che Microsoft gestirà tutte le operazioni di manutenzione e i problemi critici per l'utente. Per altre informazioni, vedere l'articolo Archiviazione di Azure.

Dopo aver completato questo corso, si avrà un'applicazione visore vr immersivo di realtà mista che sarà in grado di eseguire le operazioni seguenti:

  1. Consentire all'utente di guardare intorno a una scena.
  2. Attivare la generazione di oggetti quando l'utente guarda un "pulsante" 3D.
  3. Gli oggetti generati verranno scelti da una funzione di Azure.
  4. Poiché ogni oggetto viene generato, l'applicazione archivierà il tipo di oggetto in un file di Azure, situato in Archiviazione di Azure.
  5. Al caricamento di una seconda volta, i dati file di Azure verranno recuperati e usati per riprodurre le azioni di generazione dall'istanza precedente dell'applicazione.

Nell'applicazione è possibile integrare i risultati con la progettazione. Questo corso è progettato per insegnare come integrare un servizio di Azure con il progetto Unity. È il tuo lavoro per usare le conoscenze acquisite da questo corso per migliorare l'applicazione di realtà mista.

Supporto di dispositivi

Corso HoloLens Visori VR immersive
MR e Azure 305: Funzioni e archiviazione ✔️ ✔️

Nota

Anche se questo corso si concentra principalmente sulle visori vr (VR) immersivi Windows Mixed Reality, è anche possibile applicare ciò che si impara in questo corso per Microsoft HoloLens. Mentre segui il corso, vedrai note su eventuali modifiche che potresti dover usare per supportare HoloLens.

Prerequisiti

Nota

Questa esercitazione è progettata per gli sviluppatori che hanno esperienza di base con Unity e C#. Tenere presente anche che i prerequisiti e le istruzioni scritte all'interno di questo documento rappresentano ciò che è stato testato e verificato al momento della scrittura (maggio 2018). Si è liberi di usare il software più recente, come elencato all'interno dell'articolo degli strumenti , anche se non dovrebbe essere considerato che le informazioni in questo corso corrisponderanno perfettamente a ciò che troverete nel software più recente rispetto a quello elencato di seguito.

Per questo corso è consigliabile usare l'hardware e il software seguenti:

Prima di iniziare

Per evitare problemi durante la compilazione di questo progetto, è consigliabile creare il progetto menzionato in questa esercitazione in una cartella radice o quasi radice (i percorsi di cartelle lunghe possono causare problemi in fase di compilazione).

Capitolo 1 - Portale di Azure

Per usare il servizio di archiviazione di Azure, è necessario creare e configurare un account di archiviazione nel portale di Azure.

  1. Accedere al portale di Azure.

    Nota

    Se non si dispone già di un account Azure, sarà necessario crearne uno. Se si segue questa esercitazione in una classe o in una situazione del lab, chiedere all'insegnante o a uno dei proctor di configurare il nuovo account.

  2. Dopo aver eseguito l'accesso, fare clic su Nuovo nell'angolo superiore sinistro e cercare account di archiviazione e fare clic su Invio.

    ricerca di archiviazione di Azure

    Nota

    La parola New potrebbe essere stata sostituita con Crea una risorsa, nei portali più recenti.

  3. La nuova pagina fornisce una descrizione del servizio account di archiviazione di Azure . Nella parte inferiore sinistra del prompt selezionare il pulsante Crea per creare un'associazione con questo servizio.

    creare un servizio

  4. Dopo aver fatto clic su Crea:

    1. Inserire un nome per l'account, tenere presente che questo campo accetta solo numeri e lettere minuscole.

    2. Per Modello di distribuzione selezionare Gestione risorse.

    3. Per Tipo di account selezionare Archiviazione (utilizzo generico v1).

    4. Determinare la posizione per il gruppo di risorse ( se si sta creando un nuovo gruppo di risorse). La posizione si trova idealmente nell'area in cui l'applicazione verrà eseguita. Alcuni asset di Azure sono disponibili solo in determinate aree.

    5. Per Replica selezionare Archiviazione con ridondanza geografica di lettura (RA-GRS).

    6. Per Prestazioni selezionare Standard.

    7. Lasciare il trasferimento sicuro obbligatorio come Disabilitato.

    8. Selezionare una Sottoscrizione.

    9. Scegliere un gruppo di risorse o crearne uno nuovo. Un gruppo di risorse consente di monitorare, controllare l'accesso, il provisioning e gestire la fatturazione per una raccolta di asset di Azure. È consigliabile mantenere tutti i servizi di Azure associati a un singolo progetto (ad esempio questi lab) in un gruppo di risorse comune.

      Per altre informazioni sui gruppi di risorse di Azure, vedere l'articolo del gruppo di risorse.

    10. Dovrai anche confermare che hai capito le Condizioni e le condizioni applicate al servizio.

    11. Selezionare Crea.

      informazioni sul servizio di input

  5. Dopo aver fatto clic su Crea, è necessario attendere che il servizio venga creato, potrebbe richiedere un minuto.

  6. Una notifica verrà visualizzata nel portale dopo la creazione dell'istanza del servizio.

    nuova notifica nel portale di Azure

  7. Fare clic sulle notifiche per esplorare la nuova istanza del servizio.

    passare alla risorsa

  8. Fare clic sul pulsante Vai alla risorsa nella notifica per esplorare la nuova istanza del servizio. Verrà visualizzata la nuova istanza del servizio account di archiviazione .

    chiavi di accesso

  9. Fare clic su Chiavi di accesso per visualizzare gli endpoint per questo servizio cloud. Usare Blocco note o simile per copiare una delle chiavi da usare in un secondo momento. Si noti anche il valore della stringa di connessione , come verrà usato nella classe AzureServices , che verrà creata in seguito.

    copiare la stringa di connessione

Capitolo 2 - Configurazione di una funzione di Azure

Verrà ora scritta una funzione di Azure nel servizio di Azure.

È possibile usare una funzione di Azure per eseguire quasi tutte le operazioni eseguite con una funzione classica nel codice, la differenza è che questa funzione può essere accessibile da qualsiasi applicazione con credenziali per accedere all'account di Azure.

Per creare una funzione di Azure:

  1. Nel portale di Azure fare clic su Nuovo nell'angolo in alto a sinistra e cercare App per le funzioni e fare clic su Invio.

    creare un'app per le funzioni

    Nota

    La parola New potrebbe essere stata sostituita con Crea una risorsa, nei portali più recenti.

  2. La nuova pagina fornisce una descrizione del servizio app per le funzioni di Azure . Nella parte inferiore sinistra del prompt selezionare il pulsante Crea per creare un'associazione con questo servizio.

    informazioni sull'app per le funzioni

  3. Dopo aver fatto clic su Crea:

    1. Specificare un nome app. Solo lettere e numeri possono essere usati qui (è consentito il maiuscolo o minuscolo).

    2. Selezionare la sottoscrizione preferita.

    3. Scegliere un gruppo di risorse o crearne uno nuovo. Un gruppo di risorse consente di monitorare, controllare l'accesso, il provisioning e gestire la fatturazione per una raccolta di asset di Azure. È consigliabile mantenere tutti i servizi di Azure associati a un singolo progetto (ad esempio questi lab) in un gruppo di risorse comune.

      Per altre informazioni sui gruppi di risorse di Azure, vedere l'articolo del gruppo di risorse.

    4. Per questo esercizio selezionare Windows come sistema operativo scelto.

    5. Selezionare Piano di consumo per il piano di hosting.

    6. Determinare la posizione per il gruppo di risorse ( se si sta creando un nuovo gruppo di risorse). La posizione si trova idealmente nell'area in cui l'applicazione verrà eseguita. Alcuni asset di Azure sono disponibili solo in determinate aree. Per prestazioni ottimali, selezionare la stessa area dell'account di archiviazione.

    7. Per Archiviazione selezionare Usa esistente e quindi usando il menu a discesa, trovare l'archiviazione creata in precedenza.

    8. Lasciare Application Insights disattivato per questo esercizio.

      dettagli dell'app per le funzioni di input

  4. Fare clic sul pulsante Crea.

  5. Dopo aver fatto clic su Crea, è necessario attendere che il servizio venga creato, potrebbe richiedere un minuto.

  6. Una notifica verrà visualizzata nel portale dopo la creazione dell'istanza del servizio.

    nuova notifica del portale di Azure

  7. Fare clic sulle notifiche per esplorare la nuova istanza del servizio.

    passare all'app per le funzioni delle risorse

  8. Fare clic sul pulsante Vai alla risorsa nella notifica per esplorare la nuova istanza del servizio. Verrà visualizzata la nuova istanza del servizio app per le funzioni.

  9. Nel dashboard dell'app per le funzioni passare il mouse su Funzioni, trovato all'interno del pannello a sinistra e quindi fare clic sul simbolo + (più).

    creare una nuova funzione

  10. Nella pagina successiva assicurarsi che webhook + API sia selezionata e per Scegliere un linguaggio selezionare CSharp, come verrà usato per questa esercitazione. Infine, fare clic sul pulsante Crea questa funzione .

    Selezionare web hook csharp

  11. Si dovrebbe accedere alla tabella codici (run.csx), se non, fare clic sulla funzione appena creata nell'elenco Funzioni all'interno del pannello a sinistra.

    aprire una nuova funzione

  12. Copiare il codice seguente nella funzione. Questa funzione restituirà semplicemente un intero casuale compreso tra 0 e 2 quando viene chiamato. Non preoccuparsi del codice esistente, è possibile incollarlo sopra la parte superiore.

        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. Selezionare Salva.

  14. Il risultato dovrebbe essere simile all'immagine seguente.

  15. Fare clic su Recupera URL funzione e prendere nota dell'endpoint visualizzato. Sarà necessario inserirlo nella classe AzureServices che verrà creato più avanti in questo corso.

    Ottenere l'endpoint della funzione

    Inserire l'endpoint della funzione

Capitolo 3 - Configurazione del progetto Unity

Di seguito è riportata una configurazione tipica per lo sviluppo con Realtà mista e, di conseguenza, è un modello valido per altri progetti.

Configurare e testare il visore vr vr immersivo per la realtà mista.

Nota

Per questo corso non saranno necessari controller di movimento. Se è necessario supportare la configurazione del visore visore immersivo, visitare l'articolo sulla realtà mista.

  1. Aprire Unity e fare clic su Nuovo.

    Creare un nuovo progetto unity

  2. Sarà ora necessario specificare un nome di progetto Unity. Inserire MR_Azure_Functions. Assicurarsi che il tipo di progetto sia impostato su 3D. Impostare La posizione su un punto appropriato per l'utente (ricordarsi, più vicino alle directory radice è meglio). Fare quindi clic su Crea progetto.

    Assegnare un nuovo progetto unity a un nome

  3. Con Unity aperto, vale la pena verificare che l'editor di script predefinito sia impostato su Visual Studio. Passare a Modifica>preferenze e quindi dalla nuova finestra passare a Strumenti esterni. Modificare l'editor script esterno in Visual Studio 2017. Chiudere la finestra Preferenze .

    impostare Visual Studio come editor di script

  4. Passare quindi aImpostazioni di compilazionefile> e passare alla piattaforma in piattaforma UWP (Universal Windows Platform) facendo clic sul pulsante Cambia piattaforma.

    passare alla piattaforma uwp

  5. Passare aImpostazioni di compilazionefile> e assicurarsi che:

    1. Il dispositivo di destinazione è impostato su Qualsiasi dispositivo.

      Per Microsoft HoloLens impostare Dispositivo di destinazione su HoloLens.

    2. Il tipo di compilazione è impostato su D3D

    3. SDK è impostato su Più recente installato

    4. La versione di Visual Studio è impostata su Più recente installata

    5. Compilare ed eseguire è impostato su Computer locale

    6. Salvare la scena e aggiungerla alla compilazione.

      1. Eseguire questa operazione selezionando Aggiungi scene aperte. Verrà visualizzata una finestra di salvataggio.

        aggiungere scene aperte

      2. Creare una nuova cartella per questa e qualsiasi scena futura, quindi selezionare il pulsante Nuova cartella per creare una nuova cartella, denominarla Scene.

        creare una cartella scene

      3. Aprire la cartella Scene appena creata e quindi nel campo Nome file: testo, digitare FunctionsScene e quindi premere Salva.

        Salvare la scena delle funzioni

  6. Le impostazioni rimanenti, in Impostazioni di compilazione, devono essere lasciate come predefinite per il momento.

    Lasciare le impostazioni di compilazione predefinite

  7. Nella finestra Impostazioni di compilazione fare clic sul pulsante Impostazioni lettore , verrà aperto il pannello correlato nello spazio in cui si trova Il controllo .

    Impostazioni del lettore nel controllo

  8. In questo pannello è necessario verificare alcune impostazioni:

    1. Nella scheda Altre impostazioni :

      1. La versione del runtime di script deve essere sperimentale (equivalente.NET 4.6), che attiverà una necessità di riavviare l'editor.
      2. Scripting Back-end deve essere .NET
      3. Il livello di compatibilità api deve essere .NET 4.6
    2. Nella scheda Impostazioni di pubblicazione , in Funzionalità selezionare:

      • InternetClient

        set di funzionalità

    3. Più avanti nel pannello, in Impostazioni XR (trovate sotto Impostazioni di pubblicazione), selezionare Virtual Reality Supportato, assicurarsi che l'SDK di Windows Mixed Reality venga aggiunto.

      impostare le impostazioni XR

  9. In Build SettingsUnity C# Projects (Impostazioni di compilazione) I progetti C# non sono più disattivati; selezionare la casella di controllo accanto a questa.

    Tick c# projects (Progetti c#)

  10. Chiudere la finestra Build Settings (Impostazioni di compilazione).

  11. Salvare la scena e il progetto (FILE>SAVE SCENE /FILE>SAVE PROJECT).

Capitolo 4 - Configurare la fotocamera principale

Importante

Se si vuole ignorare i componenti di configurazione di Unity di questo corso e continuare direttamente nel codice, è possibile scaricare questo pacchetto unitypackage e importarlo nel progetto come pacchetto personalizzato. Questo conterrà anche le DLL del capitolo successivo. Dopo l'importazione, continuare dal capitolo 7.

  1. Nel pannello Hierarchy (Gerarchia) troverai un oggetto denominato Main Camera, che rappresenta il punto di vista "head" quando sei "all'interno" dell'applicazione.

  2. Con il dashboard di Unity, selezionare il GameObject della fotocamera principale. Si noterà che il Pannello di controllo (generalmente disponibile a destra, all'interno del dashboard) mostrerà i vari componenti di tale GameObject, con Transform nella parte superiore, seguito da Fotocamera e altri componenti. Sarà necessario reimpostare la trasformazione della fotocamera principale, in modo che sia posizionata correttamente.

  3. A tale scopo, selezionare l'icona a forma di ingranaggio accanto al componente Trasformazione della fotocamera e selezionare Reimposta.

    reimpostare la trasformazione

  4. Aggiornare quindi il componente Transform in modo che sia simile al seguente:

Trasforma - Posizione

X S Z
0 1 0

Trasforma - Rotazione

X S Z
0 0 0

Trasformazione - Ridimensionamento

X S Z
1 1 1

impostare la trasformazione della fotocamera

Capitolo 5 - Configurazione della scena unity

  1. Fare clic con il pulsante destro del mouse in un'area vuota del pannello Gerarchia, in Oggetto 3D, aggiungere un piano.

    creare un nuovo piano

  2. Con l'oggetto Plane selezionato, modificare i parametri seguenti nel Pannello di controllo:

Trasforma - Posizione

X S Z
0 0 4

Trasformazione - Ridimensionamento

X S Z
10 1 10

impostare la posizione e la scala del piano

visualizzazione scena del piano

  1. Fare clic con il pulsante destro del mouse in un'area vuota del pannello gerarchia, in Oggetto 3D, aggiungere un cubo.

    1. Rinominare il cubo in GazeButton (con il cubo selezionato, premere "F2").

    2. Modificare i parametri seguenti per Transform Position nel Pannello di controllo:

      X S Z
      0 3 5

      impostare la trasformazione del pulsante sguardo fisso

      visualizzazione scena pulsante sguardo fisso

    3. Fare clic sul pulsante a discesa Tag e fare clic su Aggiungi tag per aprire il riquadro Livelli tag&.

      aggiungere un nuovo tag

      selezionare più

    4. Selezionare il pulsante + (più) e nel campo Nuovo nome tag immettere GazeButton e premere Salva.

      nome nuovo tag

    5. Fare clic sull'oggetto GazeButton nel pannello gerarchia e nel Pannello di controllo assegnare il tag GazeButton appena creato.

      assegnare il pulsante dello sguardo fisso al nuovo tag

  2. Fare clic con il pulsante destro del mouse sull'oggetto GazeButton , nel Pannello gerarchia, e aggiungere un GameObject vuoto che verrà aggiunto come oggetto figlio .

  3. Selezionare il nuovo oggetto e rinominarlo ShapeSpawnPoint.

    1. Modificare i parametri seguenti per Transform Position nel Pannello di controllo:

      X S Z
      0 -1 0

      aggiornare la trasformazione del punto di generazione della forma

      visualizzazione scena punto di generazione forma

  4. Verrà quindi creato un oggetto Text 3D per fornire commenti e suggerimenti sullo stato del servizio di Azure.

    Fare di nuovo clic con il pulsante destro del mouse sul controllo GazeButton nel pannello della gerarchia e aggiungere un oggetto Text 3D Object>3D come elemento figlio.

    creare un nuovo oggetto di testo 3D

  5. Rinominare l'oggetto 3D Text in AzureStatusText.

  6. Modificare la posizione di trasformazione dell'oggetto AzureStatusText nel modo seguente:

    X S Z
    0 0 -0,6
  7. Modificare la scalabilità della trasformazione dell'oggetto AzureStatusText nel modo seguente: | X | Y | Z | | :---: | :---: | :---: | | 0.1 | 0.1 | 0.1 |

    Nota

    Non preoccuparti se sembra essere fuori centro, perché questo verrà risolto quando viene aggiornato il componente Text Mesh seguente.

  8. Modificare il componente Text Mesh in modo che corrisponda al seguente:

    impostare il componente mesh di testo

    Suggerimento

    Il colore selezionato qui è Hex color: 000000FF, anche se si è liberi di scegliere il proprio, solo assicurarsi che sia leggibile.

  9. La struttura del pannello gerarchia dovrebbe ora essere simile alla seguente:

    Mesh di testo nella gerarchia

  10. La scena dovrebbe ora essere simile alla seguente:

    Mesh di testo nella visualizzazione scena

Capitolo 6 - Importa archiviazione di Azure per Unity

Si userà Archiviazione di Azure per Unity (che sfrutta .Net SDK per Azure). Per altre informazioni, vedere l'articolo Archiviazione di Azure per Unity.

È attualmente presente un problema noto in Unity che richiede la riconfigurazione dei plug-in dopo l'importazione. Questi passaggi (4 - 7 in questa sezione) non saranno più necessari dopo che il bug è stato risolto.

Per importare l'SDK nel proprio progetto, assicurarsi di aver scaricato l'ultimo '.unitypackage' da GitHub. Procedere quindi come segue:

  1. Aggiungere il file unitypackage a Unity usando l'opzione> di menuAsset Importa pacchetto>personalizzato pacchetto.

  2. Nella casella Importa pacchetto Unity visualizzata è possibile selezionare tutto inArchiviazioneplug-in>. Deselezionare tutto il resto, perché non è necessario per questo corso.

    importare nel pacchetto

  3. Fare clic sul pulsante Importa per aggiungere gli elementi al progetto.

  4. Passare alla cartella Archiviazione in Plug-in, nella visualizzazione Progetto e selezionare solo i plug-in seguenti:

    • Microsoft.Data.Edm

    • Microsoft.Data.OData

    • Microsoft.WindowsAzure.Storage

    • Newtonsoft.Json

    • System.Spatial

      deselezionare Qualsiasi piattaforma

  5. Con questi plug-in specifici selezionati , deselezionareQualsiasi piattaforma e deselezionareWSAPlayer e quindi fare clic su Applica.

    applicare dll della piattaforma

    Nota

    Vengono contrassegnati questi plug-in specifici da usare solo nell'editor di Unity. Questo perché sono presenti versioni diverse dello stesso plug-in nella cartella WSA che verrà usata dopo l'esportazione del progetto da Unity.

  6. Nella cartella Plug-in di archiviazione selezionare solo:

    • Microsoft.Data.Services.Client

      set non elabora per le dll

  7. Selezionare la casella Non elaborare in Impostazioni piattaforma e fare clic su Applica.

    non applicare alcuna elaborazione

    Nota

    Si contrassegna questo plug-in "Non elaborare" perché l'assembly patcher unity ha difficoltà a elaborare questo plug-in. Il plug-in funzionerà comunque anche se non viene elaborato.

Capitolo 7 - Creare la classe AzureServices

La prima classe creata è la classe AzureServices .

La classe AzureServices sarà responsabile di:

  • Archiviazione delle credenziali dell'account di Azure.

  • Chiamata alla funzione app Azure.

  • Caricamento e download del file di dati nell'archiviazione cloud di Azure.

Per creare questa classe:

  1. Fare clic con il pulsante destro del mouse sulla cartella asset , disponibile nel pannello del progetto, Creare>cartella. Assegnare un nome alla cartella Script.

    creare una nuova cartella

    cartella di chiamata - script

  2. Fare doppio clic sulla cartella appena creata per aprirla.

  3. Fare clic con il pulsante destro del mouse all'interno della cartella, Creare>script C#. Chiamare lo script AzureServices.

  4. Fare doppio clic sulla nuova classe AzureServices per aprirla con Visual Studio.

  5. Aggiungere gli spazi dei nomi seguenti all'inizio di 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. Aggiungere i campi Di controllo seguenti all'interno della classe AzureServices :

        /// <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. Aggiungere quindi le variabili membro seguenti all'interno della classe AzureServices :

        /// <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

    Assicurarsi di sostituire i valori endpoint e stringa di connessione con i valori dell'archiviazione di Azure, trovati nel portale di Azure

  8. Il codice per i metodi Awake() e Start() deve ora essere aggiunto. Questi metodi verranno chiamati quando la classe inizializza:

        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

    Il codice per CallAzureFunctionForNextShape() verrà compilato in un capitolo futuro.

  9. Eliminare il metodo Update() perché questa classe non lo userà.

  10. Salvare le modifiche in Visual Studio e quindi tornare a Unity.

  11. Fare clic e trascinare la classe AzureServices dalla cartella Script all'oggetto Camera principale nel pannello gerarchia.

  12. Selezionare main camera, quindi afferrare l'oggetto figlio AzureStatusText sotto l'oggetto GazeButton e inserirlo nel campo di destinazione di riferimento AzureStatusText, nell'oggetto Inspector, per fornire il riferimento allo script AzureServices.

    assegnare la destinazione di riferimento al testo dello stato di Azure

Capitolo 8 - Creare la classe ShapeFactory

Lo script successivo da creare è la classe ShapeFactory . Il ruolo di questa classe consiste nel creare una nuova forma, quando richiesto e mantenere una cronologia delle forme create in un elenco cronologia forme. Ogni volta che viene creata una forma, l'elenco Cronologia forme viene aggiornato nella classe AzureService e quindi archiviato nell'archiviazione di Azure. All'avvio dell'applicazione, se viene trovato un file archiviato nell'archiviazione di Azure, l'elenco Cronologia forme viene recuperato e riprodotto, con l'oggetto Testo 3D che specifica se la forma generata proviene dall'archiviazione o da una nuova.

Per creare questa classe:

  1. Passare alla cartella Script creata in precedenza.

  2. Fare clic con il pulsante destro del mouse all'interno della cartella, Creare>script C#. Chiamare lo script ShapeFactory.

  3. Fare doppio clic sul nuovo script ShapeFactory per aprirlo con Visual Studio.

  4. Verificare che la classe ShapeFactory includa gli spazi dei nomi seguenti:

        using System.Collections.Generic;
        using UnityEngine;
    
  5. Aggiungere le variabili illustrate di seguito alla classe ShapeFactory e sostituire le funzioni Start() e Awake() con quelle seguenti:

        /// <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. Il metodo CreateShape() genera le forme primitive, in base al parametro integer specificato. Il parametro booleano viene usato per specificare se la forma attualmente creata è dall'archiviazione o nuova. Inserire il codice seguente nella classe ShapeFactory , sotto i metodi precedenti:

        /// <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. Assicurarsi di salvare le modifiche in Visual Studio prima di tornare a Unity.

  8. Nell'editor di Unity fare clic e trascinare la classe ShapeFactory dalla cartella Script all'oggetto Main Camera nel pannello gerarchia.

  9. Con la fotocamera principale selezionata si noterà che il componente script ShapeFactory manca il riferimento al punto spawn . Per correggerlo, trascinare l'oggetto ShapeSpawnPoint dal pannello gerarchia alla destinazione di riferimento spawn Point .

    Impostare la destinazione di riferimento di shape factory

Capitolo 9 - Creare la classe Gaze

L'ultimo script da creare è la classe Gaze .

Questa classe è responsabile della creazione di un raycast che verrà proiettato avanti dalla fotocamera principale, per rilevare l'oggetto a cui l'utente sta esaminando. In questo caso, raycast dovrà identificare se l'utente sta esaminando l'oggetto GazeButton nella scena e attivare un comportamento.

Per creare questa classe:

  1. Passare alla cartella Script creata in precedenza.

  2. Fare clic con il pulsante destro del mouse nel pannello di progetto, creare>script C#. Chiamare lo script Gaze.

  3. Fare doppio clic sul nuovo script Gaze per aprirlo con Visual Studio.

  4. Verificare che lo spazio dei nomi seguente sia incluso nella parte superiore dello script:

        using UnityEngine;
    
  5. Aggiungere quindi le variabili seguenti all'interno della classe Gaze :

        /// <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

Alcune di queste variabili potranno essere modificate nell'editor.

  1. È ora necessario aggiungere il codice per i metodi Awake() e Start( ).

        /// <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. Aggiungere il codice seguente, che creerà un oggetto cursore all'inizio, insieme al metodo Update(), che eseguirà il metodo Raycast, insieme alla posizione in cui viene attivato il valore booleano GazeEnabled:

        /// <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. Aggiungere quindi il metodo UpdateRaycast(), che proietta un Raycast e rileva la destinazione di hit.

        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. Infine, aggiungere il metodo ResetFocusedObject(), che attiva o disattiva il colore corrente degli oggetti GazeButton, che indica se sta creando una nuova forma o meno.

        /// <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. Salvare le modifiche in Visual Studio prima di tornare a Unity.

  6. Fare clic e trascinare la classe Gaze dalla cartella Scripts all'oggetto Main Camera nel Pannello gerarchia.

Capitolo 10 - Completamento della classe AzureServices

Con gli altri script sul posto, è ora possibile completare la classe AzureServices . Questa operazione verrà ottenuta tramite:

  1. Aggiunta di un nuovo metodo denominato CreateCloudIdentityAsync() per configurare le variabili di autenticazione necessarie per la comunicazione con Azure.

    Questo metodo verificherà anche l'esistenza di un file archiviato in precedenza contenente l'elenco forme.

    Se il file viene trovato, disabilita lo sguardo fisso dell'utente e attiva la creazione della forma, in base al modello di forme, come archiviato nel file di Archiviazione di Azure. L'utente può visualizzare questo valore, in quanto la mesh di testo fornirà la visualizzazione "Archiviazione" o "Nuovo", a seconda dell'origine delle forme.

    Se non viene trovato alcun file, abilita lo sguardo fisso, consentendo all'utente di creare forme quando si esamina l'oggetto GazeButton nella scena.

        /// <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. Il frammento di codice successivo proviene dal metodo Start(); in cui verrà effettuata una chiamata al metodo CreateCloudIdentityAsync(). È possibile copiare il metodo Start() corrente, con quanto segue:

        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. Compilare il codice per il metodo CallAzureFunctionForNextShape(). Si userà l'app per le funzioni di Azure creata in precedenza per richiedere un indice di forma. Una volta ricevuta la nuova forma, questo metodo invierà la forma alla classe ShapeFactory per creare la nuova forma nella scena. Usare il codice seguente per completare il corpo di 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. Aggiungere un metodo per creare una stringa, concatenando gli interi archiviati nell'elenco della cronologia delle forme e salvandolo nel file di archiviazione di Azure.

        /// <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. Aggiungere un metodo per recuperare il testo archiviato nel file che si trova nel file di archiviazione di Azure e deserializzare il testo in un elenco.

  6. Al termine di questo processo, il metodo riabilita lo sguardo fisso in modo che l'utente possa aggiungere altre forme alla scena.

        ///<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. Salvare le modifiche in Visual Studio prima di tornare a Unity.

Capitolo 11 - Creare la soluzione UWP

Per avviare il processo di compilazione:

  1. Passare aImpostazioni di compilazionefile>.

    compilare l'app

  2. Fare clic su Compila. Unity avvierà una finestra di Esplora file, in cui è necessario creare e quindi selezionare una cartella in cui compilare l'app. Creare la cartella e denominarla App. Quindi, con la cartella App selezionata, premere Seleziona cartella.

  3. Unity inizierà a compilare il progetto nella cartella App .

  4. Una volta completata la compilazione di Unity (potrebbe essere necessario del tempo), verrà aperta una finestra di Esplora file nella posizione della compilazione (controllare la barra delle applicazioni, perché potrebbe non essere sempre visualizzata sopra le finestre, ma invierà una notifica dell'aggiunta di una nuova finestra).

Capitolo 12 - Distribuzione dell'applicazione

Per distribuire l'applicazione:

  1. Passare alla cartella App creata nell'ultimo capitolo. Verrà visualizzato un file con il nome delle app, con l'estensione '.sln', che è necessario fare doppio clic, in modo da aprirlo all'interno di Visual Studio.

  2. Nella piattaforma della soluzione selezionare x86, Computer locale.

  3. In Configurazione soluzione selezionare Debug.

    Per la Microsoft HoloLens, è possibile che sia più semplice impostare questa opzione su Computer remoto, in modo che non si sia collegati al computer. Tuttavia, è necessario eseguire anche le operazioni seguenti:

    • Conoscere l'indirizzo IP del dispositivo HoloLens, disponibile all'interno di Impostazioni Impostazioni>&Opzioni avanzateWi-Fi> Internet>. IPv4 è l'indirizzo da usare.
    • Verificare che la modalità sviluppatore sia attivata; disponibile in Impostazioni>Aggiorna & sicurezza>per gli sviluppatori.

    distribuire la soluzione

  4. Passare al menu Compila e fare clic su Distribuisci soluzione per trasferire localmente l'applicazione nel computer.

  5. L'app dovrebbe ora essere visualizzata nell'elenco delle app installate, pronto per l'avvio e il test.

Applicazione di archiviazione e Funzioni di Azure completata

È stata creata un'app di realtà mista che sfrutta sia i servizi di archiviazione di Funzioni di Azure che di Archiviazione di Azure. L'app sarà in grado di disegnare sui dati archiviati e fornire un'azione basata su tali dati.

prodotto finale -end

Esercizi aggiuntivi

Esercizio 1

Creare un secondo punto di generazione e un secondo record da cui è stato creato un oggetto. Quando si carica il file di dati, riprodurre le forme create dal percorso originariamente creato.

Esercizio 2

Creare un modo per riavviare l'app, invece di riaprirla ogni volta. Caricamento delle scene è un buon punto per iniziare. Dopo aver eseguito questa operazione, creare un modo per cancellare l'elenco archiviato in Archiviazione di Azure, in modo che possa essere facilmente reimpostato dall'app.