HoloLens (1. nesil) Paylaşım 240: Birden çok HoloLens cihaz

Önemli

Karma Gerçeklik Akademi öğreticileri, HoloLens (1. nesil), Unity 2017 ve Mixed Reality Immersive Headsets ile tasarlanmıştır. Bu nedenle, bu cihazlar için geliştirme konusunda rehberlik arayan geliştiriciler için bu öğreticileri yerinde bırakmanın önemli olduğunu hissetmeyiz. Bu öğreticiler, HoloLens 2 için kullanılan en son araç kümeleri veya etkileşimlerle güncelleştirilmez ve Unity'nin yeni sürümleriyle uyumlu olmayabiliyor olabilir. Desteklenen cihazlar üzerinde çalışmaya devam etmek için bunlar korunur. 2. yıl için yeni bir öğretici HoloLens gönderildi.

Hologramlar uzaya doğru ilerlerken dünyamızda varlık olarak kalanlara yer verilir. HoloLens, nesnelerin konumunu ve yönünü izlemek için çeşitli koordinat sistemlerini kullanarak hologramları yerinde tutar. Bu koordinat sistemlerini cihazlar arasında paylaştığımız zaman, paylaşılan bir holografik dünyaya yer almamızı sağlayan paylaşılan bir deneyim oluşturabiliriz.

Bu öğreticide, şunları yapacağız:

  • Paylaşılan deneyim için bir ağ ayarlama.
  • Tüm cihazlarda hologramları HoloLens paylaşın.
  • Paylaşılan holografik dünyamızda diğer insanları keşfedin.
  • Diğer oyuncuları hedef alan ve onlara hedefleyiller başlatan paylaşılan bir etkileşimli deneyim oluşturun!

Cihaz desteği

Kurs HoloLens Çevreleyici başlığı
MR Sharing 240: Birden çok HoloLens cihaz ✔️

Başlamadan önce

Önkoşullar

Project dosyaları

  • Proje için gereken dosyaları indirin. Unity 2017.2 veya sonraki bir yıl gerektirir.
  • Dosyaları masaüstünüzde veya kolay erişilen başka bir konumda arşivden silin. Klasör adını SharedHolograms olarak kullanın.

Not

İndirmeden önce kaynak koduna bakmak için bu kodu GitHub.

Bölüm 1 - Holo World

Bu bölümde ilk Unity projemizi ayaracak ve derleme ve dağıtma sürecinde adım adım yol yapacağız.

Hedefler

  • Holografik uygulamalar geliştirmek için Unity'i ayarlama.
  • Hologramını gör!

Yönergeler

  • Unity'i başlatma.
  • ’ı seçin.
  • Daha önce arşivlemiş olduğunuz SharedHolograms klasörü olarak konum girin.
  • Ad'Project seçin ve Klasör Seç'e tıklayın.
  • Hiyerarşi'deAna Kamera'ya sağ tıklayın ve Sil'iseçin.
  • HoloToolkit-Sharing-240/Prefabs/Camera klasöründe Ana Kamera prefab'sını bulun.
  • Ana Kamerayı Sürükleyip Hiyerarşisinebırakın.
  • Hiyerarşi'de BoşOluştur ve Oluştur'a tıklayın.
  • Yeni GameObject nesnesine sağ tıklayın ve Yeniden Adlandır'ı seçin.
  • GameObject'i HologramCollection olarak yeniden adlandırarak.
  • Hiyerarşi'de HologramCollection nesnesini seçin.
  • Denetçide dönüştürme konumunu şu şekilde ayarlayın:X: 0, Y: -0,25, Z: 2.
  • Project HologramlarklasöründeEnergyHub varlını bulun.
  • EnergyHub nesnesini pano panelinden Hiyerarşi ProjectHologramCollection'ın alt bir alt adı olarak sürükleyip bırakın.
  • Dosya Sahneyi Farklı Kaydet... öğesini seçin
  • Sahneyi SharedHolograms olarak anın ve Kaydet'e tıklayın.
  • Hologramlarınızı önizlemek için Unity'de Oynat düğmesine basın.
  • Önizleme modunu durdurmak için Oynat'a ikinci kez basın.

