DirectX'te değişen kalınlıkta AA ile çizgiler oluşturmanın en hızlı yolu


14

Bu yüzden kesin olarak .NET altında SharpDX kullanarak bazı DirectX geliştirme yapıyorum (ancak DirectX / C ++ API çözümleri geçerlidir). DirectX kullanarak dikey bir projeksiyonda satırları oluşturmanın en hızlı yolunu arıyorum (örneğin, bilimsel uygulamalar için 2B çizgi çizim simülasyonu).

Oluşturmaya çalıştığım parsel türlerinin bir ekran görüntüsü aşağıdaki gibidir: resim açıklamasını buraya girin

Bu tür grafiklerin, satır başına kenar yumuşatma (veya tam ekran AA açık / kapalı) olan veya olmayan milyonlarca segmente, değişken kalınlığa sahip hatlara sahip olması nadir değildir. Çizgiler için köşeleri çok sık (örn. 20 kez / saniye) güncellemem ve GPU'ya olabildiğince fazla yüklemem gerekiyor.

Şimdiye kadar denedim:

  1. Yazılım oluşturma, örneğin GDI + aslında kötü bir performans değil, ama açıkça CPU'da ağır
  2. Direct2D API - özellikle Kenar Yumuşatma açıkken GDI'dan daha yavaş
  3. CPU tarafında köşe renkleri ve mozaikleme kullanarak AA öykünmek için bu yöntemi kullanarak Direct3D10 . Ayrıca yavaş (Ben profilli ve zaman 80% tepe konumlarını hesaplamak için harcanan)

3. yöntem için GPU'ya üçgen şerit göndermek ve her 200 ms'de yeni köşeleri güncellemek için Vertex Buffers kullanıyorum. 100.000 satır segmenti için 5FPS civarında bir yenileme hızı alıyorum. İdeal olarak milyonlara ihtiyacım var!

Şimdi GPU'da mozaikleme yapmak için en hızlı yolun, örneğin bir Geometri Shader'da olacağını düşünüyorum. Köşeleri çizgi listesi olarak gönderebilir veya bir dokuda paketleyebilir ve dörtlü oluşturmak için bir Geometri Gölgelendiricisinde paketini açabilirim. Ya da bir piksel gölgelendiriciye ham noktalar gönderin ve Bresenham Line çizimini tamamen bir piksel gölgelendiriciye uygulayın. HLSL'm 2006'dan itibaren paslı, gölgelendirici model 2, bu yüzden modern GPU'ların yapabileceği çılgın şeyleri bilmiyorum.

