Freigeben über


HoloLens (1. Generation) und Azure 309: Anwendungserkenntnisse

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 Lernprogrammen geben, die in Zukunft veröffentlicht werden, die zeigen, wie sie für HoloLens 2 entwickelt werden. Dieser Hinweis wird mit einem Link zu diesen Lernprogrammen aktualisiert, wenn sie veröffentlicht werden.

Willkommensseite des Mixed Reality Academy-Lernprogramms.

In diesem Kurs erfahren Sie, wie Sie application Insights-Funktionen zu einer Mixed Reality-Anwendung hinzufügen, indem Sie die Azure-App lication 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. Die Analyse kann alles von der Leistung bis hin zu benutzerdefinierten Informationen sein, die Sie sammeln möchten. Weitere Informationen finden Sie auf der Seite "Application Insights".

Nach Abschluss dieses Kurses haben Sie eine immersive Mixed Reality-Headset-Anwendung, die folgende Aktionen ausführen kann:

  1. Zulassen, dass der Benutzer eine Szene anvisieren und sich um eine Szene bewegt.
  2. Lösen Sie das Senden von Analysen an den Application Insights-Dienst aus, indem Sie "Gaze" und "Näherung" zu In-Szenen-Objekten verwenden.
  3. Die App ruft auch den Dienst auf und ruft Informationen darüber ab, welches Objekt innerhalb der letzten 24 Stunden am meisten vom Benutzer angegangen wurde. Das Objekt ändert seine Farbe in Grün.

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

Unterstützung für Geräte

Kurs HoloLens Immersive Headsets
MR und Azure 309: Anwendungserkenntnisse ✔️ ✔️

Hinweis

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

Voraussetzungen

Hinweis

Dieses Lernprogramm wurde für Entwickler entwickelt, die grundlegende Erfahrung mit Unity und C# haben. Bitte beachten Sie auch, dass die Voraussetzungen und schriftlichen Anweisungen in diesem Dokument darstellen, was zum Zeitpunkt der Schriftlichkeit (Juli 2018) getestet und überprüft wurde. Sie können die neueste Software verwenden, wie im Artikel "Tools installieren" aufgeführt, aber es sollte nicht davon ausgegangen werden, dass die Informationen in diesem Kurs perfekt mit dem übereinstimmen, was Sie in neuerer Software finden werden als die unten aufgeführten.

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

Vor der Installation

Um Probleme beim Erstellen dieses Projekts zu vermeiden, wird dringend empfohlen, das Projekt in diesem Lernprogramm in einem Stamm- oder Near-Root-Ordner zu erstellen (lange Ordnerpfade können zur Erstellungszeit Probleme verursachen).

Warnung

Beachten Sie, dass daten, die zu Application Insights wechseln, 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, in dem Sie erfahren, wie Sie im Portal navigieren können.

Kapitel 1 – Das Azure-Portal