Projeyi Unity'den Visual Studio

  • Unity'de Dosya Derleme'yi Ayarlar.
  • Sahneyi eklemek için Açık Sahne Ekle'ye tıklayın.
  • Platform listesinden Universal WindowsPlatform'u seçin ve Platformu Değiştir'e tıklayın.
  • SDK'yıEvrensel 10 olarak ayarlayın.
  • Hedef cihaz'HoloLens UWP DerlemeTürü'leriniD3D olarak ayarlayın.
  • Unity C# Projelerini denetleme.
  • Derleme'ye tıklayın.
  • Görüntülenen dosya gezgini penceresinde "App" adlı yeni bir Klasör oluşturun.
  • Uygulama klasörüne tek tıklama.
  • Klasör Seç'e basın.
  • Unity bittiğinde bir Dosya Gezgini penceresi görüntülenir.
  • Uygulama klasörünü açın.
  • Visual Studio'i başlatmak için SharedHolograms.sln'Visual Studio.
  • Araç çubuğunda üst araç çubuğunu Visual Studio, hedefi Hata Ayıklama yerine Yayın ve ARM'den X86 olarak değiştirebilirsiniz.
  • Yerel Makine'nin yanındaki açılan oka tıklayın ve Uzak Cihaz'ı seçin.
    • Adres'i, kullanıcı adı veya ip adresi olarak HoloLens. Cihazınızın IP adresini bilmiyorsanız, Ayarlar Ağ İnterneti Gelişmiş Seçenekleri'ne bakın veya & adresim nedir?" sorusunu sorun &>
    • Kimlik Doğrulama Modu'olarakbırakın.
    • Seç'e tıklayın
  • Hata Ayıklama Olmadan Başlat'a tıklayın veyaCtrl + F5 tuşlarına basın. Cihazınıza ilk kez dağıtıyorsanız, bunu Visual Studio.
  • Sanal HoloLens EnergyHub hologramını bulun.

Bölüm 2 - Etkileşim

Bu bölümde hologramlarımız ile etkileşim kuracağız. İlk olarak, Bakış'mızı görselleştirmek için bir imleç ekleyciz. Ardından Gestures'ı ekseriz ve hologramlarımızı uzaya eklemek için ellerimizi kullanacağız.

Hedefler

  • İmleci kontrol etmek için bakış girişini kullanın.
  • Hologramlarla etkileşim kurmak için hareket girişini kullanın.

Yönergeler

Bakış

  • Hiyerarşi panelindeHologramCollection nesnesini seçin.
  • Denetçi panelinde Bileşen Ekle düğmesine tıklayın.
  • Menüde, Arama kutusuna Gaze Manager yazın. Arama sonuçlarını seçin.
  • HoloToolkit-Sharing-240\Prefabs\Input klasöründe İmleç varlını bulun.
  • İmleç varlıklarını Hiyerarşi'ye sürükleyip bırakın.

Hareket

  • Hiyerarşi panelindehologramcollection nesnesini seçin.
  • Bileşen Ekle ' ye tıklayın ve arama alanına Hareket Yöneticisi yazın. Arama sonucunu seçin.
  • Hiyerarşi panelinde, hologramcollection' ı genişletin.
  • Alt enerji JI nesnesini seçin.
  • Inspector panelindeBileşen Ekle düğmesine tıklayın.
  • Menüsünde, arama kutusu hologram yerleşiminiyazın. Arama sonucunu seçin.
  • Dosya sahneyi kaydet' i seçerek sahneyi kaydedin.

