OpenGL Nesneleri Hakkında Her Şey
OpenGL nesneleri için standart model aşağıdaki gibidir.
Nesnelerin durumu vardır. Onları bir olarak düşünün struct
. Yani şöyle tanımlanmış bir nesneniz olabilir:
struct Object
{
int count;
float opacity;
char *name;
};
Nesnenin içinde belirli değerler vardır ve durumu vardır . OpenGL nesnelerinin durumu da vardır.
Değişen Devlet
C / C ++ 'da, bir tür örneğiniz Object
varsa, durumunu aşağıdaki gibi değiştirirsiniz: obj.count = 5;
Nesnenin bir örneğine doğrudan başvurur, değiştirmek istediğiniz belirli bir durum parçasını alırsınız ve buna bir değer itersiniz.
OpenGL'de bunu yapmazsınız .
Açıklanamayan daha iyi eski nedenlerden ötürü, bir OpenGL nesnesinin durumunu değiştirmek için önce onu bağlama bağlamalısınız . Bu, bazı glBind*
çağrılarla yapılır.
Buna C / C ++ eşdeğeri şöyledir:
Object *g_objs[MAX_LOCATIONS] = {NULL};
void BindObject(int loc, Object *obj)
{
g_objs[loc] = obj;
}
Dokular ilginç; özel bir bağlayıcı vakayı temsil ederler. Birçok glBind*
çağrının bir "hedef" parametresi vardır. Bu, OpenGL bağlamında bu tür nesnelerin bağlanabileceği farklı konumları temsil eder. Örneğin, bir framebuffer nesnesini okuma ( GL_READ_FRAMEBUFFER
) veya yazma ( GL_DRAW_FRAMEBUFFER
) için bağlayabilirsiniz . Bu, OpenGL'nin arabelleği nasıl kullandığını etkiler. Bu nedir loc
parametre yukarıda temsil eder.
Dokular özeldir, çünkü onları bir hedefe ilk bağladığınızda, özel bilgiler alırlar. Bir dokuyu ilk olarak bir olarak bağladığınızda GL_TEXTURE_2D
, aslında dokuda özel bir durum ayarlarsınız. Bu dokunun 2B bir doku olduğunu söylüyorsunuz. Ve her zaman 2B bir doku olacak; bu durum asla değiştirilemez . İlk önce a olarak bağlanmış bir dokuya GL_TEXTURE_2D
sahipseniz, onu her zaman a olarak bağlamanız gerekir GL_TEXTURE_2D
; GL_TEXTURE_1D
(çalışma zamanı sırasında) bir hataya neden olacağı için onu ciltlemeye çalışmak .
Nesne bağlandıktan sonra durumu değiştirilebilir. Bu, o nesneye özgü genel işlevler aracılığıyla yapılır. Onlar da hangi nesnenin değiştirileceğini temsil eden bir konum alırlar.
C / C ++ 'da bu şöyle görünür:
void ObjectParameteri(int loc, ObjectParameters eParam, int value)
{
if(g_objs[loc] == NULL)
return;
switch(eParam)
{
case OBJECT_COUNT:
g_objs[loc]->count = value;
break;
case OBJECT_OPACITY:
g_objs[loc]->opacity = (float)value;
break;
default:
//INVALID_ENUM error
break;
}
}
Bu işlevin o anda bağlı olan loc
değerde ne olacağını nasıl ayarladığına dikkat edin .
Doku nesneleri için, ana doku durumu değiştirme işlevleri vardır glTexParameter
. Doku durumunu değiştiren diğer işlevler yalnızca glTexImage
işlevler ve bunların varyasyonlarıdır ( glCompressedTexImage
, glCopyTexImage
son glTexStorage
). Çeşitli SubImage
versiyonlar dokunun içeriğini değiştirir, ancak teknik olarak durumunu değiştirmez . Image
Fonksiyonları doku depolama tahsis ve Doku biçimini ayarlamak; SubImage
fonksiyonlar sadece pikselleri etrafında kopyalayın. Bu, dokunun durumu olarak kabul edilmez.
Tekrarlamama izin verin: bunlar doku durumunu değiştiren tek işlevlerdir. glTexEnv
çevre durumunu değiştirir; doku nesnelerinde depolanan hiçbir şeyi etkilemez.
Aktif Doku
Dokular için durum daha karmaşıktır, yine eski nedenlerden dolayı açıklanamayan en iyi nedenlerdir. Burası devreye glActiveTexture
giriyor.
Dokular için, sadece hedefler (orada değil GL_TEXTURE_1D
, GL_TEXTURE_CUBE_MAP
vs). Ayrıca doku birimleri de vardır . C / C ++ örneğimiz açısından, sahip olduğumuz şey şudur:
Object *g_objs[MAX_OBJECTS][MAX_LOCATIONS] = {NULL};
int g_currObject = 0;
void BindObject(int loc, Object *obj)
{
g_objs[g_currObject][loc] = obj;
}
void ActiveObject(int currObject)
{
g_currObject = currObject;
}
Şimdi, sadece 2 boyutlu bir Object
s listemiz değil, aynı zamanda mevcut bir nesne kavramımızın da olduğuna dikkat edin . Mevcut nesneyi ayarlamak için bir fonksiyonumuz var, maksimum sayıda mevcut nesne konseptimiz var ve tüm nesne manipülasyon fonksiyonlarımız mevcut nesneden seçim yapacak şekilde ayarlandı.
Geçerli olarak etkin nesneyi değiştirdiğinizde, hedef konumların tamamını değiştirirsiniz. Böylece mevcut nesneye 0 giden bir şeyi bağlayabilir, mevcut nesneye 4 geçebilir ve tamamen farklı bir nesneyi değiştirebilirsiniz.
Doku nesneleriyle bu benzetme mükemmel ... neredeyse.
Bakın, glActiveTexture
bir tamsayı almaz; bir numaralandırıcı alır . O bir şey alabilir teorisi araçlarının hangi GL_TEXTURE0
için GL_TEXTURE31
. Ama anlamanız gereken bir şey var:
BU YANLIŞ!
Olabilecek gerçek menzil glActiveTexture
tarafından yönetilir GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS
. Bu, bir uygulamanın izin verdiği maksimum eşzamanlı çoklu doku sayısıdır. Bunların her biri farklı gölgelendirici aşamaları için farklı gruplara ayrılmıştır. Örneğin, GL 3.x sınıfı donanımda, 16 köşe gölgelendirici dokusu, 16 parça gölgelendirici dokusu ve 16 geometri gölgelendirici dokusu elde edersiniz. Bu nedenle, GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS
48 olacak.
Ama 48 numaracı yok. Bu yüzden glActiveTexture
gerçekten sayıcılar almıyor. Doğru çağrıya yolu glActiveTexture
aşağıdaki gibidir:
glActiveTexture(GL_TEXTURE0 + i);
burada i
0 ile arasında bir sayıdır GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS
.
sıva
Peki tüm bunların render ile ne ilgisi var?
Gölgelendiricileri kullanırken, örnekleyici üniformalarınızı bir doku görüntü birimine (görüntü birimi glUniform1i(samplerLoc, i)
nerede i
) ayarlarsınız . Bu, kullandığınız sayıyı temsil eder glActiveTexture
. Örnekleyici hedefi örnekleyici türüne göre seçecektir. Yani hedeften bir sampler2D
seçim yapacak GL_TEXTURE_2D
. Örnekleyicilerin farklı tiplere sahip olmasının bir nedeni budur.
Şimdi bu , aynı doku görüntü birimini kullanan farklı türlerde iki GLSL örnekleyiciye sahip olabileceğiniz gibi kuşkuyla geliyor . Ama yapamazsın; OpenGL bunu yasaklar ve oluşturmaya çalıştığınızda size bir hata verir.
GL_TEXTURE0 + i
- bunun geçerli olup olmadığını görmek için enum değerlerini incelemek demekti. Ve son paragraf - bunun yasal olup olmadığını bilmiyordum. Mükemmel! Tüm yanıtlarınızı yer imlerine ekliyorum, böylece tekrar başvurabilirim.