HoloLens (1. Generation) und Azure 309: Application Insights

Hinweis

Die Tutorials der Mixed Reality Academy wurden im Hinblick auf HoloLens (1. Gen.) und immersive Mixed Reality-Headsets entworfen. Daher halten wir es für wichtig, diese Tutorials für Entwickler verfügbar zu halten, die noch nach Anleitung beim Entwickeln für diese Geräte suchen. Diese Tutorials werden nicht mit den neuesten Toolsets oder Interaktionen aktualisiert, die für HoloLens 2 verwendet werden. Sie werden gewartet, um weiterhin auf den unterstützten Geräten zu funktionieren. Es wird eine neue Reihe von Tutorials geben, die in Zukunft veröffentlicht werden, die zeigen, wie für HoloLens 2 entwickelt werden kann. Dieser Hinweis wird mit einem Link zu diesen Tutorials aktualisiert, wenn sie veröffentlicht werden.

Willkommensbildschirm für das Mixed Reality Academy-Tutorial.

In diesem Kurs erfahren Sie, wie Sie Application Insights-Funktionen zu einer Mixed Reality-Anwendung hinzufügen, indem Sie die Azure-Anwendung Insights-API verwenden, um Analysen zum Benutzerverhalten zu sammeln.

Application Insights ist ein Microsoft-Dienst, mit dem Entwickler Analysen aus ihren Anwendungen sammeln und über ein benutzerfreundliches Portal verwalten können. Bei der Analyse kann es sich um eine beliebige Leistung oder um benutzerdefinierte Informationen handeln, die Sie sammeln möchten. Weitere Informationen finden Sie auf der Application Insights-Seite.

Nach Abschluss dieses Kurses verfügen Sie über eine immersive Mixed Reality-Headset-Anwendung, die folgendes ausführen kann:

  1. Erlauben Sie dem Benutzer, eine Szene zu betrachten und sich zu bewegen.
  2. Lösen Sie das Senden von Analysen an den Application Insights-Dienst aus, indem Sie Gaze und Proximity zu In-Scene-Objekten verwenden.
  3. Die App ruft auch den Dienst auf und ruft Informationen darüber ab, welches Objekt vom Benutzer innerhalb der letzten 24 Stunden am häufigsten angegangen wurde. Dieses Objekt ändert seine Farbe in Grün.

In diesem Kurs erfahren Sie, wie Sie die Ergebnisse aus dem Application Insights-Dienst in einer Unity-basierten Beispielanwendung abrufen. Sie müssen diese Konzepte auf eine benutzerdefinierte Anwendung anwenden, die Sie möglicherweise erstellen.

Geräteunterstützung

Kurs HoloLens Immersive Headsets
MR und Azure 309: Application Insights ✔️ ✔️

Hinweis

Während sich dieser Kurs hauptsächlich auf Windows Mixed Reality immersiven Headsets (VR) konzentriert, können Sie das, was Sie in diesem Kurs lernen, auch auf Microsoft HoloLens anwenden. Während Sie den Kurs befolgen, werden Ihnen Notizen zu allen Änderungen angezeigt, die Sie möglicherweise zur Unterstützung von HoloLens anwenden müssen. Wenn Sie HoloLens verwenden, können Sie während der Sprachaufnahme ein gewisses Echo bemerken.

Voraussetzungen

Hinweis

Dieses Tutorial richtet sich an Entwickler, die über grundlegende Erfahrungen mit Unity und C# verfügen. Bitte beachten Sie auch, dass die Voraussetzungen und schriftlichen Anweisungen in diesem Dokument das darstellen, was zum Zeitpunkt des Schreibens (Juli 2018) getestet und überprüft wurde. Sie können die neueste Software verwenden, wie im Artikel Installieren der Tools aufgeführt, obwohl nicht davon ausgegangen werden sollte, dass die Informationen in diesem Kurs perfekt dem entsprechen, was Sie in neuerer Software finden, als die unten aufgeführten.

Wir empfehlen die folgende Hard- und Software für diesen Kurs:

Vorbereitung

Um Probleme beim Erstellen dieses Projekts zu vermeiden, wird dringend empfohlen, das Projekt in diesem Tutorial in einem Stamm- oder Stammordner zu erstellen (lange Ordnerpfade können zur Buildzeit Zu Problemen führen).

Warnung

Seien Sie sich bewusst, dass die Daten, die an Application Insights gelangen, Zeit in Anspruch nehmen, also seien Sie geduldig. Wenn Sie überprüfen möchten, ob der Dienst Ihre Daten erhalten hat, lesen Sie Kapitel 14, das Ihnen zeigt, wie Sie im Portal navigieren.

Kapitel 1: Azure-Portal

Um Application Insights verwenden zu können, müssen Sie einen Application Insights-Dienst im Azure-Portal erstellen und konfigurieren.

  1. Melden Sie sich beim Azure-Portalan.

    Hinweis

    Wenn Sie noch nicht über ein Azure-Konto verfügen, müssen Sie ein Azure-Konto erstellen. Wenn Sie dieses Tutorial in einer Unterrichts- oder Labsituation befolgen, bitten Sie Ihren Kursleiter oder einen der Verantwortlichen um Hilfe beim Einrichten Ihres neuen Kontos.

  2. Nachdem Sie angemeldet sind, klicken Sie oben links auf Neu , suchen Sie nach Application Insights, und klicken Sie auf DIE EINGABETASTE.

    Hinweis

    Das Wort Neu wurde in neueren Portalen möglicherweise durch Ressource erstellen ersetzt.

    Screenshot: Azure-Portal: Im Bereich

  3. Die neue Seite rechts enthält eine Beschreibung des Azure-Anwendung Insights Service. Wählen Sie unten links auf dieser Seite die Schaltfläche Erstellen aus, um eine Zuordnung zu diesem Dienst zu erstellen.

    Screenshot des Application Insights-Bildschirms

  4. Nachdem Sie auf Erstellen geklickt haben:

    1. Fügen Sie den gewünschten Namen für diesen Dienst instance ein.

    2. Wählen Sie als Anwendungstypdie Option Allgemein aus.

    3. Wählen Sie ein entsprechendes Abonnement aus.

    4. Wählen Sie eine Ressourcengruppe aus, oder erstellen Sie eine neue. Eine Ressourcengruppe bietet eine Möglichkeit zum Überwachen, Steuern des Zugriffs, Bereitstellen und Verwalten der Abrechnung für eine Sammlung von Azure-Ressourcen. Es wird empfohlen, alle Azure-Dienste, die einem einzelnen Projekt (z. B. diesen Kursen) zugeordnet sind, unter einer gemeinsamen Ressourcengruppe zu speichern.

      Wenn Sie mehr über Azure-Ressourcengruppen erfahren möchten, lesen Sie den Artikel Ressourcengruppe.

    5. Wählen Sie einen Speicherortaus.

    6. Sie müssen auch bestätigen, dass Sie die Geschäftsbedingungen für diesen Dienst verstanden haben.

    7. Klicken Sie auf Erstellen.

      Screenshot des Application Insights-Fensters Name und Anwendungstyp sind hervorgehoben.

  5. Nachdem Sie auf Erstellen geklickt haben, müssen Sie warten, bis der Dienst erstellt wurde. Dies kann eine Minute dauern.

  6. Eine Benachrichtigung wird im Portal angezeigt, sobald der Dienst instance erstellt wurde.

    Screenshot: Ein Teil des Menübands mit hervorgehobenem Benachrichtigungssymbol

  7. Wählen Sie die Benachrichtigungen aus, um Ihre neue Dienst-instance zu erkunden.

    Screenshot: Dialogfeld

  8. Klicken Sie in der Benachrichtigung auf die Schaltfläche Zu Ressource wechseln, um Ihren neuen Dienst instance zu erkunden. Sie werden zu Ihrem neuen Application Insights Service-instance weitergeleitet.

    Screenshot: Application Insights Service instance, bei dem der instance Name MyNewInsight lautet.

    Hinweis

    Halten Sie diese Webseite offen und leicht zugänglich. Sie werden häufig hierher zurückkehren, um die gesammelten Daten zu sehen.

    Wichtig

    Zum Implementieren von Application Insights müssen Sie drei (3) spezifische Werte verwenden: Instrumentierungsschlüssel, Anwendungs-ID und API-Schlüssel. Nachfolgend sehen Sie, wie Sie diese Werte aus Ihrem Dienst abrufen. Notieren Sie sich diese Werte auf einer leeren Editor-Seite , da Sie sie bald in Ihrem Code verwenden werden.

  9. Um den Instrumentierungsschlüssel zu finden, müssen Sie in der Liste der Dienstfunktionen nach unten scrollen und Eigenschaften auswählen. Auf der angezeigten Registerkarte wird der Dienstschlüssel angezeigt.

    Screenshot: Dienstfunktionen, Eigenschaften sind im Abschnitt Konfigurieren hervorgehoben, und Instrumentierungsschlüssel ist im Bereich Standard hervorgehoben.

  10. Unter Eigenschaften finden Sie API-Zugriff, auf den Sie klicken müssen. Im Bereich auf der rechten Seite wird die Anwendungs-ID Ihrer App angegeben.

    Screenshot: Dienstfunktionen: Hervorgehobener P I-Zugriff Erstellen eines P I-Schlüssels und Anwendungs-I D sind im Bereich Standard hervorgehoben.

  11. Wenn der Bereich Anwendungs-ID weiterhin geöffnet ist, klicken Sie auf API-Schlüssel erstellen, wodurch der Bereich API-Schlüssel erstellen geöffnet wird.

    Screenshot: Tastenbereich

  12. Geben Sie im jetzt geöffneten Bereich API-Schlüssel erstellen eine Beschreibung ein, und aktivieren Sie die drei Kontrollkästchen.

  13. Klicken Sie auf Schlüssel generieren. Ihr API-Schlüssel wird erstellt und angezeigt.

    Screenshot des Bereichs

    Warnung

    Dies ist das einzige Mal, dass Ihr Dienstschlüssel angezeigt wird. Stellen Sie daher sicher, dass Sie jetzt eine Kopie davon erstellen.

