HoloLens (第1代) 和 Azure 309: Application insightsHoloLens (1st gen) and Azure 309: Application insights


注意

混合實境學院教學課程的設計是以 HoloLens (第 1 代) 和混合實境沉浸式頭戴裝置為準。The Mixed Reality Academy tutorials were designed with HoloLens (1st gen) and Mixed Reality Immersive Headsets in mind. 因此,對於仍在尋找這些裝置開發指引的開發人員而言,我們覺得這些教學課程很重要。As such, we feel it is important to leave these tutorials in place for developers who are still looking for guidance in developing for those devices. 這些教學課程 不會 使用用於 HoloLens 2 的最新工具組或互動進行更新。These tutorials will not be updated with the latest toolsets or interactions being used for HoloLens 2. 系統會保留這些資訊,以繼續在支援的裝置上運作。They will be maintained to continue working on the supported devices. 未來將會有一系列新的教學課程,將會示範如何針對 HoloLens 2 進行開發。There will be a new series of tutorials that will be posted in the future that will demonstrate how to develop for HoloLens 2. 當張貼這些教學課程時,將會使用這些教學課程的連結來更新此通知。This notice will be updated with a link to those tutorials when they are posted.


最終產品-開始

在此課程中,您將瞭解如何使用 Azure 應用程式 Insights API 來收集有關使用者行為的分析,以將 Application Insights 功能新增至混合現實應用程式。In this course, you will learn how to add Application Insights capabilities to a mixed reality application, using the Azure Application Insights API to collect analytics regarding user behavior.

Application Insights 是一項 Microsoft 服務,可讓開發人員從其應用程式收集分析,並從便於使用的入口網站進行管理。Application Insights is a Microsoft service, allowing developers to collect analytics from their applications and manage it from an easy-to-use portal. 分析可以是從效能到您想要收集之自訂資訊的任何內容。The analytics can be anything from performance to custom information you would like to collect. 如需詳細資訊,請造訪 Application Insights 頁面For more information, visit the Application Insights page.

完成本課程之後,您將會有一個混合現實的沉浸式耳機應用程式,可以執行下列動作:Having completed this course, you will have a mixed reality immersive headset application which will be able to do the following:

  1. 允許使用者在場景周圍四處移動。Allow the user to gaze and move around a scene.
  2. 透過使用場景內物件的注視和近距離,觸發將分析傳送至 Application Insights 服務 的程式。Trigger the sending of analytics to the Application Insights Service, through the use of Gaze and Proximity to in-scene objects.
  3. 應用程式也會在服務上呼叫,並在過去24小時內,提取有關使用者最常使用的物件資訊。The app will also call upon the Service, fetching information about which object has been approached the most by the user, within the last 24 hours. 該物件會將其色彩變更為綠色。That object will change its color to green.

本課程將告訴您如何取得 Application Insights 服務的結果,並放入 Unity 型範例應用程式中。This course will teach you how to get the results from the Application Insights Service, into a Unity-based sample application. 您必須將這些概念套用至您可能正在建立的自訂應用程式。It will be up to you to apply these concepts to a custom application you might be building.

裝置支援Device support

課程Course HoloLensHoloLens 沉浸式頭戴裝置Immersive headsets
MR 和 Azure 309:Application InsightsMR and Azure 309: Application insights ✔️✔️ ✔️✔️

注意

雖然本課程主要著重于 Windows Mixed Reality 沉浸式 (VR) 耳機,您也可以將在本課程中學到的內容套用至 Microsoft HoloLens。While this course primarily focuses on Windows Mixed Reality immersive (VR) headsets, you can also apply what you learn in this course to Microsoft HoloLens. 當您依照課程的指示進行時,您將會看到有關您可能需要採用以支援 HoloLens 的任何變更的注意事項。As you follow along with the course, you will see notes on any changes you might need to employ to support HoloLens. 使用 HoloLens 時,您可能會注意到語音捕捉期間的一些回應。When using HoloLens, you may notice some echo during voice capture.

PrerequisitesPrerequisites

注意

本教學課程是專為擁有 Unity 和 c # 基本經驗的開發人員所設計。This tutorial is designed for developers who have basic experience with Unity and C#. 另外也請注意,本檔中的必要條件和書面指示,代表在撰寫 (2018 年7月) 時已經過測試和驗證的內容。Please also be aware that the prerequisites and written instructions within this document represent what has been tested and verified at the time of writing (July 2018). You are free to use the latest software, as listed within the install the tools article, though it should not be assumed that the information in this course will perfectly match what you will find in newer software than what is listed below.You are free to use the latest software, as listed within the install the tools article, though it should not be assumed that the information in this course will perfectly match what you will find in newer software than what is listed below.

本課程建議您採用下列硬體和軟體:We recommend the following hardware and software for this course:

在您開始使用 Intune 之前Before you start

為了避免在建立此專案時發生問題,強烈建議您在根或近端根資料夾中,建立本教學課程中所述的專案 (長的資料夾路徑可能會在組建階段) 時發生問題。To avoid encountering issues building this project, it is strongly suggested that you create the project mentioned in this tutorial in a root or near-root folder (long folder paths can cause issues at build-time).

警告

請注意,要 Application Insights 的資料需要一些時間,因此請耐心等候。Be aware, data going to Application Insights takes time, so be patient. 如果您想要檢查服務是否已收到您的資料,請參閱第 14 章,其中會示範如何流覽入口網站。If you want to check if the Service has received your data, check out Chapter 14, which will show you how to navigate the portal.

第1章-Azure 入口網站Chapter 1 - The Azure Portal

