Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Penting
Tutorial Mixed Reality Academy dirancang dengan HoloLens (generasi ke-1), Unity 2017, dan Mixed Reality Headset Imersif 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 dan mungkin tidak kompatibel dengan versi Unity yang lebih baru. Mereka akan dipertahankan untuk terus bekerja pada perangkat yang didukung. Serangkaian tutorial baru telah diposting untuk HoloLens 2.
Hologram diberikan kehadiran di dunia kita dengan tetap di tempat saat kita bergerak di ruang angkasa. HoloLens menjaga hologram di tempat dengan menggunakan berbagai sistem koordinat untuk melacak lokasi dan orientasi objek. Ketika kami berbagi sistem koordinat ini antar perangkat, kami dapat menciptakan pengalaman bersama yang memungkinkan kami untuk mengambil bagian dalam dunia holografik bersama.
Dalam tutorial ini, kita akan:
- Menyiapkan jaringan untuk pengalaman bersama.
- Bagikan hologram di seluruh perangkat HoloLens.
- Temukan orang lain di dunia holografik bersama kami.
- Buat pengalaman interaktif bersama di mana Anda dapat menargetkan pemain lain - dan meluncurkan proyektil ke arah mereka!
Dukungan perangkat
| Kursus | HoloLens | Headset imersif |
|---|---|---|
| Berbagi MR 240: Beberapa perangkat HoloLens | ✔️ |
Sebelum memulai
Prasyarat
- PC Windows 10 dikonfigurasi dengan alat yang benar yang diinstal dengan akses Internet.
- Setidaknya dua perangkat HoloLens dikonfigurasi untuk pengembangan.
File proyek
- Unduh file yang diperlukan oleh proyek. Membutuhkan Unity 2017.2 atau yang lebih baru.
- Batalkan arsip file ke desktop Anda atau lokasi lain yang mudah dijangkau. Pertahankan nama folder sebagai SharedHolograms.
Catatan
Jika Anda ingin melihat melalui kode sumber sebelum mengunduh, kode tersebut tersedia di GitHub.
Bab 1 - Dunia Holo
Dalam bab ini, kami akan menyiapkan proyek Unity pertama kami dan menelusuri proses build dan deploy.
Tujuan
- Siapkan Unity untuk mengembangkan aplikasi holografik.
- Lihat hologram Anda!
Petunjuk
- Mulai Unity.
- Pilih Buka.
- Masukkan lokasi sebagai folder SharedHolograms yang sebelumnya Tidak Anda arsipkan.
- Pilih Nama Proyek dan klik Pilih Folder.
- Di Hierarki, klik kanan Kamera Utama dan pilih Hapus.
- Di folder HoloToolkit-Sharing-240/Prefabs/Camera , temukan prefab Kamera Utama .
- Seret dan letakkan Kamera Utama ke hierarki.
- Di Hierarki, klik Buat dan Buat Kosong.
- Klik kanan GameObject baru dan pilih Ganti Nama.
- Ganti nama GameObject menjadi HologramCollection.
- Pilih objek HologramCollection di Hierarki.
- Dalam Inspektur atur posisi transformasi ke: X: 0, Y: -0.25, Z: 2.
- Di folder Hologram di panel Proyek, temukan aset EnergyHub .
- Seret dan letakkan objek EnergyHub dari panel Proyek ke Hierarki sebagai anak dari HologramCollection.
- Pilih Simpan Adegan File > Sebagai...
- Beri nama adegan SharedHolograms dan klik Simpan.
- Tekan tombol Putar di Unity untuk mempratinjau hologram Anda.
- Tekan Putar untuk kedua kalinya untuk menghentikan mode pratinjau.
Mengekspor proyek dari Unity ke Visual Studio
- Di Unity pilih Pengaturan Build File>.
- Klik Tambahkan Adegan Terbuka untuk menambahkan adegan.
- Pilih Platform Windows Universal di daftar Platform dan klik Beralih Platform.
- Atur SDK ke Universal 10.
- Atur Perangkat target ke Jenis Build HoloLens dan UWP ke D3D.
- Periksa Proyek Unity C#.
- Klik Bangun.
- Di jendela penjelajah file yang muncul, buat Folder Baru bernama "Aplikasi".
- Klik tunggal folder Aplikasi .
- Tekan Pilih Folder.
- Ketika Unity selesai, jendela File Explorer akan muncul.
- Buka folder Aplikasi .
- Buka SharedHolograms.sln untuk meluncurkan Visual Studio.
- Menggunakan toolbar atas di Visual Studio, ubah target dari Debug ke Rilis dan dari ARM ke X86.
- Klik panah drop-down di samping Komputer Lokal, dan pilih Perangkat Jarak Jauh.
- Atur Alamat ke nama atau alamat IP HoloLens Anda. Jika Anda tidak tahu alamat IP perangkat Anda, lihat di Pengaturan > Jaringan & Opsi Tingkat Lanjut Internet > atau tanyakan Cortana "Hey Cortana, Apa alamat IP saya?"
- Biarkan Mode Autentikasi diatur ke Universal.
- Klik Pilih
- Klik Debug > Mulai Tanpa penelusuran kesalahan atau tekan Ctrl + F5. Jika ini adalah pertama kalinya menyebarkan ke perangkat Anda, Anda harus memasangkannya dengan Visual Studio.
- Pakai HoloLens anda dan temukan hologram EnergyHub.
Bab 2 - Interaksi
Dalam bab ini, kita akan berinteraksi dengan hologram kita. Pertama, kita akan menambahkan kursor untuk memvisualisasikan Tatapan kita. Kemudian, kita akan menambahkan Gerakan dan menggunakan tangan kita untuk menempatkan hologram kita di ruang angkasa.
Tujuan
- Gunakan input tatap untuk mengontrol kursor.
- Gunakan input gerakan untuk berinteraksi dengan hologram.
Petunjuk
Pandangan
- Di panel Hierarki pilih objek HologramCollection .
- Di panel Pemeriksa klik tombol Tambahkan Komponen .
- Di menu, ketik di kotak pencarian Gaze Manager. Pilih hasil pencarian.
- Di folder HoloToolkit-Sharing-240\Prefabs\Input , temukan aset Kursor .
- Seret dan letakkan aset Kursor ke Hierarki.
Gerakan
- Di panel Hierarki pilih objek HologramCollection .
- Klik Tambahkan Komponen dan ketik Manajer Gerakan di bidang pencarian. Pilih hasil pencarian.
- Di panel Hierarki, perluas HologramCollection.
- Pilih objek EnergyHub anak.
- Di panel Pemeriksa klik tombol Tambahkan Komponen .
- Di menu, ketik di kotak pencarian Penempatan Hologram. Pilih hasil pencarian.
- Simpan adegan dengan memilih Simpan Adegan File>.
Menyebarkan dan menikmati
- Buat dan sebarkan ke HoloLens Anda, menggunakan instruksi dari bab sebelumnya.
- Setelah aplikasi diluncurkan di HoloLens Anda, gerakkan kepala Anda dan perhatikan bagaimana EnergyHub mengikuti tatapan Anda.
- Perhatikan bagaimana kursor muncul saat Anda menatap hologram, dan berubah menjadi cahaya titik saat tidak menatap hologram.
- Lakukan ketukan udara untuk menempatkan hologram. Saat ini dalam proyek kami, Anda hanya dapat menempatkan hologram sekali (sebarkan ulang untuk mencoba lagi).
Bab 3 - Koordinat Bersama
Sangat menyenangkan untuk melihat dan berinteraksi dengan hologram, tetapi mari kita melangkah lebih jauh. Kami akan menyiapkan pengalaman bersama pertama kami - hologram yang dapat dilihat semua orang bersama.
Tujuan
- Menyiapkan jaringan untuk pengalaman bersama.
- Buat titik referensi umum.
- Bagikan sistem koordinat di seluruh perangkat.
- Semua orang melihat hologram yang sama!
Catatan
Kemampuan InternetClientServer dan PrivateNetworkClientServer harus dideklarasikan agar aplikasi tersambung ke server berbagi. Ini dilakukan untuk Anda sudah di Hologram 240, tetapi ingatlah hal ini untuk proyek Anda sendiri.
- Di Editor Unity, buka pengaturan pemutar dengan menavigasi ke "Edit > Pemutar Pengaturan > Proyek"
- Klik pada tab "Windows Store"
- Di bagian "Kemampuan Pengaturan > Penerbitan", periksa kemampuan InternetClientServer dan kemampuan PrivateNetworkClientServer
Petunjuk
- Di panel Proyek navigasikan ke folder HoloToolkit-Sharing-240\Prefabs\Sharing .
- Seret dan letakkan prefab Berbagi ke panel Hierarki.
Selanjutnya kita perlu meluncurkan layanan berbagi. Hanya satu PC dalam pengalaman bersama yang perlu melakukan langkah ini.
- Di Unity - di menu atas - pilih menu HoloToolkit-Sharing-240.
- Pilih item Luncurkan Layanan Berbagi di menu drop-down.
- Centang opsi Jaringan Privat dan klik Izinkan Akses saat permintaan firewall muncul.
- Catat alamat IPv4 yang ditampilkan di jendela konsol Layanan Berbagi. Ini adalah IP yang sama dengan mesin yang dijalankan layanan.
Ikuti instruksi lainnya di semua PC yang akan bergabung dengan pengalaman bersama.
- Di Hierarki, pilih objek Berbagi .
- Di Inspektur, pada komponen Tahap Berbagi , ubah Alamat Server dari 'localhost' ke alamat IPv4 komputer yang berjalan SharingService.exe.
- Di Hierarki pilih objek HologramCollection .
- Di Pemeriksa klik tombol Tambahkan Komponen .
- Dalam kotak pencarian, ketik Import Export Anchor Manager. Pilih hasil pencarian.
- Di panel Proyek , navigasikan ke folder Skrip .
- Klik dua kali skrip HologramPlacement untuk membukanya di Visual Studio.
- Ganti konten dengan kode di bawah ini.
using UnityEngine;
using System.Collections.Generic;
using UnityEngine.Windows.Speech;
using Academy.HoloToolkit.Unity;
using Academy.HoloToolkit.Sharing;
public class HologramPlacement : Singleton<HologramPlacement>
{
/// <summary>
/// Tracks if we have been sent a transform for the anchor model.
/// The anchor model is rendered relative to the actual anchor.
/// </summary>
public bool GotTransform { get; private set; }
private bool animationPlayed = false;
void Start()
{
// We care about getting updates for the anchor transform.
CustomMessages.Instance.MessageHandlers[CustomMessages.TestMessageID.StageTransform] = this.OnStageTransform;
// And when a new user join we will send the anchor transform we have.
SharingSessionTracker.Instance.SessionJoined += Instance_SessionJoined;
}
/// <summary>
/// When a new user joins we want to send them the relative transform for the anchor if we have it.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Instance_SessionJoined(object sender, SharingSessionTracker.SessionJoinedEventArgs e)
{
if (GotTransform)
{
CustomMessages.Instance.SendStageTransform(transform.localPosition, transform.localRotation);
}
}
void Update()
{
if (GotTransform)
{
if (ImportExportAnchorManager.Instance.AnchorEstablished &&
animationPlayed == false)
{
// This triggers the animation sequence for the anchor model and
// puts the cool materials on the model.
GetComponent<EnergyHubBase>().SendMessage("OnSelect");
animationPlayed = true;
}
}
else
{
transform.position = Vector3.Lerp(transform.position, ProposeTransformPosition(), 0.2f);
}
}
Vector3 ProposeTransformPosition()
{
// Put the anchor 2m in front of the user.
Vector3 retval = Camera.main.transform.position + Camera.main.transform.forward * 2;
return retval;
}
public void OnSelect()
{
// Note that we have a transform.
GotTransform = true;
// And send it to our friends.
CustomMessages.Instance.SendStageTransform(transform.localPosition, transform.localRotation);
}
/// <summary>
/// When a remote system has a transform for us, we'll get it here.
/// </summary>
/// <param name="msg"></param>
void OnStageTransform(NetworkInMessage msg)
{
// We read the user ID but we don't use it here.
msg.ReadInt64();
transform.localPosition = CustomMessages.Instance.ReadVector3(msg);
transform.localRotation = CustomMessages.Instance.ReadQuaternion(msg);
// The first time, we'll want to send the message to the anchor to do its animation and
// swap its materials.
if (GotTransform == false)
{
GetComponent<EnergyHubBase>().SendMessage("OnSelect");
}
GotTransform = true;
}
public void ResetStage()
{
// We'll use this later.
}
}
- Kembali ke Unity, pilih HologramCollection di panel Hierarki.
- Di panel Pemeriksa klik tombol Tambahkan Komponen .
- Di menu, ketik di kotak pencarian App State Manager. Pilih hasil pencarian.
Menyebarkan dan menikmati
- Bangun proyek untuk perangkat HoloLens Anda.
- Tentukan satu HoloLens untuk disebarkan terlebih dahulu. Anda harus menunggu Jangkar diunggah ke layanan sebelum Anda dapat menempatkan EnergyHub (ini dapat memakan waktu ~ 30-60 detik). Hingga unggahan selesai, gerakan ketukan Anda akan diabaikan.
- Setelah EnergyHub ditempatkan, lokasinya akan diunggah ke layanan dan Anda kemudian dapat menyebarkan ke semua perangkat HoloLens lainnya.
- Ketika HoloLens baru pertama kali bergabung dengan sesi, lokasi EnergyHub mungkin tidak benar pada perangkat tersebut. Namun, segera setelah jangkar dan lokasi EnergyHub telah diunduh dari layanan, EnergyHub harus melompat ke lokasi bersama yang baru. Jika ini tidak terjadi dalam ~ 30-60 detik, berjalanlah ke tempat HoloLens asli ketika mengatur jangkar untuk mengumpulkan lebih banyak petunjuk lingkungan. Jika lokasi masih tidak terkunci, sebarkan ulang ke perangkat.
- Ketika semua perangkat siap dan menjalankan aplikasi, cari EnergyHub. Dapatkah Anda semua menyetujui lokasi hologram dan arah mana teks yang dihadapi?
Bab 4 - Penemuan
Semua orang sekarang dapat melihat hologram yang sama! Sekarang mari kita lihat orang lain yang terhubung ke dunia holografik bersama kita. Dalam bab ini, kita akan mengambil lokasi utama dan rotasi semua perangkat HoloLens lainnya dalam sesi berbagi yang sama.
Tujuan
- Temukan satu sama lain dalam pengalaman bersama kami.
- Pilih dan bagikan avatar pemutar.
- Pasang avatar pemutar di samping kepala semua orang.
Petunjuk
- Di panel Proyek , navigasikan ke folder Hologram .
- Seret dan letakkan PlayerAvatarStore ke dalam Hierarki.
- Di panel Proyek , navigasikan ke folder Skrip .
- Klik dua kali skrip AvatarSelector untuk membukanya di Visual Studio.
- Ganti konten dengan kode di bawah ini.
using UnityEngine;
using Academy.HoloToolkit.Unity;
/// <summary>
/// Script to handle the user selecting the avatar.
/// </summary>
public class AvatarSelector : MonoBehaviour
{
/// <summary>
/// This is the index set by the PlayerAvatarStore for the avatar.
/// </summary>
public int AvatarIndex { get; set; }
/// <summary>
/// Called when the user is gazing at this avatar and air-taps it.
/// This sends the user's selection to the rest of the devices in the experience.
/// </summary>
void OnSelect()
{
PlayerAvatarStore.Instance.DismissAvatarPicker();
LocalPlayerManager.Instance.SetUserAvatar(AvatarIndex);
}
void Start()
{
// Add Billboard component so the avatar always faces the user.
Billboard billboard = gameObject.GetComponent<Billboard>();
if (billboard == null)
{
billboard = gameObject.AddComponent<Billboard>();
}
// Lock rotation along the Y axis.
billboard.PivotAxis = PivotAxis.Y;
}
}
- Di Hierarki pilih objek HologramCollection .
- Di Inspektur klik Tambahkan Komponen.
- Dalam kotak pencarian, ketik Manajer Pemutar Lokal. Pilih hasil pencarian.
- Di Hierarki pilih objek HologramCollection .
- Di Inspektur klik Tambahkan Komponen.
- Di kotak pencarian, ketik Manajer Pemutar Jarak Jauh. Pilih hasil pencarian.
- Buka skrip HologramPlacement di Visual Studio.
- Ganti konten dengan kode di bawah ini.
using UnityEngine;
using System.Collections.Generic;
using UnityEngine.Windows.Speech;
using Academy.HoloToolkit.Unity;
using Academy.HoloToolkit.Sharing;
public class HologramPlacement : Singleton<HologramPlacement>
{
/// <summary>
/// Tracks if we have been sent a transform for the model.
/// The model is rendered relative to the actual anchor.
/// </summary>
public bool GotTransform { get; private set; }
/// <summary>
/// When the experience starts, we disable all of the rendering of the model.
/// </summary>
List<MeshRenderer> disabledRenderers = new List<MeshRenderer>();
void Start()
{
// When we first start, we need to disable the model to avoid it obstructing the user picking a hat.
DisableModel();
// We care about getting updates for the model transform.
CustomMessages.Instance.MessageHandlers[CustomMessages.TestMessageID.StageTransform] = this.OnStageTransform;
// And when a new user join we will send the model transform we have.
SharingSessionTracker.Instance.SessionJoined += Instance_SessionJoined;
}
/// <summary>
/// When a new user joins we want to send them the relative transform for the model if we have it.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Instance_SessionJoined(object sender, SharingSessionTracker.SessionJoinedEventArgs e)
{
if (GotTransform)
{
CustomMessages.Instance.SendStageTransform(transform.localPosition, transform.localRotation);
}
}
/// <summary>
/// Turns off all renderers for the model.
/// </summary>
void DisableModel()
{
foreach (MeshRenderer renderer in gameObject.GetComponentsInChildren<MeshRenderer>())
{
if (renderer.enabled)
{
renderer.enabled = false;
disabledRenderers.Add(renderer);
}
}
foreach (MeshCollider collider in gameObject.GetComponentsInChildren<MeshCollider>())
{
collider.enabled = false;
}
}
/// <summary>
/// Turns on all renderers that were disabled.
/// </summary>
void EnableModel()
{
foreach (MeshRenderer renderer in disabledRenderers)
{
renderer.enabled = true;
}
foreach (MeshCollider collider in gameObject.GetComponentsInChildren<MeshCollider>())
{
collider.enabled = true;
}
disabledRenderers.Clear();
}
void Update()
{
// Wait till users pick an avatar to enable renderers.
if (disabledRenderers.Count > 0)
{
if (!PlayerAvatarStore.Instance.PickerActive &&
ImportExportAnchorManager.Instance.AnchorEstablished)
{
// After which we want to start rendering.
EnableModel();
// And if we've already been sent the relative transform, we will use it.
if (GotTransform)
{
// This triggers the animation sequence for the model and
// puts the cool materials on the model.
GetComponent<EnergyHubBase>().SendMessage("OnSelect");
}
}
}
else if (GotTransform == false)
{
transform.position = Vector3.Lerp(transform.position, ProposeTransformPosition(), 0.2f);
}
}
Vector3 ProposeTransformPosition()
{
// Put the model 2m in front of the user.
Vector3 retval = Camera.main.transform.position + Camera.main.transform.forward * 2;
return retval;
}
public void OnSelect()
{
// Note that we have a transform.
GotTransform = true;
// And send it to our friends.
CustomMessages.Instance.SendStageTransform(transform.localPosition, transform.localRotation);
}
/// <summary>
/// When a remote system has a transform for us, we'll get it here.
/// </summary>
/// <param name="msg"></param>
void OnStageTransform(NetworkInMessage msg)
{
// We read the user ID but we don't use it here.
msg.ReadInt64();
transform.localPosition = CustomMessages.Instance.ReadVector3(msg);
transform.localRotation = CustomMessages.Instance.ReadQuaternion(msg);
// The first time, we'll want to send the message to the model to do its animation and
// swap its materials.
if (disabledRenderers.Count == 0 && GotTransform == false)
{
GetComponent<EnergyHubBase>().SendMessage("OnSelect");
}
GotTransform = true;
}
public void ResetStage()
{
// We'll use this later.
}
}
- Buka skrip AppStateManager di Visual Studio.
- Ganti konten dengan kode di bawah ini.
using UnityEngine;
using Academy.HoloToolkit.Unity;
/// <summary>
/// Keeps track of the current state of the experience.
/// </summary>
public class AppStateManager : Singleton<AppStateManager>
{
/// <summary>
/// Enum to track progress through the experience.
/// </summary>
public enum AppState
{
Starting = 0,
WaitingForAnchor,
WaitingForStageTransform,
PickingAvatar,
Ready
}
/// <summary>
/// Tracks the current state in the experience.
/// </summary>
public AppState CurrentAppState { get; set; }
void Start()
{
// We start in the 'picking avatar' mode.
CurrentAppState = AppState.PickingAvatar;
// We start by showing the avatar picker.
PlayerAvatarStore.Instance.SpawnAvatarPicker();
}
void Update()
{
switch (CurrentAppState)
{
case AppState.PickingAvatar:
// Avatar picking is done when the avatar picker has been dismissed.
if (PlayerAvatarStore.Instance.PickerActive == false)
{
CurrentAppState = AppState.WaitingForAnchor;
}
break;
case AppState.WaitingForAnchor:
if (ImportExportAnchorManager.Instance.AnchorEstablished)
{
CurrentAppState = AppState.WaitingForStageTransform;
GestureManager.Instance.OverrideFocusedObject = HologramPlacement.Instance.gameObject;
}
break;
case AppState.WaitingForStageTransform:
// Now if we have the stage transform we are ready to go.
if (HologramPlacement.Instance.GotTransform)
{
CurrentAppState = AppState.Ready;
GestureManager.Instance.OverrideFocusedObject = null;
}
break;
}
}
}
Menyebarkan dan Menikmati
- Bangun dan sebarkan proyek ke perangkat HoloLens Anda.
- Saat Anda mendengar suara ping, temukan menu pilihan avatar dan pilih avatar dengan gerakan ketukan udara.
- Jika Anda tidak melihat hologram apa pun, cahaya titik di sekitar kursor Anda akan mengubah warna yang berbeda saat HoloLens berkomunikasi dengan layanan: menginisialisasi (ungu gelap), mengunduh jangkar (hijau), mengimpor/mengekspor data lokasi (kuning), mengunggah jangkar (biru). Jika cahaya titik di sekitar kursor adalah warna default (ungu muda), maka Anda siap untuk berinteraksi dengan pemain lain di sesi Anda!
- Lihatlah orang lain yang terhubung ke ruang Anda - akan ada robot holografik yang mengambang di atas kepala mereka dan meniru gerakan kepala mereka!
Bab 5 - Penempatan
Dalam bab ini, kita akan membuat jangkar dapat ditempatkan di permukaan dunia nyata. Kami akan menggunakan koordinat bersama untuk menempatkan jangkar tersebut di titik tengah antara semua orang yang terhubung ke pengalaman bersama.
Tujuan
- Tempatkan hologram pada jala pemetaan spasial berdasarkan posisi kepala pemain.
Petunjuk
- Di panel Proyek , navigasikan ke folder Hologram .
- Seret dan letakkan prefab CustomSpatialMapping ke Hierarki.
- Di panel Proyek , navigasikan ke folder Skrip .
- Klik dua kali skrip AppStateManager untuk membukanya di Visual Studio.
- Ganti konten dengan kode di bawah ini.
using UnityEngine;
using Academy.HoloToolkit.Unity;
/// <summary>
/// Keeps track of the current state of the experience.
/// </summary>
public class AppStateManager : Singleton<AppStateManager>
{
/// <summary>
/// Enum to track progress through the experience.
/// </summary>
public enum AppState
{
Starting = 0,
PickingAvatar,
WaitingForAnchor,
WaitingForStageTransform,
Ready
}
// The object to call to make a projectile.
GameObject shootHandler = null;
/// <summary>
/// Tracks the current state in the experience.
/// </summary>
public AppState CurrentAppState { get; set; }
void Start()
{
// The shootHandler shoots projectiles.
if (GetComponent<ProjectileLauncher>() != null)
{
shootHandler = GetComponent<ProjectileLauncher>().gameObject;
}
// We start in the 'picking avatar' mode.
CurrentAppState = AppState.PickingAvatar;
// Spatial mapping should be disabled when we start up so as not
// to distract from the avatar picking.
SpatialMappingManager.Instance.StopObserver();
SpatialMappingManager.Instance.gameObject.SetActive(false);
// On device we start by showing the avatar picker.
PlayerAvatarStore.Instance.SpawnAvatarPicker();
}
public void ResetStage()
{
// If we fall back to waiting for anchor, everything needed to
// get us into setting the target transform state will be setup.
if (CurrentAppState != AppState.PickingAvatar)
{
CurrentAppState = AppState.WaitingForAnchor;
}
// Reset the underworld.
if (UnderworldBase.Instance)
{
UnderworldBase.Instance.ResetUnderworld();
}
}
void Update()
{
switch (CurrentAppState)
{
case AppState.PickingAvatar:
// Avatar picking is done when the avatar picker has been dismissed.
if (PlayerAvatarStore.Instance.PickerActive == false)
{
CurrentAppState = AppState.WaitingForAnchor;
}
break;
case AppState.WaitingForAnchor:
// Once the anchor is established we need to run spatial mapping for a
// little while to build up some meshes.
if (ImportExportAnchorManager.Instance.AnchorEstablished)
{
CurrentAppState = AppState.WaitingForStageTransform;
GestureManager.Instance.OverrideFocusedObject = HologramPlacement.Instance.gameObject;
SpatialMappingManager.Instance.gameObject.SetActive(true);
SpatialMappingManager.Instance.DrawVisualMeshes = true;
SpatialMappingDeformation.Instance.ResetGlobalRendering();
SpatialMappingManager.Instance.StartObserver();
}
break;
case AppState.WaitingForStageTransform:
// Now if we have the stage transform we are ready to go.
if (HologramPlacement.Instance.GotTransform)
{
CurrentAppState = AppState.Ready;
GestureManager.Instance.OverrideFocusedObject = shootHandler;
}
break;
}
}
}
- Di panel Proyek , navigasikan ke folder Skrip .
- Klik dua kali skrip HologramPlacement untuk membukanya di Visual Studio.
- Ganti konten dengan kode di bawah ini.
using UnityEngine;
using System.Collections.Generic;
using UnityEngine.Windows.Speech;
using Academy.HoloToolkit.Unity;
using Academy.HoloToolkit.Sharing;
public class HologramPlacement : Singleton<HologramPlacement>
{
/// <summary>
/// Tracks if we have been sent a transform for the model.
/// The model is rendered relative to the actual anchor.
/// </summary>
public bool GotTransform { get; private set; }
/// <summary>
/// When the experience starts, we disable all of the rendering of the model.
/// </summary>
List<MeshRenderer> disabledRenderers = new List<MeshRenderer>();
/// <summary>
/// We use a voice command to enable moving the target.
/// </summary>
KeywordRecognizer keywordRecognizer;
void Start()
{
// When we first start, we need to disable the model to avoid it obstructing the user picking a hat.
DisableModel();
// We care about getting updates for the model transform.
CustomMessages.Instance.MessageHandlers[CustomMessages.TestMessageID.StageTransform] = this.OnStageTransform;
// And when a new user join we will send the model transform we have.
SharingSessionTracker.Instance.SessionJoined += Instance_SessionJoined;
// And if the users want to reset the stage transform.
CustomMessages.Instance.MessageHandlers[CustomMessages.TestMessageID.ResetStage] = this.OnResetStage;
// Setup a keyword recognizer to enable resetting the target location.
List<string> keywords = new List<string>();
keywords.Add("Reset Target");
keywordRecognizer = new KeywordRecognizer(keywords.ToArray());
keywordRecognizer.OnPhraseRecognized += KeywordRecognizer_OnPhraseRecognized;
keywordRecognizer.Start();
}
/// <summary>
/// When the keyword recognizer hears a command this will be called.
/// In this case we only have one keyword, which will re-enable moving the
/// target.
/// </summary>
/// <param name="args">information to help route the voice command.</param>
private void KeywordRecognizer_OnPhraseRecognized(PhraseRecognizedEventArgs args)
{
ResetStage();
}
/// <summary>
/// Resets the stage transform, so users can place the target again.
/// </summary>
public void ResetStage()
{
GotTransform = false;
// AppStateManager needs to know about this so that
// the right objects get input routed to them.
AppStateManager.Instance.ResetStage();
// Other devices in the experience need to know about this as well.
CustomMessages.Instance.SendResetStage();
// And we need to reset the object to its start animation state.
GetComponent<EnergyHubBase>().ResetAnimation();
}
/// <summary>
/// When a new user joins we want to send them the relative transform for the model if we have it.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Instance_SessionJoined(object sender, SharingSessionTracker.SessionJoinedEventArgs e)
{
if (GotTransform)
{
CustomMessages.Instance.SendStageTransform(transform.localPosition, transform.localRotation);
}
}
/// <summary>
/// Turns off all renderers for the model.
/// </summary>
void DisableModel()
{
foreach (MeshRenderer renderer in gameObject.GetComponentsInChildren<MeshRenderer>())
{
if (renderer.enabled)
{
renderer.enabled = false;
disabledRenderers.Add(renderer);
}
}
foreach (MeshCollider collider in gameObject.GetComponentsInChildren<MeshCollider>())
{
collider.enabled = false;
}
}
/// <summary>
/// Turns on all renderers that were disabled.
/// </summary>
void EnableModel()
{
foreach (MeshRenderer renderer in disabledRenderers)
{
renderer.enabled = true;
}
foreach (MeshCollider collider in gameObject.GetComponentsInChildren<MeshCollider>())
{
collider.enabled = true;
}
disabledRenderers.Clear();
}
void Update()
{
// Wait till users pick an avatar to enable renderers.
if (disabledRenderers.Count > 0)
{
if (!PlayerAvatarStore.Instance.PickerActive &&
ImportExportAnchorManager.Instance.AnchorEstablished)
{
// After which we want to start rendering.
EnableModel();
// And if we've already been sent the relative transform, we will use it.
if (GotTransform)
{
// This triggers the animation sequence for the model and
// puts the cool materials on the model.
GetComponent<EnergyHubBase>().SendMessage("OnSelect");
}
}
}
else if (GotTransform == false)
{
transform.position = Vector3.Lerp(transform.position, ProposeTransformPosition(), 0.2f);
}
}
Vector3 ProposeTransformPosition()
{
Vector3 retval;
// We need to know how many users are in the experience with good transforms.
Vector3 cumulatedPosition = Camera.main.transform.position;
int playerCount = 1;
foreach (RemotePlayerManager.RemoteHeadInfo remoteHead in RemotePlayerManager.Instance.remoteHeadInfos)
{
if (remoteHead.Anchored && remoteHead.Active)
{
playerCount++;
cumulatedPosition += remoteHead.HeadObject.transform.position;
}
}
// If we have more than one player ...
if (playerCount > 1)
{
// Put the transform in between the players.
retval = cumulatedPosition / playerCount;
RaycastHit hitInfo;
// And try to put the transform on a surface below the midpoint of the players.
if (Physics.Raycast(retval, Vector3.down, out hitInfo, 5, SpatialMappingManager.Instance.LayerMask))
{
retval = hitInfo.point;
}
}
// If we are the only player, have the model act as the 'cursor' ...
else
{
// We prefer to put the model on a real world surface.
RaycastHit hitInfo;
if (Physics.Raycast(Camera.main.transform.position, Camera.main.transform.forward, out hitInfo, 30, SpatialMappingManager.Instance.LayerMask))
{
retval = hitInfo.point;
}
else
{
// But if we don't have a ray that intersects the real world, just put the model 2m in
// front of the user.
retval = Camera.main.transform.position + Camera.main.transform.forward * 2;
}
}
return retval;
}
public void OnSelect()
{
// Note that we have a transform.
GotTransform = true;
// And send it to our friends.
CustomMessages.Instance.SendStageTransform(transform.localPosition, transform.localRotation);
}
/// <summary>
/// When a remote system has a transform for us, we'll get it here.
/// </summary>
/// <param name="msg"></param>
void OnStageTransform(NetworkInMessage msg)
{
// We read the user ID but we don't use it here.
msg.ReadInt64();
transform.localPosition = CustomMessages.Instance.ReadVector3(msg);
transform.localRotation = CustomMessages.Instance.ReadQuaternion(msg);
// The first time, we'll want to send the message to the model to do its animation and
// swap its materials.
if (disabledRenderers.Count == 0 && GotTransform == false)
{
GetComponent<EnergyHubBase>().SendMessage("OnSelect");
}
GotTransform = true;
}
/// <summary>
/// When a remote system has a transform for us, we'll get it here.
/// </summary>
void OnResetStage(NetworkInMessage msg)
{
GotTransform = false;
GetComponent<EnergyHubBase>().ResetAnimation();
AppStateManager.Instance.ResetStage();
}
}
Menyebarkan dan menikmati
- Bangun dan sebarkan proyek ke perangkat HoloLens Anda.
- Ketika aplikasi siap, berdiri dalam lingkaran dan perhatikan bagaimana EnergyHub muncul di tengah semua orang.
- Ketuk untuk menempatkan EnergyHub.
- Coba perintah suara 'Reset Target' untuk memilih EnergyHub mencadangkan dan bekerja sama sebagai grup untuk memindahkan hologram ke lokasi baru.
Bab 6 - Fisika Real-World
Dalam bab ini kita akan menambahkan hologram yang memantul dari permukaan dunia nyata. Perhatikan ruang Anda mengisi dengan proyek yang diluncurkan oleh Anda dan teman-teman Anda!
Tujuan
- Luncurkan proyektil yang memantul dari permukaan dunia nyata.
- Bagikan proyektil sehingga pemain lain dapat melihatnya.
Petunjuk
- Di Hierarki pilih objek HologramCollection .
- Di Inspektur klik Tambahkan Komponen.
- Dalam kotak pencarian, ketik Peluncur Proyektil. Pilih hasil pencarian.
Menyebarkan dan menikmati
- Bangun dan sebarkan ke perangkat HoloLens Anda.
- Saat aplikasi berjalan di semua perangkat, lakukan ketukan udara untuk meluncurkan proyektil di permukaan dunia nyata.
- Lihat apa yang terjadi ketika proyektil Anda bertabrakan dengan avatar pemain lain!
Bab 7 - Grand Finale
Dalam bab ini, kita akan mengungkap portal yang hanya dapat ditemukan dengan kolaborasi.
Tujuan
- Bekerja sama untuk meluncurkan proyektil yang cukup di jangkar untuk mengungkap portal rahasia!
Petunjuk
- Di panel Proyek , navigasikan ke folder Hologram .
- Seret dan letakkan aset Underworld sebagai anak dari HologramCollection.
- Dengan HologramCollection dipilih, klik tombol Tambahkan Komponen di Pemeriksa.
- Di menu, ketik di kotak pencarian ExplodeTarget. Pilih hasil pencarian.
- Dengan HologramCollection dipilih, dari Hierarki seret objek EnergyHub ke bidang Target di Inspektur.
- Dengan HologramCollection dipilih, dari Hierarki seret objek Underworld ke bidang Underworld di Pemeriksa.
Menyebarkan dan menikmati
- Bangun dan sebarkan ke perangkat HoloLens Anda.
- Ketika aplikasi telah diluncurkan, berkolaborasi bersama untuk meluncurkan proyektil di EnergyHub.
- Ketika dunia bawah muncul, luncurkan proyektil di robot underworld (tekan robot tiga kali untuk kesenangan ekstra).