Dersler neden OpenGL renderleme için farklı yaklaşımlar kullanıyor?


43

http://www.sdltutorials.com/sdl-opengl-tutorial-basics

http://www.opengl-tutorial.org/beginners-tutorials/tutorial-2-the-first-triangle/

Bu iki ders, neredeyse aynı sonucu elde etmek için tamamen farklı yaklaşımlar kullanıyor. İlk gibi şeyler kullanır glBegin(GL_QUADS). İkincisi vertexBufferObjectsise GLEW'e dayalı gölgelendiriciler gibi şeyler kullanır . Ancak sonuç aynı: temel şekiller alıyorsunuz.

Bu farklılıklar neden var?

İlk yaklaşımın anlaşılması çok daha kolay görünüyor. İkinci karmaşık yaklaşımın avantajı nedir?


4
Bir kediyi cildin asla tek bir yolu yoktur.
Philipp

4
@Philipp Evet, ancak doğru yollar ve yanlış yollar, eski yollar ve yeni yollar var (ve aşağıdaki cevapların gösterdiği gibi, eski ve yeni yollar her durumda uyumlu olmayabilir)
Andrew Hill

3
Orada hiçbir doğru yolu ve yanlış yolları, sadece kötü yolları ve (birkaç farklı boyutta) daha iyi yolları.
user253751

glBeginve glEndkullanımdan kaldırıldı çünkü şu andaki grafik mimarileri için son derece yetersizler
Alex

Yanıtlar:


77

OpenGL'nin mobil cihazlar ve gömülü sistemler (OpenGL | ES) ve Web üzerinden JavaScript (WebGL) sürümlerini saymadığı için dört ana sürümü vardır. Tıpkı Direct3D 11'in Direct3D 8'den farklı şeyler yapması gibi, OpenGL 3'ün de OpenGL 1'den farklı şeyler yapması gibi. Büyük fark, OpenGL sürümlerinin çoğunlukla eski sürümlere eklenmesidir (ancak Baştan sona).

OpenGL'nin farklı sürümleri ve sürümleri üzerine ana OpenGL, profil konseptini de ekledi. Yani, Uyumluluk Profili (eski sürümlerden API'ler için destek sağlar) ve Çekirdek Profili (bu eski API'leri devre dışı bırakır). Gibi şeyler glBeginsize Çekirdek Profili kullandığınızda basitçe işi yok ama (varsayılan olan) Uyumluluk Profili kullanacaktır zaman.

Bir başka önemli komplikasyon olarak, OpenGL'nin bazı uygulamaları (Apple gibi, diğerleri arasında olduğu gibi) Çekirdek Profilini kullanırken yalnızca yeni OpenGL özelliklerini mümkün kılar. Bu, daha yeni API'ler kullanmak için eski API'leri kullanmayı bırakmanız gerektiği anlamına gelir .

Daha sonra, öğreticiler için kafa karıştırıcı birkaç senaryo ortaya çıkıyor:

  1. Öğretici eski ve yalnızca kullanımdan kaldırılmış API'leri kullanıyor.
  2. Öğretici yeni ve iyi yazılmış ve yalnızca Core uyumlu API'ler kullanıyor.
  3. Öğretici yeni ancak Uyumluluk modunda tüm API'leri etkinleştiren ve hem yeni hem de eski API'leri serbestçe karıştıran bir sürücü ile çalıştığınızı varsayma hatasını yapıyor.
  4. Eğitim, herhangi bir sürümde eski API'lerin hiçbirini desteklemeyen OpenGL | ES gibi farklı bir OpenGL sürümü içindir.

Gibi şeyler glBeginbazen acil mod API denilen bir parçasıdır. Bu aynı zamanda kafa karıştırıcıdır çünkü OpenGL'de tutulan mod gibi bir şey yoktur ve “anında mod” grafiklerde zaten farklı bir tanımlamaya sahiptir. OpenGL 2.1’den beri kullanılmayan OpenGL 1.x API’leri olarak adlandırmak çok daha iyi.

OpenGL'nin 1.x API'si, eski günlerde derhal grafik boru hattına köşeleri gönderirdi. Bu, köşeleri oluşturan donanımın hızı, tepe verilerini oluşturan CPU'nun hızı ile kabaca aynı olduğunda iyi çalıştı. OpenGL geri döndüğünde üçgen rasterleştirmeyi boşalttı ve başka bir şey değil.

Bu günlerde, GPU, çok sayıda hızda çok yüksek hızlarda çiğneme yapabilir ve aynı zamanda gelişmiş tepe ve piksel dönüşümü gerçekleştirir ve CPU uzaktan bile kalkamaz. Bunun yanı sıra, CPU ve GPU arasındaki arabirim bu hız farkı etrafında tasarlanmıştır, yani artık GPU’ya artık bir köşe göndermenin bile mümkün olmadığı anlamına gelir.

Tüm GL sürücülerinin glBegindahili olarak bir köşe arabelleği ayırması, glVertexbu arabelleğe getirilen köşeleri koyarak ve ardından bu arabelleğin glEndçağrıldığı zaman tek bir beraberlik çağrısına göndererek taklit etmesi gerekir . Bu işlevlerin ek yükü, yalnızca köşe arabelleğini kendiniz güncellediğinizden çok daha büyüktür, bu nedenle bazı belgelerin (çok yanlışlıkla!) Köşe arabelleğini "optimizasyon" olarak adlandırması gerekir (bu bir optimizasyon değil; gerçekte tek yol bu) GPU ile konuş).

