Semua Tentang Objek OpenGL
Model standar untuk objek OpenGL adalah sebagai berikut.
Objek memiliki status. Anggap saja sebagai struct
. Jadi Anda mungkin memiliki objek yang didefinisikan seperti ini:
struct Object
{
int count;
float opacity;
char *name;
};
Objek memiliki nilai-nilai tertentu yang disimpan di dalamnya dan memiliki status . Objek OpenGL juga memiliki status.
Mengubah Status
Dalam C / C ++, jika Anda memiliki instance tipe Object
, Anda akan mengubah statusnya sebagai berikut: obj.count = 5;
Anda akan langsung mereferensikan instance objek, mendapatkan bagian tertentu dari status yang ingin Anda ubah, dan memasukkan nilai ke dalamnya.
Di OpenGL, Anda tidak melakukan ini.
Untuk alasan warisan lebih baik tidak dijelaskan, untuk mengubah status objek OpenGL, Anda harus mengikatnya terlebih dahulu ke konteks. Ini dilakukan dengan beberapa dari glBind*
panggilan.
C / C ++ yang setara dengan ini adalah sebagai berikut:
Object *g_objs[MAX_LOCATIONS] = {NULL};
void BindObject(int loc, Object *obj)
{
g_objs[loc] = obj;
}
Teksturnya menarik; mereka mewakili kasus khusus yang mengikat. Banyak glBind*
panggilan memiliki parameter "target". Ini mewakili lokasi berbeda dalam konteks OpenGL di mana objek jenis itu bisa diikat. Misalnya, Anda bisa mengikat objek framebuffer untuk reading ( GL_READ_FRAMEBUFFER
) atau untuk menulis ( GL_DRAW_FRAMEBUFFER
). Ini memengaruhi cara OpenGL menggunakan buffer. Inilah yang loc
diwakili oleh parameter di atas.
Tekstur itu istimewa karena saat Anda mengikatnya pertama kali ke target, tekstur itu mendapatkan informasi khusus. Saat Anda pertama kali mengikat tekstur sebagai a GL_TEXTURE_2D
, Anda sebenarnya menyetel status khusus dalam tekstur. Anda mengatakan bahwa tekstur ini adalah tekstur 2D. Dan itu akan selalu menjadi tekstur 2D; keadaan ini tidak dapat diubah selamanya . Jika Anda memiliki tekstur yang pertama kali dijilid sebagai a GL_TEXTURE_2D
, Anda harus selalu mengikatnya sebagai a GL_TEXTURE_2D
; mencoba untuk mengikatnya karena GL_TEXTURE_1D
akan menimbulkan kesalahan (saat run-time).
Setelah objek diikat, statusnya dapat diubah. Ini dilakukan melalui fungsi generik khusus untuk objek itu. Mereka juga mengambil lokasi yang mewakili objek mana yang akan dimodifikasi.
Di C / C ++, ini terlihat seperti:
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;
}
}
Perhatikan bagaimana fungsi ini mengatur apa pun yang terjadi pada loc
nilai yang saat ini terikat .
Untuk objek tekstur, fungsi perubahan status tekstur utama adalah glTexParameter
. Satu-satunya fungsi lain yang mengubah status tekstur adalah glTexImage
fungsi dan variasinya ( glCompressedTexImage
,, glCopyTexImage
terbaru glTexStorage
). Berbagai SubImage
versi mengubah isi dari tekstur, tetapi mereka tidak secara teknis mengubah nya negara . The Image
fungsi mengalokasikan penyimpanan tekstur dan mengatur format tekstur ini; yang SubImage
fungsi hanya menyalin piksel sekitar. Itu tidak dianggap status tekstur.
Izinkan saya untuk mengulangi: ini adalah satu - satunya fungsi yang mengubah status tekstur. glTexEnv
mengubah keadaan lingkungan; itu tidak mempengaruhi apa pun yang disimpan dalam objek tekstur.
Tekstur Aktif
Situasi tekstur lebih kompleks, sekali lagi untuk alasan warisan sebaiknya tidak diungkapkan. Di sinilah glActiveTexture
masuk.
Untuk tekstur, ada tidak hanya target ( GL_TEXTURE_1D
, GL_TEXTURE_CUBE_MAP
, dll). Ada juga unit tekstur . Dalam contoh C / C ++ kami, yang kami miliki adalah ini:
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;
}
Perhatikan bahwa sekarang, kami tidak hanya memiliki daftar 2D Object
s, tetapi kami juga memiliki konsep objek saat ini. Kami memiliki fungsi untuk mengatur objek saat ini, kami memiliki konsep jumlah maksimum objek saat ini, dan semua fungsi manipulasi objek kami disesuaikan untuk memilih dari objek saat ini.
Saat Anda mengubah objek yang saat ini aktif, Anda mengubah seluruh kumpulan lokasi target. Jadi Anda dapat mengikat sesuatu yang masuk ke objek saat ini 0, beralih ke objek 4 saat ini, dan akan memodifikasi objek yang sama sekali berbeda.
Analogi dengan objek tekstur ini sempurna ... hampir.
Lihat, glActiveTexture
tidak mengambil integer; dibutuhkan pencacah . Yang secara teori berarti dapat mengambil apa saja dari GL_TEXTURE0
hingga GL_TEXTURE31
. Tetapi ada satu hal yang harus Anda pahami:
INI SALAH!
Jangkauan sebenarnya yang glActiveTexture
dapat diambil diatur oleh GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS
. Itu adalah jumlah maksimum multitekstur simultan yang memungkinkan penerapan. Masing-masing dibagi menjadi kelompok berbeda untuk tahapan shader yang berbeda. Misalnya, pada perangkat keras kelas GL 3.x, Anda mendapatkan 16 tekstur shader vertex, 16 tekstur shader fragmen, dan 16 tekstur shader geometri. Oleh karena itu, GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS
akan menjadi 48.
Tapi tidak ada 48 pencacah. Itulah mengapa glActiveTexture
tidak menerima pencacah. The benar cara untuk panggilan glActiveTexture
adalah sebagai berikut:
glActiveTexture(GL_TEXTURE0 + i);
dimana i
adalah angka antara 0 dan GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS
.
Merender
Jadi, apa hubungan semua ini dengan rendering?
Saat menggunakan shader, Anda menyetel seragam sampler Anda ke unit gambar tekstur ( glUniform1i(samplerLoc, i)
, di mana i
unit gambar). Itu mewakili nomor yang Anda gunakan glActiveTexture
. Sampler akan memilih target berdasarkan jenis sampler. Jadi sampler2D
akan memilih dari GL_TEXTURE_2D
target. Inilah salah satu alasan mengapa sampler memiliki tipe yang berbeda.
Sekarang ini terdengar mencurigakan seperti Anda dapat memiliki dua sampler GLSL, dengan tipe berbeda yang menggunakan unit gambar tekstur yang sama. Tapi Anda tidak bisa; OpenGL melarang ini dan akan memberi Anda kesalahan saat Anda mencoba merender.
GL_TEXTURE0 + i
- saya bermaksud memeriksa nilai enum untuk melihat apakah itu valid atau tidak. Dan paragraf terakhir - tidak tahu apakah itu legal atau tidak. Luar biasa! Saya menandai semua jawaban Anda sehingga saya dapat merujuknya lagi.