Unity Occlusion Culling Sistemi

Yayınlandı: 31 Mart 2020 yasirkula tarafından Oyun Tasarımı, UNITY 3D içinde

Yeniden merhabalar,

Bu kısa derste, Unity‘nin Occlusion Culling sistemini tanıtacağım. Sahnedeki objeleri ekrana çizerken Unity otomatik olarak frustum culling optimizasyonundan faydalanır; bu optimizasyon, kameranın görüş alanının (frustum) dışında kalan objeler ile kameranın Far Clipping Plane‘inden daha uzakta yer alan objelerin boş yere GPU’ya yollanmamasını (culling) sağlar. Occlusion Culling ise, kameranın görüş alanı içinde olan ama başka bir objenin arkasında kaldığı için göremediğimiz (occlusion) objelerin boş yere GPU’ya yollanmamasını (culling) sağlar. Occlusion Culling açık olduğunda, bu iki optimizasyon tekniği beraber çalışırlar.

Hazırsanız başlayalım…

Derste Unity’nin ücretsiz Snaps Prototype | Office asset’ini kullandım:

Occlusion Culling’in olayı, başka bir objenin arkasında kalan objeleri GPU’ya yollamamak olduğu için, sadece bu optimizasyondan verim alacağınız sahnelerde Occlusion Culling kullanın. Örneğin üstteki sahnede iki odayı duvarlar ayırdığı için, duvara doğru bakarken duvarın arkasında kalan objeleri çizmemek mantıklı bir tercih. Benzer şekilde, birçok binadan oluşan bir şehirde FPS veya TPS kamera açısıyla dolaşırken de Occlusion Culling oldukça faydalı olacaktır. Ama mesela izometrik kamera açısıyla oynanan bir oyununuz varsa, çoğu zaman Occlusion Culling işinize yaramayacak, boş yere performans yiyecektir.

Occlusion Culling sisteminde 3 tip obje bulunmakta:

  • Occluder Static: Inspector’da Static değeri Occluder Static‘i içeren objelerdir:

Bu objeler, duvar görevi gören, yani arkalarında kalan objeleri gizleyen büyük objelerdir. Benim sahnemde sadece duvarlar ve büyük sütunlar Occluder Static; bilgisayar, masa, sandalye vb. küçük objeler, arkalarında kayda değer bir şey gizleyebilecek kadar büyük olmadıkları için onları Occluder Static yapmadım. Şehirde geçen bir oyun yapıyorsanız da, etraftaki binalar potansiyel Occluder Static objelerdir.

Burada static kelimesine dikkat edin; bunun anlamı, bu objeler oyun esnasında kesinlikle hareket edemezler. Instantiate ile oyun esnasında oluşturulan objeler static yapılamazlar (obje hiç hareket etmeyecek olsa bile), bu yüzden prosedürel bir şehir oluşturuyorsanız, bu şehir için Unity’nin Occlusion Culling sistemini kullanamazsınız.

NOT: LOD kullanan objelerde Occluder Static verisi hesaplanırken, LOD0 kullanılır. Eğer objenizin LOD’leri arasında çok büyük farklar varsa, bu objeyi Occluder Static yapmak istemeyebilirsiniz.

  • Occludee Static: Inspector’da Static değeri Occludee Static‘i içeren objelerdir. Bunlar, bir duvarın (Occluder Static) arkasında kalınca gizlenen objelerdir. Static oldukları için bu objeler de kesinlikle hareket edemezler. Benim sahnemdeki her şey Occludee Static çünkü sahnemdeki her objenin, bir duvarın arkasında kalma potansiyeli var. Duvar objelerim ise hem Occluder Static hem de Occludee Static, bir obje aynı anda birden çok tür Static olabilir
  • Dynamic Occlusion: Renderer component’indeki Dynamic Occlusion değeri işaretli objelerdir:

Tıpkı Occludee Static gibi, bu objeler de duvarların arkasında kalınca gizlenen objelerdir. Ancak Occludee Static’in aksine, bu objeler oyun esnasında hareket edebilir. O halde tüm objeleri Dynamic Occlusion yapmak varken niye Occludee Static diye bir şey var diyebilirsiniz. Maalesef internette bu konuda bir doküman yok o yüzden sadece tahmin yürütebiliyorum; tahminime göre Occludee Static objelerin duvarın arkasında olup olmadıklarını hesaplamak, Dynamic Occlusion’a göre daha az performans harcamakta.

Sahnemizdeki objelerin Occluder Static, Occludee Static ve Dynamic Occlusion değerleriyle oynadıktan sonra, Occlusion Culling hesaplamaları için gerekli olan veriyi oluşturmamız lazım. Bunun için Window-Rendering-Occlusion Culling yolunu izleyin ve gelen pencereden Bake sekmesine geçiş yapın:

