Örnek olay incelemesi - HoloLens'in uzamsal haritalama özelliklerini genişletme

Microsoft HoloLens için ilk uygulamalarımızı oluştururken cihazda uzamsal eşleme sınırlarını ne kadar zorlayacağımızı görmek için sabırsızlanıyorduk. Microsoft Studios'ta yazılım mühendisi olan Jeff Evertt, hologramların kullanıcının gerçek dünya ortamına nasıl yerleştirildiği üzerinde daha fazla denetime ihtiyaç duymadan yeni bir teknolojinin nasıl geliştirildiğini açıklıyor.

Not

HoloLens 2, Karma Gerçeklik geliştiricilerine çevreyle uyumlu uygulamalar için geliştirmeyi sezgisel hale getirmek üzere tasarlanmış yapılandırılmış, üst düzey bir ortam gösterimi sağlayan yeni bir Scene Understanding Runtime uygular.

Videoyu izleme

Uzamsal eşlemenin ötesinde

HoloLens'in ilk oyunlarından biri olan Fragments ve Young Conker üzerinde çalışırken, hologramları fiziksel dünyada yordamsal olarak yerleştirmeyi yaparken kullanıcının ortamı hakkında daha yüksek bir anlayış düzeyine ihtiyacımız olduğunu fark ettik. Her oyunun kendi özel yerleştirme gereksinimleri vardı: Örneğin Parçalar'da, ilgili konumlara ipuçları yerleştirmek için zemin veya masa gibi farklı yüzeyleri ayırt edebilmek istedik. Ayrıca yaşam boyu holografik karakterlerin oturabileceği koltuk veya sandalye gibi yüzeyleri de tanımlayabilmek istedik. Young Conker'da, Conker ve rakiplerinin bir oyuncunun odasındaki yükseltilmiş yüzeyleri platform olarak kullanabilmesini istedik.

Bu oyunların geliştirme ortağımız Asobo Studios, bu sorunla kafa kafaya verdi ve HoloLens'in uzamsal haritalama özelliklerini genişleten bir teknoloji oluşturdu. Bunu kullanarak bir oyuncunun odasını analiz edebilir ve duvarlar, masalar, sandalyeler ve zeminler gibi yüzeyleri tanımlayabiliriz. Ayrıca holografik nesneler için en iyi yerleşimi belirlemek üzere bir dizi kısıtlamaya karşı iyileştirme olanağı da verdi.

Uzamsal anlama kodu

Asobo'nun orijinal kodunu aldık ve bu teknolojiyi kapsülleyen bir kitaplık oluşturduk. Microsoft ve Asobo artık bu kodu açık kaynaklı hale getirdi ve kendi projelerinizde kullanabilmeniz için MixedRealityToolkit'te kullanıma sunuldu. Tüm kaynak kodlar dahil edilir ve bu sayede kodu ihtiyaçlarınıza göre özelleştirebilir ve iyileştirmelerinizi toplulukla paylaşabilirsiniz. C++ çözücü kodu bir UWP DLL'sine sarmalanmış ve MixedRealityToolkit içinde bulunan bir bırakma prefabıyla Unity'ye kullanıma sunuldu.

Unity örneğinde duvarlardaki boş alanları bulmanıza, tavana veya yerdeki geniş alanlara nesneler yerleştirmenize, karakterlerin oturacağı yerleri belirlemenize ve çok sayıda başka uzamsal anlama sorgusuna olanak sağlayan birçok yararlı sorgu vardır.