若要使用 Application Insights,您將需要在 Azure 入口網站中建立和設定 Application Insights 服務To use Application Insights, you will need to create and configure an Application Insights Service in the Azure portal.

  1. 登入 Azure 入口網站Log in to the Azure Portal.

    注意

    如果您還沒有 Azure 帳戶,您將需要建立一個帳戶。If you do not already have an Azure account, you will need to create one. 如果您在課堂或實驗室的情況下進行本教學課程,請洽詢講師或其中一個 proctors,協助您設定新的帳戶。If you are following this tutorial in a classroom or lab situation, ask your instructor or one of the proctors for help setting up your new account.

  2. 登入後,按一下左上角的 [ 新增 ],並搜尋 Application Insights,然後按一下 Enter 鍵Once you are logged in, click on New in the top left corner, and search for Application Insights, and click Enter.

    注意

    在較新的入口網站中,[建立資源] 可能已取代 的文字。The word New may have been replaced with Create a resource, in newer portals.

    Azure 入口網站

  3. 右側的新頁面將會提供 Azure 應用程式 Insights 服務的描述。The new page to the right will provide a description of the Azure Application Insights Service. 在此頁面的左下方,選取 [ 建立 ] 按鈕,以建立與此服務的關聯。At the bottom left of this page, select the Create button, to create an association with this Service.

    Azure 入口網站

  4. 當您按一下 [ 建立] 之後:Once you have clicked on Create:

    1. 為此服務實例插入您想要的 名稱Insert your desired Name for this Service instance.

    2. 選取 [一般] 作為 [應用程式類型]。As Application Type, select General.

    3. 選取適當的 用帳戶。Select an appropriate Subscription.

    4. 選擇資源群組,或建立一個新的 資源群組Choose a Resource Group or create a new one. 資源群組提供一種方式來監視、控制存取、布建及管理 Azure 資產集合的計費。A resource group provides a way to monitor, control access, provision and manage billing for a collection of Azure assets. 建議您保留與單一專案相關聯的所有 Azure 服務 (例如,) 一般資源群組下的這些課程) 。It is recommended to keep all the Azure Services associated with a single project (e.g. such as these courses) under a common resource group).

      如果您想要閱讀更多有關 Azure 資源群組的資訊,請 造訪資源群組文章If you wish to read more about Azure Resource Groups, please visit the resource group article.

    5. 選取 [位置] 。Select a Location.

    6. 您也必須確認您已瞭解套用到此服務的條款及條件。You will also need to confirm that you have understood the Terms and Conditions applied to this Service.

    7. 選取 [建立] 。Select Create.

      Azure 入口網站

  5. 當您按一下 [ 建立] 之後,就必須等待服務建立完成,這可能需要一分鐘的時間。Once you have clicked on Create, you will have to wait for the Service to be created, this might take a minute.

  6. 建立服務實例之後,入口網站中就會出現通知。A notification will appear in the portal once the Service instance is created.

    Azure 入口網站

  7. 按一下通知以探索新的服務實例。Click on the notifications to explore your new Service instance.

    Azure 入口網站

  8. 按一下通知中的 [ 移至資源 ] 按鈕,以流覽您的新服務實例。Click the Go to resource button in the notification to explore your new Service instance. 您將會進入新的 Application Insights 服務 實例。You will be taken to your new Application Insights Service instance.

    Azure 入口網站

    注意

    將此網頁保持在開啟狀態且容易存取,您會經常回到這裡查看所收集的資料。Keep this web page open and easy to access, you will come back here often to see the data collected.

    重要

    若要執行 Application Insights,您必須使用三個 (3) 特定值: 檢測金鑰應用程式識別碼API 金鑰To implement Application Insights, you will need to use three (3) specific values: Instrumentation Key, Application ID, and API Key. 在下方,您將瞭解如何從您的服務取得這些值。Below you will see how to retrieve these values from your Service. 請務必在空白的 [ 記事本 ] 頁面上記下這些值,因為您很快就會在程式碼中使用這些值。Make sure to note these values on a blank Notepad page, because you will use them soon in your code.

  9. 若要尋找 檢測金鑰,您必須將服務功能清單向下移動,然後按一下 [ 屬性],顯示的索引標籤會顯示 服務金鑰To find the Instrumentation Key, you will need to scroll down the list of Service functions, and click on Properties, the tab displayed will reveal the Service Key.

    Azure 入口網站

  10. 以下是一些 屬性,您將會發現需要按一下的 API 存取A little below Properties, you will find API Access, which you need to click. 右邊的面板會提供應用程式的 應用程式識別碼The panel to the right will provide the Application ID of your app.

    Azure 入口網站

  11. 在 [ 應用程式識別碼 ] 面板仍開啟的情況下,按一下 [ 建立 api 金鑰],這會開啟 [ 建立 api 金鑰 ] 面板。With the Application ID panel still open, click Create API Key, which will open the Create API key panel.

    Azure 入口網站

  12. 在 [現在開啟 建立 API 金鑰 ] 面板中,輸入描述,然後 將三個方塊勾選Within the now open Create API key panel, type a description, and tick the three boxes.

  13. 按一下 [ 產生金鑰]。Click Generate Key. 將會建立並顯示您的 API 金鑰Your API Key will be created and displayed.

    Azure 入口網站

    警告

    這是您的 服務金鑰 唯一的顯示時間,因此請務必立即建立複本。This is the only time your Service Key will be displayed, so ensure you make a copy of it now.

第2章-設定 Unity 專案Chapter 2 - Set up the Unity project