Dağıtma ve keyfini yaşayın

  • önceki bölümdeki yönergeleri kullanarak HoloLens derleyin ve dağıtın.
  • uygulama HoloLens başlatıldıktan sonra, kafanızı taşıyın ve enerji katın gaze 'ı nasıl takip ettiğini fark edin.
  • Hologram üzerinde ne zaman durduðundayken ve bir hologram üzerinde durmayan bir nokta ışığıyla yapılan değişiklikler üzerine gelin.
  • Hologram yerleştirmek için bir hava dokunma işlemi gerçekleştirin. Projemizdeki Şu anda, yalnızca bir kez hologram yerleştirebilirsiniz (yeniden denemek için yeniden dağıtın).

Bölüm 3-paylaşılan koordinatlar

Hologramlar görmek ve bunlarla etkileşim kurmak eğlencelidir, ancak daha fazla ilerleyelim. İlk paylaşılan deneyimimizi ayarlayacağız. bir hologram birlikte görebilecekleri bir hologram.

Hedefler

  • Paylaşılan bir deneyim için bir ağ kurun.
  • Ortak bir başvuru noktası oluşturun.
  • Koordinat sistemlerini cihazlarda paylaşma.
  • Herkes aynı hologram 'yi görür!

Not

Internetclientserver ve PrivateNetworkClientServer özellikleri, bir uygulamanın paylaşım sunucusuna bağlanması için bildirilmelidir. bu, zaten Hologramlar 240 ' de sizin için yapılır, ancak kendi projeleriniz için bunu göz önünde bulundurun.

  1. Unity düzenleyicisinde, " > Project Ayarlar oynatıcıyı düzenle" bölümüne giderek player ayarlarına gidin >
  2. "Windows deposu" sekmesine tıklayın
  3. "yayımlama Ayarlar > özellikleri" bölümünde, > özelliğini ve PrivateNetworkClientServer özelliğini denetleyin

Yönergeler

  • Project panelindeHoloToolkit-Sharing-240\Prefabs\Sharing klasörüne gidin.
  • Paylaşımı prefab ' i hiyerarşi panelinesürükleyip bırakın.

Daha sonra paylaşım hizmetini başlatması gerekiyor. Paylaşılan deneyimde yalnızca BIR bilgisayarın bu adımı yapması gerekir.

  • Unity 'de-sağ taraftaki menüde Holotoolkit-Sharing-240 menüsünüseçin.
  • Açılan kutuda Paylaşım Hizmeti 'Ni Başlat öğesini seçin.
  • Özel ağ seçeneğini işaretleyin ve güvenlik duvarı Istemi göründüğünde erişime izin ver ' e tıklayın.
  • Paylaşım hizmeti konsol penceresinde görünen IPv4 adresini aklınızda edin. Bu, hizmetin çalıştırıldığı makineyle aynı IP 'dir.

Paylaşılan deneyime katılacak tüm bilgisayarlarda kalan yönergeleri izleyin.

  • Hiyerarşide, Paylaşım nesnesini seçin.
  • Denetçisinde, Paylaşım aşaması bileşeninde, sunucu adresini ' localhost ' iken SharingService.exe çalıştıran makinenin IPv4 adresine değiştirin.
  • Hiyerarşidehologramcollection nesnesini seçin.
  • DenetçisindeBileşen Ekle düğmesine tıklayın.
  • Arama kutusuna Içeri aktarma bağlantı noktası Yöneticisiyazın. Arama sonucunu seçin.
  • Project panelindebetikler klasörüne gidin.
  • Visual Studio ' de açmak için Hologramplaçıt betiğine çift tıklayın.
  • İçeriği aşağıdaki kodla değiştirin.
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.
    }
}
  • Unity 'ye geri döndüğünüzde hiyerarşi panelindehologramcollection ' ı seçin.
  • Inspector panelindeBileşen Ekle düğmesine tıklayın.
  • Menüsünde, arama kutusu uygulama durumu Yöneticisi' ni yazın. Arama sonucunu seçin.

