GlDrawArrays ve glDrawElements arasındaki fark


12

OpenGL ES'de fikrimi yenilerken, karşıma çıktım glDrawArraysve glDrawElements.

Nasıl kullanıldıklarını ve neden farklı olduklarını anlıyorum.

Anlayamadığım görünmüyor, ben görmek başarısız olmasıdır glDrawElementsaramaları çizmek kaydedebilirsiniz ( beraberlik çağrıları kaydetme dolayısıyla benim burada da söz okudum kitapların çoğu tarafından bahsedilen bir açıklamasıdır).

2 üçgen kullanarak bir kare çizmeye çalıştığım basit bir senaryo düşünün.

Kullandığım 6 köşe bir dizi olması gerekir glDrawArrayskullanırken glDrawElements, ben 6 öğesi vardır bir dizin diziye sadece 4 ek gerekir.

Yukarıdakiler göz önüne alındığında, işte anlamadığım şey:

  1. glDrawElements4 elemanlı (6 kez) köşe dizime indekslemek için hala indeks dizisini (bir kare durumunda 6 endeks) kullanması gerekiyorsa, beraberlik çağrılarını nasıl kaydedebilirim? Diğer bir deyişle, glDrawElementsyine de toplamda 6 çizim çağrısı olması gerektiği anlamına glDrawArraysmı geliyor ?
  2. glDrawElementseğer biri hala 2 diziye ihtiyaç duyarsa, yerden tasarruf etmek nasıl kullanılır , yani biri köşeler için ve diğeri endeksler için?
  3. 2 üçgenden bir kare çizilmesi durumunda, basitlik için, kaç çizim çağrısının glDrawElements(tepe dizisindeki 4 öğe ve dizin dizisindeki glDrawArrays6 öğe ) ve (yalnızca köşe dizisindeki 6 öğe) ayrı ayrı gerekir?

Teşekkürler.

Yanıtlar:


16

Her glDraw * bir çizim çağrısıdır.

1 glDrawArrays 1 çizim çağrısıdır.
1 glDrawElements 1 çizim çağrısıdır.

Kaç tane köşe veya indeks kullandığınız önemli değil (çizim çağrısı sayısı söz konusu olduğunda), 1 glDraw * 1 çizim çağrısıdır.

Dörtlü çizim basit örnekleri (kullandığınız GL sürümünün dörtlü kaldırılmadığını varsayarak) veya üçgenler bunları karşılaştırmak için iyi bir örnek değildir, çünkü dörtlü bir liste veya üçgen listesi tek bir çağrı ile de çizilebilir, ve glDrawArrays ek dizine ek yükü olmadığından daha verimli görünecektir.

Biraz daha karmaşık bir durumu ele alalım, ancak daha gerçek bir dünya senaryosunu temsil eden bir davaya bakalım. Birden çok üçgen şerit ve fandan oluşan bir modeliniz olduğunu düşünün:

glDrawArrays (GL_TRIANGLE_FAN, .....);
glDrawArrays (GL_TRIANGLE_STRIP, .....);
glDrawArrays (GL_TRIANGLE_STRIP, .....);
glDrawArrays (GL_TRIANGLE_FAN, .....);
glDrawArrays (GL_TRIANGLE_STRIP, .....);
glDrawArrays (GL_TRIANGLE_FAN, .....);

Bu örnekte glDrawArrays kullanmak, model için toplam 6 çizim çağrısı verir. Bununla birlikte, hem şeritler hem de fanlar kolayca dizinlenmiş üçgenlere dönüştürülebilir, bu nedenle indeksler ekleyin ve olur:

glDrawElements (GL_TRIANGLES, .....);

Bu, tüm model için bir beraberlik çağrısı.


