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. Ci sarà una nuova serie di esercitazioni che verranno pubblicate in futuro che dimostreranno come sviluppare per HoloLens 2. Questo avviso verrà aggiornato con un collegamento a tali esercitazioni quando vengono pubblicate.
In questo corso si apprenderà come creare e usare Funzioni di Azure e archiviare i dati con una risorsa 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, vedere 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à tutti i problemi di manutenzione e critici per l'utente. Per altre informazioni, vedere l'articolo Archiviazione di Azure.
Dopo aver completato questo corso, si avrà un'applicazione visore VR immersive di realtà mista che sarà in grado di eseguire le operazioni seguenti:
- Consentire all'utente di guardare intorno a una scena.
- Attivare la generazione di oggetti quando l'utente guarda un pulsante 3D.
- Gli oggetti generati verranno scelti da una funzione di Azure.
- Quando ogni oggetto viene generato, l'applicazione archivierà il tipo di oggetto in un file di Azure, che si trova in Archiviazione di Azure.
- Al caricamento di una seconda volta, i dati di File di Azure verranno recuperati e usati per riprodurre le azioni di generazione dall'istanza precedente dell'applicazione.
Nell'applicazione spetta all'utente come integrare i risultati con la progettazione. Questo corso è progettato per illustrare come integrare un servizio di Azure con il progetto Unity. È il tuo compito 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 è incentrato principalmente sui visori VR immersive di Windows Realtà mista, puoi anche applicare ciò che impari in questo corso a Microsoft HoloLens. Mentre segui il corso, vedrai le 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). Sei libero di usare il software più recente, come elencato all'interno dell'articolo installare gli strumenti , anche se non si deve presumere che le informazioni in questo corso corrispondano perfettamente a ciò che troverai nel software più recente rispetto a quello elencato di seguito.
Per questo corso è consigliabile usare l'hardware e il software seguenti:
- Un PC di sviluppo, compatibile con Windows Realtà mista per lo sviluppo di visori VR immersive
- Windows 10 Fall Creators Update (o versione successiva) con la modalità sviluppatore abilitata
- La versione più recente di Windows 10 SDK
- Unity 2017.4
- Visual Studio 2017
- Visore VR immersive di Windows Realtà mista o Microsoft HoloLens con la modalità sviluppatore abilitata
- Una sottoscrizione a un account Azure per la creazione di risorse di Azure
- Accesso a Internet per la configurazione e il recupero dei dati di Azure
Prima di iniziare
Per evitare di riscontrare problemi durante la compilazione di questo progetto, è consigliabile creare il progetto menzionato in questa esercitazione in una cartella radice o quasi radice (i percorsi delle cartelle lunghe possono causare problemi in fase di compilazione).
Capitolo 1 - Portale di Azure
Per usare il servizio Archiviazione di Azure, è necessario creare e configurare un account di archiviazione nel portale di Azure.
Accedere al portale di Azure.
Nota
Se non si ha già un account Azure, è necessario crearne uno. Se si segue questa esercitazione in una classe o in una situazione di laboratorio, chiedere all'insegnante o a uno dei prottori di assistenza per configurare il nuovo account.
Dopo aver eseguito l'accesso, fare clic su Nuovo nell'angolo superiore sinistro e cercare Account di archiviazione e fare clic su INVIO.
Nota
La parola New potrebbe essere stata sostituita con Crea una risorsa, nei portali più recenti.
La nuova pagina fornirà una descrizione del servizio account Archiviazione di Azure. Nella parte inferiore sinistra di questo prompt selezionare il pulsante Crea per creare un'associazione con questo servizio.
Dopo aver fatto clic su Crea:
Inserire un nome per l'account, tenere presente che questo campo accetta solo numeri e lettere minuscole.
In Modello di distribuzione selezionare Resource Manager.
Per Tipo di account selezionare Archiviazione (utilizzo generico v1).
Determinare la località per il gruppo di risorse (se si sta creando un nuovo gruppo di risorse). La posizione si trova idealmente nell'area in cui verrà eseguita l'applicazione. Alcuni asset di Azure sono disponibili solo in determinate aree.
Per Replica selezionare Archiviazione con ridondanza geografica e accesso in lettura.For Replication select Read-access-geo-redundant storage (RA-GRS) (Archiviazione con ridondanza geografica e accesso in lettura).
Per Prestazioni selezionare Standard.
Lasciare Obbligatorio trasferimento sicuro come Disabilitato.
Selezionare una Sottoscrizione.
Scegliere un gruppo di risorse o crearne uno nuovo. Un gruppo di risorse consente di monitorare, controllare l'accesso, effettuare 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 relativo al gruppo di risorse.
Sarà anche necessario verificare di aver compreso le condizioni e le condizioni applicate al servizio.
Seleziona Crea.
Dopo aver fatto clic su Crea, è necessario attendere che il servizio venga creato, l'operazione potrebbe richiedere un minuto.
Una notifica verrà visualizzata nel portale dopo la creazione dell'istanza del servizio.
Fare clic sulle notifiche per esplorare la nuova istanza del servizio.
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.
Fare clic su Chiavi di accesso per visualizzare gli endpoint per questo servizio cloud. Usare blocco note o simile per copiare una delle chiavi per usarle in un secondo momento. Si noti anche il valore della stringa di connessione, perché verrà usato nella classe AzureServices , che verrà creata in un secondo momento.
Capitolo 2 - Configurazione di una funzione di Azure
Si scriverà ora 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 consiste nel fatto che questa funzione può essere accessibile da qualsiasi applicazione con credenziali per accedere all'account Azure.
Per creare una funzione di Azure:
Nel portale di Azure fare clic su Nuovo nell'angolo superiore sinistro e cercare App per le funzioni e fare clic su INVIO.
Nota
La parola New potrebbe essere stata sostituita con Crea una risorsa, nei portali più recenti.
La nuova pagina fornirà una descrizione del servizio app per le funzioni di Azure . Nella parte inferiore sinistra di questo prompt selezionare il pulsante Crea per creare un'associazione con questo servizio.
Dopo aver fatto clic su Crea:
Specificare un nome app. Solo lettere e numeri possono essere usati qui (è consentito maiuscolo o minuscolo).
Selezionare la sottoscrizione preferita.
Scegliere un gruppo di risorse o crearne uno nuovo. Un gruppo di risorse consente di monitorare, controllare l'accesso, effettuare 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 relativo al gruppo di risorse.
Per questo esercizio selezionare Windows come sistema operativo scelto.
Selezionare Piano a consumo per il piano di hosting.
Determinare la località per il gruppo di risorse (se si sta creando un nuovo gruppo di risorse). La posizione si trova idealmente nell'area in cui verrà eseguita l'applicazione. Alcuni asset di Azure sono disponibili solo in determinate aree. Per ottenere prestazioni ottimali, selezionare la stessa area dell'account di archiviazione.
Per Archiviazione selezionare Usa esistente e quindi usare il menu a discesa per trovare l'archiviazione creata in precedenza.
Lasciare Disattivato Application Insights per questo esercizio.
Fare clic sul pulsante Crea.
Dopo aver fatto clic su Crea, è necessario attendere che il servizio venga creato, l'operazione potrebbe richiedere un minuto.
Una notifica verrà visualizzata nel portale dopo la creazione dell'istanza del servizio.
Fare clic sulle notifiche per esplorare la nuova istanza del servizio.
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.
Nel dashboard dell'app per le funzioni passare il puntatore del mouse su Funzioni, disponibile all'interno del pannello a sinistra, quindi fare clic sul simbolo + (più).
Nella pagina successiva verificare che webhook e API sia selezionato e in Scegliere un linguaggio selezionare CSharp, perché sarà il linguaggio usato per questa esercitazione. Infine, fare clic sul pulsante Crea questa funzione .
Si dovrebbe accedere alla tabella codici (run.csx), in caso contrario, fare clic sulla funzione appena creata nell'elenco Funzioni all'interno del pannello a sinistra.
Copiare il codice seguente nella funzione. Questa funzione restituirà semplicemente un numero 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;} }
Seleziona Salva.
Il risultato dovrebbe essere simile all'immagine seguente.
Fare clic su Recupera URL funzione e prendere nota dell'endpoint visualizzato. Sarà necessario inserirlo nella classe AzureServices che verrà creata più avanti in questo corso.
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 immersive di realtà mista.
Nota
Per questo corso non saranno necessari controller di movimento. Se è necessario supportare la configurazione del visore VR immersive, visitare l'articolo sulla configurazione della realtà mista.
Aprire Unity e fare clic su Nuovo.
Sarà ora necessario specificare un nome di progetto Unity. Inserisci MR_Azure_Functions. Assicurarsi che il tipo di progetto sia impostato su 3D. Impostare La posizione su un punto appropriato per l'utente (tenere presente che più vicino alle directory radice è preferibile). Fare quindi clic su Crea progetto.
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 di script esterni in Visual Studio 2017. Chiudere la finestra Preferenze .
Passare quindi a Impostazioni compilazione file>e passare alla piattaforma per piattaforma UWP (Universal Windows Platform), facendo clic sul pulsante Cambia piattaforma.
Passare a Impostazioni di compilazione file>e assicurarsi che:
Il dispositivo di destinazione è impostato su Qualsiasi dispositivo.
Per Microsoft HoloLens impostare Dispositivo di destinazione su HoloLens.
Il tipo di compilazione è impostato su D3D
L'SDK è impostato su Latest installed (Versione più recente installata)
La versione di Visual Studio è impostata su Versione più recente installata
Compilazione ed esecuzione è impostata su Computer locale
Salvare la scena e aggiungerla alla compilazione.
A tale scopo, selezionare Aggiungi scene aperte. Verrà visualizzata una finestra di salvataggio.
Creare una nuova cartella per questa cartella e qualsiasi scena futura, quindi selezionare il pulsante Nuova cartella per creare una nuova cartella, denominarla Scene.
Aprire la cartella Scene appena creata e quindi nel campo Nome file: testo digitare FunctionsScene, quindi premere Salva.
Le impostazioni rimanenti, in Impostazioni di compilazione, devono essere lasciate come predefinite per il momento.
Nella finestra Impostazioni di compilazione fare clic sul pulsante Impostazioni lettore per aprire il pannello correlato nello spazio in cui si trova il controllo.
In questo pannello è necessario verificare alcune impostazioni:
Nella scheda Altre impostazioni :
- La versione del runtime di scripting deve essere sperimentale (equivalente a .NET 4.6), che attiverà la necessità di riavviare l'editor.
- Il back-end di scripting deve essere .NET
- Il livello di compatibilità api deve essere .NET 4.6
Nella scheda Impostazioni di pubblicazione, in Funzionalità selezionare:
InternetClient
Più in basso nel pannello, in Impostazioni XR (disponibile sotto Impostazioni di pubblicazione), selezionare Virtual Reality Supported (Realtà virtuale supportata), assicurarsi che Windows Realtà mista SDK sia stato aggiunto.
Tornare in Build Settings Unity C# Projects (Impostazioni di compilazione) I progetti C# non sono più disattivati. Selezionare la casella di controllo accanto a questa opzione.
Chiudere la finestra Build Settings (Impostazioni di compilazione).
Salvare la scena e il progetto (FILE>SAVE SCENE/FILE>SAVE PROJECT).
Capitolo 4 - Configurazione 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.
Nel pannello Hierarchy (Gerarchia) troverai un oggetto denominato Main Camera, questo oggetto rappresenta il punto di vista "head" quando sei "all'interno" dell'applicazione.
Con il dashboard unity davanti a te, seleziona il GameObject principale della fotocamera. Si noterà che il Pannello di controllo (in genere 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.
A tale scopo, selezionare l'icona a forma di ingranaggio accanto al componente Trasforma della fotocamera e selezionare Reimposta.
Aggiornare quindi il componente Transform in modo che sia simile al seguente:
Trasforma - Posizione
X | Y | Z |
---|---|---|
0 | 1 | 0 |
Trasforma - Rotazione
X | Y | Z |
---|---|---|
0 | 0 | 0 |
Trasforma - Ridimensionamento
X | Y | Z |
---|---|---|
1 | 1 | 1 |
Capitolo 5 - Configurazione della scena unity
Fare clic con il pulsante destro del mouse in un'area vuota del pannello gerarchia, in Oggetto 3D, aggiungere un piano.
Con l'oggetto Plane selezionato, modificare i parametri seguenti nel Pannello di controllo:
Trasforma - Posizione
X | Y | Z |
---|---|---|
0 | 0 | 4 |
Trasforma - Ridimensionamento
X | Y | Z |
---|---|---|
10 | 1 | 10 |
Fare clic con il pulsante destro del mouse in un'area vuota del pannello gerarchia, in Oggetto 3D aggiungere un cubo.
Rinominare il cubo in GazeButton (con il cubo selezionato, premere "F2").
Modificare i parametri seguenti per Transform Position nel pannello di controllo:
X Y Z 0 3 5 Fare clic sul pulsante a discesa Tag e fare clic su Aggiungi tag per aprire il riquadro Tag e livelli.
Selezionare il pulsante + (più) e nel campo Nuovo nome tag immettere GazeButton e premere Salva.
Fare clic sull'oggetto GazeButton nel pannello Hierarchy (Gerarchia) e nel pannello inspector (Pannello di controllo) assegnare il tag GazeButton appena creato.
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 ).
Selezionare il nuovo oggetto e rinominarlo ShapeSpawnPoint.
Modificare i parametri seguenti per Transform Position nel pannello di controllo:
X Y Z 0 -1 0
Successivamente si creerà 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 gerarchia e aggiungere un oggetto Text 3D object>3D come elemento figlio.
Rinominare l'oggetto 3D Text in AzureStatusText.
Modificare la posizione di trasformazione dell'oggetto AzureStatusText nel modo seguente:
X Y Z 0 0 -0,6 Modificare la scala della trasformazione dell'oggetto AzureStatusText nel modo seguente: | X | Y | Z | | :---: | :---: | :---: | | 0.1 | 0.1 | 0.1 | 0,1 |
Nota
Non preoccuparti se sembra essere fuori centro, perché verrà corretto quando viene aggiornato il componente Mesh di testo seguente.
Modificare il componente Text Mesh in modo che corrisponda al seguente:
Suggerimento
Il colore selezionato qui è Colore esadecimale: 000000FF, anche se è libero di scegliere il proprio, è sufficiente assicurarsi che sia leggibile.
La struttura Del pannello gerarchia avrà ora un aspetto simile al seguente:
La scena dovrebbe ora essere simile alla seguente:
Capitolo 6 - Importare Archiviazione di Azure per Unity
Si userà Archiviazione di Azure per Unity (che si basa su .Net SDK per Azure). Per altre informazioni, vedere l'articolo Archiviazione di Azure per Unity.
Esiste attualmente un problema noto in Unity che richiede la riconfigurazione dei plug-in dopo l'importazione. Questi passaggi (da 4 a 7 in questa sezione) non saranno più necessari dopo la risoluzione del bug.
Per importare l'SDK nel proprio progetto, assicurarsi di aver scaricato la versione più recente di '.unitypackage' da GitHub. Procedere quindi come segue:
Aggiungere il file unitypackage a Unity usando l'opzione di menu Asset>Importa pacchetto> personalizzato pacchetto.
Nella casella Importa pacchetto Unity visualizzata è possibile selezionare tutti gli elementi in Archiviazione plug-in>. Deselezionare tutto il resto, perché non è necessario per questo corso.
Fare clic sul pulsante Importa per aggiungere gli elementi al progetto.
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
Con questi plug-in specifici selezionati, deselezionare Qualsiasi piattaforma e deselezionare WSAPlayer e quindi fare clic su Applica.
Nota
Questi plug-in specifici vengono contrassegnati per essere usati solo nell'editor di Unity. Questo perché esistono versioni diverse degli stessi plug-in nella cartella WSA che verranno usate dopo l'esportazione del progetto da Unity.
Nella cartella Plug-in di archiviazione selezionare solo:
Microsoft.Data.Services.Client
Selezionare la casella Non elaborare in Impostazioni piattaforma e fare clic su Applica.
Nota
Questo plug-in viene contrassegnato come "Non elaborare" perché l'assembly patcher di Unity ha difficoltà a elaborare questo plug-in. Il plug-in funzionerà ancora anche se non viene elaborato.
Capitolo 7 : Creare la classe AzureServices
La prima classe che si intende creare è la classe AzureServices .
La classe AzureServices sarà responsabile di:
Archiviazione delle credenziali dell'account Azure.
Chiamata della funzione app Azure.
Caricamento e download del file di dati in Archiviazione cloud di Azure.
Per creare questa classe:
Fare clic con il pulsante destro del mouse nella cartella asset, che si trova nel pannello del progetto, Crea>cartella. Denominare la cartella Scripts.
Fare doppio clic sulla cartella appena creata per aprirla.
Fare clic con il pulsante destro del mouse all'interno della cartella Crea>script C#. Chiamare lo script AzureServices.
Fare doppio clic sulla nuova classe AzureServices per aprirla con Visual Studio.
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;
Aggiungere i campi inspector 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;
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 l'endpoint e i valori stringa di connessione con i valori dell'archiviazione di Azure, disponibili nel portale di Azure
È ora necessario aggiungere il codice per i metodi Awake() e Start(). 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.
Eliminare il metodo Update() perché questa classe non lo userà.
Salvare le modifiche in Visual Studio e quindi tornare a Unity.
Fare clic e trascinare la classe AzureServices dalla cartella Scripts all'oggetto Main Camera nel pannello Gerarchia.
Selezionare la fotocamera principale, quindi acquisire l'oggetto figlio AzureStatusText sotto l'oggetto GazeButton e inserirlo all'interno del campo di destinazione di riferimento AzureStatusText, in Inspector, per fornire il riferimento allo script AzureServices.
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 nella Archiviazione di Azure. All'avvio dell'applicazione, se nella Archiviazione di Azure viene trovato un file archiviato, l'elenco Cronologia forme viene recuperato e riprodotto, con l'oggetto Text 3D che specifica se la forma generata proviene dall'archiviazione o dalla nuova.
Per creare questa classe:
Passare alla cartella Scripts creata in precedenza.
Fare clic con il pulsante destro del mouse all'interno della cartella Crea>script C#. Chiamare lo script ShapeFactory.
Fare doppio clic sul nuovo script ShapeFactory per aprirlo con Visual Studio.
Verificare che la classe ShapeFactory includa gli spazi dei nomi seguenti:
using System.Collections.Generic; using UnityEngine;
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>(); }
Il metodo CreateShape() genera le forme primitive, in base al parametro integer specificato. Il parametro booleano viene utilizzato per specificare se la forma attualmente creata è dalla risorsa di 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); } }
Assicurarsi di salvare le modifiche in Visual Studio prima di tornare a Unity.
Nell'editor di Unity fare clic e trascinare la classe ShapeFactory dalla cartella Scripts all'oggetto Camera principale nel pannello Gerarchia.
Con la fotocamera principale selezionata si noterà che il componente script ShapeFactory manca il riferimento a Punto spawn. Per correggerlo, trascinare l'oggetto ShapeSpawnPoint dal pannello gerarchia alla destinazione di riferimento punto spawn.
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 in avanti dalla fotocamera principale, per rilevare l'oggetto che 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:
Passare alla cartella Scripts creata in precedenza.
Fare clic con il pulsante destro del mouse nel pannello del progetto, Crea>script C#. Chiamare lo script Sguardo fisso.
Fare doppio clic sul nuovo script sguardo fisso per aprirlo con Visual Studio.
Verificare che lo spazio dei nomi seguente sia incluso nella parte superiore dello script:
using UnityEngine;
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.
È 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(); }
Aggiungere il codice seguente, che creerà un oggetto cursore all'inizio, insieme al metodo Update(), che eseguirà il metodo Raycast, insieme a dove viene attivato o disattivato 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(); } }
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(); } } } }
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; } } }
Salvare le modifiche in Visual Studio prima di tornare a Unity.
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:
Aggiunta di un nuovo metodo denominato CreateCloudIdentityAsync() per configurare le variabili di autenticazione necessarie per la comunicazione con Azure.
Questo metodo verificherà inoltre l'esistenza di un file archiviato in precedenza contenente l'elenco forme.
Se viene trovato, il file disabiliterà lo sguardo fisso dell'utente e attiverà la creazione della forma, in base al modello di forme, come archiviato nel file Archiviazione di Azure. L'utente può visualizzare questa situazione, perché la mesh di testo fornirà la visualizzazione "Archiviazione" o "Nuovo", a seconda dell'origine delle forme.
Se non viene trovato alcun file, verrà abilitato 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(); } }
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(); }
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(); }
Aggiungere un metodo per creare una stringa, concatenando gli interi archiviati nell'elenco della cronologia delle forme e salvandolo nel file 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); }
Aggiungere un metodo per recuperare il testo archiviato nel file che si trova nel file Archiviazione di Azure e deserializzarlo in un elenco.
Una volta completato 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!"; }
Salvare le modifiche in Visual Studio prima di tornare a Unity.
Capitolo 11 - Creare la soluzione UWP
Per avviare il processo di compilazione:
Passare a Impostazioni di compilazione file>.
Fare clic su Compila. Unity avvierà una finestra Esplora file, in cui è necessario creare e quindi selezionare una cartella in cui compilare l'app. Creare ora la cartella e denominarla App. Quindi, con la cartella App selezionata, premere Seleziona cartella.
Unity inizierà a compilare il progetto nella cartella App .
Una volta completata la compilazione di Unity (potrebbe essere necessario del tempo), verrà aperta una finestra 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:
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.
Nella piattaforma della soluzione selezionare x86, Computer locale.
Nella configurazione della soluzione selezionare Debug.
Per Microsoft HoloLens, potrebbe risultare 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 di HoloLens, che è possibile trovare all'interno di Impostazioni>Rete e>Internet Wi-Fi>Advanced Options. IPv4 è l'indirizzo da usare.
- Assicurarsi che la modalità sviluppatore sia attivata. Disponibile in Impostazioni>Aggiornamento e sicurezza>per gli sviluppatori.
Passare al menu Compila e fare clic su Distribuisci soluzione per trasferire localmente l'applicazione nel computer.
L'app dovrebbe ora essere visualizzata nell'elenco delle app installate, pronte 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 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.
Esercizi aggiuntivi
Esercizio 1
Creare un secondo punto di generazione e registrare il punto da cui è stato creato un oggetto. Quando si carica il file di dati, riprodurre le forme da generare dalla posizione originariamente create.
Esercizio 2
Creare un modo per riavviare l'app, invece di dover 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.