Burada karşımıza çıkan 3 parametre var:

  • Smallest Occluder: bir Occluder Static objenin duvar sayılabilmesi için, en az kaç birim büyüklüğünde olması gerektiğini belirtir. Bu değer azaldıkça, Occlusion Culling verisi daha detaylı olur ama haliyle biraz daha yer kaplar. Bu değer çok azaldıkça, Occlusion Culling’in işe yararlığının da azaldığını fark ettim, bu yüzden deneme yanılma yoluyla bu değere ince ayar yapmanız faydalı olacaktır
  • Smallest Hole: eğer bir Occluder Static duvarın içinde delik varsa, bu deliğin en az kaç birim büyüklüğünde olması gerektiğini belirtir. Bu değerden daha küçük delikler, Occlusion Culling’in gözünde delik sayılmazlar ve bu deliklerden karşıya bakarken, duvarın arkasında kalan objeler Occlusion Culling yüzünden gözükmeyebilirler. Bu değer ne kadar azalırsa, Occlusion Culling verisinin boyutu o kadar artar. Aşağıdaki resimde Smallest Hole’ün etkisini görebilirsiniz:
  • Backface Threshold: bir kürenin/küpün içinde veya bir terrain’in yüzeyinin altında kalan kısımlarda, boş yere Occlusion Culling verisi oluşmamasını sağlar. Oyunlarda kamera genelde katı objelerin içine girmez veya bir terrain’e aşağısından bakmaz, bu yüzden buralarda Occlusion Culling verisinin yer kaplaması lüzumsuzdur. Küpün içini veya terrain’in altını tespit etmek için, Unity belli bir nokta seçer ve bu noktadan dışarı yönde pek çok raycast ışını yollar. Ardından bu raycast ışınlarının çarptığı yüzeylerden yüzde kaçının normal vektörlerinin, raycast ışını ile aynı yöne baktığını hesaplar. Eğer bu değer Backface Threshold’dan büyükse, o noktada Occlusion Culling verisi oluşturulmaz. Varsayılan olarak bu değer 100’dür, yani bu optimizasyondan faydalanılmaz. Ancak örneğin eğer bu değeri 75 yaparsak, raycast ışınlarının çarptığı yüzeylerin %75 veya daha fazlasının normal vektörleri dışarı yöne bakıyorsa (yani muhtemelen objeye içinden veya terrain’e altından bakıyorsak), o nokta Occlusion Culling’e dahil olmaz. Bu değer ne kadar azalırsa, Occlusion Culling verisinin boyutu da o kadar azalır; ancak buna bağlı olarak Unity’nin yanlışlıkla bir noktayı Occlusion Culling’e dahil etmemesi şansı da artar

Ben kendi sahnemde Smallest Occluder‘ı 1.0 yaptım çünkü duvarlarımın hemen hiçbiri 5 birim büyüklüğünde değil, genel olarak 1 veya 1.5 birim büyüklüğündeler. Diğer parametreleri olduğu gibi bıraktım. Ancak eğer oyun bir şehirde geçseydi, binaların büyüklüğüne göre bu değeri 5’de bırakmak mantıklı olabilirdi. Değiştirdiğiniz parametreleri varsayılan değerlere döndürmek isterseniz, Set default parameters butonuna tıklayabilirsiniz.

Artık Occlusion Culling verisini hesaplamaya hazırız, bunun için Bake butonuna tıklamamız yeterli. Unity hesaplamaları arkaplanda yapacak ve hesaplamaların yüzde kaçının bittiği, Unity’nin sağ altındaki barda gözükecek:

İşlem tamamlanınca, Occlusion Culling verisinin boyutunu, Bake butonunun altında görebilirsiniz:

Veriyi temizlemek için Clear butonuna tıklayabilirsiniz.

Şu anda, Camera component’indeki Occlusion Culling‘i açık olan kameralar otomatik olarak Occlusion Culling’den faydalanmakta. Kamerayı bir duvarın arkasına getirip ardından Game panelinin sağ üstündeki Stats‘ta yer alan değerlere bakarak bunu gözlemleyebilirsiniz:

Hierarchy’de kamera seçili iken, Occlusion Culling penceresindeki Visualization sekmesine geçiş yaparak, Scene panelinde Occlusion Culling’i önizleyebiliriz. Örneğin üstteki sahneyi bir de Scene panelinden önizleyecek olursak:

Önizleme esnasında, Unity hem frustum culling’den hem de Occlusion Culling’den faydalanır. Eğer Scene panelinin sağ altında yer alan ufak penceredeki Occlusion culling açıksa, her iki optimizasyon da devreye girer, yoksa sadece frustum culling devreye girer. Kameranın görüş alanı dışındaki objelerin Scene’de gözükmemesinin, Occlusion Culling’in değil de frustum culling’in eseri olduğunu bilin. Occlusion Culling’in yaptığı işi görmek için, ufak kutucuktaki Occlusion culling değerini açıp kapatabilirsiniz. Frustum culling’in yaptığı işi görmek için ise, Occlusion culling kapalı iken Visualize sekmesi ile Bake sekmesi arasında geçiş yapabilirsiniz (frustum culling oyun esnasında otomatik olarak aktiftir, biz burada sadece frustum culling’in yaptığı işi önizliyoruz):

