Örnek olay incelemesi - Karma gerçeklikte galaksi oluşturma

Microsoft HoloLens gönderilmeden önce geliştirici topluluğumuza yeni cihaz için deneyimli bir iç ekip derlemesini görmek istedikleri uygulama türünü sorduk. 5000'den fazla fikir paylaşıldı ve 24 saat süren Twitter anketinden sonra kazanan , Galaxy Explorer adlı bir fikirdi.

Projenin sanat lideri Andy Zibits ve ekibin grafik mühendisi Karim Luccin, Galaksi Gezgini'nde Samanyolu galaksisinin doğru, etkileşimli bir gösteriminin oluşturulmasına yol açan sanat ve mühendislik arasındaki işbirliği çabalarından bahsediyor.

Teknoloji

İki tasarımcı, üç geliştirici, dört sanatçı, bir yapımcı ve bir testçiden oluşan ekibimizin, insanların Samanyolu Galaksimizin uçsuz bucaksızlığını ve güzelliğini öğrenmesine ve keşfetmesine olanak tanıyan tam işlevsel bir uygulama oluşturmak için altı haftası vardı.

HoloLens'in 3B nesneleri doğrudan yaşam alanınızda işleme özelliğinden tam olarak yararlanmak istedik, bu nedenle insanların yakınlaşabileceği ve her biri kendi yörüngelerinde ayrı ayrı yıldızları görebileceği gerçekçi görünümlü bir galaksi oluşturmak istediğimize karar verdik.

Gelişimin ilk haftasında, Samanyolu Galaksisi'ni temsil etmek için birkaç hedef bulduk: Galaksinin şeklini oluşturmaya yardımcı olacak yıldızlarla dolu derinlik, hareket ve hacimli hissetmesi gerekiyordu.

Milyarlarca yıldızı olan animasyonlu bir galaksi oluşturmanın sorunu, güncelleştirilmesi gereken çok sayıda tek öğenin HoloLens'in CPU kullanarak animasyon ekleyemeyecek kadar büyük olmasıydı. Çözümümüz, sanat ve bilimin karmaşık bir karışımını içerir.

Arka planda

İnsanların tek tek yıldızları keşfetmesine izin vermek için ilk adımımız aynı anda kaç tane parçacık işleyebileceğimizi bulmaktı.

Parçacıkları işleme

Geçerli CPU'lar seri görevleri ve aynı anda birkaç paralel görevi işlemek için harikadır (sahip oldukları çekirdeğe bağlı olarak), ancak GPU'lar binlerce işlemi paralel olarak işlemede çok daha etkilidir. Ancak genellikle CPU ile aynı belleği paylaşmadıkları için CPU<>GPU arasında veri alışverişi hızla bir performans sorununa neden olabilir. Çözümümüz GPU üzerinde bir galaksi oluşturmaktı ve tamamen GPU üzerinde yaşamak zorunda kaldı.

Çeşitli desenlerdeki binlerce nokta parçacığıyla stres testlerine başladık. Bu sayede HoloLens'te galaksiyi neyin çalışıp neyin işe yaradığını görmemizi sağladı.

Yıldızların konumunu oluşturma

Ekip üyelerimizden biri ilk konumlarında yıldız oluşturacak C# kodunu zaten yazmıştı. Yıldızlar üç nokta üzerindedir ve konumları (curveOffset, ellipseSize, elevation) ile tanımlanabilir; burada curveOffset üç nokta boyunca star açısıdır, elipseSize X ve Z boyunca üç noktanın boyutudur ve galaksideki star uygun şekilde yükseltilir. Bu nedenle, her star özniteliğiyle başlatılacak bir arabellek (Unity'nin ComputeBuffer'ı) oluşturabilir ve deneyimin geri kalanında yaşayabileceği GPU'ya gönderebiliriz. Bu arabelleği çizmek için Unity'nin DrawProcedural özelliğini kullanarak galaksiyi temsil eden gerçek bir ağa sahip olmadan rastgele bir nokta kümesinde gölgelendirici (GPU'da kod) çalıştırmayı sağlarız:

CPU:

GraphicsDrawProcedural(MeshTopology.Points, starCount, 1);

GPU:

v2g vert (uint index : SV_VertexID)
{

 // _Stars is the buffer we created that contains the initial state of the system
 StarDescriptor star = _Stars[index];
 …

}

Binlerce parçacıklı ham dairesel desenlerle başladık. Bu bize, çok sayıda parçacığı yönetip yüksek hızlarda çalıştırabildiğimize dair ihtiyacımız olan kanıtı verdi, ancak galaksinin genel şeklinden memnun değildik. Şekli geliştirmek için dönüşlü çeşitli desenler ve parçacık sistemleri denedik. Bunlar başlangıçta umut vericiydi çünkü parçacık sayısı ve performans tutarlı kaldı, ancak şekil ortaya yakın bir yerde bozuldu ve yıldızlar dışa doğru yayılıyordu ve bu gerçekçi değildi. Zamanı kontrol etmemize ve parçacıkların galaksinin merkezine daha yakın bir yere doğru hareket etmesini sağlayacak bir emisyona ihtiyacımız vardı.

