HoloLens (generasi ke-1) dan Azure 309: Wawasan aplikasi
Catatan
Tutorial Mixed Reality Academy dirancang dengan HoloLens (generasi ke-1) dan Mixed Reality Immersive Headsets dalam pikiran. Dengan demikian, kami merasa penting untuk meninggalkan tutorial ini di tempat bagi pengembang yang masih mencari panduan dalam mengembangkan untuk perangkat tersebut. Tutorial ini tidak akan diperbarui dengan toolset atau interaksi terbaru yang digunakan untuk HoloLens 2. Mereka akan dipertahankan untuk terus bekerja pada perangkat yang didukung. Akan ada serangkaian tutorial baru yang akan diposting di masa depan yang akan menunjukkan cara mengembangkan untuk HoloLens 2. Pemberitahuan ini akan diperbarui dengan tautan ke tutorial tersebut ketika diposting.
Dalam kursus ini, Anda akan mempelajari cara menambahkan kemampuan Application Insights ke aplikasi realitas campuran, menggunakan API Azure Application Insights untuk mengumpulkan analitik mengenai perilaku pengguna.
Application Insights adalah layanan Microsoft, memungkinkan pengembang mengumpulkan analitik dari aplikasi mereka dan mengelolanya dari portal yang mudah digunakan. Analitik dapat berupa apa saja mulai dari performa hingga informasi kustom yang ingin Anda kumpulkan. Untuk informasi selengkapnya, kunjungi halaman Application Insights.
Setelah menyelesaikan kursus ini, Anda akan memiliki aplikasi headset imersif realitas campuran, yang akan dapat melakukan hal berikut:
- Izinkan pengguna untuk menatap dan bergerak di sekitar adegan.
- Picu pengiriman analitik ke Application Insights Service, dengan menggunakan Tatapan dan Kedekatan ke objek dalam adegan.
- Aplikasi ini juga akan memanggil Layanan, mengambil informasi tentang objek mana yang paling banyak didekati oleh pengguna, dalam 24 jam terakhir. Objek itu akan mengubah warnanya menjadi hijau.
Kursus ini akan mengajarkan Anda cara mendapatkan hasil dari Application Insights Service, ke dalam aplikasi sampel berbasis Unity. Terserah Anda untuk menerapkan konsep ini ke aplikasi kustom yang mungkin Anda bangun.
Dukungan perangkat
Kursus | HoloLens | Headset imersif |
---|---|---|
MR dan Azure 309: Application insights | ✔️ | ✔️ |
Catatan
Meskipun kursus ini terutama berfokus pada headset imersif Windows Mixed Reality (VR), Anda juga dapat menerapkan apa yang Anda pelajari dalam kursus ini ke Microsoft HoloLens. Saat mengikuti kursus, Anda akan melihat catatan tentang perubahan apa pun yang mungkin perlu Anda gunakan untuk mendukung HoloLens. Saat menggunakan HoloLens, Anda mungkin melihat beberapa gema selama pengambilan suara.
Prasyarat
Catatan
Tutorial ini dirancang untuk pengembang yang memiliki pengalaman dasar dengan Unity dan C#. Perlu diketahui juga bahwa prasyarat dan instruksi tertulis dalam dokumen ini mewakili apa yang telah diuji dan diverifikasi pada saat penulisan (Juli 2018). Anda bebas menggunakan perangkat lunak terbaru, seperti yang tercantum dalam artikel instal alat , meskipun tidak boleh diasumsikan bahwa informasi dalam kursus ini akan sangat cocok dengan apa yang akan Anda temukan di perangkat lunak yang lebih baru daripada apa yang tercantum di bawah ini.
Kami merekomendasikan perangkat keras dan perangkat lunak berikut untuk kursus ini:
- PC pengembangan, kompatibel dengan Windows Mixed Reality untuk pengembangan headset imersif (VR)
- Pembaruan Windows 10 Fall Creators (atau yang lebih baru) dengan mode Pengembang diaktifkan
- Windows 10 SDK terbaru
- Unity 2017.4
- Visual Studio 2017
- Headset Windows Mixed Reality immersive (VR) atau Microsoft HoloLens dengan mode Pengembang diaktifkan
- Sekumpulan headphone dengan mikrofon bawaan (jika headset tidak memiliki mikrofon dan speaker bawaan)
- Akses internet untuk penyiapan Azure dan pengambilan data Application Insights
Sebelum memulai
Untuk menghindari masalah saat membangun proyek ini, sangat disarankan agar Anda membuat proyek dalam tutorial ini di folder root atau near-root (jalur folder panjang dapat menyebabkan masalah pada build-time).
Peringatan
Ketahuilah, data yang masuk ke Application Insights membutuhkan waktu, jadi bersabarlah. Jika Anda ingin memeriksa apakah Layanan telah menerima data Anda, lihat Bab 14, yang akan menunjukkan kepada Anda cara menavigasi portal.
Bab 1 - Portal Microsoft Azure
Untuk menggunakan Application Insights, Anda harus membuat dan mengonfigurasi Application Insights Service di portal Azure.
Masuk ke Portal Azure.
Catatan
Jika Anda belum memiliki akun Azure, Anda harus membuatnya. Jika Anda mengikuti tutorial ini dalam situasi ruang kelas atau lab, mintalah instruktur atau salah satu proktor untuk membantu menyiapkan akun baru Anda.
Setelah Anda masuk, klik Baru di sudut kiri atas, dan cari Application Insights, dan klik Enter.
Catatan
Kata Baru mungkin telah diganti dengan Buat sumber daya, di portal yang lebih baru.
Halaman baru di sebelah kanan akan memberikan deskripsi Azure Application Insights Service. Di kiri bawah halaman ini, pilih tombol Buat , untuk membuat asosiasi dengan Layanan ini.
Setelah Anda mengklik Buat:
Sisipkan Nama yang Anda inginkan untuk instans Layanan ini.
Sebagai Jenis Aplikasi, pilih Umum.
Pilih Langganan yang sesuai.
Pilih Grup Sumber Daya atau buat yang baru. Grup sumber daya menyediakan cara untuk memantau, mengontrol akses, menyediakan, dan mengelola penagihan untuk kumpulan aset Azure. Disarankan untuk menyimpan semua Layanan Azure yang terkait dengan satu proyek (misalnya, seperti kursus ini) di bawah grup sumber daya umum).
Jika Anda ingin membaca selengkapnya tentang Grup Sumber Daya Azure, silakan kunjungi artikel grup sumber daya.
Pilih Lokasi.
Anda juga perlu mengonfirmasi bahwa Anda telah memahami Syarat dan Ketentuan yang diterapkan pada Layanan ini.
Pilih Buat.
Setelah mengklik Buat, Anda harus menunggu Layanan dibuat, ini mungkin memakan waktu satu menit.
Pemberitahuan akan muncul di portal setelah instans Layanan dibuat.
Pilih pemberitahuan untuk menjelajahi instans Layanan baru Anda.
Klik tombol Buka sumber daya di pemberitahuan untuk menjelajahi instans Layanan baru Anda. Anda akan dibawa ke instans Application Insights Service baru Anda.
Catatan
Biarkan halaman web ini terbuka dan mudah diakses, Anda akan sering kembali ke sini untuk melihat data yang dikumpulkan.
Penting
Untuk menerapkan Application Insights, Anda harus menggunakan tiga (3) nilai tertentu: Kunci Instrumentasi, ID Aplikasi, dan Kunci API. Di bawah ini Anda akan melihat cara mengambil nilai-nilai ini dari Layanan Anda. Pastikan untuk mencatat nilai-nilai ini di halaman Notepad kosong, karena Anda akan segera menggunakannya dalam kode Anda.
Untuk menemukan Kunci Instrumentasi, Anda harus menggulir ke bawah daftar fungsi Layanan, dan memilih Properti, tab yang ditampilkan akan mengungkapkan Kunci Layanan.
Sedikit di bawah Properti, Anda akan menemukan Akses API, yang perlu Anda klik. Panel di sebelah kanan akan memberikan ID Aplikasi aplikasi Anda.
Dengan panel ID Aplikasi masih terbuka, klik Buat Kunci API, yang akan membuka panel buat kunci API.
Dalam panel buat kunci API yang sekarang terbuka, ketik deskripsi, dan centang tiga kotak.
Klik Buat Kunci. Kunci API Anda akan dibuat dan ditampilkan.
Peringatan
Ini adalah satu-satunya waktu Kunci Layanan Anda akan ditampilkan, jadi pastikan Anda membuat salinannya sekarang.
Bab 2 - Menyiapkan proyek Unity
Berikut ini adalah pengaturan khas untuk mengembangkan dengan realitas campuran, dan dengan demikian, adalah templat yang baik untuk proyek lain.
Buka Unity dan klik Baru.
Sekarang Anda harus memberikan nama Proyek Unity, menyisipkan MR_Azure_Application_Insights. Pastikan Templat diatur ke 3D. Atur Lokasi ke tempat yang sesuai untuk Anda (ingat, lebih dekat ke direktori akar lebih baik). Lalu, klik Buat proyek.
Dengan Unity terbuka, ada baiknya memeriksa Editor Skrip default diatur ke Visual Studio. Buka Edit > Preferensi lalu dari jendela baru, navigasikan ke Alat Eksternal. Ubah Editor Skrip Eksternal ke Visual Studio 2017. Tutup jendela Preferensi .
Selanjutnya, buka Pengaturan Build File > dan alihkan platform ke Platform Windows Universal, dengan mengklik tombol Beralih Platform.
Buka Pengaturan Build File > dan pastikan bahwa:
Perangkat Target diatur ke Perangkat apa pun
Untuk Microsoft HoloLens, atur Perangkat Target ke HoloLens.
Jenis Build diatur ke D3D
SDK diatur ke Terbaru diinstal
Build and Run diatur ke Komputer Lokal
Simpan adegan dan tambahkan ke build.
Lakukan ini dengan memilih Tambahkan Adegan Terbuka. Jendela penyimpanan akan muncul.
Buat folder baru untuk ini, dan adegan mendatang, lalu klik tombol Folder baru, untuk membuat folder baru, beri nama Adegan.
Buka folder Adegan yang baru dibuat, lalu di bidang Nama file: teks, ketik ApplicationInsightsScene, lalu klik Simpan.
Pengaturan yang tersisa, di Pengaturan Build, harus dibiarkan sebagai default untuk saat ini.
Di jendela Pengaturan Build, pilih Pengaturan Pemutar, ini akan membuka panel terkait di ruang tempat Pemeriksa berada.
Di panel ini, beberapa pengaturan perlu diverifikasi:
Di tab Pengaturan Lainnya:
Versi Runtime Pembuatan Skrip harus Eksperimental (Setara.NET 4.6), yang akan memicu kebutuhan untuk memulai ulang Editor.
Scripting Backend harus .NET
Tingkat Kompatibilitas API harus .NET 4.6
Dalam tab Pengaturan Penerbitan, di bawah Kemampuan, periksa:
InternetClient
Selanjutnya di bawah panel, di Pengaturan XR (ditemukan di bawah Pengaturan Penerbitan), centang Virtual Reality Didukung, pastikan Windows Mixed Reality SDK ditambahkan.
Kembali ke Pengaturan Build, Proyek Unity C# tidak lagi berwarna abu-abu; centang kotak di samping ini.
Tutup jendela Pengaturan Build.
Simpan Adegan dan Proyek Anda (FILE>SAVE SCENE / FILE>SAVE PROJECT).
Bab 3 - Impor paket Unity
Penting
Jika Anda ingin melewati komponen Unity Siapkan kursus ini, dan lanjutkan langsung ke dalam kode, jangan ragu untuk mengunduh Paket Azure-MR-309.unity ini, impor ke proyek Anda sebagai Paket Kustom. Ini juga akan berisi DLL dari Bab berikutnya. Setelah impor, lanjutkan dari Bab 6.
Penting
Untuk menggunakan Application Insights dalam Unity, Anda perlu mengimpor DLL untuk itu, bersama dengan DLL Newtonsoft. Saat ini ada masalah yang diketahui di Unity yang mengharuskan plugin dikonfigurasi ulang setelah impor. Langkah-langkah ini (4 - 7 di bagian ini) tidak akan lagi diperlukan setelah bug diselesaikan.
Untuk mengimpor Application Insights ke dalam proyek Anda sendiri, pastikan Anda telah mengunduh '.unitypackage', yang berisi plugin. Kemudian, lakukan hal berikut:
Tambahkan the.unitypackage** ke Unity dengan menggunakan opsi menu Paket Kustom Paket > Impor Aset>.
Dalam kotak Impor Paket Unity yang muncul, pastikan semuanya di bawah (dan termasuk) Plugin dipilih.
Klik tombol Impor , untuk menambahkan item ke proyek Anda.
Buka folder Wawasan di bawah Plugin dalam tampilan Proyek dan pilih plugin berikut saja:
- Microsoft.ApplicationInsights
Dengan plugin ini dipilih, pastikan bahwa Platform Apa pun tidak dicentang, lalu pastikan bahwa WSAPlayer juga tidak dicentang, lalu klik Terapkan. Melakukan ini hanya untuk mengonfirmasi bahwa file dikonfigurasi dengan benar.
Catatan
Menandai plugin seperti ini, mengonfigurasinya untuk hanya digunakan di Editor Unity. Ada sekumpulan DLL yang berbeda di folder WSA yang akan digunakan setelah proyek diekspor dari Unity.
Selanjutnya, Anda perlu membuka folder WSA , di dalam folder Insights . Anda akan melihat salinan file yang sama dengan yang Anda konfigurasi. Pilih file ini, lalu di pemeriksa, pastikan platform apa pun tidak dicentang, lalu pastikan bahwa hanya WSAPlayer yang dicentang. Klik Terapkan.
Anda sekarang harus mengikuti langkah 4-6, tetapi untuk plugin Newtonsoft sebagai gantinya. Lihat cuplikan layar di bawah ini untuk tampilan hasilnya.
Bab 4 - Menyiapkan kontrol kamera dan pengguna
Dalam Bab ini, Anda akan menyiapkan kamera dan kontrol untuk memungkinkan pengguna melihat dan berpindah di adegan.
Klik kanan di area kosong di Panel Hierarki, lalu pada Buat>Kosong.
Ganti nama GameObject kosong baru menjadi Induk Kamera.
Klik kanan di area kosong di Panel Hierarki, lalu pada Objek 3D, lalu di Sphere.
Ganti nama Sphere menjadi Tangan Kanan.
Atur Skala Transformasi Tangan Kanan ke 0.1, 0.1, 0.1
Hapus komponen Sphere Collider dari Tangan Kanan dengan mengklik Roda Gigi di komponen Sphere Collider, lalu Hapus Komponen.
Di Panel Hierarki, seret Kamera Utama dan objek Tangan Kanan ke objek Induk Kamera.
Atur Posisi Transformasi Kamera Utama dan objek Tangan Kanan ke 0, 0, 0.
Bab 5 - Siapkan objek di adegan Unity
Sekarang Anda akan membuat beberapa bentuk dasar untuk adegan Anda, yang dapat berinteraksi dengan pengguna.
Klik kanan di area kosong di Panel Hierarki, lalu pada Objek 3D, lalu pilih Bidang.
Atur Posisi Transformasi Bidang ke 0, -1, 0.
Atur Skala Transformasi Bidang ke 5, 1, 5.
Buat bahan dasar untuk digunakan dengan objek Plane Anda, sehingga bentuk lain lebih mudah dilihat. Navigasi ke Panel Proyek Anda, klik kanan, lalu Buat, diikuti oleh Folder, untuk membuat folder baru. Beri nama Bahan.
Buka folder Materi, lalu klik kanan, klik Buat, lalu Materi, untuk membuat materi baru. Sebut saja Blue.
Dengan materi Biru baru dipilih, lihat Pemeriksa, dan klik jendela persegi panjang bersama Albedo. Pilih warna biru (satu gambar di bawah ini adalah Warna Hex: #3592FFFF). Klik tombol tutup setelah Anda memilih.
Seret materi baru Anda dari folder Bahan, ke Pesawat yang baru dibuat, di dalam adegan Anda (atau letakkan pada objek Plane dalam Hierarki).
Klik kanan di area kosong di Panel Hierarki, lalu pada Objek 3D, Kapsul.
- Dengan Kapsul dipilih, ubah Posisi Transformasinya menjadi: -10, 1, 0.
Klik kanan di area kosong di Panel Hierarki, lalu pada Objek 3D, Kubus.
- Dengan Kubus dipilih, ubah Posisi Transformasinya menjadi: 0, 0, 10.
Klik kanan di area kosong di Panel Hierarki, lalu pada Objek 3D, Sphere.
- Dengan Sphere dipilih, ubah Posisi Transformasinya menjadi: 10, 0, 0.
Catatan
Nilai Posisi ini adalah saran. Anda bebas mengatur posisi objek ke apa pun yang Anda inginkan, meskipun lebih mudah bagi pengguna aplikasi jika jarak objek tidak terlalu jauh dari kamera.
Saat aplikasi Anda berjalan, aplikasi harus dapat mengidentifikasi objek dalam adegan, untuk mencapainya, mereka perlu ditandai. Pilih salah satu objek, dan di panel Pemeriksa , klik Tambahkan Tag..., yang akan menukar Pemeriksa dengan panel Tag & Lapisan .
Klik simbol + (plus), lalu ketik nama tag sebagai ObjectInScene.
Peringatan
Jika Anda menggunakan nama yang berbeda untuk tag Anda, Anda harus memastikan perubahan ini juga membuat DataFromAnalytics, ObjectTrigger, dan Gaze, skrip nanti, sehingga objek Anda ditemukan, dan terdeteksi, dalam adegan Anda.
Dengan tag yang dibuat, Anda sekarang perlu menerapkannya ke ketiga objek Anda. Dari Hierarki, tahan tombol Shift, lalu klik Kapsul, Kubus, dan Sphere, objek, lalu di Pemeriksa, klik menu dropdown bersama Tag, lalu klik tag ObjectInScene yang Anda buat.
Bab 6 - Buat kelas ApplicationInsightsTracker
Skrip pertama yang perlu Anda buat adalah ApplicationInsightsTracker, yang bertanggung jawab untuk:
Membuat peristiwa berdasarkan interaksi pengguna untuk dikirimkan ke Azure Application Insights.
Membuat Nama peristiwa yang sesuai, bergantung pada interaksi pengguna.
Mengirimkan peristiwa ke instans Application Insights Service.
Untuk membuat kelas ini:
Klik kanan di Panel Proyek, lalu Buat>Folder. Beri nama folder Skrip.
Dengan folder Skrip dibuat, klik dua kali, untuk membukanya. Kemudian, di dalam folder tersebut, klik kanan, Buat>Skrip C#. Beri nama skrip ApplicationInsightsTracker.
Klik dua kali skrip ApplicationInsightsTracker baru untuk membukanya dengan Visual Studio.
Perbarui namespace layanan di bagian atas skrip menjadi seperti di bawah ini:
using Microsoft.ApplicationInsights; using Microsoft.ApplicationInsights.DataContracts; using Microsoft.ApplicationInsights.Extensibility; using UnityEngine;
Di dalam kelas sisipkan variabel berikut:
/// <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;
Catatan
Atur nilai instrumentationKey, applicationId, dan API_Key dengan tepat, menggunakan Kunci Layanan dari Portal Microsoft Azure seperti yang disebutkan dalam Bab 1, langkah 9 dan seterusnya.
Kemudian tambahkan metode Start() dan Awake(), yang akan dipanggil saat kelas menginisialisasi:
/// <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; }
Tambahkan metode yang bertanggung jawab untuk mengirim peristiwa dan metrik yang didaftarkan oleh aplikasi Anda:
/// <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); }
Pastikan untuk menyimpan perubahan Anda di Visual Studio sebelum kembali ke Unity.
Bab 7 - Buat skrip Tatap
Skrip berikutnya yang akan dibuat adalah skrip Tatapan. Skrip ini bertanggung jawab untuk membuat Raycast yang akan diproyeksikan ke depan dari Kamera Utama, untuk mendeteksi objek mana yang dilihat pengguna. Dalam hal ini, Raycast perlu mengidentifikasi apakah pengguna melihat objek dengan tag ObjectInScene , dan kemudian menghitung berapa lama pengguna menatap objek tersebut.
Klik ganda folder Skrip, untuk membukanya.
Klik kanan di dalam folder Skrip, klik Buat>Skrip C#. Beri nama tataian skrip.
Klik dua kali skrip untuk membukanya dengan Visual Studio.
Ganti kode yang ada dengan yang berikut ini:
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; }
Kode untuk metode Awake() dan Start() sekarang perlu ditambahkan.
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; }
Di dalam kelas Tatapan, tambahkan kode berikut dalam metode Update() untuk memproyeksikan Raycast dan mendeteksi target yang tercapai:
/// <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; } }
Tambahkan metode ResetFocusedObject(), untuk mengirim data ke Application Insights saat pengguna telah melihat objek.
/// <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; } } }
Anda sekarang telah menyelesaikan skrip Tatap. Simpan perubahan Anda di Visual Studio sebelum kembali ke Unity.
Bab 8 - Buat kelas ObjectTrigger
Skrip berikutnya yang perlu Anda buat adalah ObjectTrigger, yang bertanggung jawab untuk:
- Menambahkan komponen yang diperlukan untuk tabrakan ke Kamera Utama.
- Mendeteksi apakah kamera berada di dekat objek yang ditandai sebagai ObjectInScene.
Untuk membuat skrip:
Klik ganda folder Skrip, untuk membukanya.
Klik kanan di dalam folder Skrip, klik Buat>Skrip C#. Beri nama skrip ObjectTrigger.
Klik dua kali skrip untuk membukanya dengan Visual Studio. Ganti kode yang ada dengan yang berikut ini:
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); } } }
Pastikan untuk menyimpan perubahan Anda di Visual Studio sebelum kembali ke Unity.
Bab 9 - Buat kelas DataFromAnalytics
Anda sekarang perlu membuat skrip DataFromAnalytics , yang bertanggung jawab untuk:
- Mengambil data analitik tentang objek mana yang paling banyak didekati oleh kamera.
- Menggunakan Kunci Layanan, yang memungkinkan komunikasi dengan instans Azure Application Insights Service Anda.
- Mengurutkan objek dalam adegan, yang menurutnya memiliki jumlah peristiwa tertinggi.
- Mengubah warna bahan, dari objek yang paling didekati, menjadi hijau.
Untuk membuat skrip:
Klik ganda folder Skrip, untuk membukanya.
Klik kanan di dalam folder Skrip, klik Buat>Skrip C#. Beri nama skrip DataFromAnalytics.
Klik dua kali skrip untuk membukanya dengan Visual Studio.
Sisipkan namespace berikut:
using Newtonsoft.Json; using System; using System.Collections; using System.Collections.Generic; using System.Linq; using UnityEngine; using UnityEngine.Networking;
Di dalam skrip, sisipkan yang berikut ini:
/// <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(); }
Dalam kelas DataFromAnalytics, tepat setelah metode Start(), tambahkan metode berikut yang disebut FetchAnalytics(). Metode ini bertanggung jawab untuk mengisi daftar pasangan nilai kunci, dengan GameObject dan nomor jumlah peristiwa tempat penampung. Kemudian menginisialisasi koroutine GetWebRequest(). Struktur kueri panggilan ke Application Insights juga dapat ditemukan dalam metode ini, sebagai titik akhir URL Kueri.
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)); } }
Tepat di bawah metode FetchAnalytics(), tambahkan metode yang disebut GetWebRequest(), yang mengembalikan IEnumerator. Metode ini bertanggung jawab untuk meminta berapa kali peristiwa, sesuai dengan GameObject tertentu, telah dipanggil dalam Application Insights. Ketika semua kueri yang dikirim telah dikembalikan, metode DetermineWinner() dipanggil.
/// <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(); } } } }
Metode berikutnya adalah DetermineWinner(), yang mengurutkan daftar pasangan GameObject dan Int , menurut jumlah peristiwa tertinggi. Kemudian mengubah warna material GameObject tersebut menjadi hijau (sebagai umpan balik untuk memiliki jumlah tertinggi). Ini menampilkan pesan dengan hasil analitik.
/// <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); }
Tambahkan struktur kelas yang akan digunakan untuk mendeserialisasi objek JSON, yang diterima dari Application Insights. Tambahkan kelas ini di bagian paling bawah file kelas DataFromAnalytics Anda, di luar definisi kelas.
/// <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; } }
Pastikan untuk menyimpan perubahan Anda di Visual Studio sebelum kembali ke Unity.
Bab 10 - Buat kelas Gerakan
Skrip Gerakan adalah skrip berikutnya yang perlu Anda buat. Ini bertanggung jawab untuk:
- Memindahkan Kamera Utama sesuai dengan arah yang dicari kamera.
- Menambahkan semua skrip lain ke objek adegan.
Untuk membuat skrip:
Klik ganda folder Skrip, untuk membukanya.
Klik kanan di dalam folder Skrip, klik Buat>Skrip C#. Beri nama Gerakan skrip.
Klik dua kali skrip untuk membukanya dengan Visual Studio.
Ganti kode yang ada dengan yang berikut ini:
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() { } }
Dalam kelas Gerakan, di bawah metode Update() kosong, sisipkan metode berikut yang memungkinkan pengguna menggunakan pengontrol tangan untuk berpindah di ruang virtual:
/// <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); }
Terakhir tambahkan panggilan metode dalam metode Update().
// Update is called once per frame void Update() { UpdateControllerState(); }
Pastikan untuk menyimpan perubahan Anda di Visual Studio sebelum kembali ke Unity.
Bab 11 - Menyiapkan referensi skrip
Dalam Bab ini Anda perlu menempatkan skrip Gerakan ke Induk Kamera dan mengatur target referensinya. Skrip itu kemudian akan menangani penempatan skrip lain di mana mereka perlu berada.
Dari folder Skrip di Panel Proyek, seret skrip Gerakan ke objek Induk Kamera, yang terletak di Panel Hierarki.
Klik Induk Kamera. Di Panel Hierarki, seret objek Tangan Kanan dari Panel Hierarki ke target referensi, Pengontrol, di Panel Pemeriksa. Atur Kecepatan Pengguna ke 5, seperti yang ditunjukkan pada gambar di bawah ini.
Bab 12 - Bangun proyek Unity
Semua yang diperlukan untuk bagian Unity dari proyek ini sekarang telah selesai, jadi saatnya untuk membangunnya dari Unity.
Navigasi ke Pengaturan Build, (Pengaturan Build File>).
Dari jendela Pengaturan Build, klik Bangun.
Jendela File Explorer akan muncul, meminta Lokasi untuk build. Buat folder baru (dengan mengklik Folder Baru di sudut kiri atas), dan beri nama BUILDS.
Buka folder BUILDS baru, dan buat folder lain (menggunakan Folder Baru sekali lagi), dan beri nama MR_Azure_Application_Insights.
Dengan folder MR_Azure_Application_Insights dipilih, klik Pilih Folder. Proyek akan memakan waktu satu menit atau lebih untuk membangun.
Setelah Build, File Explorer akan muncul yang menunjukkan lokasi proyek baru Anda.
Bab 13 - Menyebarkan aplikasi MR_Azure_Application_Insights ke komputer Anda
Untuk menyebarkan aplikasi MR_Azure_Application_Insights di Komputer Lokal Anda:
Buka file solusi aplikasi MR_Azure_Application_Insights Anda di Visual Studio.
Di Platform Solusi, pilih x86, Komputer Lokal.
Di Konfigurasi Solusi pilih Debug.
Buka menu Build dan klik Sebarkan Solusi untuk memuat samping aplikasi ke komputer Anda.
Aplikasi Anda sekarang akan muncul dalam daftar aplikasi yang diinstal, siap untuk diluncurkan.
Luncurkan aplikasi realitas campuran.
Bergerak di sekitar adegan, mendekati objek dan melihatnya, ketika Azure Insight Service telah mengumpulkan data peristiwa yang cukup, itu akan mengatur objek yang telah didekati paling ke hijau.
Penting
Sementara waktu tunggu rata-rata untuk Peristiwa dan Metrik yang akan dikumpulkan oleh Layanan membutuhkan waktu sekitar 15 menit, dalam beberapa kesempatan mungkin perlu waktu hingga 1 jam.
Bab 14 - Portal Application Insights Service
Setelah Anda menjelajah di sekitar adegan dan menatap beberapa objek, Anda dapat melihat data yang dikumpulkan di portal Layanan Application Insights.
Kembali ke portal Layanan Application Insights Anda.
Pilih Penjelajah Metrik.
Ini akan terbuka di tab yang berisi grafik, yang mewakili Peristiwa dan Metrik yang terkait dengan aplikasi Anda. Seperti disebutkan di atas, mungkin perlu waktu (hingga 1 jam) agar data ditampilkan dalam grafik
Pilih bilah Peristiwa di Total Peristiwa menurut Versi Aplikasi, untuk melihat perincian terperinci peristiwa dengan namanya.
Aplikasi Application Insights Service Anda yang sudah selesai
Selamat, Anda membuat aplikasi realitas campuran yang memanfaatkan Layanan Application Insights untuk memantau aktivitas pengguna dalam aplikasi Anda.
Latihan Bonus
Latihan 1
Coba pemijahan, daripada membuat secara manual, objek ObjectInScene dan atur koordinatnya pada bidang dalam skrip Anda. Dengan cara ini, Anda dapat bertanya kepada Azure apa objek paling populer (baik dari tatapan atau hasil kedekatan) dan menghasilkan tambahan salah satu objek tersebut.
Latihan 2
Urutkan hasil Application Insights Anda menurut waktu, sehingga Anda mendapatkan data yang paling relevan, dan menerapkan data sensitif waktu tersebut dalam aplikasi Anda.