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 anser vi att det är viktigt att låta de här självstudierna vara kvar för utvecklare som fortfarande letar efter 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 underhålls 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 du utvecklar för HoloLens 2. Det här meddelandet uppdateras med en länk till de självstudierna 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.

Screenshot that shows the scheduled meetings in the application interface.

Microsoft Graph är en uppsättning API:er som har 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 till relationer, vilket innebär att ett program kan komma åt alla typer av anslutna användardata. Mer information finns på sidan Microsoft Graph.

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.

Efter att ha slutfört den här kursen kommer du att ha en mixad verklighet HoloLens program, som kommer att kunna göra följande:

  1. Tryck på ett objekt med gesten Tryck, 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 vad som har testats och verifierats i skrivande stund (juli 2018). Du är fri att använda den senaste programvaran, som anges i installera verktyg artikeln, även om det inte bör antas att informationen i den här kursen kommer att perfekt matcha 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 din HoloLens. Om du behöver support för att konfigurera din HoloLens bör du gå till artikeln HoloLens installation.
  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 till att utföra dessa uppgifter för varje användare).

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

Om du behöver hjälp med sensorjustering följer du den här länken till artikeln HoloLens Sensorjustering.

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 tjänstnyckeln som gör att du kan ringa anrop till Microsoft Graph för att komma åt ditt kontoinnehåll.

  1. Gå till Microsofts programregistreringsportal 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.

    Screenshot that shows where to select Add an 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.

    Screenshot that shows where to add a name for your application.

  4. När programmet har skapats omdirigeras du till programmets huvudsida. Kopiera program-ID:t och se till att notera det här värdet någonstans säkert. Du kommer snart att använda det i koden.

    Screenshot that shows where to view the Application Id.

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

    Screenshot that highlights the Native Application section.

  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.

    Screenshot that shows where to select Add next to Delegated Permissions.

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

    Screenshot that shows the Calendars.Read checkbox.

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

    Screenshot that shows where to select Save.

  9. Din sparande 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å Nytt.

    Screenshot that shows the Unity interface.

  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 rotkataloger är bättre). Klicka sedan på Skapa projekt.

    Screenshot that shows where to select Create Project.

  3. När Unity är öppet är det värt att kontrollera att standardskriptredigeraren är inställd på Visual Studio. Gå till EditPreferences> 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 .

    Screenshot that shows where to set the External Script Editor to Visual Studio 2017.

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

    Screenshot that shows where to select Switch Platform.

  5. När du fortfarande är i FileBuild> Inställningar kontrollerar du att:

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

    2. Byggtyp är inställt på D3D

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

    4. Visual Studio version ä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.

        Screenshot that shows where to select Add Open Scenes.

      2. Skapa en ny mapp för detta, och alla framtida scenar. Välj knappen Ny mapp om du vill skapa en ny mapp och ge den namnet Scener.

        Screenshot that shows where to name the new folder.

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

        Screenshot that shows where to type the file name.

        Viktigt

        Tänk på att du måste spara Unity-scenerna i mappen Tillgångar eftersom de måste associeras med Unity-projektet. Att skapa mappen scener (och andra liknande mappar) är ett typiskt sätt att strukturera ett Unity-projekt.

    7. De återstående inställningarna i Build Inställningar bör lämnas som standard för tillfället.

  6. I fönstret Skapa Inställningar klickar du på knappen Spelare Inställningar. Då öppnas den relaterade panelen i det utrymme där kontrollanten finns.

    Screenshot that shows the Player Settings dialog box.

  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 Motsvarande), vilket utlöser ett behov av att starta om redigeraren.

      2. Skriptserverdelen ska vara .NET

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

        Screenshot that shows where to check the API compatibility level.

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

      • InternetClient

        Screenshot that shows where to select the InternetClient option.

    3. Längre ned på panelen, i XR-Inställningar (finns nedan Publicera Inställningar), kontrollerar du att virtual reality stöds och kontrollerar att Windows Mixed Reality SDK har lagts till.

      Screenshot that shows where to add Windows Mixed Reality SDK.

  8. I Build Instä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 (FILESAVE>SCENES/FILESAVE> PROJECT).

Kapitel 3 – Importera bibliotek i Unity

Viktigt