OpenGL’de yıllarca süren itiraz edilmiş veya kullanılmamış çeşitli API'ler vardır. Sabit fonksiyonlu boru hattı denilen başka bir parça. Bazı belgeler hala bu boru hattını kullanabilir veya programlanabilir boru hattıyla karıştırılabilir. Sabit işlevli boru hattı eski günlerden itibaren ekran kartlarının 3D sahneleri oluşturmak için kullanılan matematiğin kodunu zorlaştırdığında ve OpenGL API'sı bu matematik için bazı yapılandırma değerlerini ayarlamakla sınırlı kalıyordu. Bugünlerde donanım çok az kodlanmış bir matematiğe sahip ve (CPU'nuz gibi) bunun yerine kullanıcı tarafından sağlanan programları (genellikle gölgelendiriciler olarak adlandırılıyor) çalıştırıyor.

Bir kez daha, sabit işlev özellikleri artık donanımda bulunmadığından, sürücüler eski API'yi taklit etmelidir. Bu, sürücünün içinde, kendi gölgelendiricinizi sağlamadığınızda kullanılan sabit işlevli günlerden eski matematiği yürüten bir dizi uyumluluk gölgelendiricisine sahip olduğu anlamına gelir. Eski OpenGL, eski sabit işlev durumunu (eski OpenGL aydınlatma API'si gibi) değiştiren işlevleri aslında bu değerleri sürücünün uyumluluk gölgelendiricilerine beslemek için tek tip arabellek gibi modern OpenGL özelliklerini kullanıyor.

Uyumluluğu destekleyen sürücüler bir çok sahne arkasında durmak zorundadır, bu eski özellikleri kullanırken ve bunları modern özellikler ile sorunsuz bir şekilde birleştirebildiğinizden emin olmak için çalışırlar, bu da sürücüyü büyük ölçüde zorlar. Bu, bazı sürücülerin sizi Çekirdek Profilinin daha yeni özelliklere erişmesini sağlamaya zorlama nedenlerinden biridir; aynı anda kullanılan eski ve yeni API'leri desteklemelerine gerek kalmadan sürücü iç sürücülerini büyük ölçüde basitleştirir.

Birçok belge, başlamak için daha kolay olmaları nedeniyle eski API'lerle başlamanızı önerebilir. Direct3D , uzmanlıkınız arttıkça ham Direct3D 11 kullanımıyla serbestçe karıştırılabilen daha basit çizim API'leri ve önceden yazılmış gölgelendiriciler sunan bir yardımcı kitaplık ( DirectX Tool Kit ) sunarak yeni başlayanlar için bu sorunu çözdü . Daha geniş OpenGL topluluğu, yeni başlayanlar için Uyumluluk Profili'ne sıkıştı, maalesef, eski OpenGL API'lerini yenileriyle karıştırmanıza izin vermeyen sistemler olduğu için yine sorunlu. Yeni OpenGL'de farklı seviyelerde özelliklere ve hedef kullanım durumlarına ve dillere sahip daha basit görüntü oluşturma için resmi olmayan kütüphaneler ve araçlar var ( MonoGame Örneğin, .NET kullanıcıları için), ancak resmi olarak onaylanan veya geniş ölçüde üzerinde anlaşılan hiçbir şey yoktur.

Bulduğunuz belgeler OpenGL için bile olmayabilir, ancak diğer benzer API'lerden biri için de olabilir. OpenGL | ES 1.x sabit fonksiyona sahipti ancak köşe gönderimi için OpenGL 1.x API'leri yoktu. OpenGL | ES 2.x + ve WebGL 1+ hiçbir sabit işlev özelliğine sahip değildir ve bu API'ler için geriye dönük uyumluluk modları yoktur.

Bu API'ler ana OpenGL'ye çok benziyor; oldukça uyumlu değiller, ancak OpenGL'de (bazılarının tümü değil) bazı sürücülerin OpenGL | ES (hangi WebGL'nin temel aldığı) ile uyumlu olmak için desteklediği resmi uzantıları var. Çünkü daha önce işler yeterince kafa karıştırıcı değildi.


4
+1 Harika cevap! Yeni OpenGL'de basit render için birkaç gayri resmi kütüphane ve araçtan bahsedebilirseniz çok iyi olur :)
Mehrdad