Şimdi Scene panelinin sağ altında yer alan ufak kutucuktaki parametrelere bakalım. Bu panel sadece sahnedeki kamera seçili iken işe yarar:

  • Camera Volumes: açık olduğunda, kameranın etrafında sarı bir dikdörtgen gözükür. Occlusion Culling sahneyi birkaç parçaya böler ve bu sarı alan da, kameranın hangi parçanın içinde yer aldığını gösterir. Eğer kameranın etrafında sarı bir dikdörtgen yoksa, o noktada Occlusion Culling verisi oluşturulmamıştır
  • Visibility Lines: Occlusion Culling sisteminin duvarları tespit etmek için attığı raycast ışınları yeşil renkte gösterilir:
  • Portals: Occlusion Culling verisi, sahneyi ufak hücrelere böler. Kameranın görüş alanındaki hücrelerin birleşme noktaları (portal), bu seçenek açıkken görülebilir:

Occlusion Culling sisteminin oluşturduğu veriyi etkileyen iki component mevcuttur:

  • Occlusion Area

Occlusion Culling verisi oluşturulurken sahnenin hangi kısımlarına öncelik verilmesi gerektiğini belirler. Dokümantasyonda yazdığına göre, Occlusion Area kullanarak Occlusion Culling’in boyutunu, veri hesaplama hızını ve oyun esnasında çalışma hızını olumlu yönde etkilemek mümkünmüş:

Her Occlusion Area esasında bir dikdörtgenler prizmasıdır, sahnenin karışıklığına göre birden çok Occlusion Area kullanmanız gerekebilir. Eğer Is View Volume kapalı ise, Occlusion Area inaktif hale gelir, Occlusion Culling sistemine bir etkisi olmaz. Ben sahnemde şu şekilde 4 Occlusion Area kullandım:

  • Occlusion Portal

Occlusion Culling sisteminde duvar görevi gören bir objenin, oyun esnasında kapanıp açılabilmesini sağlar. Örneğin iki odayı birbirine bağlayan ve açılabilen bir kapı düşünün. Bu kapı kapalıyken, kapının arkasındaki objelerin Occlusion Culling ile gizlenmesini isteriz ama kapı açıldığında bunu istemeyiz. Bu durumda kapıya Occlusion Portal component’i verebiliriz. Occlusion Portal’ın çalışması için, bu component’in verildiği objenin ne Occluder Static ne de Occludee Static olması lazım, objede bu seçenekler açıksa kapatın.

Örneğin ben sahnemdeki iki odayı birbirine şöyle bir kapı ile bağladım:

Kapıyı static yapmadım ve kapıya bir Occlusion Portal component’i verdim:

Buradaki Open değişkeni aktif iken, kapı açıkmış varsayılır ve arkasındaki objeler Occlusion Culling tarafından gizlenmez. Bu değişkeni oyun esnasında GetComponent<OcclusionPortal>().open = true; kodu ile değiştirebilirsiniz.

Occlusion Portal da esasında bir dikdörtgenler prizmasıdır, ben bu prizmayı kapıyı güzelce çevreleyecek şekilde ayarladım:

Component’teki Open değişkeninin etkisini aşağıda görebilirsiniz:

Ve bir dersin daha sonuna geldik. Sonraki derslerde görüşmek üzere, sağlıcakla kalın!

yorum
  1. mustafayaya dedi ki:

    Harika bir yazı eline sağlık.

  2. Bulent dedi ki:

    Yasir bey uçak sümilasyon tarzi oyununda sehir uzerinde yada binalarin arasinda oynayisi olan oyunda fps arttırımı.

  3. Berk Uçmaz dedi ki:

    Harika, yasir hocam Mesh Deform hakkında da böyle detaylı bi yazı yazarsanız bizim için çok faydalı olur türkçe kaynak hiç yok bi siz varsınız yardımcı olursanız çok seviniriz

    • yasirkula dedi ki:

      Mesh Deform çok spesifik bir konu olduğu ve piyasada gördüğümüz oyunlar arasında çok kullanım alanı olmadığı için bu konuda bir söz vermiyorum.

  4. Anonim dedi ki:

    emeğiniz için cok teşkkürler

    ________________________________

Cevap Yazın

Aşağıya bilgilerinizi girin veya oturum açmak için bir simgeye tıklayın:

WordPress.com Logosu

WordPress.com hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap /  Değiştir )

Google fotoğrafı

Google hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap /  Değiştir )

Twitter resmi

Twitter hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap /  Değiştir )

Facebook fotoğrafı

Facebook hesabınızı kullanarak yorum yapıyorsunuz. Çıkış  Yap /  Değiştir )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.