以下是使用混合式開發進行開發的一般設定,因此,它是適用于其他專案的絕佳範本。The following is a typical set up for developing with the mixed reality, and as such, is a good template for other projects.

  1. 開啟 Unity ,然後按一下 [ 新增]。Open Unity and click New.

    設定 Unity 專案

  2. 您現在將需要提供 Unity 專案名稱,請插入 MR _ Azure _ application _ InsightsYou will now need to provide a Unity Project name, insert MR_Azure_Application_Insights. 請確定 範本 已設定為 3dMake sure the Template is set to 3D. 位置 設定為適合您 (記住,較接近根目錄的) 。Set the Location to somewhere appropriate for you (remember, closer to root directories is better). 然後,按一下 [ 建立專案]。Then, click Create project.

    設定 Unity 專案

  3. 在 Unity 開啟的情況下,值得檢查預設 腳本編輯器 是否設定為 Visual StudioWith Unity open, it is worth checking the default Script Editor is set to Visual Studio. 移至 [ 編輯 > 喜好 設定],然後在新視窗中,流覽至 [ 外部工具]。Go to Edit > Preferences and then from the new window, navigate to External Tools. 外部腳本編輯器 變更為 Visual Studio 2017Change External Script Editor to Visual Studio 2017. 關閉 [ 喜好 設定] 視窗。Close the Preferences window.

    設定 Unity 專案

  4. 接下來,移至 [檔案 > 組建設定],然後按一下 [切換平臺] 按鈕,將平臺切換至 通用 Windows 平臺Next, go to File > Build Settings and switch the platform to Universal Windows Platform, by clicking on the Switch Platform button.

    設定 Unity 專案

  5. 移至 檔案 > 組建設定 ,並確定:Go to File > Build Settings and make sure that:

    1. 目標裝置 已設定為 任何裝置Target Device is set to Any device

      針對 Microsoft HoloLens,請將 目標裝置 設定為 HoloLensFor the Microsoft HoloLens, set Target Device to HoloLens.

    2. 組建類型 設定為 D3DBuild Type is set to D3D

    3. SDK 已設定為 最新安裝SDK is set to Latest installed

    4. 組建並執行 設定為 本機電腦Build and Run is set to Local Machine

    5. 儲存場景,並將其新增至組建。Save the scene and add it to the build.

      1. 若要這麼做,請選取 [ 新增開啟的場景]。Do this by selecting Add Open Scenes. [儲存] 視窗隨即出現。A save window will appear.

        設定 Unity 專案

      2. 為此建立新的資料夾,以及任何未來的場景,然後按一下 [ 新增資料夾 ] 按鈕,建立新的資料夾,將它命名為 場景Create a new folder for this, and any future scene, then click the New folder button, to create a new folder, name it Scenes.

        設定 Unity 專案

      3. 開啟新建立的 場景 資料夾,然後在 [ 檔案名: 文字] 欄位中,輸入 ApplicationInsightsScene,然後按一下 [ 儲存]。Open your newly created Scenes folder, and then in the File name: text field, type ApplicationInsightsScene, then click Save.

        設定 Unity 專案

  6. [ 組建設定] 中的其餘設定,現在應該保持為預設值。The remaining settings, in Build Settings, should be left as default for now.

  7. 在 [ 組建設定 ] 視窗中,按一下 [ 播放程式設定 ] 按鈕,這會開啟偵測 所在空間中的相關面板。In the Build Settings window, click on the Player Settings button, this will open the related panel in the space where the Inspector is located.

    設定 Unity 專案

  8. 在此面板中,需要驗證幾個設定:In this panel, a few settings need to be verified:

    1. 在 [ 其他設定 ] 索引標籤中:In the Other Settings tab:

      1. 腳本****執行階段版本 應該是 實驗 ( .net 4.6 對等),這會觸發重新開機編輯器的需求。Scripting Runtime Version should be Experimental (.NET 4.6 Equivalent), which will trigger a need to restart the Editor.

      2. 腳本後端 應該是 .netScripting Backend should be .NET

      3. API 相容性層級 應為 .net 4.6API Compatibility Level should be .NET 4.6

      設定 Unity 專案

    2. 在 [ 發行設定 ] 索引標籤的 [ 功能] 下,選取:Within the Publishing Settings tab, under Capabilities, check:

      • InternetClientInternetClient

        設定 Unity 專案

    3. 在面板的 [ XR 設定 ] 中,在 [設定] () 的 [ 發佈設定 ] 下方找到 [支援的滴答 虛擬事實],請確定已新增 Windows Mixed Reality SDKFurther down the panel, in XR Settings (found below Publishing Settings), tick Virtual Reality Supported, make sure the Windows Mixed Reality SDK is added.

      設定 Unity 專案

  9. 回到 組建設定Unity c # 專案 不再呈現灰色;勾選此方塊旁邊的核取方塊。Back in Build Settings, Unity C# Projects is no longer greyed out; tick the checkbox next to this.

  10. 關閉 [建置設定] 視窗。Close the Build Settings window.

  11. 儲存場景和專案 ( > 儲存場景/ 檔案 > 儲存專案) 。Save your Scene and Project (FILE > SAVE SCENE / FILE > SAVE PROJECT).

第3章-匯入 Unity 套件Chapter 3 - Import the Unity package

重要

如果您想要略過 Unity 設定 此課程的元件,並直接繼續進行程式碼,您可以隨意下載此 Azure-MR. unitypackage,並將其匯入到您的專案中做為 自訂套件If you wish to skip the Unity Set up components of this course, and continue straight into code, feel free to download this Azure-MR-309.unitypackage, import it into your project as a Custom Package. 這也會包含下一章中的 Dll。This will also contain the DLLs from the next Chapter. 匯入之後,請從 第6章繼續。After import, continue from Chapter 6.

重要

若要在 Unity 中使用 Application Insights,您需要匯入其 DLL 以及 Newtonsoft DLL。To use Application Insights within Unity, you need to import the DLL for it, along with the Newtonsoft DLL. Unity 中目前有已知的問題,需要在匯入之後重新設定外掛程式。There is currently a known issue in Unity which requires plugins to be reconfigured after import. 在解決 bug 之後,將不再需要這一節中的這些步驟 (4-7) 。These steps (4 - 7 in this section) will no longer be required after the bug has been resolved.

