HoloLens (första generationen) och Azure 311 – Microsoft Graph

Anteckning

Självstudierna Mixed Reality Academy har utformats med HoloLens (första generationen) och Mixed Reality integrerande headset i åtanke. Därför tycker vi att det är viktigt att låta de här självstudierna vara kvar för utvecklare som fortfarande behöver vägledning för att utveckla för dessa enheter. De här självstudierna uppdateras inte med de senaste verktygsuppsättningarna eller interaktionerna som används för HoloLens 2. De kommer att underhållas för att fortsätta arbeta på de enheter som stöds. Det kommer att finnas en ny serie självstudier som kommer att publiceras i framtiden som visar hur man utvecklar för HoloLens 2. Det här meddelandet uppdateras med en länk till dessa självstudier när de publiceras.

I den här kursen får du lära dig hur du använder Microsoft Graph för att logga in på ditt Microsoft-konto med säker autentisering i ett mixed reality-program. Sedan hämtar och visar du dina schemalagda möten i programgränssnittet.

Skärmbild som visar de schemalagda mötena i programgränssnittet.

Microsoft Graph är en uppsättning API:er som utformats för att ge åtkomst till många av Microsofts tjänster. Microsoft beskriver Microsoft Graph som en matris med resurser som är anslutna via relationer, vilket innebär att ett program kan komma åt alla typer av anslutna användardata. Mer information finns på Microsoft Graph-sidan.

Utveckling omfattar skapandet av en app där användaren uppmanas att titta på och sedan trycka på en sfär, vilket uppmanar användaren att logga in på ett Microsoft-konto på ett säkert sätt. När användaren har loggat in på sitt konto kan han eller hon se en lista över möten som är schemalagda för dagen.

När du har slutfört den här kursen har du ett HoloLens-program för mixad verklighet som kan göra följande:

  1. Med gesten Tryck trycker du på ett objekt, vilket uppmanar användaren att logga in på ett Microsoft-konto (flytta ut från appen för att logga in och sedan tillbaka till appen igen).
  2. Visa en lista över möten som är schemalagda för dagen.

I ditt program är det upp till dig hur du ska integrera resultaten med din design. Den här kursen är utformad för att lära dig hur du integrerar en Azure-tjänst med ditt Unity-projekt. Det är ditt jobb att använda den kunskap du får från den här kursen för att förbättra ditt mixed reality-program.

Stöd för enheter

Kurs HoloLens Integrerande headset
MR och Azure 311: Microsoft Graph ✔️

Förutsättningar

Anteckning

Den här självstudien är utformad för utvecklare som har grundläggande erfarenhet av Unity och C#. Tänk också på att kraven och de skriftliga instruktionerna i det här dokumentet representerar det som har testats och verifierats i skrivande stund (juli 2018). Du är fri att använda den senaste programvaran, som anges i artikeln installera verktyg , men det bör inte antas att informationen i denna kurs kommer att matcha perfekt vad du hittar i nyare programvara än vad som anges nedan.

Vi rekommenderar följande maskinvara och programvara för den här kursen:

Innan du börjar

  1. För att undvika problem med att skapa det här projektet rekommenderar vi starkt att du skapar projektet som nämns i den här självstudien i en rotmapp eller nära rotmapp (långa mappsökvägar kan orsaka problem vid byggtiden).
  2. Konfigurera och testa HoloLens. Om du behöver stöd för att konfigurera HoloLens kan du läsa artikeln om HoloLens-konfiguration.
  3. Det är en bra idé att utföra kalibrering och sensorjustering när du börjar utveckla en ny HoloLens-app (ibland kan det hjälpa att utföra dessa uppgifter för varje användare).

Om du behöver hjälp med kalibrering följer du den här länken till holoLenskalibreringsartikeln.

Om du vill ha hjälp med sensorjustering följer du den här länken till artikeln HoloLens Sensor Tuning.

Kapitel 1 – Skapa din app i programregistreringsportalen

Till att börja med måste du skapa och registrera ditt program i programregistreringsportalen.