Yani soru şudur: - bunu daha önce kimse yaptı mı ve denemek için herhangi bir öneriniz var mı? - Hızla güncellenen geometri ile performansı iyileştirmek için herhangi bir öneriniz var mı (örneğin her 20 ms'de bir yeni köşe listesi)?

21 Ocak GÜNCELLEME

O zamandan beri yukarıdaki yöntem (3) LineStrip ve Dinamik Köşe Tamponları kullanarak Geometri gölgelendiricileri kullanarak uyguladık. Şimdi 100k noktada 100FPS ve 1.000.000 noktada 10FPS alıyorum. Bu çok büyük bir gelişme ama şimdi doldurma oranı ve hesaplama sınırlıyım, bu yüzden diğer teknikleri / fikirleri düşündüm.

  • Çizgi Segmenti geometrisinin Donanım Kurulumu ne olacak?
  • Sprite Batch ne olacak?
  • Peki ya diğer (Piksel gölgelendirici) yönelimli yöntemler?
  • GPU veya CPU'da etkin bir şekilde kenetleyebilir miyim?

Yorum ve önerileriniz çok takdir!


1
Direct3D'de yerel AA'ya ne dersiniz?
API-Beast

5
Çizmek istediğiniz birkaç örnek eğri gösterebilir misiniz? Bir milyon köşeden bahsediyorsunuz, ancak ekranınızda muhtemelen bir milyondan fazla piksel yok , bu miktar gerçekten gerekli mi? Bana öyle geliyor ki, her yerde tam veri yoğunluğuna ihtiyacınız olmayacak. LOD'ları düşündünüz mü?
sam hocevar

1
Bağladığınız ikinci yaklaşım iyi görünüyor, güncellediğiniz dinamik bir köşe arabelleği mi kullanıyorsunuz yoksa her seferinde yeni bir tane mi oluşturuyorsunuz?

1
Muhtemelen dinamik bir tepe tamponu ile gitmelisiniz (çok fazla çalışma değil, köşe tamponunuza dinamik olmasını söyleyin, tamponu eşleştirin, verilerinizi kopyalayın, eşlemesini kaldırın), ancak darboğazınız ilk etapta köşe nesli ise, muhtemelen şu an çok yardım etmiyor. CPU'daki yükü hafifletmek için GS kullanma konusunda çılgın bir şey olduğunu düşünmeyin

1
Köşelerin sayısı GPU için çok büyükse, girişlerinizi altörneklemeye çalışmayı deneyebilirsiniz - ekranınız birkaç bin piksel genişliğinde olacaksa, tek bir eğri için gerçekten yüz milyonlarca çizgi parçasına ihtiyacınız yok en fazla.

Yanıtlar:


16

Y = f(X)Yalnızca grafikler oluşturacaksanız , aşağıdaki yöntemi denemenizi öneririz.

Eğri verileri doku verisi olarak geçirilir , bu da kalıcı hale gelir ve glTexSubImage2Dörneğin kısmi güncellemelere izin verir . Kaydırmaya ihtiyacınız varsa, dairesel bir arabellek bile uygulayabilir ve çerçeve başına yalnızca birkaç değeri güncelleyebilirsiniz. Her eğri tam ekran dörtlü olarak oluşturulur ve tüm işler piksel gölgelendirici tarafından yapılır.

Tek bileşenli doku içerikleri şöyle görünebilir:

+----+----+----+----+
| 12 | 10 |  5 | .. | values for curve #1
+----+----+----+----+
| 55 | 83 | 87 | .. | values for curve #2
+----+----+----+----+

Piksel gölgelendiricinin çalışması aşağıdaki gibidir:

  • veri kümesi alanındaki geçerli parçanın X koordinatını bulma
  • örneğin. veri içeren en yakın 4 veri noktası; Örneğin X değeri ise 41.3o seçsin 40, 41, 42ve 43.
  • 4 Y değerleri için dokuyu sorgulayın (örnekleyicinin herhangi bir enterpolasyon yapmadığından emin olun)
  • X,Yçiftleri ekran alanına dönüştür
  • akım parçasından üç parçanın ve dört noktanın her birine olan mesafeyi hesaplayın
  • mesafeyi geçerli parça için alfa değeri olarak kullan

Potansiyel yakınlaştırma seviyesine bağlı olarak 4 yerine daha büyük değerler koymak isteyebilirsiniz.

Bu özelliği uygulayan çok hızlı ve kirli bir GLSL gölgelendirici yazdım . Daha sonra HLSL sürümünü ekleyebilirim, ancak çok fazla çaba harcamadan dönüştürebilmelisiniz. Sonuç, farklı çizgi boyutları ve veri yoğunlukları ile aşağıda görülebilir:

eğrileri

Açık bir avantaj, aktarılan veri miktarının çok düşük olması ve çekmece sayısının sadece bir olmasıdır.


Bu çok güzel bir teknik - GPGPU'yu daha önce yaptım, bu yüzden dokuları veriyle paketlemek bildiğim bir şey, ama bunun için düşündüğüm bir şey değil. En büyük boyut nedir (örneğin yükleyebileceğiniz en büyük veri kümesi?). Eğer sakıncası yoksa ve onunla oynamak yoksa kodunuzu indireceğim - Performansı görmek için istekli.
Dr. ABT

@ Dr.ABT Veri kümesi boyutu yalnızca maksimum doku boyutu ile sınırlıdır. Düzgün veri düzeni verildiğinde milyonlarca noktanın neden işe yaramadığını anlamıyorum. Kodumun kesinlikle üretim kalitesi olmadığını, ancak herhangi bir sorun varsa özel olarak benimle iletişime geçmekten çekinmeyin.
sam hocevar

Şerefe @SamHocevar - Ben bir deneyeyim. OpenGL örnek bir zihin derlediğimden beri bir süre geçti! :-)
Dr. ABT