若要將 Application Insights 匯入您自己的專案中,請確定您已 下載包含外掛程式的 ' unitypackage 'To import Application Insights into your own project, make sure you have downloaded the '.unitypackage', containing the plugins. 然後執行下列動作:Then, do the following:

  1. 使用 [資產匯 > 入封裝 > 自訂套件] 功能表選項,將 unitypackage 新增至 Unity。Add the .unitypackage to Unity by using the Assets > Import Package > Custom Package menu option.

  2. 在彈出的 [匯 入 Unity 套件 ] 方塊中,確定已選取 [ (] 下的所有專案,並包含) 外掛程式In the Import Unity Package box that pops up, ensure everything under (and including) Plugins is selected.

    匯入 Unity 封裝

  3. 按一下 [匯 ] 按鈕,將專案加入至您的專案。Click the Import button, to add the items to your project.

  4. 移至專案視圖中 [外掛程式] 下的 [ Insights ] 資料夾,並 選取下列外掛程式:Go to the Insights folder under Plugins in the Project view and select the following plugins only:

    • Microsoft.ApplicationInsightsMicrosoft.ApplicationInsights

    匯入 Unity 封裝

  5. 選取此 外掛程式 之後,請確定已 取消 選取 任何平臺,然後確定 WSAPlayer 也未 核取,然後 按一下 [ 套用]。With this plugin selected, ensure that Any Platform is unchecked, then ensure that WSAPlayer is also unchecked, then click Apply. 這麼做只是為了確認檔案已正確設定。Doing this is just to confirm that the files are configured correctly.

    匯入 Unity 封裝

    注意

    標記這類外掛程式,會將其設定為僅用於 Unity 編輯器。Marking the plugins like this, configures them to only be used in the Unity Editor. 在 [WSA] 資料夾中有一組不同的 Dll,會在從 Unity 匯出專案之後使用。There are a different set of DLLs in the WSA folder which will be used after the project is exported from Unity.

  6. 接下來,您必須開啟 [ Insights ] 資料夾內的 [ WSA ] 資料夾。Next, you need to open the WSA folder, within the Insights folder. 您會看到您剛剛設定的相同檔案的複本。You will see a copy of the same file you just configured. 選取此檔案,然後在 [偵測器] 中,確定已 取消選取****任何平臺,然後 確定只****選取[ WSAPlayer ]。Select this file, and then in the inspector, ensure that Any Platform is unchecked, then ensure that only WSAPlayer is checked. 按一下 [套用]。Click Apply.

    匯入 Unity 封裝

  7. 您現在必須遵循 步驟 4-6,但改為 Newtonsoft 外掛程式。You will now need to follow steps 4-6, but for the Newtonsoft plugins instead. 請參閱下列螢幕擷取畫面,以瞭解結果看起來的樣子。See the below screenshot for what the outcome should look like.

    匯入 Unity 封裝

第4章-設定相機和使用者控制項Chapter 4 - Set up the camera and user controls

在本章中,您將設定相機和控制項,以允許使用者在場景中查看及移動。In this Chapter you will set up the camera and the controls to allow the user to see and move in the scene.

  1. 以滑鼠右鍵按一下 [階層] 面板中的空白區域,然後在 [建立 > 的]。Right-click in an empty area in the Hierarchy Panel, then on Create > Empty.

    設定相機和使用者控制項

  2. 將新的空白 GameObject 重新命名為 相機父代Rename the new empty GameObject to Camera Parent.

    設定相機和使用者控制項

  3. 以滑鼠右鍵按一下 [階層] 面板中的空白區域,然後在 [ 3D 物件] 和 [ 球體] 上按一下。Right-click in an empty area in the Hierarchy Panel, then on 3D Object, then on Sphere.

  4. 將球體重新命名為 右手 邊。Rename the Sphere to Right Hand.

  5. 將右手邊的 轉換比例 設定為 0.1、0.1、0.1Set the Transform Scale of the Right Hand to 0.1, 0.1, 0.1

    設定相機和使用者控制項

  6. 按一下 球體碰撞 器元件中的 齒輪,然後 移除元件,以從右邊移除 球體碰撞 器元件。Remove the Sphere Collider component from the Right Hand by clicking on the Gear in the Sphere Collider component, and then Remove Component.

    設定相機和使用者控制項

  7. 在 [階層] 面板中,將 主要攝影機右手 邊的物件拖曳至 相機父 物件。In the Hierarchy Panel drag the Main Camera and the Right Hand objects onto the Camera Parent object.

    設定相機和使用者控制項

  8. 主要攝影機右手 邊物件的 轉換位置 設定為 0、0、0Set the Transform Position of both the Main Camera and the Right Hand object to 0, 0, 0.

    設定相機和使用者控制項

    設定相機和使用者控制項

第5章-在 Unity 場景中設定物件Chapter 5 - Set up the objects in the Unity scene