I det här kapitlet hittar du även den tjänstnyckel som gör att du kan göra anrop till Microsoft Graph för att få åtkomst till ditt kontoinnehåll.

  1. Gå till Microsoft Application Registration Portal och logga in med ditt Microsoft-konto. När du har loggat in omdirigeras du till programregistreringsportalen.

  2. I avsnittet Mina program klickar du på knappen Lägg till en app.

    Skärmbild som visar var du väljer Lägg till en app.

    Viktigt

    Programregistreringsportalen kan se annorlunda ut beroende på om du tidigare har arbetat med Microsoft Graph. Skärmbilderna nedan visar dessa olika versioner.

  3. Lägg till ett namn för ditt program och klicka på Skapa.

    Skärmbild som visar var du lägger till ett namn för ditt program.

  4. När programmet har skapats omdirigeras du till programmets huvudsida. Kopiera program-ID :t och se till att anteckna det här värdet på en säker plats. Du kommer snart att använda det i koden.

    Skärmbild som visar var program-ID:t ska visas.

  5. I avsnittet Plattformar kontrollerar du att Internt program visas. Om du inte klickar på Lägg till plattform och väljer Internt program.

    Skärmbild som visar avsnittet Internt program.

  6. Rulla nedåt på samma sida och i avsnittet Microsoft Graph-behörigheter måste du lägga till ytterligare behörigheter för programmet. Klicka på Lägg till bredvid Delegerade behörigheter.

    Skärmbild som visar var du väljer Lägg till bredvid Delegerade behörigheter.

  7. Eftersom du vill att programmet ska få åtkomst till användarens kalender markerar du kryssrutan Calendars.Read och klickar på OK.

    Skärmbild som visar kryssrutan Calendars.Read.

  8. Rulla längst ned och klicka på knappen Spara .

    Skärmbild som visar var du väljer Spara.

  9. Spara kommer att bekräftas och du kan logga ut från programregistreringsportalen.

Kapitel 2 – Konfigurera Unity-projektet

Följande är en typisk konfiguration för utveckling med mixad verklighet och är därför en bra mall för andra projekt.

  1. Öppna Unity och klicka på Ny.

    Skärmbild som visar Unity-gränssnittet.

  2. Du måste ange ett Unity-projektnamn. Infoga MSGraphMR. Kontrollera att projektmallen är inställd på 3D. Ange plats till någonstans som passar dig (kom ihåg att närmare rotkatalogerna är bättre). Klicka sedan på Skapa projekt.

    Skärmbild som visar var du väljer Skapa projekt.

  3. När Unity är öppet är det värt att kontrollera att standardskriptredigeraren är inställd på Visual Studio. Gå till Redigera>inställningar och gå sedan till Externa verktyg från det nya fönstret. Ändra extern skriptredigerare till Visual Studio 2017. Stäng fönstret Inställningar .

    Skärmbild som visar var du ställer in den externa skriptredigeraren på Visual Studio 2017.

  4. Gå till Inställningarförfilbygge> och välj Universell Windows-plattform och klicka sedan på knappen Växla plattform för att tillämpa ditt val.

    Skärmbild som visar var du väljer Växla plattform.

  5. När du fortfarande är i Inställningar förfilbygge> kontrollerar du att:

    1. Målenheten är inställd på HoloLens

    2. Byggtyp är inställd på D3D

    3. SDK är inställt på Senaste installerat

    4. Visual Studio-versionen är inställd på Senaste installerad

    5. Build and Run är inställt på Lokal dator

    6. Spara scenen och lägg till den i bygget.

      1. Gör detta genom att välja Lägg till öppna scener. Ett spara-fönster visas.

        Skärmbild som visar var du väljer Lägg till öppna scener.

      2. Skapa en ny mapp för den här och eventuell framtida scen. Välj knappen Ny mapp om du vill skapa en ny mapp och ge den namnet Scener.

        Skärmbild som visar var den nya mappen ska namnges.

      3. Öppna mappen Scener och skriv MR_ComputerVisionScene i fältet Filnamn: text och klicka sedan på Spara.

        Skärmbild som visar var filnamnet ska skrivas.

        Viktigt

        Tänk på att du måste spara Unity-scenerna i mappen Assets eftersom de måste vara associerade med Unity-projektet. Att skapa mappen scenes (och andra liknande mappar) är ett vanligt sätt att strukturera ett Unity-projekt.

    7. De återstående inställningarna i Build Settings (Bygginställningar) bör vara kvar som standard för tillfället.

  6. I fönstret Build Settings (Bygginställningar ) klickar du på knappen Spelarinställningar . Då öppnas den relaterade panelen i utrymmet där Inspector finns.

    Skärmbild som visar dialogrutan Spelarinställningar.

  7. I den här panelen måste några inställningar verifieras:

    1. På fliken Andra inställningar :

      1. ScriptingRuntime-versionen ska vara experimentell (.NET 4.6 Equivalent), vilket utlöser ett behov av att starta om redigeraren.

      2. Skriptserverdelen ska vara .NET

      3. API-kompatibilitetsnivån ska vara .NET 4.6

        Skärmbild som visar var du kontrollerar API-kompatibilitetsnivån.

    2. På fliken Publiceringsinställningar går du till Funktioner och kontrollerar:

      • InternetClient

        Skärmbild som visar var du väljer alternativet InternetClient.

    3. Längre ned på panelen går du till XR-inställningar (finns under Publiceringsinställningar) och markerar Virtual Reality Supported (Virtual Reality Supported) och kontrollerar att Windows Mixed Reality SDK har lagts till.

      Skärmbild som visar var du lägger till Windows Mixed Reality SDK.

  8. Tillbaka i Build Settings (Bygginställningar) är Unity C# Projects inte längre nedtonat. markera kryssrutan bredvid detta.

  9. Stäng fönstret Build Settings (Bygginställningar).

  10. Spara din scen och ditt projekt (FILE>SAVE SCENES/FILE>SAVE PROJECT).

