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.Saya akan mencobanya ! Semua ini tidak terlalu rumit, hanya masalah istilah, semoga saya bisa menjelaskan.
Anda dapat membuat Objek Tekstur kira-kira sebanyak yang tersedia memori di sistem Anda. Objek ini menyimpan data aktual (texel) tekstur Anda, bersama dengan parameter, yang disediakan oleh glTexParameter (lihat FAQ ).
Ketika sedang dibuat, Anda harus menetapkan satu Tekstur Sasaran untuk satu objek tekstur, yang merupakan jenis tekstur (
GL_TEXTURE_2D
,GL_TEXTURE_3D
,GL_TEXTURE_CUBE
, ...).Kedua item ini, objek tekstur dan target tekstur merupakan data tekstur. Kami akan kembali lagi nanti.
Unit tekstur
Sekarang, OpenGL menyediakan larik unit tekstur , yang dapat digunakan secara bersamaan saat menggambar. Ukuran array bergantung pada sistem OpenGL, milik Anda memiliki 8.
Anda dapat mengikat objek tekstur ke unit tekstur untuk menggunakan tekstur yang diberikan saat menggambar.
Di dunia yang sederhana dan mudah, untuk menggambar dengan tekstur tertentu, Anda akan mengikat objek tekstur ke unit tekstur, dan Anda akan melakukannya (kodesemu):
Karena GL adalah mesin negara, sayangnya, GL tidak bekerja dengan cara ini. Misalkan kami
textureObject
memiliki data untukGL_TEXTURE_2D
target tekstur, kami akan mengekspresikan tugas sebelumnya sebagai:Perhatikan bahwa
GL_TEXTURE_2D
sangat tergantung pada jenis tekstur yang ingin Anda ikat.Objek tekstur
Dalam pseudo code, untuk mengatur data tekstur atau parameter tekstur, Anda akan melakukan misalnya:
OpenGL tidak dapat secara langsung memanipulasi objek tekstur, untuk memperbarui / menyetel kontennya, atau mengubah parameternya, Anda harus mengikatnya terlebih dahulu ke unit tekstur aktif (mana pun itu). Kode yang setara menjadi:
Naungan
Shader memiliki akses ke semua unit tekstur, mereka tidak peduli dengan tekstur aktif.
Seragam sampler adalah
int
nilai yang mewakili indeks unit tekstur yang akan digunakan untuk sampler (dan bukan objek tekstur yang akan digunakan).Jadi, Anda harus mengikat objek tekstur ke unit yang ingin Anda gunakan.
Jenis sampler akan melakukan pencocokan dengan target tekstur yang digunakan dalam unit tekstur:
Sampler2D
untukGL_TEXTURE_2D
, dan seterusnya ...sumber
Bayangkan GPU seperti pabrik pemrosesan cat.
Ada sejumlah tangki, yang mengirimkan pewarna ke beberapa mesin pengecatan. Di mesin lukis pewarna kemudian dioleskan ke objek. Tangki tersebut adalah unit tekstur
Tangki tersebut dapat dilengkapi dengan berbagai jenis pewarna. Setiap jenis pewarna membutuhkan jenis pelarut lainnya. "Pelarut" adalah target tekstur . Untuk kenyamanan, setiap tangki dihubungkan ke beberapa pasokan pelarut, dan hanya satu jenis pelarut yang dapat digunakan di setiap tangki dalam satu waktu. Jadi ada katup / switch
TEXTURE_CUBE_MAP
,TEXTURE_3D
,TEXTURE_2D
,TEXTURE_1D
. Anda dapat mengisi semua jenis pewarna ke dalam tangki pada saat yang sama, tetapi karena hanya satu jenis pelarut yang masuk, ini hanya akan "mengencerkan" jenis pewarna yang cocok. Jadi Anda dapat memiliki setiap jenis tekstur yang terikat, tetapi pengikatan dengan pelarut "terpenting" akan benar-benar masuk ke dalam tangki dan bercampur dengan jenis pewarna yang dimilikinya.Lalu ada pewarna itu sendiri, yang berasal dari gudang dan diisi ke dalam tangki dengan "mengikatnya". Itu teksturmu.
sumber
Jika di shader Anda, Anda memerlukan pencarian dari 2 tekstur:
untuk tex1 dan tex2 perlu disebutkan sumbernya sebagai berikut:
di loop render:
Dengan gl_bindtexture, tidak mungkin melakukan hal seperti itu. Di sisi lain, kemungkinan penggunaan pengikatan dalam loop rendering, adalah kasus di mana Anda memberi makan tekstur dengan konten dalam aliran (video, webcam):
sumber