HoloLens tarafından sağlanan uzamsal haritalama çözümü, sorun alanlarının tüm gamının ihtiyaçlarını karşılayacak kadar genel olacak şekilde tasarlanmış olsa da uzamsal anlama modülü, belirli iki oyunun ihtiyaçlarını destekleyecek şekilde oluşturulmuştu. Bu nedenle, çözümü belirli bir süreç ve varsayımlar kümesi etrafında yapılandırılmıştır:

  • Sabit boyutlu oynatma alanı: Kullanıcı, başlatma çağrısında en büyük oynatma alanı boyutunu belirtir.
  • Tek seferlik tarama işlemi: İşlem, kullanıcının playspace'i tanımlayarak gezindiği ayrı bir tarama aşaması gerektirir. Tarama sonlandırılana kadar sorgu işlevleri çalışmaz.
  • Kullanıcı kullanımlı oyun alanı "boyama": Tarama aşamasında kullanıcı, dahil edilmesi gereken alanları etkili bir şekilde boyamak için oyun alanını hareket eder ve etrafa bakar. Oluşturulan ağ, bu aşamada kullanıcı geri bildirimi sağlamak için önemlidir.
  • İç mekan ev veya ofis kurulumu: Sorgu işlevleri düz yüzeylerin ve duvarların çevresinde dik açılarda tasarlanmıştır. Bu geçici bir sınırlamadır. Ancak tarama aşamasında, ana ve küçük eksenler boyunca mesh tessellation'ı iyileştirmek için birincil eksen analizi tamamlanır.

Oda Tarama İşlemi

Uzamsal anlama modülünü yüklediğinizde yapacağınız ilk şey alanınızı taramaktır; böylece zemin, tavan ve duvarlar gibi tüm kullanılabilir yüzeyler tanımlanır ve etiketlenir. Tarama işlemi sırasında odanızın çevresine bakar ve taramaya dahil edilmesi gereken alanları "boyarsınız".

Bu aşamada görülen ağ, kullanıcıların odanın hangi bölümlerinin tarandığını bilmesini sağlayan önemli bir görsel geri bildirimdir. Uzamsal anlama modülünün DLL'si, oyun alanını 8cm boyutlu voksel küplerinden oluşan bir kılavuz olarak dahili olarak depolar. Taramanın ilk bölümünde, odanın eksenlerini belirlemek için birincil bileşen analizi tamamlanır. Dahili olarak, voksel alanını bu eksenlere hizalanmış olarak depolar. Voksel hacminden izosurface ayıklanarak yaklaşık olarak her saniyede bir mesh oluşturulur.

Beyazda uzamsal haritalama ağı ve yeşil playspace mesh'i anlama

Beyazda uzamsal haritalama ağı ve yeşil playspace mesh'i anlama

Dahil edilen SpatialUnderstanding.cs dosyası tarama aşaması işlemini yönetir. Aşağıdaki işlevleri çağırır:

  • SpatialUnderstanding_Init: Başlangıçta bir kez çağrılır.
  • GeneratePlayspace_InitScan: Tarama aşamasının başlaması gerektiğini gösterir.
  • GeneratePlayspace_UpdateScan_DynamicScan: Tarama işlemini güncelleştirmek için her kareyi çağırır. Kamera konumu ve yönü geçirilir ve yukarıda açıklanan playspace boyama işlemi için kullanılır.
  • GeneratePlayspace_RequestFinish: Playspace'i sonlandırmak için çağrılır. Bu işlem, oynatma alanını tanımlamak ve kilitlemek için tarama aşamasında "boyanmış" alanları kullanır. Uygulama tarama aşamasında istatistikleri sorgulayabilir ve kullanıcı geri bildirimi sağlamak için özel ağı sorgulayabilir.
  • Import_UnderstandingMesh: Tarama sırasında modül tarafından sağlanan ve anlama prefabına yerleştirilen SpatialUnderstandingCustomMesh davranışı, işlem tarafından oluşturulan özel ağı düzenli aralıklarla sorgular. Ayrıca, tarama sonlandırıldıktan sonra bu işlem bir kez daha gerçekleştirilir.

SpatialUnderstanding davranışı tarafından yönlendiren tarama akışı InitScan'ı ve ardından UpdateScan'ı her kareyi çağırır. İstatistik sorgusu makul kapsam bildirdiğinde, kullanıcı tarama aşamasının sonunu belirtmek üzere RequestFinish çağrısı yapmak için airtap yapabilir. Dönüş değeri DLL'nin işlenmesinin tamamlandığını belirtene kadar UpdateScan çağrılmaya devam eder.