Kapitel 3 – Importera bibliotek i Unity

Viktigt

Om du vill hoppa över unity-konfigurationskomponenten i den här kursen och fortsätta direkt i kod kan du ladda ned azure-MR-311.unitypackage, importera den till ditt projekt som ett anpassat paket och sedan fortsätta från kapitel 5.

Om du vill använda Microsoft Graph i Unity måste du använda DLL-filen Microsoft.Identity.Client . Det går att använda Microsoft Graph SDK, men det kräver att du lägger till ett NuGet-paket när du har skapat Unity-projektet (vilket innebär att du redigerar projektet efter kompilering). Det anses enklare att importera de nödvändiga DLL:erna direkt till Unity.

Anteckning

Det finns för närvarande ett känt problem i Unity som kräver att plugin-program konfigureras om efter importen. De här stegen (4–7 i det här avsnittet) krävs inte längre när felet har lösts.

Om du vill importera Microsoft Graph till ditt eget projekt laddar du ned filen MSGraph_LabPlugins.zip. Det här paketet har skapats med versioner av biblioteken som har testats.

Om du vill veta mer om hur du lägger till anpassade DLL:er i ditt Unity-projekt följer du den här länken.

Så här importerar du paketet:

  1. Lägg till Unity-paketet i Unity med menyalternativetImportera paket> för tillgångar>anpassat paket. Välj det paket som du precis laddade ned.

  2. I rutan Importera Unity-paket som visas kontrollerar du att allt under (och inklusive) Plugin-program är markerat.

    Skärmbild som visar de valda konfigurationsparametrarna under Plugin-program.

  3. Klicka på knappen Importera för att lägga till objekten i projektet.

  4. Gå till mappen MSGraph under Plugin-program i projektpanelen och välj plugin-programmet Microsoft.Identity.Client.

    Skärmbild som visar plugin-programmet Microsoft.Identity.Client.

  5. När plugin-programmet har valts kontrollerar du att Alla plattformar är avmarkerade och kontrollerar sedan att WSAPlayer också är avmarkerat och klickar sedan på Tillämpa. Detta är bara för att bekräfta att filerna är korrekt konfigurerade.

    Skärmbild som visar var du kan bekräfta att Any Platform och WSAPlayer inte är markerade.

    Anteckning

    Om du markerar dessa plugin-program konfigureras de så att de endast används i Unity-redigeraren. Det finns en annan uppsättning DLL:er i WSA-mappen som ska användas när projektet har exporterats från Unity som ett universellt Windows-program.

  6. Därefter måste du öppna WSA-mappen i MAPPEN MSGraph . Du ser en kopia av samma fil som du precis har konfigurerat. Välj filen och sedan i inspektören:

    • se till att Alla plattformar är avmarkerade och att endastWSAPlayer är markerat.

    • Kontrollera att SDK är inställt på UWP och att Scripting Backend är inställt på Dot Net

    • Kontrollera att Processa inte är markerat.

      Skärmbild som visar att Bearbeta inte har valts.

  7. Klicka på Applicera.

Kapitel 4 – Kamerainstallation