Kapitel 2: Einrichten des Unity-Projekts

Es folgt ein typisches Setup für die Entwicklung mit Mixed Reality und ist daher eine gute Vorlage für andere Projekte.

  1. Öffnen Sie Unity , und klicken Sie auf Neu.

    Screenshot des Fensters

  2. Sie müssen nun einen Unity-Projektnamen angeben, MR_Azure_Application_Insights einfügen. Stellen Sie sicher, dass die Vorlage auf 3D festgelegt ist. Legen Sie den Speicherort auf einen für Sie geeigneten Ort fest (denken Sie daran, dass näher an Stammverzeichnissen besser ist). Klicken Sie dann auf Projekt erstellen.

    Screenshot des Unity-Fensters

  3. Wenn Unity geöffnet ist, lohnt es sich, zu überprüfen, ob der Standardskript-Editor auf Visual Studio festgelegt ist. Navigieren Sie zu Bearbeitungseinstellungen>, und navigieren Sie dann im neuen Fenster zu Externe Tools. Ändern Sie den externen Skript-Editor in Visual Studio 2017. Schließen Sie das Fenster Einstellungen.

    Screenshot: Visual Studio ist als externer Skript-Editor eingerichtet.

  4. Wechseln Sie als Nächstes zu Dateibuildeinstellungen>, und ändern Sie die Plattform auf Universelle Windows-Plattform, indem Sie auf die Schaltfläche Plattform wechseln klicken.

    Screenshot des Fensters

  5. Wechseln Sie zu Dateibuildeinstellungen>, und stellen Sie folgendes sicher:

    1. Zielgerät ist auf "Beliebiges Gerät" festgelegt.

      Legen Sie für die Microsoft HoloLens Zielgerät auf HoloLens fest.

    2. Buildtyp ist auf D3D festgelegt.

    3. SDK ist auf Latest installed (Neueste Installation) festgelegt.

    4. Build and Run ist auf Lokaler Computer festgelegt.

    5. Speichern Sie die Szene, und fügen Sie sie dem Build hinzu.

      1. Wählen Sie dazu Offene Szenen hinzufügen aus. Ein Speicherfenster wird angezeigt.

        Screenshot des Fensters

      2. Erstellen Sie einen neuen Ordner für diese und jede zukünftige Szene, und klicken Sie dann auf die Schaltfläche Neuer Ordner , um einen neuen Ordner zu erstellen, nennen Sie ihn Szenen.

        Screenshot des Fensters

      3. Öffnen Sie den neu erstellten Ordner Scenes , und geben Sie dann im Textfeld Dateiname:ApplicationInsightsScene ein, und klicken Sie dann auf Speichern.

        Screenshot des Fensters

  6. Die restlichen Einstellungen in Buildeinstellungen sollten vorerst als Standard beibehalten werden.

  7. Wählen Sie im Fenster Buildeinstellungendie Option Playereinstellungen aus. Dadurch wird der zugehörige Bereich in dem Bereich geöffnet, in dem sich der Inspektor befindet.

    Screenshot der Registerkarte

  8. In diesem Bereich müssen einige Einstellungen überprüft werden:

    1. Auf der Registerkarte Andere Einstellungen :

      1. DieSkriptruntimeversion sollte experimental (.NET 4.6 Equivalent) lauten, was einen Neustart des Editors auslöst.

      2. Skript-Back-End sollte .NET sein

      3. API-Kompatibilitätsgrad sollte .NET 4.6 sein.

      Screenshot der Registerkarte

    2. Aktivieren Sie auf der Registerkarte Veröffentlichungseinstellungen unter Funktionen Folgendes:

      • InternetClient

        Screenshot der Liste

    3. Wählen Sie weiter unten im Bereich unter XR-Einstellungen (unter Veröffentlichungseinstellungen) das Kontrollkästchen Virtual Reality Unterstützt aus, und stellen Sie sicher, dass das Windows Mixed Reality SDK hinzugefügt wurde.

      Screenshot des Abschnitts

  9. Zurück in den Buildeinstellungen ist Unity C#-Projekte nicht mehr ausgegraut. aktivieren Sie das Kontrollkästchen neben diesem.

  10. Schließen Sie das Fenster „Build Settings“ (Buildeinstellungen).

  11. Speichern Sie Ihre Szene und Ihr Projekt (FILE>SAVE SCENE /FILE>SAVE PROJECT).

Kapitel 3: Importieren des Unity-Pakets

Wichtig

Wenn Sie die Unity Setup-Komponenten dieses Kurses überspringen und direkt mit dem Code fortfahren möchten, können Sie dieses Azure-MR-309.unitypackage herunterladen und als benutzerdefiniertes Paket in Ihr Projekt importieren. Dies enthält auch die DLLs aus dem nächsten Kapitel. Fahren Sie nach dem Import aus Kapitel 6 fort.