Sorgular

Tarama tamamlandıktan sonra arabirimde üç farklı sorgu türüne erişebilirsiniz:

  • Topoloji sorguları: Bunlar taranan odanın topolojisini temel alan hızlı sorgulardır.
  • Şekil sorguları: Bunlar, tanımladığınız özel şekillerle iyi eşleşen yatay yüzeyleri bulmak için topoloji sorgularınızın sonuçlarını kullanır.
  • Nesne yerleştirme sorguları: Bunlar, nesne için bir dizi kural ve kısıtlamaya göre en uygun konumu bulayan daha karmaşık sorgulardır.

Üç birincil sorguya ek olarak, etiketli yüzey türlerini almak için kullanılabilecek bir raycasting arabirimi vardır ve özel bir su geçirmez oda ağı kopyalanabilir.

Topoloji sorguları

DLL içinde, topoloji yöneticisi ortamın etiketlemesini işler. Yukarıda belirtildiği gibi, verilerin çoğu voksel hacmi içinde yer alan sörfçüler içinde depolanır. Buna ek olarak, PlaySpaceInfos yapısı dünya hizalaması (aşağıda daha ayrıntılı bilgi), zemin ve tavan yüksekliği dahil olmak üzere oyun alanı hakkında bilgi depolamak için kullanılır.

Buluşsal yöntemler zemin, tavan ve duvarları belirlemek için kullanılır. Örneğin, 1 m2'den büyük yüzey alanına sahip en büyük ve en düşük yatay yüzey zemin olarak kabul edilir. Tarama işlemi sırasında kamera yolunun da bu işlemde kullanıldığını unutmayın.

Topoloji yöneticisi tarafından kullanıma sunulan sorguların bir alt kümesi DLL aracılığıyla kullanıma sunulur. Kullanıma sunulan topoloji sorguları aşağıdaki gibidir:

  • QueryTopology_FindPositionsOnWalls
  • QueryTopology_FindLargePositionsOnWalls
  • QueryTopology_FindLargestWall
  • QueryTopology_FindPositionsOnFloor
  • QueryTopology_FindLargestPositionsOnFloor
  • QueryTopology_FindPositionsSittable

Sorguların her biri, sorgu türüne özgü bir dizi parametreye sahiptir. Aşağıdaki örnekte, kullanıcı istenen birimin en düşük yükseklik & genişliğini, zeminin üzerinde minimum yerleştirme yüksekliğini ve birimin önündeki minimum boşluk miktarını belirtir. Tüm ölçümler metreler içindedir.

EXTERN_C __declspec(dllexport) int QueryTopology_FindPositionsOnWalls(
          _In_ float minHeightOfWallSpace,
          _In_ float minWidthOfWallSpace,
          _In_ float minHeightAboveFloor,
          _In_ float minFacingClearance,
          _In_ int locationCount,
          _Inout_ Dll_Interface::TopologyResult* locationData)

Bu sorguların her biri topolojiResult yapılarından oluşan önceden ayrılmış bir dizi alır. locationCount parametresi, geçirilen dizinin uzunluğunu belirtir. Dönüş değeri, döndürülen konumların sayısını bildirir. Bu sayı hiçbir zaman geçirilen locationCount parametresinden büyük değildir.

TopologyResult, döndürülen birimin merkez konumunu, bakan yönü (normal) ve bulunan alanın boyutlarını içerir.

struct TopologyResult
     {
          DirectX::XMFLOAT3 position;
          DirectX::XMFLOAT3 normal;
          float width;
          float length;
     };

Unity örneğinde, bu sorguların her birinin sanal kullanıcı arabirimi panelindeki bir düğmeye bağlandığını unutmayın. Örnek, bu sorguların her biri için parametreleri makul değerlere sabit olarak kodlar. Daha fazla örnek için örnek koddaki SpaceVisualizer.cs dosyasına bakın.

Şekil sorguları