Under detta kapitel kommer du att ställa in huvudkameran för din scen:

  1. I hierarkipanelen väljer du huvudkameran.

  2. När du har valt kan du se alla komponenter i huvudkameran i panelen Kontroll .

    1. Kameraobjektet måste ha namnet Huvudkamera (observera stavningen!)

    2. Huvudkamerataggen måste vara inställd på MainCamera (observera stavningen!)

    3. Kontrollera att transformeringspositionen är inställd på 0, 0, 0

    4. Ställ in Clear FlagsSolid Color (Hel färg)

    5. Ange bakgrundsfärgen för kamerakomponenten till Svart, Alpha 0(Hexkod: #000000000)

      Skärmbild som visar var bakgrundsfärgen ska anges.

  3. Den slutliga objektstrukturen i hierarkipanelen bör se ut som den som visas i bilden nedan:

    Skärmbild som visar den slutliga objektstrukturen på hierarkipanelen.

Kapitel 5 – Skapa MeetingsUI-klass

Det första skriptet som du behöver skapa är MeetingsUI, som ansvarar för att vara värd för och fylla i programmets användargränssnitt (välkomstmeddelande, instruktioner och mötesinformation).

Så här skapar du den här klassen:

  1. Högerklicka på mappen Tillgångarprojektpanelen och välj sedan Skapa>mapp. Ge mappen namnet Skript.

    Skärmbild som visar var du hittar mappen Tillgångar.Skärmbild som visar var du skapar mappen Skript.

  2. Öppna mappen Skript och högerklicka sedan på Skapa>C#-skript i mappen. Ge skriptet namnet MeetingsUI.

    Skärmbild som visar var du skapar mappen MeetingsUI.

  3. Dubbelklicka på det nya MeetingsUI-skriptet för att öppna det med Visual Studio.

  4. Infoga följande namnområden:

    using System;
    using UnityEngine;
    
  5. Infoga följande variabler i klassen:

        /// <summary>
        /// Allows this class to behave like a singleton
        /// </summary>
        public static MeetingsUI Instance;
    
        /// <summary>
        /// The 3D text of the scene
        /// </summary>
        private TextMesh _meetingDisplayTextMesh;
    
  6. Ersätt sedan metoden Start() och lägg till en Awake() -metod. Dessa anropas när klassen initieras:

        /// <summary>
        /// Called on initialization
        /// </summary>
        void Awake()
        {
            Instance = this;
        }
    
        /// <summary>
        /// Called on initialization, after Awake
        /// </summary>
        void Start ()
        {
            // Creating the text mesh within the scene
            _meetingDisplayTextMesh = CreateMeetingsDisplay();
        }
    
  7. Lägg till de metoder som ansvarar för att skapa mötesgränssnittet och fyll i det med de aktuella mötena när det begärs:

        /// <summary>
        /// Set the welcome message for the user
        /// </summary>
        internal void WelcomeUser(string userName)
        {
            if(!string.IsNullOrEmpty(userName))
            {
                _meetingDisplayTextMesh.text = $"Welcome {userName}";
            }
            else 
            {
                _meetingDisplayTextMesh.text = "Welcome";
            }
        }
    
        /// <summary>
        /// Set up the parameters for the UI text
        /// </summary>
        /// <returns>Returns the 3D text in the scene</returns>
        private TextMesh CreateMeetingsDisplay()
        {
            GameObject display = new GameObject();
            display.transform.localScale = new Vector3(0.03f, 0.03f, 0.03f);
            display.transform.position = new Vector3(-3.5f, 2f, 9f);
            TextMesh textMesh = display.AddComponent<TextMesh>();
            textMesh.anchor = TextAnchor.MiddleLeft;
            textMesh.alignment = TextAlignment.Left;
            textMesh.fontSize = 80;
            textMesh.text = "Welcome! \nPlease gaze at the button" +
                "\nand use the Tap Gesture to display your meetings";
    
            return textMesh;
        }
    
        /// <summary>
        /// Adds a new Meeting in the UI by chaining the existing UI text
        /// </summary>
        internal void AddMeeting(string subject, DateTime dateTime, string location)
        {
            string newText = $"\n{_meetingDisplayTextMesh.text}\n\n Meeting,\nSubject: {subject},\nToday at {dateTime},\nLocation: {location}";
    
            _meetingDisplayTextMesh.text = newText;
        }
    
  8. Ta bort metoden Update() och spara ändringarna i Visual Studio innan du återgår till Unity.

Kapitel 6 – Skapa graph-klassen

Nästa skript att skapa är Graph-skriptet . Det här skriptet ansvarar för att göra anrop för att autentisera användaren och hämta de schemalagda mötena för den aktuella dagen från användarens kalender.

Så här skapar du den här klassen:

  1. Dubbelklicka på mappen Skript för att öppna den.

  2. Högerklicka i mappen Skript och klicka på Skapa>C#-skript. Ge skriptet namnet Graph.

  3. Dubbelklicka på skriptet för att öppna det med Visual Studio.

  4. Infoga följande namnområden:

    using System.Collections.Generic;
    using UnityEngine;
    using Microsoft.Identity.Client;
    using System;
    using System.Threading.Tasks;
    
    #if !UNITY_EDITOR && UNITY_WSA
    using System.Net.Http;
    using System.Net.Http.Headers;
    using Windows.Storage;
    #endif
    

    Viktigt

    Du kommer att märka att delar av koden i det här skriptet omsluts av förkompilerade direktiv. Detta är för att undvika problem med biblioteken när du skapar Visual Studio-lösningen.

  5. Ta bort metoderna Start() och Update() eftersom de inte kommer att användas.

  6. Utanför graph-klassen infogar du följande objekt, som är nödvändiga för att deserialisera JSON-objektet som representerar de dagliga schemalagda mötena:

    /// <summary>
    /// The object hosting the scheduled meetings
    /// </summary>
    [Serializable]
    public class Rootobject
    {
        public List<Value> value;
    }
    
    [Serializable]
    public class Value
    {
        public string subject { get; set; }
        public StartTime start { get; set; }
        public Location location { get; set; }
    }
    
    [Serializable]
    public class StartTime
    {
        public string dateTime;
    
        private DateTime? _startDateTime;
        public DateTime StartDateTime
        {
            get
            {
                if (_startDateTime != null)
                    return _startDateTime.Value;
                DateTime dt;
                DateTime.TryParse(dateTime, out dt);
                _startDateTime = dt;
                return _startDateTime.Value;
            }
        }
    }
    
    [Serializable]
    public class Location
    {
        public string displayName { get; set; }
    }
    
  7. Lägg till följande variabler i graph-klassen :

        /// <summary>
        /// Insert your Application Id here
        /// </summary>
        private string _appId = "-- Insert your Application Id here --";
    
        /// <summary>
        /// Application scopes, determine Microsoft Graph accessibility level to user account
        /// </summary>
        private IEnumerable<string> _scopes = new List<string>() { "User.Read", "Calendars.Read" };
    
        /// <summary>
        /// Microsoft Graph API, user reference
        /// </summary>
        private PublicClientApplication _client;
    
        /// <summary>
        /// Microsoft Graph API, authentication
        /// </summary>
        private AuthenticationResult _authResult;
    
    

    Anteckning

    Ändra appId-värdet till det app-ID som du har antecknade i kapitel 1, steg 4. Det här värdet ska vara samma som det som visas i programregistreringsportalen på sidan för programregistrering.

  8. I graph-klassen lägger du till metoderna SignInAsync() och AquireTokenAsync(), som uppmanar användaren att infoga inloggningsuppgifterna.

        /// <summary>
        /// Begin the Sign In process using Microsoft Graph Library
        /// </summary>
        internal async void SignInAsync()
        {
    #if !UNITY_EDITOR && UNITY_WSA
            // Set up Grap user settings, determine if needs auth
            ApplicationDataContainer localSettings = ApplicationData.Current.LocalSettings;
            string userId = localSettings.Values["UserId"] as string;
            _client = new PublicClientApplication(_appId);
    
            // Attempt authentication
            _authResult = await AcquireTokenAsync(_client, _scopes, userId);
    
            // If authentication is successful, retrieve the meetings
            if (!string.IsNullOrEmpty(_authResult.AccessToken))
            {
                // Once Auth as been completed, find the meetings for the day
                await ListMeetingsAsync(_authResult.AccessToken);
            }
    #endif
        }
    
        /// <summary>
        /// Attempt to retrieve the Access Token by either retrieving
        /// previously stored credentials or by prompting user to Login
        /// </summary>
        private async Task<AuthenticationResult> AcquireTokenAsync(
            IPublicClientApplication app, IEnumerable<string> scopes, string userId)
        {
            IUser user = !string.IsNullOrEmpty(userId) ? app.GetUser(userId) : null;
            string userName = user != null ? user.Name : "null";
    
            // Once the User name is found, display it as a welcome message
            MeetingsUI.Instance.WelcomeUser(userName);
    
            // Attempt to Log In the user with a pre-stored token. Only happens
            // in case the user Logged In with this app on this device previously
            try
            {
                _authResult = await app.AcquireTokenSilentAsync(scopes, user);
            }
            catch (MsalUiRequiredException)
            {
                // Pre-stored token not found, prompt the user to log-in 
                try
                {
                    _authResult = await app.AcquireTokenAsync(scopes);
                }
                catch (MsalException msalex)
                {
                    Debug.Log($"Error Acquiring Token: {msalex.Message}");
                    return _authResult;
                }
            }
    
            MeetingsUI.Instance.WelcomeUser(_authResult.User.Name);
    
    #if !UNITY_EDITOR && UNITY_WSA
            ApplicationData.Current.LocalSettings.Values["UserId"] = 
            _authResult.User.Identifier;
    #endif
            return _authResult;
        }
    
  9. Lägg till följande två metoder:

    1. BuildTodayCalendarEndpoint(), som skapar den URI som anger dagen och tidsintervallet, där de schemalagda mötena hämtas.

    2. ListMeetingsAsync(), som begär schemalagda möten från Microsoft Graph.

        /// <summary>
        /// Build the endpoint to retrieve the meetings for the current day.
        /// </summary>
        /// <returns>Returns the Calendar Endpoint</returns>
        public string BuildTodayCalendarEndpoint()
        {
            DateTime startOfTheDay = DateTime.Today.AddDays(0);
            DateTime endOfTheDay = DateTime.Today.AddDays(1);
            DateTime startOfTheDayUTC = startOfTheDay.ToUniversalTime();
            DateTime endOfTheDayUTC = endOfTheDay.ToUniversalTime();
    
            string todayDate = startOfTheDayUTC.ToString("o");
            string tomorrowDate = endOfTheDayUTC.ToString("o");
            string todayCalendarEndpoint = string.Format(
                "https://graph.microsoft.com/v1.0/me/calendarview?startdatetime={0}&enddatetime={1}",
                todayDate,
                tomorrowDate);
    
            return todayCalendarEndpoint;
        }
    
        /// <summary>
        /// Request all the scheduled meetings for the current day.
        /// </summary>
        private async Task ListMeetingsAsync(string accessToken)
        {
    #if !UNITY_EDITOR && UNITY_WSA
            var http = new HttpClient();
    
            http.DefaultRequestHeaders.Authorization = 
            new AuthenticationHeaderValue("Bearer", accessToken);
            var response = await http.GetAsync(BuildTodayCalendarEndpoint());
    
            var jsonResponse = await response.Content.ReadAsStringAsync();
    
            Rootobject rootObject = new Rootobject();
            try
            {
                // Parse the JSON response.
                rootObject = JsonUtility.FromJson<Rootobject>(jsonResponse);
    
                // Sort the meeting list by starting time.
                rootObject.value.Sort((x, y) => DateTime.Compare(x.start.StartDateTime, y.start.StartDateTime));
    
                // Populate the UI with the meetings.
                for (int i = 0; i < rootObject.value.Count; i++)
                {
                    MeetingsUI.Instance.AddMeeting(rootObject.value[i].subject,
                                                rootObject.value[i].start.StartDateTime.ToLocalTime(),
                                                rootObject.value[i].location.displayName);
                }
            }
            catch (Exception ex)
            {
                Debug.Log($"Error = {ex.Message}");
                return;
            }
    #endif
        }
    
  10. Nu har du slutfört Graph-skriptet . Spara ändringarna i Visual Studio innan du återvänder till Unity.

Kapitel 7 – Skapa GazeInput-skriptet

Nu ska du skapa GazeInput. Den här klassen hanterar och håller reda på användarens blick med hjälp av en Raycast som kommer från huvudkameran och projicerar framåt.

Så här skapar du skriptet:

  1. Dubbelklicka på mappen Skript för att öppna den.

  2. Högerklicka i mappen Skript och klicka på Skapa>C#-skript. Ge skriptet namnet GazeInput.

  3. Dubbelklicka på skriptet för att öppna det med Visual Studio.

  4. Ändra namnområdeskoden så att den matchar den nedan, tillsammans med att lägga till taggen "[System.Serializable]" ovanför klassen GazeInput , så att den kan serialiseras:

    using UnityEngine;
    
    /// <summary>
    /// Class responsible for the User's Gaze interactions
    /// </summary>
    [System.Serializable]
    public class GazeInput : MonoBehaviour
    {
    
  5. Lägg till följande variabler i klassen GazeInput :

        [Tooltip("Used to compare whether an object is to be interacted with.")]
        internal string InteractibleTag = "SignInButton";
    
        /// <summary>
        /// Length of the gaze
        /// </summary>
        internal float GazeMaxDistance = 300;
    
        /// <summary>
        /// Object currently gazed
        /// </summary>
        internal GameObject FocusedObject { get; private set; }
    
        internal GameObject oldFocusedObject { get; private set; }
    
        internal RaycastHit HitInfo { get; private set; }
    
        /// <summary>
        /// Cursor object visible in the scene
        /// </summary>
        internal GameObject Cursor { get; private set; }
    
        internal bool Hit { get; private set; }
    
        internal Vector3 Position { get; private set; }
    
        internal Vector3 Normal { get; private set; }
    
        private Vector3 _gazeOrigin;
    
        private Vector3 _gazeDirection;
    
  6. Lägg till metoden CreateCursor() för att skapa HoloLens-markören i scenen och anropa metoden från metoden Start( ):

        /// <summary>
        /// Start method used upon initialisation.
        /// </summary>
        internal virtual void Start()
        {
            FocusedObject = null;
            Cursor = CreateCursor();
        }
    
        /// <summary>
        /// Method to create a cursor object.
        /// </summary>
        internal 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 = new Vector3(0.05f, 0.05f, 0.05f);
            Material mat = new Material(Shader.Find("Diffuse"));
            newCursor.GetComponent<MeshRenderer>().material = mat;
            mat.color = Color.HSVToRGB(0.0223f, 0.7922f, 1.000f);
            newCursor.SetActive(true);
    
            return newCursor;
        }
    
  7. Följande metoder aktiverar blicken Raycast och håller reda på de fokuserade objekten.

    /// <summary>
    /// Called every frame
    /// </summary>
    internal virtual void Update()
    {
        _gazeOrigin = Camera.main.transform.position;
    
        _gazeDirection = Camera.main.transform.forward;
    
        UpdateRaycast();
    }
    /// <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))
            {
                // Provide the 'Gaze Exited' event.
                oldFocusedObject.SendMessage("OnGazeExited", SendMessageOptions.DontRequireReceiver);
            }
        }
    }
    
        private void UpdateRaycast()
        {
            // Set the old focused gameobject.
            oldFocusedObject = FocusedObject;
            RaycastHit hitInfo;
    
            // Initialise Raycasting.
            Hit = Physics.Raycast(_gazeOrigin,
                _gazeDirection,
                out hitInfo,
                GazeMaxDistance);
                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. If so, reset the focused object.
            if (FocusedObject != oldFocusedObject)
            {
                ResetFocusedObject();
                if (FocusedObject != null)
                {
                    if (FocusedObject.CompareTag(InteractibleTag))
                    {
                        // Provide the 'Gaze Entered' event.
                        FocusedObject.SendMessage("OnGazeEntered", 
                            SendMessageOptions.DontRequireReceiver);
                    }
                }
            }
        }
    
  8. Spara ändringarna i Visual Studio innan du återvänder till Unity.