Um Application Insights zu verwenden, 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 Konto erstellen. Wenn Sie diesem Lernprogramm in einer Unterrichts- oder Laborsituation folgen, bitten Sie Ihren Kursleiter oder einen der Betreuer, Hilfe beim Einrichten Ihres neuen Kontos zu erhalten.

  2. Nachdem Sie angemeldet sind, klicken Sie in der oberen linken Ecke auf "Neu ", suchen Sie nach "Application Insights", und klicken Sie auf " Eingabetaste".

    Hinweis

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

    Screenshot des Azure-Portals, Einblicke ist im Bereich

  3. Die neue Seite rechts enthält eine Beschreibung des Azure-App lication 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 Bildschirms

  4. Nachdem Sie auf "Erstellen" geklickt haben:

    1. Fügen Sie ihren gewünschten Namen für diese Dienstinstanz ein.

    2. Wählen Sie als Anwendungstyp "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, die Abrechnung für eine Sammlung von Azure-Ressourcen zu überwachen, zu steuern, den Zugriff zu steuern, bereitzustellen und zu verwalten. Es wird empfohlen, alle Azure-Dienste, die einem einzelnen Projekt zugeordnet sind (z. B. diese Kurse), unter einer gemeinsamen Ressourcengruppe zu halten.

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

    5. Wählen Sie einen Speicherortaus.

    6. Sie müssen auch bestätigen, dass Sie die auf diesen Dienst angewendeten Allgemeinen Geschäftsbedingungen verstanden haben.

    7. Klicken Sie auf Erstellen.

      Screenshot des Fensters

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

  6. Sobald die Dienstinstanz erstellt wurde, wird im Portal eine Benachrichtigung angezeigt.

    Screenshot eines Teils des Menübands, das Benachrichtigungssymbol ist hervorgehoben.

  7. Wählen Sie die Benachrichtigungen aus, um Ihre neue Dienstinstanz zu erkunden.

    Screenshot, der das Dialogfeld

  8. Klicken Sie in der Benachrichtigung auf die Schaltfläche "Zur Ressource wechseln", um Ihre neue Dienstinstanz zu erkunden. Sie werden zu Ihrer neuen Application Insights Service-Instanz weitergeleitet.

    Screenshot der Application Insights Service-Instanz, in der der Instanzname

    Hinweis

    Halten Sie diese Webseite offen und einfach zugänglich, werden Sie hier oft zurückkehren, um die gesammelten Daten anzuzeigen.

    Wichtig

    Um Application Insights zu implementieren, müssen Sie drei (3) spezifische Werte verwenden: Instrumentation Key, Anwendungs-ID und API-Schlüssel. Im Folgenden erfahren Sie, wie Sie diese Werte aus Ihrem Dienst abrufen. Achten Sie darauf, diese Werte auf einer leeren Editorseite zu notieren, da Sie diese in Kürze 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 mit Dienstfunktionen, Eigenschaften sind im Abschnitt

  10. Unter " Eigenschaften" finden Sie DEN API-Zugriff, auf den Sie klicken müssen. Der Bereich rechts stellt die Anwendungs-ID Ihrer App bereit.

    Screenshot mit Dienstfunktionen, A P I Access ist hervorgehoben.

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

    Screenshot des Bereichs

  12. Geben Sie im nun geöffneten Bereich "API-Schlüssel erstellen" eine Beschreibung ein, und markieren Sie die drei Felder.

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

    Screenshot des Bereichs

    Warnung

    Dies ist das einzige Mal, wenn 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 Unity-Projektfensters. Es werden keine Projektinformationen angezeigt.

  2. Sie müssen jetzt einen Unity-Projektnamen angeben, MR_Azure_Application_Insights einfügen. Stellen Sie sicher, dass die Vorlage auf 3D festgelegt ist. Legen Sie den Speicherort an einer für Sie geeigneten Stelle fest (denken Sie daran, dass die Stammverzeichnisse besser sind). Klicken Sie dann auf "Projekt erstellen".

    Screenshot des Fensters

  3. Wenn Unity geöffnet ist, lohnt es sich, den Standardmäßigen Skript-Editor auf Visual Studio festzulegen. Wechseln Sie zu "Einstellungen bearbeiten>", 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, der zeigt, dass Visual Studio als externer Skript-Editor eingerichtet ist.

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

    Screenshot des Fensters

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

    1. Zielgerät ist auf ein beliebiges Gerät festgelegt.

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

    2. Buildtyp ist auf D3D festgelegt

    3. SDK ist auf "Neueste Installation" festgelegt.

    4. Build und Ausführung ist auf den lokalen 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 dafür 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 "Szenen ", und klicken Sie dann im Feld "Datei": "Textfeld" , geben Sie "ApplicationInsightsScene" ein, und klicken Sie dann auf " Speichern".

        Screenshot des Fensters

  6. Die übrigen Einstellungen in den Buildeinstellungen sollten jetzt als Standard beibehalten werden.

  7. Wählen Sie im Fenster "Buildeinstellungen " die Option "Spielereinstellungen" aus. Dadurch wird der zugehörige Bereich im 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" folgendes:

      1. Die Skripting-Runtime-Version sollte experimental (.NET 4.6 Equivalent) sein, wodurch ein Neustart des Editors ausgelöst wird.

      2. Scripting Back-End sollte .NET sein

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

      Screenshot der Registerkarte

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

      • InternetClient

        Screenshot der Liste

    3. Klicken Sie weiter unten im Bereich unter "XR-Einstellungen" (unter "Veröffentlichungseinstellungen") auf "Virtual Reality Unterstützt", und stellen Sie sicher, dass das Windows Mixed Reality SDK hinzugefügt wird.

      Screenshot des Abschnitts

  9. Zurück in build settings, Unity C# Projects is no longer greyed out; tick the checkbox next to this.

  10. Schließen Sie das Fenster 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 Set up-Komponenten dieses Kurses überspringen und direkt mit Code fortfahren möchten, können Sie dieses Azure-MR-309.unitypackage herunterladen, es 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. Diese Schritte (4 - 7 in diesem Abschnitt) sind nach der Behebung des Fehlers nicht mehr erforderlich.

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 "Benutzerdefiniertes Paket für ressourcenimportieren > > " verwenden.

  2. Stellen Sie im Popupfeld "Unity-Paket importieren" sicher, dass alles unter (und einschließlich) Plug-Ins ausgewählt ist.

    Screenshot des Dialogfelds

  3. Klicken Sie auf die Schaltfläche "Importieren ", um dem Projekt die Elemente 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. Stellen Sie bei diesem Plug-In sicher, dass "Beliebige Plattform" deaktiviert ist, und stellen Sie 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 Inspektorbereichs mit aktivierter Editor- und Eigenständiger Überprüfung.

    Hinweis

    Wenn Sie die Plug-Ins wie folgt markieren, konfigurieren Sie sie so, dass sie nur im Unity-Editor verwendet werden. Es gibt einen anderen Satz von DLLs im WSA-Ordner, der verwendet wird, 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 Plattform" deaktiviert ist, und stellen Sie dann sicher, dass nur WSAPlayer aktiviert ist. Klicken Sie auf Anwenden.

    Screenshot des Inspektorbereichs mit aktiviertem W S A Player.

  7. Sie müssen jetzt die Schritte 4-6 ausführen, aber für die Newtonsoft-Plug-Ins. Sehen Sie sich den folgenden Screenshot an, wie das Ergebnis aussehen soll.

    Screenshot von vier Ansichten der Bereiche