Bunlar gibi dönen çeşitli desenler ve parçacık sistemleri denedik.

Bunlar gibi dönen çeşitli desenler ve parçacık sistemleri denedik.

Ekibimiz galaksilerin çalışma şekli hakkında biraz araştırma yaptı ve galaksi için özel bir parçacık sistemi yaptık, böylece parçacıkları "yoğunluk dalgası teorisine" göre üç nokta üzerinde hareket ettirebiliyorduk, bu da galaksinin kollarının trafik sıkışıklığı gibi daha yüksek yoğunluklu alanlar olduğunu ancak sabit bir akışta olduğunu teorileştiriyor. Sabit ve sağlam görünüyor, ancak yıldızlar aslında kendi üç noktalarında hareket ettikçe kollardan içeri ve dışarı hareket ediyor. Sistemimizde parçacıklar CPU'da hiç bulunmaz; kartları oluşturur ve hepsini GPU'ya yönlendiririz, böylece sistemin tamamı yalnızca ilk durum + zaman olur. Şu şekilde ilerledi:

GPU işleme ile parçacık sisteminin ilerlemesi

GPU işleme ile parçacık sisteminin ilerlemesi

Yeterince üç nokta eklendikten ve döndürülecek şekilde ayarlandıktan sonra, galaksiler yıldızların hareketinin birleşeceği "kollar" oluşturmaya başladı. Her eliptik yoldaki yıldızların aralığına rastgelelik verildi ve her star biraz konumsal rastgelelik eklendi. Bu, star hareketin ve kol şeklinin çok daha doğal görünümlü bir dağılımını oluşturdu. Son olarak, merkezden uzaklık temelinde renk sürme özelliğini ekledik.

Yıldızların hareketini oluşturma

Genel star hareketine animasyon eklemek için her kare için sabit bir açı eklememiz ve yıldızların sabit radyal hızda üç nokta boyunca hareket etmelerini sağlamak gerekiyordu. curveOffset kullanmanın birincil nedeni budur. Yıldızlar üç noktanın uzun kenarları boyunca daha hızlı hareket edeceğinden bu teknik olarak doğru değildir, ancak genel hareket iyi hissettirdi.

Yıldızlar uzun yayda daha hızlı hareket eder, kenarlarda daha yavaş hareket eder.

Yıldızlar uzun yayda daha hızlı hareket eder, kenarlarda daha yavaş hareket eder.

Bununla birlikte, her star (curveOffset, ellipseSize, elevation, Age) tarafından tam olarak tanımlanır. Burada Age, sahne yüklendiğinden bu yana geçen toplam sürenin birikmesidir.

float3 ComputeStarPosition(StarDescriptor star)
{

  float curveOffset = star.curveOffset + Age;
  
  // this will be coded as a “sincos” on the hardware which will compute both sides
  float x = cos(curveOffset) * star.xRadii;
  float z = sin(curveOffset) * star.zRadii;
   
  return float3(x, star.elevation, z);
  
}

Bu, uygulamanın başlangıcında bir kez on binlerce yıldız oluşturmamıza olanak sağladı, ardından yerleşik eğriler boyunca tek bir yıldız kümesini animasyonladık. Her şey GPU'da olduğundan sistem, CPU'ya hiçbir ücret ödemeden tüm yıldızlara paralel animasyon ekleyebilir.

Beyaz dörtlü çizerken aşağıdaki gibi görünür.

Beyaz dörtlü çizerken aşağıdaki gibi görünür.

Her dörtlü yüzü kameraya dönüştürmek için, her star konumunu ekranda star dokumuzu içerecek bir 2B dikdörtgene dönüştürmek için bir geometri gölgelendiricisi kullandık.

Dörtlü yerine elmaslar.

Dörtlü yerine elmaslar.

Fazla çizmeyi (bir pikselin işlenme sayısı) mümkün olduğunca sınırlamak istediğimizden, dörtlülerimizi daha az çakışma olacak şekilde döndürdük.

Bulut ekleme

Bir birimin içinde hareket eden ışından bulut simülasyonu yapmak için mümkün olduğunca çok parçacık çizmeye kadar parçacıklarla hacimli bir his elde etmenin birçok yolu vardır. Gerçek zamanlı ışın yürüyüşü çok pahalı ve yazması zor olacak, bu yüzden ilk olarak oyunlarda ormanları işlemek için bir yöntem kullanarak, kameraya bakan çok sayıda 2B ağaç görüntüsüyle bir sahtekarlık sistemi oluşturmayı denedik. Bunu bir oyunda yaptığımızda, etrafında dönen bir kameradan işlenen ağaç dokularına sahip olabilir, tüm bu görüntüleri kaydedebilir ve her pano kartı için çalışma zamanında görünüm yönüyle eşleşen görüntüyü seçebiliriz. Bu, görüntüler hologram olduğunda da işe yaramaz. Sol gözle sağ göz arasındaki fark, çok daha yüksek bir çözünürlüğe ihtiyacımız olmasını sağlar, aksi halde düz, diğer adla veya yinelenen görünür.