Kapitel 8 – Skapa klassen Interaktioner

Nu måste du skapa skriptet Interaktioner , som ansvarar för:

  • Hantering av Tap-interaktionen och Camera Gaze, som gör det möjligt för användaren att interagera med inloggningens "knapp" i scenen.

  • Skapa inloggningsobjektet "knapp" i scenen där användaren kan interagera med.

Så här skapar du skriptet:

  1. Dubbelklicka på mappen Skript för att öppna den.

  2. Högerklicka i mappen Skript och klicka på Skapa>C#-skript. Ge skriptet namnet Interaktioner.

  3. Dubbelklicka på skriptet för att öppna det med Visual Studio.

  4. Infoga följande namnområden:

    using UnityEngine;
    using UnityEngine.XR.WSA.Input;
    
  5. Ändra arvet för klassen Interaktion från MonoBehaviour till GazeInput.

    offentliga klassinteraktioner: MonoBehaviour

    public class Interactions : GazeInput
    
  6. Infoga följande variabel i klassen Interaktion :

        /// <summary>
        /// Allows input recognition with the HoloLens
        /// </summary>
        private GestureRecognizer _gestureRecognizer;
    
  7. Ersätt startmetoden . observera att det är en åsidosättningsmetod som anropar "base" Gaze-klassmetoden. Start() anropas när klassen initieras, registrerar för indataigenkänning och skapar inloggningsknappen i scenen:

        /// <summary>
        /// Called on initialization, after Awake
        /// </summary>
        internal override void Start()
        {
            base.Start();
    
            // Register the application to recognize HoloLens user inputs
            _gestureRecognizer = new GestureRecognizer();
            _gestureRecognizer.SetRecognizableGestures(GestureSettings.Tap);
            _gestureRecognizer.Tapped += GestureRecognizer_Tapped;
            _gestureRecognizer.StartCapturingGestures();
    
            // Add the Graph script to this object
            gameObject.AddComponent<MeetingsUI>();
            CreateSignInButton();
        }
    
  8. Lägg till metoden CreateSignInButton(), som instansierar inloggningsknappen i scenen och anger dess egenskaper:

        /// <summary>
        /// Create the sign in button object in the scene
        /// and sets its properties
        /// </summary>
        void CreateSignInButton()
        {
            GameObject signInButton = GameObject.CreatePrimitive(PrimitiveType.Sphere);
    
            Material mat = new Material(Shader.Find("Diffuse"));
            signInButton.GetComponent<Renderer>().material = mat;
            mat.color = Color.blue;
    
            signInButton.transform.position = new Vector3(3.5f, 2f, 9f);
            signInButton.tag = "SignInButton";
            signInButton.AddComponent<Graph>();
        }
    
  9. Lägg till metoden GestureRecognizer_Tapped() som ska svara för händelsen Tryck på användare.

        /// <summary>
        /// Detects the User Tap Input
        /// </summary>
        private void GestureRecognizer_Tapped(TappedEventArgs obj)
        {
            if(base.FocusedObject != null)
            {
                Debug.Log($"TAP on {base.FocusedObject.name}");
                base.FocusedObject.SendMessage("SignInAsync", SendMessageOptions.RequireReceiver);
            }
        }
    
  10. Ta bort metoden Update() och spara sedan ändringarna i Visual Studio innan du återgår till Unity.