DLL'nin içinde şekil çözümleyicisi (ShapeAnalyzer_W), topoloji çözümleyicisini kullanarak kullanıcı tarafından tanımlanan özel şekillerle eşleşir. Unity örneği, şekil sekmesindeki sorgu menüsünde gösterilen önceden tanımlanmış bir şekil kümesine sahiptir.

Şekil analizinin yalnızca yatay yüzeylerde çalıştığını unutmayın. Örneğin, bir kanepe, düz koltuk yüzeyi ve koltuğun arkasının düz üstü ile tanımlanır. Şekil sorgusu, belirli bir boyut, yükseklik ve en boy aralığında iki yüzeyi hizalanmış ve bağlanmış olarak arar. API terminolojisini kullanarak kanepe koltuğu ve koltuğun arka kısmının üstü şekil bileşenleridir ve hizalama gereksinimleri şekil bileşeni kısıtlamalarıdır.

Unity örneğinde (ShapeDefinition.cs) "sittable" nesneleri için tanımlanan örnek sorgu aşağıdaki gibidir:

shapeComponents = new List<ShapeComponent>()
     {
          new ShapeComponent(
               new List<ShapeComponentConstraint>()
               {
                    ShapeComponentConstraint.Create_SurfaceHeight_Between(0.2f, 0.6f),
                    ShapeComponentConstraint.Create_SurfaceCount_Min(1),
                    ShapeComponentConstraint.Create_SurfaceArea_Min(0.035f),
               }),
     };
     AddShape("Sittable", shapeComponents);

Her şekil sorgusu, her biri bileşen kısıtlamaları kümesine ve bileşenler arasındaki bağımlılıkları listeleyen bir şekil kısıtlamaları kümesine sahip bir şekil bileşenleri kümesi tarafından tanımlanır. Bu örnek, tek bir bileşen tanımında üç kısıtlama içerir ve bileşenler arasında şekil kısıtlaması yoktur (çünkü tek bir bileşen vardır).

Buna karşılık, kanepe şeklinin iki şekil bileşeni ve dört şekil kısıtlaması vardır. Bileşenlerin, kullanıcının bileşen listesindeki dizinleri tarafından tanımlandığını unutmayın (bu örnekte 0 ve 1).

shapeConstraints = new List<ShapeConstraint>()
        {
              ShapeConstraint.Create_RectanglesSameLength(0, 1, 0.6f),
              ShapeConstraint.Create_RectanglesParallel(0, 1),
              ShapeConstraint.Create_RectanglesAligned(0, 1, 0.3f),
              ShapeConstraint.Create_AtBackOf(1, 0),
        };

Sarmalayıcı işlevleri, özel şekil tanımlarının kolayca oluşturulması için Unity modülünde sağlanır. Bileşen ve şekil kısıtlamalarının tam listesi ShapeComponentConstraint ve ShapeConstraint yapılarının içindeki SpatialUnderstandingDll.cs dosyasında bulunabilir.

Mavi dikdörtgen, sandalye şekli sorgusunun sonuçlarını vurgular.

Mavi dikdörtgen, sandalye şekli sorgusunun sonuçlarını vurgular.

Nesne yerleştirme çözücü

Nesne yerleştirme sorguları, nesnelerinizi yerleştirmek için fiziksel odadaki ideal konumları belirlemek için kullanılabilir. Çözücü, nesne kuralları ve kısıtlamalarına göre en uygun konumu bulur. Buna ek olarak, nesne Solver_RemoveObject veya Solver_RemoveAllObjects çağrıları ile kaldırılana kadar nesne sorguları devam eder ve kısıtlanmış çok nesneli yerleştirmeye olanak sağlar.

Nesne yerleştirme sorguları üç bölümden oluşur: parametrelerle yerleştirme türü, kurallar listesi ve kısıtlamaların listesi. Sorgu çalıştırmak için aşağıdaki API'yi kullanın:

public static int Solver_PlaceObject(
                [In] string objectName,
                [In] IntPtr placementDefinition,	// ObjectPlacementDefinition
                [In] int placementRuleCount,
                [In] IntPtr placementRules,     	// ObjectPlacementRule
                [In] int constraintCount,
                [In] IntPtr placementConstraints,	// ObjectPlacementConstraint
                [Out] IntPtr placementResult)