Wichtig

Um Application Insights in Unity zu verwenden, müssen Sie die DLL zusammen mit der Newtonsoft-DLL importieren. Es gibt derzeit ein bekanntes Problem in Unity, das erfordert, dass Plug-Ins nach dem Import neu konfiguriert werden müssen. Diese Schritte (4 bis 7 in diesem Abschnitt) sind nicht mehr erforderlich, nachdem der Fehler behoben wurde.

Um Application Insights in Ihr eigenes Projekt zu importieren, stellen Sie sicher, dass Sie das ".unitypackage" heruntergeladen haben, das die Plug-Ins enthält. Gehen Sie nun wie folgt vor:

  1. Fügen Sie unitypackage** zu Unity hinzu, indem Sie die Menüoption Assets > Import Package > Custom Package (Benutzerdefiniertes Paket importieren ) verwenden.

  2. Vergewissern Sie sich im eingeblendeten Feld Unity-Paket importieren , dass alles unter (und einschließlich) Plug-Ins ausgewählt ist.

    Screenshot des Dialogfelds

  3. Klicken Sie auf die Schaltfläche Importieren , um die Elemente ihrem Projekt hinzuzufügen.

  4. Wechseln Sie in der Projektansicht zum Ordner Insights unter Plugins , und wählen Sie nur die folgenden Plug-Ins aus:

    • Microsoft.ApplicationInsights

    Screenshot des Projektbereichs, der Ordner

  5. Wenn Dieses Plug-In ausgewählt ist, stellen Sie sicher, dass Beliebige Plattformdeaktiviert ist. Stellen Sie dann sicher, dass WSAPlayer ebenfalls deaktiviert ist, und klicken Sie dann auf Übernehmen. Dies geschieht nur, um zu bestätigen, dass die Dateien ordnungsgemäß konfiguriert sind.

    Screenshot des Bereichs

    Hinweis

    Wenn Sie die Plug-Ins wie folgt markieren, werden sie so konfiguriert, dass sie nur im Unity-Editor verwendet werden. Es gibt eine andere Gruppe von DLLs im WSA-Ordner, die verwendet werden, nachdem das Projekt aus Unity exportiert wurde.

  6. Als Nächstes müssen Sie den WSA-Ordner im Ordner Insights öffnen. Es wird eine Kopie derselben Datei angezeigt, die Sie konfiguriert haben. Wählen Sie diese Datei aus, und stellen Sie dann im Inspektor sicher, dass Beliebige Plattformdeaktiviert ist, und stellen Sie dann sicher, dass nurWSAPlayeraktiviert ist. Klicken Sie auf Anwenden.

    Screenshot des Bereichs

  7. Sie müssen nun die Schritte 4 bis 6 ausführen, aber stattdessen für die Newtonsoft-Plug-Ins. Wie das Ergebnis aussehen sollte, sehen Sie sich den folgenden Screenshot an.

    Screenshot: Vier Ansichten der Bereiche

Kapitel 4: Einrichten der Kamera- und Benutzersteuerung

In diesem Kapitel richten Sie die Kamera und die Steuerelemente so ein, dass der Benutzer die Szene sehen und bewegen kann.

  1. Klicken Sie im Hierarchiebereich mit der rechten Maustaste auf einen leeren Bereich, und klicken Sie dann auf Leer erstellen>.

    Screenshot des Hierarchiebereichs, in dem

  2. Benennen Sie das neue leere GameObject in Übergeordnete Kamera um.

    Screenshot des Hierarchiebereichs mit ausgewählter Option

  3. Klicken Sie im Hierarchiebereich mit der rechten Maustaste auf einen leeren Bereich, dann auf 3D-Objekt und dann auf Sphere.

  4. Benennen Sie die Sphäre in rechts um.

  5. Legen Sie die Transformationsskala der rechten Hand auf 0,1, 0,1, 0,1 fest.

    Screenshot der Bereiche

  6. Entfernen Sie die Sphere Collider-Komponente aus der rechten Hand, indem Sie in der Sphere Collider-Komponente auf das Zahnrad und dann auf Komponente entfernen klicken.

    Screenshot des Bereichs

  7. Ziehen Sie im Hierarchiebereich die Objekte Hauptkamera und rechte Hand auf das Übergeordnete Kameraobjekt .

    Screenshot des Hierarchiebereichs mit ausgewählter Hauptkamera und aktivierter Hauptkamera im Bereich

  8. Legen Sie die Transformationsposition der Hauptkamera und des Rechtshandobjekts auf 0, 0, 0 fest.

    Screenshot des Hierarchiebereichs mit ausgewählter Hauptkamera und hervorgehobenen Transformationseinstellungen im Inspektorbereich.

    Screenshot des Hierarchiebereichs mit ausgewählter rechten Hand und hervorgehobenen Transformationseinstellungen im Bereich

Kapitel 5: Einrichten der Objekte in der Unity-Szene