Om du vill hoppa över Unity Set up-komponenten i den här kursen och fortsätta direkt till kod kan du ladda ned den här Azure-MR-311.unitypackage, importera den till projektet 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:en Microsoft.Identity.Client. Det är möjligt att använda Microsoft Graph SDK, men det kräver tillägg av ett NuGet-paket när du har skapat Unity-projektet (vilket innebär att du redigerar projektet efter kompilering). Det anses enklare att importera nödvändiga DLL:er 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 menyalternativet TillgångarImportera>paketAnpassat> 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.

    Screenshot that shows the selected configuration parameters under Plugins.

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

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

    Screenshot that shows the Microsoft.Identity.Client plugin.

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

    Screenshot that shows where to confirm that Any Platform and WSAPlayer aren't checked.

    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 just konfigurerade. Välj filen och sedan i inspektören:

    • kontrollera att Alla plattformar är avmarkerade och att endastWSAPlayerär markerat.

    • Kontrollera att SDK är inställt på UWP och att skriptserverdelen är inställd på Dot Net

    • Kontrollera att Processen Inte är markerad.

      Screenshot that shows that Don't Process is selected.

  7. Klicka på Applicera.

Kapitel 4 – Kamerainstallation

Under det här kapitlet konfigurerar du 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 Inspector .

    1. Kameraobjektet måste ha namnet Main Camera (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. Ange Ta bort flaggor till Enfärgad

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

      Screenshot that highlights where to set the background color.

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

    Screenshot that shows the final object structure in the Hierarchy Panel.

Kapitel 5 – Skapa MeetingsUI-klass

Det första skriptet 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ångar i Project-panelen och välj sedan CreateFolder>. Namnge mappen Skript.

    Screenshot that shows where to find the Assets folder.Screenshot that shows where to create the Scripts folder.

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

    Screenshot that shows where to create the MeetingsUI folder.

  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 användargränssnittet för möten 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 klassen Graph

Nästa skript att skapa är det Graph skriptet. Det här skriptet ansvarar för att göra anropen 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å SkapaC>#-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 klassen Graph 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 klassen Graph:

        /// <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 antecknade i kapitel 1, steg 4. Det här värdet ska vara samma som det som visas i programregistreringsportalen på programregistreringssidan.

  8. I klassen Graph 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 dag och tidsintervall, 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 skriptet Graph. 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å SkapaC>#-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 koden 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 möjliggör 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 interaktionsskriptet , som ansvarar för:

  • Hantering av tryckinteraktion och Kamera blick, vilket gör att användaren kan interagera med inloggningen "knapp" i scenen.

  • Skapa inloggningsobjektet "knapp" i scenen så att 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å SkapaC>#-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 Interaction från MonoBehaviour till GazeInput.

    offentliga klassinteraktioner: MonoBehaviour

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

        /// <summary>
        /// Allows input recognition with the HoloLens
        /// </summary>
        private GestureRecognizer _gestureRecognizer;
    
  7. Ersätt Start-metoden ; observera att det är en åsidosättningsmetod som anropar "base" Gaze-klassmetoden. Start() anropas när klassen initieras, registreras för indataigenkänning och inloggningsknappen skapas 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 placering av de andra skripten där de behöver vara.

  • Dra skriptinteraktioner till huvudkameraobjektet från mappen Skript i Project panelen enligt bilden nedan.

    Screenshot that shows where to drag the Interactions script.

Kapitel 10 – Konfigurera taggen

Den kod som hanterar blicken använder Tag SignInButton för att identifiera vilket objekt användaren interagerar 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å MainCameraTag för att öppna en listruta. Klicka på Lägg till tagg...

    Screenshot that highlights the Add Tag... option.

  3. Klicka på + knappen.

    Screenshot that shows the + button.

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

    Screenshot that shows where to add the SignInButton tag name.

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 Inställningar (FileBuild> Inställningar).

    Screenshot that shows the Build Settings dialog box.

  2. Om du inte redan gjort det markerar du Unity C#-projekt.

  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 mappnär appmappen är markerad.

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

  5. När Unity har byggt klart (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 fönstren, 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 din HoloLens (för fjärrdistribution) och för att se till att din HoloLens är i utvecklarläge. Så här gör du:

    1. Öppna Inställningar medan du bär din HoloLens.

    2. Gå till Nätverk &InternetWi-FiAvancerade>>alternativ

    3. Anteckna IPv4-adressen .

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

    5. Ställ in Utvecklarläge på.

  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 antecknade).

    Screenshot that shows where to select x86 and Remote Machine.

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

  6. Din app bör nu visas i listan över installerade appar på din 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.

Screenshot that shows the completed mixed reality app.

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 Användargränssnittet för Microsoft Graph.