Bu işlev bir nesne adı, yerleştirme tanımı ve kural ve kısıtlamaların listesini alır. C# sarmalayıcıları, kural ve kısıtlama oluşturma işlemini kolaylaştırmak için yapı yardımcı işlevleri sağlar. Yerleştirme tanımı sorgu türünü içerir; yani aşağıdakilerden birini içerir:

public enum PlacementType
                {
                    Place_OnFloor,
                    Place_OnWall,
                    Place_OnCeiling,
                    Place_OnShape,
                    Place_OnEdge,
                    Place_OnFloorAndCeiling,
                    Place_RandomInAir,
                    Place_InMidAir,
                    Place_UnderFurnitureEdge,
                };

Yerleştirme türlerinin her biri, türüne özgü bir parametre kümesine sahiptir. ObjectPlacementDefinition yapısı, bu tanımları oluşturmak için bir dizi statik yardımcı işlev içerir. Örneğin, bir nesneyi yere yerleştirebileceğiniz bir yer bulmak için aşağıdaki işlevi kullanabilirsiniz:

public static ObjectPlacementDefinition Create_OnFloor(Vector3 halfDims)

Yerleştirme türüne ek olarak, bir dizi kural ve kısıtlama sağlayabilirsiniz. Kurallar ihlal edilemez. Türü ve kuralları karşılayan olası yerleştirme konumları daha sonra en uygun yerleştirme konumunu seçmek için kısıtlamalar kümesine göre iyileştirilir. Kuralların ve kısıtlamaların her biri, sağlanan statik oluşturma işlevleri tarafından oluşturulabilir. Aşağıda örnek bir kural ve kısıtlama oluşturma işlevi verilmiştir.

public static ObjectPlacementRule Create_AwayFromPosition(
                    Vector3 position, float minDistance)
               public static ObjectPlacementConstraint Create_NearPoint(
                    Vector3 position, float minDistance = 0.0f, float maxDistance = 0.0f)

Aşağıdaki nesne yerleştirme sorgusu, bir yüzeyin kenarına, önceden yerleştirilen diğer nesnelerden uzakta ve odanın merkezine yakın bir yerde yarım metre küp yerleştirecek bir yer arıyor.

List<ObjectPlacementRule> rules = 
          new List<ObjectPlacementRule>() {
               ObjectPlacementRule.Create_AwayFromOtherObjects(1.0f),
          };

     List<ObjectPlacementConstraint> constraints = 
          new List<ObjectPlacementConstraint> {
               ObjectPlacementConstraint.Create_NearCenter(),
          };

     Solver_PlaceObject(
          “MyCustomObject”,
          new ObjectPlacementDefinition.Create_OnEdge(
          new Vector3(0.25f, 0.25f, 0.25f), 
          new Vector3(0.25f, 0.25f, 0.25f)),
          rules.Count,
          UnderstandingDLL.PinObject(rules.ToArray()),
          constraints.Count,
          UnderstandingDLL.PinObject(constraints.ToArray()),
          UnderstandingDLL.GetStaticObjectPlacementResultPtr());

Başarılı olursa, yerleştirme konumunu, boyutlarını ve yönlendirmesini içeren bir ObjectPlacementResult yapısı döndürülür. Buna ek olarak, yerleştirme DLL'nin yerleştirilen nesneler iç listesine eklenir. Sonraki yerleştirme sorguları bu nesneyi hesaba katacaktır. Unity örneğindeki LevelSolver.cs dosyası daha fazla örnek sorgu içerir.

Mavi kutular, üç Place On Floor sorgusunun sonucunu

Mavi kutular, üç Place On Floor sorgusunun sonucunu "kamera konumundan uzakta" kurallarıyla gösterir.