您現在將為您的場景建立一些基本圖形,讓使用者可以進行互動。You will now create some basic shapes for your scene, with which the user can interact.

  1. 以滑鼠右鍵按一下 [階層] 面板 中的空白區域,然後在 [ 3d 物件] 上,選取 [ 平面]。Right-click in an empty area in the Hierarchy Panel, then on 3D Object, then select Plane.

  2. 將平面 轉換位置 設定為 0、-1、0Set the Plane Transform Position to 0, -1, 0.

  3. 將平面 轉換比例 設定為 5,1,5Set the Plane Transform Scale to 5, 1, 5.

    設定 Unity 場景中的物件

  4. 建立要與 平面 物件搭配使用的基本材質,讓其他圖形更容易查看。Create a basic material to use with your Plane object, so that the other shapes are easier to see. 流覽至您的 [專案] 面板,然後以滑鼠右鍵按一下,然後 建立****資料夾,再建立新的資料夾。Navigate to your Project Panel, right-click, then Create, followed by Folder, to create a new folder. 命名 it 教材Name it Materials.

    設定 Unity 場景中的物件 設定 Unity 場景中的物件

  5. 開啟 [ 材質 ] 資料夾,然後按一下滑鼠右鍵,再按一下 [ 建立],再按一下 [ 材質],建立新的材質。Open the Materials folder, then right-click, click Create, then Material, to create a new material. 將它命名為 藍色Name it Blue.

    設定 Unity 場景中的物件 設定 Unity 場景中的物件

  6. 選取新的 藍色 材質之後,查看 [偵測 ],然後按一下 [矩形] 視窗與 [ >albedo]。With the new Blue material selected, look at the Inspector, and click the rectangular window alongside Albedo. 選取藍色色彩 (下一張圖片是 十六進位色彩: # 3592FFFF) 。Select a blue color (the one picture below is Hex Color: #3592FFFF). 選擇之後,請按一下 [關閉] 按鈕。Click the close button once you have chosen.

    設定 Unity 場景中的物件

  7. 從 [材質] 資料夾中,將新的材質拖曳至您新建立的 平面 上, (,或將它放在階層 ) 內平面 物件上。Drag your new material from the Materials folder, onto your newly created Plane, within your scene (or drop it on the Plane object within the Hierarchy).

    設定 Unity 場景中的物件

  8. 以滑鼠右鍵按一下 [階層] 面板 中的空白區域,然後在 [ 3d 物件]、[膠囊] 上按一下。Right-click in an empty area in the Hierarchy Panel, then on 3D Object, Capsule.

    • 選取 膠囊 之後,將其 *轉換***位置 變更為: -10、1、0With the Capsule selected, change its Transform Position to: -10, 1, 0.
  9. 以滑鼠右鍵按一下 [階層] 面板 中的空白區域,然後在 [ 3d 物件] 上按一下 [Cube]。Right-click in an empty area in the Hierarchy Panel, then on 3D Object, Cube.

    • 選取 Cube 之後,將其 *轉換***位置 變更為: 0、0、10With the Cube selected, change its Transform Position to: 0, 0, 10.
  10. 以滑鼠右鍵按一下 [階層] 面板 中的空白區域,然後在 [ 3d 物件]、[球體] 上按一下。Right-click in an empty area in the Hierarchy Panel, then on 3D Object, Sphere.

    • 選取 球體 之後,將其 *轉換***位置 變更為: 10、0、0With the Sphere selected, change its Transform Position to: 10, 0, 0.

    設定 Unity 場景中的物件

    注意

    這些 位置 值為 建議These Position values are suggestions. 您可以自由地將物件的位置設定為您想要的任何位置,不過如果物件距離與相機之間的距離不太遠,您就可以更輕鬆地使用應用程式的使用者。You are free to set the positions of the objects to whatever you would like, though it is easier for the user of the application if the objects distances are not too far from the camera.

  11. 當您的應用程式正在執行時,它必須能夠識別場景內的物件,若要達到此目的,必須標記這些物件。When your application is running, it needs to be able to identify the objects within the scene, to achieve this, they need to be tagged. 選取其中一個物件,然後在 [偵測 ] 面板中,按一下 [ 新增標記],這會將偵測 & 圖層 面板的標記交換。Select one of the objects, and in the Inspector panel, click Add Tag..., which will swap the Inspector with the Tags & Layers panel.

    設定 Unity 場景 中的物件 Set up the objects in the Unity Scene

  12. 按一下 + (加號) 符號,然後將標記名稱輸入為 ObjectInSceneClick the + (plus) symbol, then type the tag name as ObjectInScene.

    設定 Unity 場景中的物件

    警告

    如果您的標籤使用不同的名稱,您將需要確定這項變更也會在您的場景中進行 DataFromAnalyticsObjectTrigger注視 腳本,以便在您的場景內找到並偵測到您的物件。If you use a different name for your tag, you will need to ensure this change is also made the DataFromAnalytics, ObjectTrigger, and Gaze, scripts later, so that your objects are found, and detected, within your scene.

  13. 建立標籤之後,您現在必須將它套用至您的三個物件。With the tag created, you now need to apply it to all three of your objects. 從階層 中,按住 Shift 鍵,然後按一下 [ 膠囊]、[ Cube] 和 [ 球體],然後在 [偵測 ] 中,按一下下拉式功能表加上卷 標,然後按一下您建立的 ObjectInScene 標記。From the Hierarchy, hold the Shift key, then click the Capsule, Cube, and Sphere, objects, then in the Inspector, click the dropdown menu alongside Tag, then click the ObjectInScene tag you created.

    設定 Unity 場景 中的物件 Set up the objects in the Unity Scene

第6章-建立 ApplicationInsightsTracker 類別Chapter 6 - Create the ApplicationInsightsTracker class

您需要建立的第一個腳本是 ApplicationInsightsTracker,其負責:The first script you need to create is ApplicationInsightsTracker, which is responsible for:

  1. 根據使用者互動建立事件,以提交給 Azure 應用程式見解。Creating events based on user interactions to submit to Azure Application Insights.

  2. 根據使用者互動建立適當的事件名稱。Creating appropriate Event names, depending on user interaction.

  3. 將事件提交至 Application Insights 服務實例。Submitting events to the Application Insights Service instance.

若要建立此類別:To create this class:

  1. 在 [專案] 面板 中按一下滑鼠右鍵,然後 建立 > 資料夾Right-click in the Project Panel, then Create > Folder. 將資料夾命名為 腳本Name the folder Scripts.

    建立 ApplicationInsightsTracker 類別 建立 ApplicationInsightsTracker 類別

  2. 在 [ 腳本 ] 資料夾建立後,按兩下以開啟。With the Scripts folder created, double-click it, to open. 然後,在該資料夾中,以滑鼠右鍵按一下,然後 建立 > c # 腳本Then, within that folder, right-click, Create > C# Script. 將腳本命名為 ApplicationInsightsTrackerName the script ApplicationInsightsTracker.

  3. 按兩下新的 ApplicationInsightsTracker 腳本,以 Visual Studio 開啟。Double-click on the new ApplicationInsightsTracker script to open it with Visual Studio.

  4. 更新腳本頂端的命名空間,如下所示:Update namespaces at the top of the script to be as below:

        using Microsoft.ApplicationInsights;
        using Microsoft.ApplicationInsights.DataContracts;
        using Microsoft.ApplicationInsights.Extensibility;
        using UnityEngine;
    
  5. 在類別內插入下列變數:Inside the class insert the following variables:

        /// <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;
    

    注意

    使用 Azure 入口網站中所述的 Azure 入口網站中的 服務金鑰,適當地設定 instrumentationKey、applicationId 和 API_Key 值(如第 1 章第9章所述)。Set the instrumentationKey, applicationId and API_Key values appropriately, using the Service Keys from the Azure Portal as mentioned in Chapter 1, step 9 onwards.

  6. 然後,新增 啟動 ()喚醒的 () 方法,當類別初始化時,就會呼叫這些方法:Then add the Start() and Awake() methods, which will be called when the class initializes:

        /// <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. 新增負責傳送事件和您的應用程式所註冊之計量的方法:Add the methods responsible for sending the events and metrics registered by your application:

        /// <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. 返回 Unity 之前,請務必將您的變更儲存在 Visual Studio 中。Be sure to save your changes in Visual Studio before returning to Unity.

第7章-建立注視腳本Chapter 7 - Create the Gaze script

下一個要建立的腳本是 注視 腳本。The next script to create is the Gaze script. 此腳本負責建立將從 主要相機 向前投影的 Raycast ,以偵測使用者所查看的物件。This script is responsible for creating a Raycast that will be projected forward from the Main Camera, to detect which object the user is looking at. 在此情況下, Raycast 將需要識別使用者是否正在查看具有 ObjectInScene 標記的物件,然後計算使用者在該物件上 gazes 的時間長度。In this case, the Raycast will need to identify if the user is looking at an object with the ObjectInScene tag, and then count how long the user gazes at that object.

  1. 按兩下 [ 腳本 ] 資料夾以開啟它。Double-click on the Scripts folder, to open it.

  2. 在 [腳本] 資料夾內按一下滑鼠右鍵,然後按一下 [建立 > c # 腳本]。Right-click inside the Scripts folder, click Create > C# Script. 將腳本命名為 注視Name the script Gaze.

  3. 按兩下腳本,以 Visual Studio 開啟。Double-click on the script to open it with Visual Studio.

  4. 將現有的程式碼取代為下列程式碼:Replace the existing code with the following:

        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 for the Awake() and Start() methods now needs to be added.

        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. 注視 類別內,于 Update () 方法中新增下列程式碼,以投影 Raycast 並偵測目標點擊:Inside the Gaze class, add the following code in the Update() method to project a Raycast and detect the target hit:

        /// <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. 新增 ResetFocusedObject () 方法,以在使用者查看物件時將資料傳送至 Application InsightsAdd the ResetFocusedObject() method, to send data to Application Insights when the user has looked at an object.

        /// <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. 您現在已完成 注視 腳本。You have now completed the Gaze script. 在回到 Unity 之前,請先將您的變更儲存在 Visual Studio 中。Save your changes in Visual Studio before returning to Unity.

第8章-建立 ObjectTrigger 類別Chapter 8 - Create the ObjectTrigger class

您需要建立的下一個腳本是 ObjectTrigger,其負責:The next script you need to create is ObjectTrigger, which is responsible for:

  • 將衝突所需的元件新增至主要攝影機。Adding components needed for collision to the Main Camera.
  • 偵測相機是否接近標記為 ObjectInScene 的物件。Detecting if the camera is near an object tagged as ObjectInScene.

建立指令碼:To create the script:

  1. 按兩下 [ 腳本 ] 資料夾以開啟它。Double-click on the Scripts folder, to open it.

  2. 在 [腳本] 資料夾內按一下滑鼠右鍵,然後按一下 [建立 > c # 腳本]。Right-click inside the Scripts folder, click Create > C# Script. 將腳本命名為 ObjectTriggerName the script ObjectTrigger.

  3. 按兩下腳本,以 Visual Studio 開啟。Double-click on the script to open it with Visual Studio. 將現有的程式碼取代為下列程式碼:Replace the existing code with the following:

        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. 返回 Unity 之前,請務必將您的變更儲存在 Visual Studio 中。Be sure to save your changes in Visual Studio before returning to Unity.

第9章-建立 DataFromAnalytics 類別Chapter 9 - Create the DataFromAnalytics class

現在您將需要建立 DataFromAnalytics 腳本,其負責:You will now need to create the DataFromAnalytics script, which is responsible for:

  • 正在提取最多相機已接近哪個物件的分析資料。Fetching analytics data about which object has been approached by the camera the most.
  • 使用 服務金鑰,以允許與您的 Azure 應用程式 Insights 服務實例進行通訊。Using the Service Keys, that allow communication with your Azure Application Insights Service instance.
  • 根據具有最高事件計數的場景排序物件。Sorting the objects in scene, according to which has the highest event count.
  • 將最接近物件的材質色彩變更為 綠色Changing the material color, of the most approached object, to green.

建立指令碼:To create the script:

  1. 按兩下 [ 腳本 ] 資料夾以開啟它。Double-click on the Scripts folder, to open it.

  2. 在 [腳本] 資料夾內按一下滑鼠右鍵,然後按一下 [建立 > c # 腳本]。Right-click inside the Scripts folder, click Create > C# Script. 將腳本命名為 DataFromAnalyticsName the script DataFromAnalytics.

  3. 按兩下腳本,以 Visual Studio 開啟。Double-click on the script to open it with Visual Studio.

  4. 插入下列命名空間:Insert the following namespaces:

        using Newtonsoft.Json;
        using System;
        using System.Collections;
        using System.Collections.Generic;
        using System.Linq;
        using UnityEngine;
        using UnityEngine.Networking;
    
  5. 在腳本中插入下列內容:Inside the script, insert the following:

        /// <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. DataFromAnalytics 類別中,于 開始 () 方法之後,新增下列稱為 FetchAnalytics () 的方法。Within the DataFromAnalytics class, right after the Start() method, add the following method called FetchAnalytics(). 這個方法會負責填入金鑰值組的清單,以及 GameObject 和預留位置事件計數。This method is responsible for populating the list of key value pairs, with a GameObject and a placeholder event count number. 然後,它會初始化 GetWebRequest () 協同程式。It then initializes the GetWebRequest() coroutine. 您也可以在此方法中找到 Application Insights 呼叫的查詢結構,作為 查詢 URL 端點。The query structure of the call to Application Insights can be found within this method also, as the Query URL endpoint.

        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. FetchAnalytics () 方法的下方,新增名為 GetWebRequest () 的方法,它會傳回 IEnumeratorRight below the FetchAnalytics() method, add a method called GetWebRequest(), which returns an IEnumerator. 這個方法會負責要求在 Application Insights 內呼叫事件(對應至特定 GameObject)的次數。This method is responsible for requesting the number of times an event, corresponding with a specific GameObject, has been called within Application Insights. 傳回所有傳送的查詢之後,就會呼叫 DetermineWinner () 方法。When all the sent queries have returned, the DetermineWinner() method is called.

        /// <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. 下一個方法是 DetermineWinner (),根據最高的事件計數來排序 GameObjectInt 配對的清單。The next method is DetermineWinner(), which sorts the list of GameObject and Int pairs, according to the highest event count. 然後,它會將該 GameObject 的材質色彩變更為 綠色 (,以提供最高計數) 的意見反應。It then changes the material color of that GameObject to green (as feedback for it having the highest count). 這會顯示具有分析結果的訊息。This displays a message with the analytics results.

        /// <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. 新增類別結構,此結構將用來還原序列化從 Application Insights 接收的 JSON 物件。Add the class structure which will be used to deserialize the JSON object, received from Application Insights. 在類別定義 之外DataFromAnalytics 類別檔案最下方,加入這些類別。Add these classes at the very bottom of your DataFromAnalytics class file, outside of the class definition.

        /// <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. 返回 Unity 之前,請務必將您的變更儲存在 Visual Studio 中。Be sure to save your changes in Visual Studio before returning to Unity.

第10章-建立移動類別Chapter 10 - Create the Movement class

移動 腳本是您將需要建立的下一個腳本。The Movement script is the next script you will need to create. 它負責:It is responsible for:

  • 根據相機的方向移動主要攝影機。Moving the Main Camera according to the direction the camera is looking towards.
  • 將所有其他腳本新增至場景物件。Adding all other scripts to scene objects.

建立指令碼:To create the script:

  1. 按兩下 [ 腳本 ] 資料夾以開啟它。Double-click on the Scripts folder, to open it.

  2. 在 [腳本] 資料夾內按一下滑鼠右鍵,然後按一下 [建立 > c # 腳本]。Right-click inside the Scripts folder, click Create > C# Script. 為腳本的 移動 命名。Name the script Movement.

  3. 按兩下腳本,以 Visual Studio 開啟。Double-click on the script to open it with Visual Studio.

  4. 將現有的程式碼取代為下列程式碼:Replace the existing code with the following:

        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. 移動 類別內的空白 更新 () 方法 底下,插入下列可讓使用者使用手形控制器移至虛擬空間的方法:Within the Movement class, below the empty Update() method, insert the following methods that allow the user to use the hand controller to move in the virtual space:

        /// <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. 最後,在 Update () 方法內新增方法呼叫。Lastly add the method call within the Update() method.

        // Update is called once per frame
        void Update()
        {
            UpdateControllerState();
        }
    
  7. 返回 Unity 之前,請務必將您的變更儲存在 Visual Studio 中。Be sure to save your changes in Visual Studio before returning to Unity.

第11章-設定腳本參考Chapter 11 - Setting up the scripts references

在本章中,您必須將 移動 腳本放到 相機父系 ,並設定其參考目標。In this Chapter you need to place the Movement script onto the Camera Parent and set its reference targets. 該腳本接著會處理將其他腳本放在需要的位置。That script will then handle placing the other scripts where they need to be.

  1. 從 [專案] 面板 中的 [腳本] 資料夾,將 移動 腳本拖曳至位於 [階層]面板 中的 [相機] 父 物件。From the Scripts folder in the Project Panel, drag the Movement script to the Camera Parent object, located in the Hierarchy Panel.

    在 Unity 場景中設定腳本參考

  2. 按一下 相機上層Click on the Camera Parent. 在 [階層]面板 中,從 [階層]面板右手 邊的物件拖曳至 [偵測器]面板 中的參考目標 [控制器]。In the Hierarchy Panel, drag the Right Hand object from the Hierarchy Panel to the reference target, Controller, in the Inspector Panel. 使用者速度 設定為 5,如下圖所示。Set the User Speed to 5, as shown in the image below.

    在 Unity 場景中設定腳本參考

第12章-建立 Unity 專案Chapter 12 - Build the Unity project

此專案的 Unity 區段所需的所有專案現在都已完成,因此您可以從 Unity 建立它。Everything needed for the Unity section of this project has now been completed, so it is time to build it from Unity.

  1. 流覽至 組建設定 , (檔案 > 組建設定) 。Navigate to Build Settings, (File > Build Settings).

  2. 從 [ 組建設定 ] 視窗中,按一下 [ 建立]。From the Build Settings window, click Build.

    將 Unity 專案建立到 UWP 方案

  3. 檔案總管 視窗會隨即顯示,提示您輸入組建的位置。A File Explorer window will pop-up, prompting you for a location for the build. 按一下左上角的 [ 新增資料夾 ],以建立新的資料夾 () ,並為其 建立 名稱。Create a new folder (by clicking New Folder in the top-left corner), and name it BUILDS.

    將 Unity 專案建立到 UWP 方案

    1. 開啟 [新 組建 ] 資料夾,然後使用 新) 資料夾 (建立另一個資料夾,並將它命名為 _ Azure _ Application _ Insights 的 MROpen the new BUILDS folder, and create another folder (using New Folder once more), and name it MR_Azure_Application_Insights.

      將 Unity 專案建立到 UWP 方案

    2. 選取 [ MR _ Azure _ application _ Insights ] 資料夾,然後按一下 [ 選取資料夾]。With the MR_Azure_Application_Insights folder selected, click Select Folder. 專案需要一分鐘的時間才能建立。The project will take a minute or so to build.

  4. 下列 組建 之後, 檔案總管 將會顯示新專案的位置。Following Build, File Explorer will appear showing you the location of your new project.

第13章-將 MR_Azure_Application_Insights 應用程式部署至您的電腦Chapter 13 - Deploy MR_Azure_Application_Insights app to your machine

若要在本機電腦上部署 MR _ Azure _ application _ Insights 應用程式:To deploy the MR_Azure_Application_Insights app on your Local Machine:

  1. Visual Studio 中開啟 MR _ Azure _ application _ Insights 應用程式的解決方案檔案。Open the solution file of your MR_Azure_Application_Insights app in Visual Studio.

  2. 在 [ 方案平臺] 中,選取 [ x86]、[本機電腦]。In the Solution Platform, select x86, Local Machine.

  3. 在 [ 方案 設定] 中選取 [ Debug]。In the Solution Configuration select Debug.

    將 Unity 專案建立到 UWP 方案

  4. 移至 [ 組建] 功能表 ,然後按一下 [ 部署方案 ],將應用程式側載至您的電腦。Go to Build menu and click on Deploy Solution to sideload the application to your machine.

  5. 您的應用程式現在應該會出現在已安裝的應用程式清單中,準備好要啟動。Your app should now appear in the list of installed apps, ready to be launched.

  6. 啟動混合現實應用程式。Launch the mixed reality application.

  7. 在場景中四處移動、接近物件並查看它們,當 Azure 深入解析服務 收集到足夠的事件資料時,它會將最接近綠色的物件設定為最多。Move around the scene, approaching objects and looking at them, when the Azure Insight Service has collected enough event data, it will set the object that has been approached the most to green.

重要

雖然服務收集的 事件和計量 平均等待時間大約需要15分鐘,但在某些情況下,可能需要最多1小時的時間。While the average waiting time for the Events and Metrics to be collected by the Service takes around 15 min, in some occasions it might take up to 1 hour.

第14章-Application Insights Service 入口網站Chapter 14 - The Application Insights Service portal

當您漫遊場景並 gazed 數個物件時,您可以在 Application Insights Service 入口網站中看到收集到的資料。Once you have roamed around the scene and gazed at several objects you can see the data collected in the Application Insights Service portal.

  1. 返回至您的 Application Insights 服務入口網站。Go back to your Application Insights Service portal.

  2. 按一下 [ 計量瀏覽器]。Click on Metrics Explorer.

    查看收集的資料

  3. 它會在包含圖表的索引標籤中開啟,以代表與您的應用程式相關的 事件和計量It will open in a tab containing the graph which represent the Events and Metrics related to your application. 如上所述,在圖形中顯示資料可能需要一些時間 (1 小時的時間) As mentioned above, it might take some time (up to 1 hour) for the data to be displayed in the graph

    查看收集的資料

  4. 按一下 [依應用程式版本的 事件總計] 中的 [事件] 列,以查看事件的詳細明細及其名稱。Click on the Events bar in the Total of Events by Application Version, to see a detailed breakdown of the events with their names.

    查看收集的資料

您已完成 Application Insights 服務應用程式Your finished your Application Insights Service application

恭喜,您建立了一個混合現實應用程式,利用 Application Insights 服務來監視應用程式內的使用者活動。Congratulations, you built a mixed reality app that leverages the Application Insights Service to monitor user's activity within your app.

課程結果

額外練習Bonus Exercises

練習1Exercise 1

嘗試產生,而不是以手動方式建立 ObjectInScene 物件,並在您的腳本內的平面上設定其座標。Try spawning, rather than manually creating, the ObjectInScene objects and set their coordinates on the plane within your scripts. 如此一來,您就可以向 Azure 詢問 Azure 最受歡迎的物件 (從注視或鄰近的結果) ,然後產生 額外 的其中一個物件。In this way, you could ask Azure what the most popular object was (either from gaze or proximity results) and spawn an extra one of those objects.

練習2Exercise 2

依時間排序您的 Application Insights 結果,以便取得最相關的資料,並在您的應用程式中執行該時間敏感的資料。Sort your Application Insights results by time, so that you get the most relevant data, and implement that time sensitive data in your application.