Cevap olarak işaretleme, doku yükünü kullanmıyorum gibi, bir piksel gölgelendiricisine çizgiler çizip bizi doğru yöne yerleştirebilecek gerçek bir OpenGL örneği sundunuz! :)
Dr. ABT

4

Kenar yumuşatma çizgileri oluşturma hakkında bir GPU Mücevherleri bölümü vardı: Hızlı Ön Filtrelenmiş Çizgiler . Temel fikir, her çizgi parçasını dörtlü olarak oluşturmak ve her pikselde, piksel merkezinin çizgi parçasından uzaklığının Gauss işlevini hesaplamaktır.

Bu, grafikteki her çizgi parçasını ayrı bir dörtlü olarak çizmek anlamına gelir, ancak D3D11'de dörtlüleri oluşturmak için kesinlikle bir geometri gölgelendirici ve / veya örnekleme kullanarak GPU'ya yalnızca veri noktalarına aktarılacak veri miktarını azaltabilirsiniz. kendilerini. Muhtemelen veri noktalarını köşe / geometri gölgelendiricisi tarafından okunacak bir StructuredBuffer olarak ayarlayıp daha sonra çizilecek segment sayısını belirten bir çizim çağrısı yapardım. Gerçek köşe tamponları olmazdı; köşe gölgelendiricisi, hangi veri noktalarına bakılacağını belirlemek için yalnızca SV_VertexID veya SV_InstanceID kullanır.


Hey teşekkürler - evet bu makalenin farkındayım, maalesef kaynak kodu yok :-( GeoShader + FragShader'in öncülüğü bu tür bir çalışma için kazanan gibi görünüyor. zor bölüm!
Dr. ABT

Hey @NathanReed buna geri dönüyorsa - Geometri Gölgelendirici veya dörtlü çizmek için örnek oluşturduysam, Nokta1 / Nokta2 bir dörtlünün zıt köşeleridir, Piksel Gölgelendiricide Pt1 ve Pt2 arasındaki çizgiye olan mesafeyi nasıl hesaplayabilirim? Piksel gölgelendirici giriş geometrisi hakkında bilgi sahibi mi?
Dr. ABT

@ Dr.ABT Matematiksel çizginin parametreleri enterpolatörler yoluyla piksel gölgelendiriciye gönderilmelidir. Piksel gölgelendiricinin geometriye doğrudan erişimi yoktur.
Nathan Reed

Görüyorum ki bu GeometryShader'dan çıktılar göndererek veya örnekleyerek yapılabilir mi? Ekstra kredi için (ilgileniyorsanız) buraya bir Q ekledim: gamedev.stackexchange.com/questions/47831/…
Dr. ABT

@ Dr.ABT Doku koordinatları, normal vektörler ve tüm bu tür şeyler normal olarak piksel gölgelendiriciye gönderilir - enterpolasyonlu köşe / geometri gölgelendiricisinden çıktılar yazarak ve piksel gölgelendiriciye girdi.
Nathan Reed

0

@ Dr.ABT - Bunun için özür bir soru, cevap değil. Yukarıdaki Sam Hocevar'ın cevabı içinde sormanın bir yolunu bulamadım.

Grafiğiniz için satırları nihayet uyguladığınız hakkında daha fazla ayrıntı paylaşabilir misiniz? Aynı WPF uygulamasına da ihtiyacım var. Bu konuda paylaşabileceğiniz herhangi bir ayrıntı veya kod için şimdiden teşekkür ederiz.


bildiğiniz gibi bir cevap değil lütfen düzenleyin ve yorum olarak koyun
MephistonX

Bunu yapmaya çalışıyordum ama orijinal yayında "yorum ekle" düğmesi yok.
ErcGeek

Merhaba ErcGeek, Üzgünüm, bu bilgi şirketime özel olduğundan nihai çözümü paylaşamıyorum. Her ne kadar yukarıdaki örnekler ve öneriler bizi doğru yola koysa da. Herşey gönlünce olsun!
Dr. ABT

Belirli bir itibara ulaşmadan yorum gönderemezsiniz. Ve tüm bu inişler size bu fırsatı sunmayacak.
Mathias Lykkegaard Lorenzen

Son sonucu bilmek istediği için ve cezalandırılmadığı için cezalandırılmamalıdır. Cevabı iptal etti.
David Ching
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.