İkinci denememizde mümkün olduğunca çok parçacık bulundurmayı denedik. En iyi görseller, parçacıkları sahneye eklemeden önce ek olarak çizdiğimizde ve bulanıklaştırdığımızda elde edildi. Bu yaklaşımla ilgili tipik sorunlar, tek seferde kaç tane parçacık çekebileceğimiz ve 60fps'yi korurken ne kadar ekran alanını kapladıklarıyla ilgiliydi. Bu bulut hissini elde etmek için ortaya çıkan görüntüyü bulanıklaştırma genellikle çok maliyetli bir işlemdi.

Doku olmadan bulutlar %2 opaklıkla böyle görünür.

Doku olmadan bulutlar %2 opaklıkla böyle görünür.

Katkısal olmak ve bunların birçoğuna sahip olmak, aynı pikseli art arda gölgelendikten sonra üst üste birkaç dörtlünün olması anlamına gelir. Galaksinin merkezinde, aynı pikselin üst üste yüzlerce dörtlü vardır ve tam ekran yapılırken bu büyük bir maliyete sahipti.

Tam ekran bulutları yapmak ve bulanıklaştırmaya çalışmak kötü bir fikir olurdu, bu nedenle bunun yerine bizim için işi donanımın yapmasına izin vermeye karar verdik.

Önce biraz bağlam

Bir oyunda doku kullanırken doku boyutu, kullanmak istediğimiz alanla nadiren eşleşecektir, ancak grafik kartının doku piksellerinden istediğimiz rengi ilişkilendirmek için farklı türde doku filtrelemesi kullanabiliriz (Doku Filtreleme). bizi ilgilendiren filtreleme, en yakın 4 komşuyu kullanarak herhangi bir pikselin değerini hesaplayacak olan bilinear filtrelemedir .

Filtrelemeden önce özgün

Filtrelemeden sonra elde edilen sonuç

Bu özelliği kullanarak, bir dokuyu iki kat daha büyük bir alana çizmeye çalışırken sonucu bulanıklaştırdığını görüyoruz.

Tam ekrana işlemek ve bu değerli milisaniyeleri kaybetmek yerine başka bir şeye harcama yapmak yerine ekranın küçük bir sürümüne işliyoruz. Ardından, bu dokuyu kopyalayıp birkaç kez 2 kat uzatarak, işlemdeki içeriği bulanıklaştırırken tam ekrana geri döneriz.

x3 ölçeğini yeniden tam çözünürlüğe ayarlayın.

x3 ölçeğini yeniden tam çözünürlüğe ayarlayın.

Bu, bulut bölümünü özgün maliyetin yalnızca bir bölümüyle almamızı sağladı. Bulutları tam çözünürlüğe eklemek yerine piksellerin yalnızca 1/64'ünde boyar ve dokuyu tam çözünürlüğe geri uzatırız.

Solda, 1/8' den tam çözünürlüğe kadar bir ölçekle; ve sağa doğru, 2'nin gücünü kullanarak 3 ölçeği artırarak.

Solda, 1/8' den tam çözünürlüğe kadar bir ölçekle; ve sağa doğru, 2'nin gücünü kullanarak 3 ölçeği artırarak.

Tek seferde boyutun 1/64'ünden tam boyuta geçmeye çalışmanın tamamen farklı görüneceğini unutmayın. Grafik kartı kurulumumuzda daha büyük bir alanı gölgelendirmek için 4 pikseli kullanmaya devam eder ve yapıtlar görünmeye başlar.

Ardından, daha küçük kartlarla tam çözünürlüklü yıldızlar eklersek tüm galaksiyi elde ederiz:

Tam çözünürlüklü yıldızlar kullanılarak galaksi işlemenin son sonucuna yakın

Şekille doğru yolda olduğumuzda, bir bulut katmanı ekledik, Photoshop'ta boyadığımız geçici noktaları kaydırdık ve biraz daha renk ekledik. Sonuçta samanyolu galaksisi hem sanat hem de mühendislik ekiplerimiz iyi hissettiler ve CPU'ya vergi eklemeden derinlik, hacim ve harekete sahip olma hedeflerimizi karşıladılar.

Son Samanyolu Galaksimiz 3B.

Son Samanyolu Galaksimiz 3B.

Keşfedilecek daha fazla bilgi

Galaxy Explorer uygulamasının kodunu açık kaynaklı hale getirdik ve geliştiricilerin derlemesi için GitHub'da kullanılabilir hale getirdik.

Galaxy Explorer geliştirme süreci hakkında daha fazla bilgi edinmek mi istiyorsun? Microsoft HoloLens YouTube kanalındaki tüm geçmiş proje güncelleştirmelerimize göz atın.

Yazarlar hakkında

Karim Luccin'in masasındaki resmi Karim Luccin bir Yazılım Mühendisi ve süslü görseller meraklısı. Galaxy Explorer'ın Grafik Mühendisiydi.
Sanat lideri Andy Zibits'in fotoğrafı Andy Zibits , Galaxy Explorer için 3B modelleme takımını yöneten ve daha da fazla parçacık için savaşmış bir Sanat Lideri ve uzay meraklısı.

Ayrıca bkz.