GlDrawElements'in glDrawArrays'e göre avantajları, bellek tasarrufundan daha fazlasıdır, bu da onu ölçmenin naif yoludur. Köşelerin yeniden kullanılabileceği yerlerde bellek tasarrufu potansiyeli vardır , çünkü bir dizin tipik olarak bir tepe noktasından daha küçüktür (bu nedenle dengede çok sayıda endeksiniz olsa bile bunlar daha küçük olacaktır), ancak diğer avantajlar şunları içerir:

  • Azaltılmış çekiliş sayısı. Her çizim çağrısı, durumun doğrulanması, bir şeylerin ayarlanması vb. Gibi bazı ek yüklere neden olur ve bu ek yükün çoğu CPU tarafında olur. Çekiliş çağrılarının sayısını azaltarak bu ek yükün çoğunu önleriz.

  • Köşe yeniden kullanımı. Bu sadece bellek tasarrufundan çok daha fazlası. GPU'nuzun muhtemelen yakın zamanda dönüştürülmüş köşelerin depolanabileceği bir donanım tepe önbelleği vardır; aynı tepe noktası tekrar gelirse ve önbellekte bulunuyorsa, yeniden dönüştürmek yerine önbellekten yeniden kullanılabilir. Donanımınız dizinleri karşılaştırarak önbelleği kontrol edecektir, bu nedenle OpenGL terimlerinde önbelleği kullanmanın tek yolu glDrawElements kullanmaktır.


Belirli sorularınızı cevaplamak için:

  1. glDrawElements beraberlik çağrılarını nasıl kaydedebilir ...? Kullandığınız örnekte öyle değil. Her birinin bir çizim çağrısı vardır. Yukarıda tartıştığım gibi, bu örnek ikisini karşılaştırmak için çok kötü bir örnek.

  2. glDrawElements kullanmak nasıl yer tasarrufu sağlar? Çünkü endeksler köşe noktalarından daha küçüktür. 16 bitlik bir dizin iki bayttır, bir konum / renk / texcoord tepe noktası 24 bayttır. 6 köşe 144 bayt, 4 köşe artı 6 endeks 108 bayttır.

  3. 2 üçgenden bir kare çizilmesi durumunda ...? Bir ve bir. GlDraw * çağrısı bir çizim çağrısıdır, kullanılan köşe veya dizin sayısı bu ölçüm için önemsizdir. Ama yeniden vurgulamalıyım, bu ikisini karşılaştırmak için çok kötü bir örnek.


Son olarak, ve sadece sorunları biraz karmaşıklaştırmak için, üçgenli glDrawElements masaüstü GPU'larında en uygun yoldur, mobilde ise çok farklı olabilir. Bazı mobil GPU'lar GL_TRIANGLE_STRIP ile glDrawArrays'i tercih edebilir (bu durumda ilkelleri birleştirmek için dejenere üçgenler eklersiniz) ve ilkel yeniden başlatma veya çoklu çizim gibi daha gelişmiş konulara bile dokunmadım.


Geri bildiriminiz için çok teşekkür ederiz; Paylaştıklarınızı okumak için biraz zaman ayırıyorum. Sadece cevabını kabul ettiğimi bildirmek istedim. Tekrar teşekkürler.
Unheilig

6 DrawTriangleFans ve DrawTriangleStrips çağrılarını 1 tek DrawTriangles çağrısına dönüştürme örneğinizde. Bu gerçekten bazı performansı geliştiriyor mu? Anladığım kadarıyla, 100 üçgenden oluşan bir üçgen şerit çizmek, tek tek 100 üçgen çizmekten çok daha etkilidir ve fayda, 1 yerine 6 işlev çağrısı kullanmaktan kaynaklanan herhangi bir cezayı kolayca telafi edecektir.
Samuel Li

@SamuelLi 6'dan 1'e kadar büyük bir gelişme olmayacak, sadece prensibi göstermesi amaçlanıyor. Ayrıca ve belirttiğim gibi, şeritler genellikle 1998 sonrası masaüstü donanımında dizinlenmiş listelere göre bir performans kazancı değildir. Şerit kullanmanızı tavsiye eden dokümanlardaki tarihi kontrol edin.
Maximus Minimus

Demek istediğin nokta var, açıklama için teşekkürler Minimus
Samuel Li
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.