Dağıtma ve keyfini yaşayın

  • HoloLens cihazlarınız için projeyi derleyin.
  • ilk olarak dağıtılacak bir HoloLens belirleyin. Enerji Gyhub 'ını yerleştirebilmeniz için önce bağlayıcının hizmete yüklenmesini beklemeniz gerekir (Bu işlem, 30-60 saniye sürebilir). Karşıya yükleme işlemi tamamlanana kadar dokunma hareketleriniz yoksayılacak.
  • enerji gyhub 'ı yerleştirildikten sonra, konumu hizmete yüklenir ve ardından diğer tüm HoloLens cihazlara dağıtabilirsiniz.
  • yeni bir HoloLens ilk olarak oturuma katıldığında, bu cihazda enerji gyhub 'ın konumu doğru olmayabilir. Ancak, bağlantı ve enerji Gyhub konumları hizmetten indirildikten sonra, enerji Gyhub yeni, paylaşılan konuma atmalıdır. bu, ~ 30-60 saniye içinde gerçekleşmezse, daha fazla ortam ipuçları toplamak için bağlayıcıyı ayarlarken orijinal HoloLens nereye olduğunu gözden geçirelim. Konum hala kilitlenmezse cihaza yeniden dağıtın.
  • Cihazların tümü çalışmaya ve uygulamayı çalıştırmaya göre, enerjne kadar enerji merkezine bakın. Her şey, hologram konumunun konumunu ve metnin hangi yöne dönük olduğunu kabul edebilir misiniz?

Bölüm 4-bulma

Herkes artık aynı hologram ' i görebilir! Şimdi, paylaşılan holographic dünyamıza başka herkes bağlandığını görelim. bu bölümde, tüm diğer HoloLens cihazlarının aynı paylaşım oturumunda baş konumunu ve döndürmesini inceleyeceğiz.

Hedefler

  • Paylaşılan deneyimimizde birbirini bulun.
  • Bir oyuncu avatarını seçin ve paylaşabilirsiniz.
  • Oyuncu kafalarını herkes 'in yanına ekleyin.

Yönergeler

  • Project panelindeHologramlar klasörüne gidin.
  • Playeravatarstore öğesini hiyerarşiyesürükleyin ve bırakın.
  • Project panelindebetikler klasörüne gidin.
  • Visual Studio ' de açmak için Avatarselector betiğine çift tıklayın.
  • İçeriği aşağıdaki kodla değiştirin.
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;
    }
}
  • Hiyerarşidehologramcollection nesnesini seçin.
  • DenetçisindeBileşen Ekle' ye tıklayın.
  • Arama kutusuna yerel oynatıcı Yöneticisiyazın. Arama sonucunu seçin.
  • Hiyerarşidehologramcollection nesnesini seçin.
  • DenetçisindeBileşen Ekle' ye tıklayın.
  • Arama kutusuna, uzak oynatıcı Yöneticisiyazın. Arama sonucunu seçin.
  • Visual Studio 'te Hologramplaçatma betiğini açın.
  • İçeriği aşağıdaki kodla değiştirin.
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.
    }
}
  • Visual Studio içinde Appstatemanager betiğini açın.
  • İçeriği aşağıdaki kodla değiştirin.
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;
        }
    }
}

Dağıtma ve keyfini yaşayın

  • projeyi derleyin ve HoloLens cihazlarınıza dağıtın.
  • Bir ping sesi duyduğunuzda, avatar seçim menüsünü bulun ve AIR dokunma hareketiyle bir avatar seçin.
  • herhangi bir holograma bakmadıysanız, HoloLens hizmetle iletişim kurduğunda imlecinizin yanındaki nokta ışığı farklı bir renk kullanacaktır: başlatılıyor (koyu mor), tutturucu (yeşil), konum verilerini içeri/dışarı aktarma (sarı), tutturucu (mavi) karşıya yükleniyor. İmlecinizin etrafında işaret ışığı varsayılan renktedir (hafif mor), oturumunuzun diğer yürütücülerle etkileşime geçmeye hazır olursunuz!
  • Alanınıza bağlı diğer kişilere bakın. holographic bir robot, bunların en üstünde bir olacak şekilde görünür ve bu kişilerin baş Hara değerlerini inceleyeceğiz!

Bölüm 5-yerleştirme