2
Mükemmel cevap. DirectX ile aynı günlerde aynı sorunla karşılaştım - OpenGL'den çok daha basit, ancak tutulan / acil moddan gölgelendiricilere geçiş çok büyüktü. Neyse ki, belgeler çok yardımcı oldu (OpenGL'lerin aksine, en azından benim için), ama "nasıl ışık
tutabilirim

Opengl-tutorial.org'un yazarıyım ve Sean ile aynı fikirdeyim. API, öncelikle performans nedenleriyle bu şekilde gelişti.
Calvin1602

Konu hakkında çok iyi bilgi ..
reynmar

1
@Mehrdad: Kafamın tepesinden hiçbir şey hatırlamıyorum; Basitleştirilmiş 2D renderleme, çeşitli sahne grafiği kütüphaneleri, C # için MonoGame, vb. ekleyen SDL2 veya SFML gibi kütüphaneler var. Gönderiyi düzenleyeceğinden beri "çok" diyerek büyük şişman bir yalan olabilir. :)
Sean Middleditch

9

Birincil fark, stratejilerin ne kadar güncel olduğudur. İlk derste kullanılan anlık mod:

glBegin(GL_QUADS);
    glColor3f(1, 0, 0); glVertex3f(0, 0, 0);
    glColor3f(1, 1, 0); glVertex3f(100, 0, 0);
    glColor3f(1, 0, 1); glVertex3f(100, 100, 0);
    glColor3f(1, 1, 1); glVertex3f(0, 100, 0);
glEnd();

Eski ve yeni sürümlerde desteklenmiyor.

Köşe tamponları ve gölgelendiricileri kullanmak, OpenGL ile oluşturulmuş geçerli yöntemdir. Daha karmaşık görünebilir, ancak çok daha iyi bir performans sergiliyor. Ek olarak, destek kodunuzu OpenGL öğelerini sararken, farklar çoğunlukla ortadan kalkar.


2

Sadece diğer mükemmel cevaplara daha fazla bağlam eklemek için.

İlk bağlantıda açıklandığı gibi anlık mod, diğerlerinin söylediği gibi, OpenGL'nin en eski sürümlerinden gelen eski koddur (1.1). GPU'ların üçgen rasterleştiricilerden biraz daha az olduğu ve programlanabilir boru hatları fikri olmadığı zaman kullanıldı. Örneğin GLQuake ve Quake 2 gibi donanım hızlandırmalı oyunların bazıları için kaynak koduna bakarsanız, kullanımda anında modu göreceksiniz. Basit bir ifadeyle, CPU, ekranda üçgenler çizmeye başlamak için her seferinde tek tek GPU'ya talimatlar gönderir. Kayıt için, GL_QUADS, GLURIANGLES ile aynı sonuca sahiptir, ancak GPU, bu dörtlüleri anında üçgenler haline getirmek zorundadır.

Modern (3.2+) OpenGL farklı bir yaklaşım getiriyor. Hızlı veri erişimi için tepe verilerini GPU belleğine tamponlar ve sonra glDrawArrays veya glDrawElements kullanarak çizim talimatları gönderebilirsiniz. Ayrıca GPU'nun köşeleri nasıl konumlandırdığını ve renklendirdiğini özelleştirmenize olanak tanıyan programlanabilir bir boru hattına (glUseProgram) sahip olursunuz.

Acil durum modunun kullanımdan kaldırılmasının birkaç nedeni var, bunun başlıca nedeni performans. Sean'ın cevabında dediği gibi, günümüzde GPU'lar, verileri CPU'nun yükleyebileceğinden daha hızlı daraltabiliyor, bu nedenle GPU performansını daraltıyorsunuz. Yaptığınız her OpenGL çağrısına dahil olan küçük bir ek yük var, bu minik ama bir araya gelmeye başladığı her karede onbinlerce çağrı yaparken. Basitçe söylemek gerekirse, hemen modunu kullanarak dokulu bir model çizmek için, kare başına en az 2 çağrıya (glTexCoord2f ve glVertex3f) ihtiyacınız var. Modern OpenGL ile veriyi arabelleğe almak için başlangıçta birkaç çağrı kullanırsınız, sonra ne kadar tepe noktası olduğuna bakılmaksızın tüm modeli çizebilirsiniz, tepe dizisi nesnesini bağlamak için sadece birkaç çağrı kullanarak, bazı özellik işaretleyicileri etkinleştirin ve daha sonra glDrawElements veya glDrawArrays için tek bir çağrı.

Hangi teknik doğrudur? Bu ne yapmaya çalıştığınıza bağlı. Herhangi bir fantezi post-process tekniği ya da gölgelendirici gerektirmeyen basit bir 2D oyun, acil modu kullanarak gayet iyi çalışır ve kodu yazmak muhtemelen daha kolay olacaktır. Bununla birlikte, daha modern bir 3D oyun gerçekten zor olurdu ve GLSL (gölgelendirici dili) öğrenmeyi planlıyorsanız, o zaman kesinlikle modern tekniği öğrenin.

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.