Kapitel 9 – Konfigurera skriptreferenserna

I det här kapitlet måste du placera interaktionsskriptethuvudkameran. Skriptet hanterar sedan att placera de andra skripten där de behöver vara.

  • Dra skriptinteraktionerna till huvudkameraobjektet från mappen Skript i projektpanelen enligt bilden nedan.

    Skärmbild som visar var interaktionsskriptet ska dras.

Kapitel 10 – Konfigurera taggen

Koden som hanterar blicken använder taggen SignInButton för att identifiera vilket objekt användaren ska interagera med för att logga in på Microsoft Graph.

Så här skapar du taggen:

  1. I Unity-redigeraren klickar du på huvudkameran i hierarkipanelen.

  2. I Kontrollpanelen klickar du på MainCamera-taggen för att öppna en listruta. Klicka på Lägg till tagg...

    Skärmbild som markerar lägg till tagg... Alternativet.

  3. Klicka på + knappen.

    Skärmbild som visar knappen + .

  4. Skriv taggnamnet som SignInButton och klicka på Spara.

    Skärmbild som visar var taggnamnet SignInButton ska läggas till.

Kapitel 11 – Skapa Unity-projektet till UWP

Allt som behövs för Unity-avsnittet i det här projektet har nu slutförts, så det är dags att bygga det från Unity.

  1. Gå till Build Settings (File>Build Settings).

    Skärmbild som visar dialogrutan Skapa inställningar.

  2. Om inte redan markerar du Unity C# Projects.

  3. Klicka på Skapa. Unity startar ett Utforskaren fönster där du behöver skapa och väljer sedan en mapp som appen ska byggas in i. Skapa mappen nu och ge den namnet App. Klicka sedan på Välj mappmed appmappen markerad.

  4. Unity börjar skapa projektet i mappen App .

  5. När Unity har skapats (det kan ta lite tid) öppnas ett Utforskaren fönster på platsen för bygget (kontrollera aktivitetsfältet eftersom det kanske inte alltid visas ovanför dina fönster, men meddelar dig om att ett nytt fönster har lagts till).