Bu bölümde, bağlayıcıyı gerçek dünyada yüzeylere yerleştirilebilecek hale yapacağız. Bu bağlayıcıyı paylaşılan deneyime bağlı herkes arasında orta noktaya yerleştirmek için paylaşılan koordinatları kullanacağız.

Hedefler

  • Oyuncu baş konumuna göre uzamsal eşleme ağı üzerine hologramlar koyun.

Yönergeler

  • Project panelindeHologramlar klasörüne gidin.
  • Customspatıalmapping prefab öğesini hiyerarşiyesürükleyin ve bırakın.
  • Project panelindebetikler klasörüne gidin.
  • Appstatemanager betiğine çift tıklayarak Visual Studio açın.
  • İçeriği aşağıdaki kodla değiştirin.
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;
        }
    }
}
  • Project panelindebetikler klasörüne gidin.
  • Visual Studio ' de açmak için Hologramplaçıt betiğine çift tıklayın.
  • İçeriği aşağıdaki kodla değiştirin.
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();
    }
}

Dağıtma ve keyfini yaşayın

  • projeyi derleyin ve HoloLens cihazlarınıza dağıtın.
  • Uygulama hazırsanız, bir daire içinde ve enerji ortamerkezinin herkesin merkezinde nasıl göründüğünü fark edersiniz.
  • Enerji Gyhub 'ını yerleştirmek için dokunun.
  • ' Sıfırlama hedefi ' sesli komutunu deneyerek enerji Gyhub yedeklemesini seçin ve bir grup olarak birlikte çalışarak, hologram yeni bir konuma taşıyın.

Bölüm 6-Real-World fizik

Bu bölümde, gerçek dünya yüzeylerini kapatan hologramlar ekleyeceğiz. Alanınızı hem sizin hem de arkadaşlarınızla başlatılan projelerle doldurmanızı izleyin!

Hedefler

  • Gerçek dünya yüzeylerini kapatan projeckutucukları başlatın.
  • Diğer oyuncuların onları görebilmesi için projeckutucuklarını paylaşabilirsiniz.

Yönergeler

  • Hiyerarşidehologramcollection nesnesini seçin.
  • DenetçisindeBileşen Ekle' ye tıklayın.
  • Arama kutusuna Projectile başlatıcısıyazın. Arama sonucunu seçin.

Dağıtma ve keyfini yaşayın

  • HoloLens cihazlarınıza derleyin ve dağıtın.
  • Uygulama tüm cihazlarda çalışırken, gerçek dünyada Projectile başlatmak için bir AIR dokunma işlemi gerçekleştirin.
  • Projectuğunuz başka bir oyuncunun avatar ile çakışıyorsa ne olacağını görün!

Bölüm 7-genel finale

Bu bölümde, yalnızca işbirliği ile keşfedilebilir bir portal göstereceğiz.

Hedefler

  • Bir gizli portalı açmak için bağlayıcı üzerinde yeterli sayıda projecat başlatmak üzere birlikte çalışın!

Yönergeler

  • Project panelindeHologramlar klasörüne gidin.
  • Underworld varlığını hologramcollection 'ın alt öğesiolarak sürükleyip bırakın.
  • Hologramcollection seçiliyken, Inspector'daki Bileşen Ekle düğmesine tıklayın.
  • Menüsünde, arama kutusuna Patsıtargetyazın. Arama sonucunu seçin.
  • Hologramcollection seçiliyken, hiyerarşideenerji Gyhub nesnesini Inspector'daki hedef alana sürükleyin.
  • Hologramcollection seçiliyken, hiyerarşideUnderworld nesnesini Inspector'daki Underworld alanına sürükleyin.

Dağıtma ve keyfini yaşayın

  • HoloLens cihazlarınıza derleyin ve dağıtın.
  • Uygulama başlatıldığında, Enerjce enerji merkezinde projeckutucukları başlatmak için birlikte işbirliği yapın.
  • Eksik dünya göründüğünde, habotlar üzerinde projeckutucukları başlatın (ekstra eğlenceye yönelik bir robot 'a üç kez basın).