Kapitel 4 – Einrichten der Kamera- und Benutzersteuerungen

In diesem Kapitel richten Sie die Kamera und die Steuerelemente ein, damit der Benutzer in der Szene sehen und navigieren kann.

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

    Screenshot des Hierarchiebereichs,

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

    Screenshot des Hierarchiebereichs mit ausgewählter Option

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

  4. Benennen Sie die Kugel in die rechte Hand um.

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

    Screenshot der Bereiche

  6. Entfernen Sie die Kugel-Kollidierungskomponente von der rechten Hand, indem Sie auf das Zahnrad in der Kugel-Kollidierungskomponente klicken und dann die Komponente entfernen.

    Screenshot des Inspektorbereichs, das Zahnradsymbol und

  7. Ziehen Sie im Hierarchiebereich die Hauptkamera und die Rechtshandobjekte auf das übergeordnete Objekt "Camera" .

    Screenshot des Hierarchiebereichs mit ausgewählter Hauptkamera, im Inspektorbereich wird die Hauptkamera aktiviert.

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

    Screenshot des Hierarchiebereichs mit ausgewählter Hauptkamera, Transformationseinstellungen werden im Inspektorbereich hervorgehoben.

    Screenshot des Hierarchiebereichs, in dem

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, und wählen Sie dann im 3D-Objekt die Option "Ebene" aus.

  2. Legen Sie die Position der Ebenentransformation auf 0, -1, 0 fest.

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

    Screenshot der Bereiche

  4. Erstellen Sie ein grundlegendes Material für die Verwendung mit Dem Plane-Objekt , damit die anderen Formen leichter zu erkennen sind. Navigieren Sie zu Ihrem Projektbereich, klicken Sie mit der rechten Maustaste, und erstellen Sie dann ordner, um einen neuen Ordner zu erstellen. Nennen Sie es Materialien.

    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 es Blau.

    Screenshot des Bereichs Screenshot des Bereichs

  6. Sehen Sie sich das neue blaue Material an, und klicken Sie auf das rechteckige Fenster neben Albedo. Wählen Sie eine blaue Farbe aus (das bild unten ist Hex Color: #3592FFFF). Klicken Sie auf die Schaltfläche "Schließen", nachdem Sie sie ausgewählt haben.

    Screenshot des Inspektorbereichs. Der Farbabschnitt ist hervorgehoben.

  7. Ziehen Sie das neue Material aus dem Ordner "Materialien" in die neu erstellte Ebene innerhalb Der Szene (oder legen Sie es auf dem Plane-Objekt in der Hierarchie ab).

    Screenshot des Szenenbereichs mit dem neuen Material aus dem Ordner

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

    • 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 im 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, Kugel.

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

    Screenshot der Bereiche

    Hinweis

    Diese Positionswerte sind Vorschläge. Sie können die Positionen der Objekte auf die gewünschten Objekte festlegen, obwohl es für den Benutzer der Anwendung einfacher ist, wenn die Entfernungen der 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, um dies zu erreichen, müssen sie markiert werden. Wählen Sie eines der Objekte aus, und klicken Sie im Inspektorbereich auf "Tag hinzufügen...", wodurch der Inspektor durch den Bereich "Tags & Ebenen" ersetzt wird.

    Screenshot des Inspektorbereichs mit hervorgehobener Option Screenshot des Inspektorbereichs mit hervorgehobenen Kategorien und Ebenen.

  12. Klicken Sie auf das Pluszeichen + (Plus), und geben Sie dann den Tagnamen als ObjectInScene ein.

    Screenshot des Inspektorbereichs mit ausgewählter Option

    Warnung

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

  13. Nachdem das Tag erstellt wurde, müssen Sie es jetzt auf alle drei Ihrer Objekte anwenden. Halten Sie in der Hierarchie die UMSCHALTTASTE gedrückt, klicken Sie dann auf die Kapsel, den Würfel und die Kugel, und klicken Sie dann im Inspektor auf das Dropdownmenü neben Tag, und klicken Sie dann auf das objektinScene-Tag, das Sie erstellt haben.

    Screenshot des Inspektorbereichs, ein Pfeil zeigt auf Screenshot mit zwei Menüs mit hervorgehobener Option

Kapitel 6 – Erstellen der ApplicationInsightsTracker-Klasse

Das erste Skript, das Sie erstellen müssen, ist ApplicationInsightsTracker, der für Folgendes zuständig ist:

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

  2. Erstellen sie je nach Benutzerinteraktion geeignete Ereignisnamen.

  3. Übermitteln von Ereignissen an die Application Insights Service-Instanz.

So erstellen Sie diese Klasse:

  1. Klicken Sie mit der rechten Maustaste in den Projektbereich, und erstellen Sie>dann den Ordner. Benennen Sie den Ordner Skripts.

    Screenshot des Bereichs Screenshot mit Menüoptionen, in denen die Optionen

  2. Doppelklicken Sie beim Erstellen des Ordners "Skripts" auf den Ordner, um ihn zu öffnen. Klicken Sie dann in diesem Ordner mit der rechten Maustaste auf "C#-Skript erstellen>". Nennen Sie das Skript ApplicationInsightsTracker.

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

  4. Aktualisieren Sie Namespaces oben im Skript so, dass sie wie folgt sein:

        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 angemessen" fest, indem Sie die Dienstschlüssel aus dem Azure-Portal verwenden, wie in Kapitel 1, Schritt 9 erwähnt.

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

        /// <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 Ereignisse und Metriken verantwortlich sind, die von Ihrer Anwendung registriert wurden:

        /// <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. Achten Sie darauf, ihre Änderungen in Visual Studio zu speichern, bevor Sie zu Unity zurückkehren.

Kapitel 7 – Erstellen des Gaze-Skripts

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

  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 auf "C#-Skript erstellen>". 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 innerhalb 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 betrachtet 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 Kollisionen mit der Hauptkamera erforderlich sind.
  • 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 auf "C#-Skript erstellen>". 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. Achten Sie darauf, ihre Änderungen in Visual Studio zu speichern, bevor Sie zu Unity zurückkehren.

Kapitel 9 – Erstellen der DataFromAnalytics-Klasse

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

  • Abrufen von Analysedaten darüber, welches Objekt von der Kamera am meisten angenähert wurde.
  • Verwenden Sie die Dienstschlüssel, die die Kommunikation mit Ihrer Azure-App lication Insights Service-Instanz ermöglichen.
  • Sortieren der Objekte in der Szene, nach denen die höchste Ereignisanzahl aufweist.
  • Ändern der Materialfarbe des am weitesten näher angegangenen Objekts auf 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 auf "C#-Skript erstellen>". 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 im Skript Folgendes 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 in der DataFromAnalytics-Klasse direkt nach der Start() -Methode die folgende Methode namens FetchAnalytics()hinzu. Diese Methode ist für das Auffüllen der Liste der Schlüsselwertpaare mit einem GameObject und einer Platzhalterereignisanzahl verantwortlich. Anschließend wird das GetWebRequest() -Coroutine initialisiert. Die Abfragestruktur des Aufrufs von Application Insights kann auch innerhalb 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 unterhalb der FetchAnalytics()- Methode eine Methode namens "GetWebRequest()" hinzu, die einen IEnumerator zurückgibt. Diese Methode ist dafür verantwortlich, die Anzahl der Male anzufordern, die ein Ereignis, das einem bestimmten GameObject entspricht, innerhalb von Application Insights aufgerufen wurde. 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 GameObjects grün (als Feedback für dieses Objekt mit der höchsten Anzahl) geändert. 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 JSON-Objekts verwendet wird, das von Application Insights empfangen wird. Fügen Sie diese Klassen am unteren Rand der DataFromAnalytics-Klassendatei auß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. Achten Sie darauf, ihre Änderungen in Visual Studio zu speichern, bevor Sie zu Unity zurückkehren.

Kapitel 10 – Erstellen der Movement-Klasse

Das Bewegungsskript ist das nächste Skript, das Sie erstellen müssen. IISConfigurator ist für Folgendes zuständig:

  • Die Hauptkamera wird entsprechend der Richtung bewegt, in der die Kamera hinschaut.
  • 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 auf "C#-Skript erstellen>". Benennen 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-Klasse unterhalb der leeren Update() -Methode die folgenden Methoden ein, mit denen der Benutzer den Handcontroller im virtuellen Raum bewegen kann:

        /// <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 schließlich den Methodenaufruf innerhalb der Update()- Methode hinzu.

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

Kapitel 11 – Einrichten der Skriptverweise

In diesem Kapitel müssen Sie das Bewegungsskript auf das Übergeordnete Element "Kamera" setzen und seine Referenzziele festlegen. Dieses Skript behandelt dann das Platzieren der anderen Skripts, wo sie sein müssen.

  1. Ziehen Sie im Ordner "Skripts" im Projektbereich das Bewegungsskript auf das übergeordnete Kameraobjekt, das sich im Hierarchiebereich befindet.

    Screenshot der Bereiche

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

    Screenshot der Bereiche

Kapitel 12 – Erstellen des Unity-Projekts

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

  1. Navigieren Sie zu "Buildeinstellungen", (Dateibuildeinstellungen>).

  2. Klicken Sie im Fenster "Buildeinstellungen " auf "Erstellen".

    Screenshot des Fensters

  3. Ein Explorer Fenster wird angezeigt, in dem Sie aufgefordert werden, einen Speicherort für den Build einzugeben. Erstellen Sie einen neuen Ordner (indem Sie in der oberen linken Ecke auf "Neuer Ordner" klicken), und nennen Sie ihn BUILDS.

    Screenshot Explorer mit hervorgehobener Ordner

    1. Öffnen Sie den neuen BUILDS-Ordner, und erstellen Sie einen anderen Ordner (mithilfe des neuen Ordners erneut), und nennen Sie ihn MR_Azure_Application_Insights.

      Screenshot des Datei-Explorers mit dem Ordner MR_Azure_Insights.

    2. Klicken Sie bei ausgewähltem MR_Azure_Application_Insights Ordner auf "Ordner auswählen". Das Projekt dauert eine Minute oder so, bis das Projekt erstellt wird.

  4. Nach dem Build wird Explorer angezeigt, der 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 in der Lösungsplattform x86, lokaler Computer aus.

  3. Wählen Sie in der Lösungskonfiguration "Debuggen" aus.

    Screenshot des Visual Studio-Projektmappenkonfigurationsbildschirms mit

  4. Wechseln Sie zum Menü " Erstellen", und klicken Sie auf " Projektmappe bereitstellen", um die Anwendung auf Ihren Computer querzuladen.

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

  6. Starten Sie die Mixed Reality-Anwendung.

  7. Bewegen Sie sich um die Szene, nähert sich Objekten und betrachten Sie sie, wenn der Azure Insight Service genügend Ereignisdaten gesammelt hat, legt es das Objekt fest, das am meisten auf Grün nähert wurde.

Wichtig

Während die durchschnittliche Wartezeit für die Ereignisse und Metriken, die vom Dienst erfasst werden, etwa 15 Minuten dauert, kann es in einigen Fällen bis zu 1 Stunde dauern.

Kapitel 14 – Das Application Insights Service-Portal

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

  1. Wechseln Sie zurück zum Application Insights Service-Portal.

  2. Klicken Sie auf Metrik-Explorer.

    Screenshot des Bereichs

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

    Screenshot des Metrik-Explorers mit den Ereignissen und Metrikendiagramm.

  4. Wählen Sie die Ereignisleiste in der Gesamtanzahl 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 Anwendung "Application Insights Service" fertig gestellt

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

Willkommensseite des Kurses.

Bonusübungen

Übung 1

Versuchen Sie, die ObjectInScene-Objekte manuell zu erstellen und ihre Koordinaten auf der Ebene in Ihren Skripts festzulegen. Auf diese Weise könnten Sie Azure fragen, was das beliebteste Objekt war (entweder aus Blick- oder Näherungsergebnissen) und ein zusätzliches Objekt dieser Objekte.

Übung 2

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