İpuçları:

  • Bir düzey veya uygulama senaryosu için gereken birden çok nesnenin yerleşim konumunu çözerken, bir alanın bulunma olasılığını en üst düzeye çıkarmak için önce vazgeçilmez ve büyük nesneleri çözün.
  • Yerleştirme sırası önemlidir. Nesne yerleşimleri bulunamazsa daha az kısıtlanmış yapılandırmaları deneyin. Bir dizi geri dönüş yapılandırmasına sahip olmak, birçok oda yapılandırmasında işlevselliği desteklemek için kritik öneme sahiptir.

Ray casting

Üç birincil sorguya ek olarak, etiketli yüzey türlerini almak için bir ışın döküm arabirimi kullanılabilir ve özel bir su geçirmez playspace ağı kopyalanabilir Oda tarandıktan ve sonlandırıldıktan sonra, zemin, tavan ve duvarlar gibi yüzeyler için dahili olarak etiketler oluşturulur. PlayspaceRaycast işlevi bir ışın alır ve ışın bilinen bir yüzeyle çarpışırsa ve öyleyse, bu yüzey hakkındaki bilgiler bir RaycastResult biçiminde döndürülür.

struct RaycastResult
     {
          enum SurfaceTypes
          {
               Invalid,	// No intersection
               Other,
               Floor,
               FloorLike,         // Not part of the floor topology, 
                                  //     but close to the floor and looks like the floor
               Platform,          // Horizontal platform between the ground and 
                                  //     the ceiling
               Ceiling,
               WallExternal,
               WallLike,          // Not part of the external wall surface, 
                                  //     but vertical surface that looks like a 
                                  //	wall structure
               };
               SurfaceTypes SurfaceType;
               float SurfaceArea;	// Zero if unknown 
                                        //	(i.e. if not part of the topology analysis)
               DirectX::XMFLOAT3 IntersectPoint;
               DirectX::XMFLOAT3 IntersectNormal;
     };

Dahili olarak, raycast, playspace'in hesaplanan 8cm küp voksel gösterimine göre hesaplanır. Her vokel, işlenen topoloji verilerine (sörfçü olarak da bilinir) sahip bir dizi yüzey öğesi içerir. Kesişen voksel hücresinde bulunan sörfçüler karşılaştırılır ve topoloji bilgilerini aramak için kullanılan en iyi eşleşmedir. Bu topoloji verileri, SurfaceTypes sabit listesi biçiminde döndürülen etiketlemeyi ve kesişen yüzeyin yüzey alanını içerir.

Unity örneğinde imleç her karede bir ışın oluşturur. İlk olarak Unity'nin çarpışanlarına karşı; İkincisi, modülün dünya temsilini anlamanın karşısında; ve son olarak, kullanıcı arabirimi öğelerine karşı. Bu uygulamada kullanıcı arabirimi önceliğe, ardından anlama sonucuna ve son olarak Unity'nin harmanlayıcılarına öncelik tanır. SurfaceType, imlecin yanında metin olarak bildirilir.

Raycast sonuç raporlaması zeminle kesişim.

Raycast sonuç raporlaması zeminle kesişim.

Kodu alma

Açık kaynak kodu MixedRealityToolkit içinde kullanılabilir. Kodu bir projede kullanıyorsanız HoloLens Geliştirici Forumları'nda bize bildirin. Ne yaptığını görmek için sabırsızlanıyoruz!

Yazar hakkında

Jeff Evertt, Microsoft'ta Yazılım Mühendisliği Lideri Jeff Evertt , ilk günlerden beri inkübasyondan geliştirme deneyimine kadar HoloLens üzerinde çalışan bir yazılım mühendisliği lideridir. HoloLens'den önce Xbox Kinect ve oyunlar sektöründe çok çeşitli platformlar ve oyunlar üzerinde çalıştı. Jeff, bip sesi veren yanıp sönen ışıklarla robotlar, grafikler ve şeyler konusunda tutkuludur. Yeni şeyler öğrenmekten ve yazılım, donanım üzerinde ve özellikle ikisinin kesiştiği alanda çalışmayı sever.

Ayrıca bkz.