Kapitel 12 – Distribuera till HoloLens

Så här distribuerar du på HoloLens:

  1. Du behöver IP-adressen för holoLens (för fjärrdistribution) och för att säkerställa att HoloLens är i utvecklarläge. Gör så här:

    1. Öppna inställningarna när du använder HoloLens.

    2. Gå tillAvancerade alternativför nätverk & Internet>Wi-Fi>

    3. Observera IPv4-adressen .

    4. Gå sedan tillbaka till Inställningar och sedan till Uppdatera & säkerhet>för utvecklare

    5. Aktivera utvecklarläge.

  2. Gå till din nya Unity-version ( mappen App ) och öppna lösningsfilen med Visual Studio.

  3. I Lösningskonfiguration väljer du Felsök.

  4. I Lösningsplattform väljer du x86, Fjärrdator. Du uppmanas att infoga IP-adressen för en fjärrenhet (HoloLens, i det här fallet som du noterade).

    Skärmbild som visar var du väljer x86 och Fjärrdator.

  5. Gå till menyn Skapa och klicka på Distribuera lösning för att separat läsa in programmet till holoLens.

  6. Din app bör nu visas i listan över installerade appar på HoloLens, redo att startas!

Ditt Microsoft Graph HoloLens-program

Grattis, du har skapat en mixed reality-app som använder Microsoft Graph för att läsa och visa användarkalenderdata.

Skärmbild som visar den färdiga mixed reality-appen.

Bonusövningar

Övning 1

Använd Microsoft Graph för att visa annan information om användaren

  • Användarens e-post/telefonnummer/profilbild

Övning 1

Implementera röststyrning för att navigera i Microsoft Graph-användargränssnittet.