Sie erstellen nun einige grundlegende Shapes für Ihre Szene, mit denen der Benutzer interagieren kann.

  1. Klicken Sie mit der rechten Maustaste in einen leeren Bereich im Hierarchiebereich, dann auf 3D-Objekt, und wählen Sie dann Ebene aus.

  2. Legen Sie die Ebene Transformationsposition auf 0, -1, 0 fest.

  3. Legen Sie die Ebenentransformationsskalierung auf 5, 1, 5 fest.

    Screenshot der Bereiche

  4. Erstellen Sie ein grundlegendes Material, das mit Ihrem Plane-Objekt verwendet werden soll, damit die anderen Formen leichter zu sehen sind. Navigieren Sie zu Ihrem Projektbereich, klicken Sie mit der rechten Maustaste auf Erstellen, gefolgt von Ordner, um einen neuen Ordner zu erstellen. Nennen Sie es Materials.

    Screenshot des Bereichs Screenshot des Bereichs

  5. Öffnen Sie den Ordner Materialien , klicken Sie dann mit der rechten Maustaste auf Erstellen und dann auf Material, um ein neues Material zu erstellen. Nennen Sie ihn Blau.

    Screenshot des Bereichs Screenshot des Bereichs

  6. Wenn Sie das neue Blaue Material ausgewählt haben, sehen Sie sich den Inspector an, und klicken Sie auf das rechteckige Fenster neben Albedo. Wählen Sie eine blaue Farbe aus (das folgende Bild ist Hex Color: #3592FFFF). Klicken Sie auf die Schaltfläche Schließen, nachdem Sie die Option ausgewählt haben.

    Screenshot des Bereichs

  7. Ziehen Sie Ihr neues Material aus dem Ordner Materialien in Ihre neu erstellte Ebene innerhalb Ihrer Szene (oder legen Sie es im Objekt Plane innerhalb der Hierarchie ab).

    Screenshot des Bereichs

  8. Klicken Sie mit der rechten Maustaste in einen leeren Bereich im Hierarchiebereich, und klicken Sie dann auf 3D-Objekt, Capsule.

    • Wenn die Kapsel ausgewählt ist, ändern Sie ihre Transformationsposition in: -10, 1, 0.
  9. Klicken Sie mit der rechten Maustaste in einen leeren Bereich im Hierarchiebereich, und klicken Sie dann auf 3D-Objekt, Cube.

    • Wenn der Cube ausgewählt ist, ändern Sie die Transformationsposition in: 0, 0, 10.
  10. Klicken Sie mit der rechten Maustaste in einen leeren Bereich im Hierarchiebereich, und klicken Sie dann auf 3D-Objekt, Sphere.

    • Wenn die Kugel ausgewählt ist, ändern Sie ihre Transformationsposition in: 10, 0, 0.

    Screenshot der Bereiche

    Hinweis

    Diese Positionswerte sind Vorschläge. Sie können die Positionen der Objekte auf das festlegen, was Sie möchten, obwohl es für den Benutzer der Anwendung einfacher ist, wenn die Objekte nicht zu weit von der Kamera entfernt sind.

  11. Wenn Ihre Anwendung ausgeführt wird, muss sie in der Lage sein, die Objekte innerhalb der Szene zu identifizieren. Dazu müssen sie markiert werden. Wählen Sie eines der Objekte aus, und klicken Sie im Bereich Inspektor auf Tag hinzufügen..., wodurch der Inspektor durch den Bereich Tags & Ebenen ausgetauscht wird.

    Screenshot des Bereichs Screenshot des Bereichs

  12. Klicken Sie auf das +-Symbol (plus), und geben Sie den Tagnamen als ObjectInScene ein.

    Screenshot des Bereichs

    Warnung

    Wenn Sie einen anderen Namen für Ihr Tag verwenden, müssen Sie sicherstellen, dass diese Änderung später auch in den Skripts DataFromAnalytics, ObjectTrigger und Gaze vorgenommen wird, damit Ihre Objekte innerhalb Ihrer Szene gefunden und erkannt werden.

  13. Nachdem das Tag erstellt wurde, müssen Sie es jetzt auf alle drei Objekte anwenden. Halten Sie in der Hierarchie die UMSCHALTTASTE gedrückt, klicken Sie dann auf die Objekte Kapsel, Cube und Kugel, und klicken Sie dann im Inspektor auf das Dropdownmenü neben Tag und dann auf das von Ihnen erstellte ObjectInScene-Tag .

    Screenshot des Bereichs Screenshot: zwei Menüs mit hervorgehobener Option

Kapitel 6: Erstellen der ApplicationInsightsTracker-Klasse

Das erste Skript, das Sie erstellen müssen, ist ApplicationInsightsTracker, das für Folgendes verantwortlich ist:

  1. Erstellen von Ereignissen basierend auf Benutzerinteraktionen, die an Azure-Anwendung Insights übermittelt werden sollen.

  2. Erstellen geeigneter Ereignisnamen, abhängig von der Benutzerinteraktion.

  3. Übermitteln von Ereignissen an den Application Insights Service-instance.

So erstellen Sie diese Klasse:

  1. Klicken Sie mit der rechten Maustaste im Projektbereich, und klicken Siedannauf Ordner erstellen>. Nennen Sie den Ordner Skripts.

    Screenshot des Bereichs Screenshot: Menüoptionen, in denen die Optionen Erstellen und C#-Skript ausgewählt sind.

  2. Doppelklicken Sie auf den Ordner Skripts , um ihn zu öffnen. Klicken Sie dann in diesem Ordner mit der rechten Maustaste aufC#-Skripterstellen>. Nennen Sie das Skript ApplicationInsightsTracker.

  3. Doppelklicken Sie auf das neue ApplicationInsightsTracker-Skript , um es mit Visual Studio zu öffnen.

  4. Aktualisieren Sie Namespaces am oberen Rand des Skripts wie folgt:

        using Microsoft.ApplicationInsights;
        using Microsoft.ApplicationInsights.DataContracts;
        using Microsoft.ApplicationInsights.Extensibility;
        using UnityEngine;
    
  5. Fügen Sie in der -Klasse die folgenden Variablen ein:

        /// <summary>
        /// Allows this class to behavior like a singleton
        /// </summary>
        public static ApplicationInsightsTracker Instance;
    
        /// <summary>
        /// Insert your Instrumentation Key here
        /// </summary>
        internal string instrumentationKey = "Insert Instrumentation Key here";
    
        /// <summary>
        /// Insert your Application Id here
        /// </summary>
        internal string applicationId = "Insert Application Id here";
    
        /// <summary>
        /// Insert your API Key here
        /// </summary>
        internal string API_Key = "Insert API Key here";
    
        /// <summary>
        /// Represent the Analytic Custom Event object
        /// </summary>
        private TelemetryClient telemetryClient;
    
        /// <summary>
        /// Represent the Analytic object able to host gaze duration
        /// </summary>
        private MetricTelemetry metric;
    

    Hinweis

    Legen Sie die Werte instrumentationKey, applicationId und API_Key entsprechend fest, indem Sie die Dienstschlüssel aus dem Azure-Portal verwenden, wie in Kapitel 1, Schritt 9 beschrieben.

  6. Fügen Sie dann die Methoden Start() und Awake() hinzu, die aufgerufen werden, wenn die Klasse initialisiert:

        /// <summary>
        /// Sets this class instance as a singleton
        /// </summary>
        void Awake()
        {
            Instance = this;
        }
    
        /// <summary>
        /// Use this for initialization
        /// </summary>
        void Start()
        {
            // Instantiate telemetry and metric
            telemetryClient = new TelemetryClient();
    
            metric = new MetricTelemetry();
    
            // Assign the Instrumentation Key to the Event and Metric objects
            TelemetryConfiguration.Active.InstrumentationKey = instrumentationKey;
    
            telemetryClient.InstrumentationKey = instrumentationKey;
        }
    
  7. Fügen Sie die Methoden hinzu, die für das Senden der von Ihrer Anwendung registrierten Ereignisse und Metriken verantwortlich sind:

        /// <summary>
        /// Submit the Event to Azure Analytics using the event trigger object
        /// </summary>
        public void RecordProximityEvent(string objectName)
        {
            telemetryClient.TrackEvent(CreateEventName(objectName));
        }
    
        /// <summary>
        /// Uses the name of the object involved in the event to create 
        /// and return an Event Name convention
        /// </summary>
        public string CreateEventName(string name)
        {
            string eventName = $"User near {name}";
            return eventName;
        }
    
        /// <summary>
        /// Submit a Metric to Azure Analytics using the metric gazed object
        /// and the time count of the gaze
        /// </summary>
        public void RecordGazeMetrics(string objectName, int time)
        {
            // Output Console information about gaze.
            Debug.Log($"Finished gazing at {objectName}, which went for <b>{time}</b> second{(time != 1 ? "s" : "")}");
    
            metric.Name = $"Gazed {objectName}";
    
            metric.Value = time;
    
            telemetryClient.TrackMetric(metric);
        }
    
  8. Speichern Sie ihre Änderungen in Visual Studio , bevor Sie zu Unity zurückkehren.

Kapitel 7: Erstellen des Skripts "Gaze"

Das nächste zu erstellende Skript ist das Gaze-Skript . Dieses Skript ist für das Erstellen eines Raycasts verantwortlich, der von der Hauptkamera nach vorne projiziert wird, um zu erkennen, welches Objekt der Benutzer betrachtet. In diesem Fall muss raycast ermitteln, ob der Benutzer ein Objekt mit dem ObjectInScene-Tag betrachtet, und dann zählen, wie lange der Benutzer dieses Objekt betrachtet.

  1. Doppelklicken Sie auf den Ordner Skripts , um ihn zu öffnen.

  2. Klicken Sie mit der rechten Maustaste in den Ordner Skripts, und klicken Sie aufC#-Skripterstellen>. Nennen Sie das Skript Gaze.

  3. Doppelklicken Sie auf das Skript, um es mit Visual Studio zu öffnen.

  4. Ersetzen Sie den vorhandenen Code durch folgenden Code:

        using UnityEngine;
    
        public class Gaze : MonoBehaviour
        {
            /// <summary>
            /// Provides Singleton-like behavior to this class.
            /// </summary>
            public static Gaze Instance;
    
            /// <summary>
            /// Provides a reference to the object the user is currently looking at.
            /// </summary>
            public GameObject FocusedGameObject { get; private set; }
    
            /// <summary>
            /// Provides whether an object has been successfully hit by the raycast.
            /// </summary>
            public bool Hit { get; private set; }
    
            /// <summary>
            /// Provides a reference to compare whether the user is still looking at 
            /// the same object (and has not looked away).
            /// </summary>
            private GameObject _oldFocusedObject = null;
    
            /// <summary>
            /// Max Ray Distance
            /// </summary>
            private float _gazeMaxDistance = 300;
    
            /// <summary>
            /// Max Ray Distance
            /// </summary>
            private float _gazeTimeCounter = 0;
    
            /// <summary>
            /// The cursor object will be created when the app is running,
            /// this will store its values. 
            /// </summary>
            private GameObject _cursor;
        }
    
  5. Code für die Methoden Awake() und Start() muss jetzt hinzugefügt werden.

        private void Awake()
        {
            // Set this class to behave similar to singleton
            Instance = this;
            _cursor = CreateCursor();
        }
    
        void Start()
        {
            FocusedGameObject = null;
        }
    
        /// <summary>
        /// Create a cursor object, to provide what the user
        /// is looking at.
        /// </summary>
        /// <returns></returns>
        private GameObject CreateCursor()    
        {
            GameObject newCursor = GameObject.CreatePrimitive(PrimitiveType.Sphere);
    
            // Remove the collider, so it does not block raycast.
            Destroy(newCursor.GetComponent<SphereCollider>());
    
            newCursor.transform.localScale = new Vector3(0.1f, 0.1f, 0.1f);
    
            newCursor.GetComponent<MeshRenderer>().material.color = 
            Color.HSVToRGB(0.0223f, 0.7922f, 1.000f);
    
            newCursor.SetActive(false);
            return newCursor;
        }
    
  6. Fügen Sie in der Gaze-Klasse den folgenden Code in der Update() -Methode hinzu, um einen Raycast zu projizieren und den Zieltreffer zu erkennen:

        /// <summary>
        /// Called every frame
        /// </summary>
        void Update()
        {
            // Set the old focused gameobject.
            _oldFocusedObject = FocusedGameObject;
    
            RaycastHit hitInfo;
    
            // Initialize Raycasting.
            Hit = Physics.Raycast(Camera.main.transform.position, Camera.main.transform.forward, out hitInfo, _gazeMaxDistance);
    
            // Check whether raycast has hit.
            if (Hit == true)
            {
                // Check whether the hit has a collider.
                if (hitInfo.collider != null)
                {
                    // Set the focused object with what the user just looked at.
                    FocusedGameObject = hitInfo.collider.gameObject;
    
                    // Lerp the cursor to the hit point, which helps to stabilize the gaze.
                    _cursor.transform.position = Vector3.Lerp(_cursor.transform.position, hitInfo.point, 0.6f);
    
                    _cursor.SetActive(true);
                }
                else
                {
                    // Object looked on is not valid, set focused gameobject to null.
                    FocusedGameObject = null;
    
                    _cursor.SetActive(false);
                }
            }
            else
            {
                // No object looked upon, set focused gameobject to null.
                FocusedGameObject = null;
    
                _cursor.SetActive(false);
            }
    
            // Check whether the previous focused object is this same object. If so, reset the focused object.
            if (FocusedGameObject != _oldFocusedObject)
            {
                ResetFocusedObject();
            }
            // If they are the same, but are null, reset the counter. 
            else if (FocusedGameObject == null && _oldFocusedObject == null)
            {
                _gazeTimeCounter = 0;
            }
            // Count whilst the user continues looking at the same object.
            else
            {
                _gazeTimeCounter += Time.deltaTime;
            }
        }
    
  7. Fügen Sie die ResetFocusedObject() -Methode hinzu, um Daten an Application Insights zu senden, wenn der Benutzer ein Objekt angesehen hat.

        /// <summary>
        /// Reset the old focused object, stop the gaze timer, and send data if it
        /// is greater than one.
        /// </summary>
        public void ResetFocusedObject()
        {
            // Ensure the old focused object is not null.
            if (_oldFocusedObject != null)
            {
                // Only looking for objects with the correct tag.
                if (_oldFocusedObject.CompareTag("ObjectInScene"))
                {
                    // Turn the timer into an int, and ensure that more than zero time has passed.
                    int gazeAsInt = (int)_gazeTimeCounter;
    
                    if (gazeAsInt > 0)
                    {
                        //Record the object gazed and duration of gaze for Analytics
                        ApplicationInsightsTracker.Instance.RecordGazeMetrics(_oldFocusedObject.name, gazeAsInt);
                    }
                    //Reset timer
                    _gazeTimeCounter = 0;
                }
            }
        }
    
  8. Sie haben nun das Skript "Gaze" abgeschlossen. Speichern Sie Ihre Änderungen in Visual Studio , bevor Sie zu Unity zurückkehren.

Kapitel 8: Erstellen der ObjectTrigger-Klasse

Das nächste Skript, das Sie erstellen müssen, ist ObjectTrigger, das für Folgendes verantwortlich ist:

  • Hinzufügen von Komponenten, die für die Kollision erforderlich sind, zur Hauptkamera.
  • Erkennt, ob sich die Kamera in der Nähe eines Objekts befindet, das als ObjectInScene markiert ist.

So erstellen Sie das Skript:

  1. Doppelklicken Sie auf den Ordner Skripts , um ihn zu öffnen.

  2. Klicken Sie mit der rechten Maustaste in den Ordner Skripts, und klicken Sie aufC#-Skripterstellen>. Nennen Sie das Skript ObjectTrigger.

  3. Doppelklicken Sie auf das Skript, um es mit Visual Studio zu öffnen. Ersetzen Sie den vorhandenen Code durch folgenden Code:

        using UnityEngine;
    
        public class ObjectTrigger : MonoBehaviour
        {
            private void Start()
            {
                // Add the Collider and Rigidbody components, 
                // and set their respective settings. This allows for collision.
                gameObject.AddComponent<SphereCollider>().radius = 1.5f;
    
                gameObject.AddComponent<Rigidbody>().useGravity = false;
            }
    
            /// <summary>
            /// Triggered when an object with a collider enters this objects trigger collider.
            /// </summary>
            /// <param name="collision">Collided object</param>
            private void OnCollisionEnter(Collision collision)
            {
                CompareTriggerEvent(collision, true);
            }
    
            /// <summary>
            /// Triggered when an object with a collider exits this objects trigger collider.
            /// </summary>
            /// <param name="collision">Collided object</param>
            private void OnCollisionExit(Collision collision)
            {
                CompareTriggerEvent(collision, false);
            }
    
            /// <summary>
            /// Method for providing debug message, and sending event information to InsightsTracker.
            /// </summary>
            /// <param name="other">Collided object</param>
            /// <param name="enter">Enter = true, Exit = False</param>
            private void CompareTriggerEvent(Collision other, bool enter)
            {
                if (other.collider.CompareTag("ObjectInScene"))
                {
                    string message = $"User is{(enter == true ? " " : " no longer ")}near <b>{other.gameObject.name}</b>";
    
                    if (enter == true)
                    {
                        ApplicationInsightsTracker.Instance.RecordProximityEvent(other.gameObject.name);
                    }
                    Debug.Log(message);
                }
            }
        }
    
  4. Speichern Sie ihre Änderungen in Visual Studio , bevor Sie zu Unity zurückkehren.

Kapitel 9: Erstellen der DataFromAnalytics-Klasse

Sie müssen nun das DataFromAnalytics-Skript erstellen, das für Folgendes verantwortlich ist:

  • Ruft Analysedaten darüber ab, welches Objekt von der Kamera am häufigsten angegangen wurde.
  • Verwenden Sie die Dienstschlüssel, die die Kommunikation mit Ihrem Azure-Anwendung Insights Service instance ermöglichen.
  • Sortieren der Objekte in Szene, nach der die höchste Ereignisanzahl aufweist.
  • Ändern der Materialfarbe des am häufigsten angegangenen Objekts in Grün.

So erstellen Sie das Skript:

  1. Doppelklicken Sie auf den Ordner Skripts , um ihn zu öffnen.

  2. Klicken Sie mit der rechten Maustaste in den Ordner Skripts, und klicken Sie aufC#-Skripterstellen>. Nennen Sie das Skript DataFromAnalytics.

  3. Doppelklicken Sie auf das Skript, um es mit Visual Studio zu öffnen.

  4. Fügen Sie die folgenden Namespaces ein:

        using Newtonsoft.Json;
        using System;
        using System.Collections;
        using System.Collections.Generic;
        using System.Linq;
        using UnityEngine;
        using UnityEngine.Networking;
    
  5. Fügen Sie Folgendes in das Skript ein:

        /// <summary>
        /// Number of most recent events to be queried
        /// </summary>
        private int _quantityOfEventsQueried = 10;
    
        /// <summary>
        /// The timespan with which to query. Needs to be in hours.
        /// </summary>
        private int _timepspanAsHours = 24;
    
        /// <summary>
        /// A list of the objects in the scene
        /// </summary>
        private List<GameObject> _listOfGameObjectsInScene;
    
        /// <summary>
        /// Number of queries which have returned, after being sent.
        /// </summary>
        private int _queriesReturned = 0;
    
        /// <summary>
        /// List of GameObjects, as the Key, with their event count, as the Value.
        /// </summary>
        private List<KeyValuePair<GameObject, int>> _pairedObjectsWithEventCount = new List<KeyValuePair<GameObject, int>>();
    
        // Use this for initialization
        void Start()
        {
            // Find all objects in scene which have the ObjectInScene tag (as there may be other GameObjects in the scene which you do not want).
            _listOfGameObjectsInScene = GameObject.FindGameObjectsWithTag("ObjectInScene").ToList();
    
            FetchAnalytics();
        }
    
  6. Fügen Sie innerhalb der DataFromAnalytics-Klasse direkt nach der Start() -Methode die folgende Methode mit dem Namen FetchAnalytics()hinzu. Diese Methode ist für das Auffüllen der Liste der Schlüsselwertpaare mit einer GameObject-Nummer und einer Platzhalterereignisanzahl verantwortlich. Anschließend wird die GetWebRequest() -Coroutine initialisiert. Die Abfragestruktur des Aufrufs von Application Insights kann auch in dieser Methode als Abfrage-URL-Endpunkt gefunden werden.

        private void FetchAnalytics()
        {
            // Iterate through the objects in the list
            for (int i = 0; i < _listOfGameObjectsInScene.Count; i++)
            {
                // The current event number is not known, so set it to zero.
                int eventCount = 0;
    
                // Add new pair to list, as placeholder, until eventCount is known.
                _pairedObjectsWithEventCount.Add(new KeyValuePair<GameObject, int>(_listOfGameObjectsInScene[i], eventCount));
    
                // Set the renderer of the object to the default color, white
                _listOfGameObjectsInScene[i].GetComponent<Renderer>().material.color = Color.white;
    
                // Create the appropriate object name using Insights structure
                string objectName = _listOfGameObjectsInScene[i].name;
    
     		    // Build the queryUrl for this object.
     		    string queryUrl = Uri.EscapeUriString(string.Format(
                    "https://api.applicationinsights.io/v1/apps/{0}/events/$all?timespan=PT{1}H&$search={2}&$select=customMetric/name&$top={3}&$count=true",
     			    ApplicationInsightsTracker.Instance.applicationId, _timepspanAsHours, "Gazed " + objectName, _quantityOfEventsQueried));
    
    
                // Send this object away within the WebRequest Coroutine, to determine it is event count.
                StartCoroutine("GetWebRequest", new KeyValuePair<string, int>(queryUrl, i));
            }
        }
    
  7. Fügen Sie direkt unter der FetchAnalytics() -Methode eine Methode namens GetWebRequest() hinzu, die einen IEnumerator zurückgibt. Diese Methode ist dafür verantwortlich, wie oft ein Ereignis in Application Insights aufgerufen wurde, das einem bestimmten GameObject entspricht. Wenn alle gesendeten Abfragen zurückgegeben wurden, wird die DetermineWinner() -Methode aufgerufen.

        /// <summary>
        /// Requests the data count for number of events, according to the
        /// input query URL.
        /// </summary>
        /// <param name="webQueryPair">Query URL and the list number count.</param>
        /// <returns></returns>
        private IEnumerator GetWebRequest(KeyValuePair<string, int> webQueryPair)
        {
            // Set the URL and count as their own variables (for readability).
            string url = webQueryPair.Key;
            int currentCount = webQueryPair.Value;
    
            using (UnityWebRequest unityWebRequest = UnityWebRequest.Get(url))
            {
                DownloadHandlerBuffer handlerBuffer = new DownloadHandlerBuffer();
    
                unityWebRequest.downloadHandler = handlerBuffer;
    
                unityWebRequest.SetRequestHeader("host", "api.applicationinsights.io");
    
                unityWebRequest.SetRequestHeader("x-api-key", ApplicationInsightsTracker.Instance.API_Key);
    
                yield return unityWebRequest.SendWebRequest();
    
                if (unityWebRequest.isNetworkError)
                {
                    // Failure with web request.
                    Debug.Log("<color=red>Error Sending:</color> " + unityWebRequest.error);
                }
                else
                {
                    // This query has returned, so add to the current count.
                    _queriesReturned++;
    
                    // Initialize event count integer.
                    int eventCount = 0;
    
                    // Deserialize the response with the custom Analytics class.
                    Analytics welcome = JsonConvert.DeserializeObject<Analytics>(unityWebRequest.downloadHandler.text);
    
                    // Get and return the count for the Event
                    if (int.TryParse(welcome.OdataCount, out eventCount) == false)
                    {
                        // Parsing failed. Can sometimes mean that the Query URL was incorrect.
                        Debug.Log("<color=red>Failure to Parse Data Results. Check Query URL for issues.</color>");
                    }
                    else
                    {
                        // Overwrite the current pair, with its actual values, now that the event count is known.
                        _pairedObjectsWithEventCount[currentCount] = new KeyValuePair<GameObject, int>(_pairedObjectsWithEventCount[currentCount].Key, eventCount);
                    }
    
                    // If all queries (compared with the number which was sent away) have 
                    // returned, then run the determine winner method. 
                    if (_queriesReturned == _pairedObjectsWithEventCount.Count)
                    {
                        DetermineWinner();
                    }
                }
            }
        }
    
  8. Die nächste Methode ist DetermineWinner(),, die die Liste der GameObject - und Int-Paare nach der höchsten Ereignisanzahl sortiert. Anschließend wird die Materialfarbe dieses GameObject in Grün geändert (als Feedback für die höchste Anzahl). Dadurch wird eine Meldung mit den Analyseergebnissen angezeigt.

        /// <summary>
        /// Call to determine the keyValue pair, within the objects list, 
        /// with the highest event count.
        /// </summary>
        private void DetermineWinner()
        {
            // Sort the values within the list of pairs.
            _pairedObjectsWithEventCount.Sort((x, y) => y.Value.CompareTo(x.Value));
    
            // Change its colour to green
            _pairedObjectsWithEventCount.First().Key.GetComponent<Renderer>().material.color = Color.green;
    
            // Provide the winner, and other results, within the console window. 
            string message = $"<b>Analytics Results:</b>\n " +
                $"<i>{_pairedObjectsWithEventCount.First().Key.name}</i> has the highest event count, " +
                $"with <i>{_pairedObjectsWithEventCount.First().Value.ToString()}</i>.\nFollowed by: ";
    
            for (int i = 1; i < _pairedObjectsWithEventCount.Count; i++)
            {
                message += $"{_pairedObjectsWithEventCount[i].Key.name}, " +
                    $"with {_pairedObjectsWithEventCount[i].Value.ToString()} events.\n";
            }
    
            Debug.Log(message);
        }
    
  9. Fügen Sie die Klassenstruktur hinzu, die zum Deserialisieren des von Application Insights empfangenen JSON-Objekts verwendet wird. Fügen Sie diese Klassen ganz unten in der DataFromAnalytics-Klassendateiaußerhalb der Klassendefinition hinzu.

        /// <summary>
        /// These classes represent the structure of the JSON response from Azure Insight
        /// </summary>
        [Serializable]
        public class Analytics
        {
            [JsonProperty("@odata.context")]
            public string OdataContext { get; set; }
    
            [JsonProperty("@odata.count")]
            public string OdataCount { get; set; }
    
            [JsonProperty("value")]
            public Value[] Value { get; set; }
        }
    
        [Serializable]
        public class Value
        {
            [JsonProperty("customMetric")]
            public CustomMetric CustomMetric { get; set; }
        }
    
        [Serializable]
        public class CustomMetric
        {
            [JsonProperty("name")]
            public string Name { get; set; }
        }
    
  10. Speichern Sie ihre Änderungen in Visual Studio , bevor Sie zu Unity zurückkehren.

Kapitel 10: Erstellen der Movement-Klasse

Das Bewegungsskript ist das nächste Skript, das Sie erstellen müssen. Es ist verantwortlich für:

  • Bewegen der Hauptkamera entsprechend der Richtung, in die die Kamera schaut.
  • Hinzufügen aller anderen Skripts zu Szenenobjekten.

So erstellen Sie das Skript:

  1. Doppelklicken Sie auf den Ordner Skripts , um ihn zu öffnen.

  2. Klicken Sie mit der rechten Maustaste in den Ordner Skripts, und klicken Sie aufC#-Skripterstellen>. Nennen Sie das Skript Movement.

  3. Doppelklicken Sie auf das Skript, um es mit Visual Studio zu öffnen.

  4. Ersetzen Sie den vorhandenen Code durch folgenden Code:

        using UnityEngine;
        using UnityEngine.XR.WSA.Input;
    
        public class Movement : MonoBehaviour
        {
            /// <summary>
            /// The rendered object representing the right controller.
            /// </summary>
            public GameObject Controller;
    
            /// <summary>
            /// The movement speed of the user.
            /// </summary>
            public float UserSpeed;
    
            /// <summary>
            /// Provides whether source updates have been registered.
            /// </summary>
            private bool _isAttached = false;
    
            /// <summary>
            /// The chosen controller hand to use. 
            /// </summary>
            private InteractionSourceHandedness _handness = InteractionSourceHandedness.Right;
    
            /// <summary>
            /// Used to calculate and proposes movement translation.
            /// </summary>
            private Vector3 _playerMovementTranslation;
    
            private void Start()
            {
                // You are now adding components dynamically 
                // to ensure they are existing on the correct object  
    
                // Add all camera related scripts to the camera. 
                Camera.main.gameObject.AddComponent<Gaze>();
                Camera.main.gameObject.AddComponent<ObjectTrigger>();
    
                // Add all other scripts to this object.
                gameObject.AddComponent<ApplicationInsightsTracker>();
                gameObject.AddComponent<DataFromAnalytics>();
            }
    
            // Update is called once per frame
            void Update()
            {
    
            }
        }
    
  5. Fügen Sie in der Movement-Klasseunter der leeren Update() -Methode die folgenden Methoden ein, die es dem Benutzer ermöglichen, den Handcontroller zu verwenden, um sich im virtuellen Raum zu bewegen:

        /// <summary>
        /// Used for tracking the current position and rotation of the controller.
        /// </summary>
        private void UpdateControllerState()
        {
    #if UNITY_WSA && UNITY_2017_2_OR_NEWER
            // Check for current connected controllers, only if WSA.
            string message = string.Empty;
    
            if (InteractionManager.GetCurrentReading().Length > 0)
            {
                foreach (var sourceState in InteractionManager.GetCurrentReading())
                {
                    if (sourceState.source.kind == InteractionSourceKind.Controller && sourceState.source.handedness == _handness)
                    {
                        // If a controller source is found, which matches the selected handness, 
                        // check whether interaction source updated events have been registered. 
                        if (_isAttached == false)
                        {
                            // Register events, as not yet registered.
                            message = "<color=green>Source Found: Registering Controller Source Events</color>";
                            _isAttached = true;
    
                            InteractionManager.InteractionSourceUpdated += InteractionManager_InteractionSourceUpdated;
                        }
    
                        // Update the position and rotation information for the controller.
                        Vector3 newPosition;
                        if (sourceState.sourcePose.TryGetPosition(out newPosition, InteractionSourceNode.Pointer) && ValidPosition(newPosition))
                        {
                            Controller.transform.localPosition = newPosition;
                        }
    
                        Quaternion newRotation;
    
                        if (sourceState.sourcePose.TryGetRotation(out newRotation, InteractionSourceNode.Pointer) && ValidRotation(newRotation))
                        {
                            Controller.transform.localRotation = newRotation;
                        }
                    }
                }
            }
            else
            {
                // Controller source not detected. 
                message = "<color=blue>Trying to detect controller source</color>";
    
                if (_isAttached == true)
                {
                    // A source was previously connected, however, has been lost. Disconnected
                    // all registered events. 
    
                    _isAttached = false;
    
                    InteractionManager.InteractionSourceUpdated -= InteractionManager_InteractionSourceUpdated;
    
                    message = "<color=red>Source Lost: Detaching Controller Source Events</color>";
                }
            }
    
            if(message != string.Empty)
            {
                Debug.Log(message);
            }
    #endif
        }
    
        /// <summary>
        /// This registered event is triggered when a source state has been updated.
        /// </summary>
        /// <param name="obj"></param>
        private void InteractionManager_InteractionSourceUpdated(InteractionSourceUpdatedEventArgs obj)
        {
            if (obj.state.source.handedness == _handness)
            {
                if(obj.state.thumbstickPosition.magnitude > 0.2f)
                {
                    float thumbstickY = obj.state.thumbstickPosition.y;
    
                    // Vertical Input.
                    if (thumbstickY > 0.3f || thumbstickY < -0.3f)
                    {
                        _playerMovementTranslation = Camera.main.transform.forward;
                        _playerMovementTranslation.y = 0;
                        transform.Translate(_playerMovementTranslation * UserSpeed * Time.deltaTime * thumbstickY, Space.World);
                    }
                }
            }
        }
    
        /// <summary>
        /// Check that controller position is valid. 
        /// </summary>
        /// <param name="inputVector3">The Vector3 to check</param>
        /// <returns>The position is valid</returns>
        private bool ValidPosition(Vector3 inputVector3)
        {
            return !float.IsNaN(inputVector3.x) && !float.IsNaN(inputVector3.y) && !float.IsNaN(inputVector3.z) && !float.IsInfinity(inputVector3.x) && !float.IsInfinity(inputVector3.y) && !float.IsInfinity(inputVector3.z);
        }
    
        /// <summary>
        /// Check that controller rotation is valid. 
        /// </summary>
        /// <param name="inputQuaternion">The Quaternion to check</param>
        /// <returns>The rotation is valid</returns>
        private bool ValidRotation(Quaternion inputQuaternion)
        {
            return !float.IsNaN(inputQuaternion.x) && !float.IsNaN(inputQuaternion.y) && !float.IsNaN(inputQuaternion.z) && !float.IsNaN(inputQuaternion.w) && !float.IsInfinity(inputQuaternion.x) && !float.IsInfinity(inputQuaternion.y) && !float.IsInfinity(inputQuaternion.z) && !float.IsInfinity(inputQuaternion.w);
        }   
    
  6. Fügen Sie zuletzt den Methodenaufruf innerhalb der Update() -Methode hinzu.

        // Update is called once per frame
        void Update()
        {
            UpdateControllerState();
        }
    
  7. Speichern Sie ihre Änderungen in Visual Studio , bevor Sie zu Unity zurückkehren.

Kapitel 11: Einrichten der Skriptverweise

In diesem Kapitel müssen Sie das Bewegungsskript auf der übergeordneten Kamera platzieren und dessen Referenzziele festlegen. Dieses Skript behandelt dann die Platzierung der anderen Skripts an der erforderlichen Stelle.

  1. Ziehen Sie aus dem Ordner Skripts im Projektbereich das Skript Movement in das übergeordnete Kameraobjekt , das sich im Hierarchiebereich befindet.

    Screenshot der Bereiche

  2. Klicken Sie auf die übergeordnete Kamera. Ziehen Sie im Hierarchiebereich das Objekt mit der rechten Hand aus dem Hierarchiebereich auf das Referenzziel Controller im Inspektorbereich. Legen Sie die Benutzergeschwindigkeit auf 5 fest, wie in der abbildung unten gezeigt.

    Screenshot der Bereiche

Kapitel 12: Erstellen des Unity-Projekts

Alles, was für den Unity-Abschnitt dieses Projekts erforderlich ist, wurde nun abgeschlossen, daher ist es an der Zeit, es von Unity aus zu erstellen.

  1. Navigieren Sie zu Buildeinstellungen (Dateibuildeinstellungen>).

  2. Klicken Sie im Fenster Buildeinstellungen auf Erstellen.

    Screenshot des Fensters

  3. Es wird ein Explorer Fenster angezeigt, in dem Sie zur Eingabe eines Speicherorts für den Build aufgefordert werden. Erstellen Sie einen neuen Ordner (indem Sie oben links auf Neuer Ordner klicken), und nennen Sie ihn BUILDS.

    Screenshot: Explorer mit hervorgehobenem Ordner Builds

    1. Öffnen Sie den neuen ORDNER BUILDS , und erstellen Sie einen weiteren Ordner (mit erneut neuem Ordner ), und benennen Sie ihn MR_Azure_Application_Insights.

      Screenshot: Datei-Explorer mit MR_Azure_Insights Ordner

    2. Klicken Sie bei ausgewählter MR_Azure_Application_Insights Ordner auf Ordner auswählen. Die Erstellung des Projekts dauert etwa eine Minute.

  4. Nach dem Buildvorgang wird Explorer angezeigt, der Ihnen den Speicherort Ihres neuen Projekts anzeigt.

Kapitel 13: Bereitstellen MR_Azure_Application_Insights-App auf Ihrem Computer

So stellen Sie die MR_Azure_Application_Insights-App auf Ihrem lokalen Computer bereit:

  1. Öffnen Sie die Projektmappendatei Ihrer MR_Azure_Application_Insights-App in Visual Studio.

  2. Wählen Sie auf der Lösungsplattformdie Option x86, Lokaler Computer aus.

  3. Wählen Sie in der Projektmappenkonfigurationdebuggen aus.

    Screenshot des Bildschirms

  4. Wechseln Sie zum Menü Erstellen , und klicken Sie auf Lösung bereitstellen , um die Anwendung auf Ihren Computer querzuladen.

  5. Ihre App sollte jetzt in der Liste der installierten Apps angezeigt werden, die zum Starten bereit sind.

  6. Starten Sie die Mixed Reality-Anwendung.

  7. Bewegen Sie sich in der Szene, nähern Sie sich Objekten an, und betrachten Sie sie. Wenn der Azure Insight Service genügend Ereignisdaten gesammelt hat, legt er das Objekt, das am meisten angesprochen wurde, auf Grün fest.

Wichtig

Während die durchschnittliche Wartezeit für die vom Dienst erfassten Ereignisse und Metriken etwa 15 Minuten dauert, kann dies in manchen Fällen bis zu einer Stunde dauern.

Kapitel 14: Application Insights Service-Portal

Nachdem Sie sich in der Szene bewegt und mehrere Objekte betrachtet haben, können Sie die im Application Insights Service-Portal gesammelten Daten sehen.

  1. Zurück zu Ihrem Application Insights Service-Portal.

  2. Klicken Sie auf Metrik-Explorer.

    Screenshot des Bereichs

  3. Es wird in einer Registerkarte geöffnet, die das Diagramm enthält, das die Ereignisse und Metriken im Zusammenhang mit Ihrer Anwendung darstellt. Wie oben erwähnt, kann es einige Zeit dauern (bis zu 1 Stunde), bis die Daten im Diagramm angezeigt werden.

    Screenshot: Metriken Explorer mit dem Diagramm

  4. Wählen Sie die Leiste Ereignisse in der Summe der Ereignisse nach Anwendungsversion aus, um eine detaillierte Aufschlüsselung der Ereignisse mit ihren Namen anzuzeigen.

    Screenshot des Suchbereichs mit den Ergebnissen eines benutzerdefinierten Ereignisfilters

Ihre Application Insights Service-Anwendung wurde abgeschlossen

Herzlichen Glückwunsch! Sie haben eine Mixed Reality-App erstellt, die den Application Insights Service nutzt, um die Aktivitäten des Benutzers in Ihrer App zu überwachen.

Willkommensbildschirm des Kurses.

Bonusübungen

Übung 1

Versuchen Sie, die ObjectInScene-Objekte nicht manuell zu erstellen, sondern zu spawnen, und legen Sie ihre Koordinaten auf der Ebene in Ihren Skripts fest. Auf diese Weise können Sie Azure fragen, welches das beliebteste Objekt ist (entweder anhand von Blick- oder Näherungsergebnissen) und ein zusätzliches Objekt dieser Objekte erstellen.

Übung 2

Sortieren Sie Ihre Application Insights-Ergebnisse nach Zeit, sodass Sie die relevantesten Daten erhalten und diese zeitsensiblen Daten in Ihrer Anwendung implementieren.