Alles über OpenGL-Objekte
Das Standardmodell für OpenGL-Objekte lautet wie folgt.
Objekte haben Zustand. Betrachten Sie sie als struct
. Möglicherweise haben Sie ein Objekt wie folgt definiert:
struct Object
{
int count;
float opacity;
char *name;
};
Das Objekt enthält bestimmte Werte und den Status . OpenGL-Objekte haben auch Status.
Status ändern
Wenn Sie in C / C ++ eine Instanz vom Typ haben Object
, ändern Sie ihren Status wie folgt: obj.count = 5;
Sie verweisen direkt auf eine Instanz des Objekts, erhalten den bestimmten Status, den Sie ändern möchten, und verschieben einen Wert in diesen.
In OpenGL tun Sie dies nicht .
Um den Status eines OpenGL-Objekts zu ändern, müssen Sie es aus früheren Gründen, die besser ungeklärt bleiben, zunächst an den Kontext binden . Dies geschieht mit einigen von glBind*
Anrufen.
Das C / C ++ - Äquivalent dazu lautet wie folgt:
Object *g_objs[MAX_LOCATIONS] = {NULL};
void BindObject(int loc, Object *obj)
{
g_objs[loc] = obj;
}
Texturen sind interessant; Sie stellen einen Sonderfall der Bindung dar. Viele glBind*
Aufrufe haben einen "Ziel" -Parameter. Dies stellt verschiedene Stellen im OpenGL-Kontext dar, an denen Objekte dieses Typs gebunden werden können. Sie können beispielsweise ein Framebuffer-Objekt zum Lesen ( GL_READ_FRAMEBUFFER
) oder zum Schreiben ( GL_DRAW_FRAMEBUFFER
) binden . Dies wirkt sich darauf aus, wie OpenGL den Puffer verwendet. Dies ist, was der loc
obige Parameter darstellt.
Texturen sind etwas Besonderes, da sie beim ersten Binden an ein Ziel besondere Informationen erhalten. Wenn Sie eine Textur zum ersten Mal als binden, legen GL_TEXTURE_2D
Sie tatsächlich einen speziellen Status in der Textur fest. Sie sagen, dass diese Textur eine 2D-Textur ist. Und es wird immer eine 2D-Textur sein; Dieser Zustand kann niemals geändert werden . Wenn Sie eine Textur haben, die zuerst als gebunden wurde GL_TEXTURE_2D
, müssen Sie sie immer als binden GL_TEXTURE_2D
. Der Versuch, es so zu binden GL_TEXTURE_1D
, führt zu einem Fehler (zur Laufzeit).
Sobald das Objekt gebunden ist, kann sein Status geändert werden. Dies erfolgt über generische Funktionen, die für dieses Objekt spezifisch sind. Auch sie nehmen einen Ort ein, der angibt, welches Objekt geändert werden soll.
In C / C ++ sieht dies folgendermaßen aus:
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;
}
}
Beachten Sie, wie diese Funktion den aktuell gebundenen loc
Wert festlegt .
Für Texturobjekte sind die Hauptfunktionen zum Ändern des Texturzustands glTexParameter
. Die einzigen anderen Funktionen , dass Veränderungen Textur Zustand sind die glTexImage
Funktionen und deren Variationen ( glCompressedTexImage
, glCopyTexImage
die jüngste glTexStorage
). Die verschiedenen SubImage
Versionen ändern den Inhalt der Textur, ändern jedoch technisch nicht ihren Zustand . Die Image
Funktionen weisen Texturspeicher zu und legen das Format der Textur fest. Die SubImage
Funktionen kopieren nur Pixel. Dies wird nicht als Zustand der Textur angesehen.
Lassen Sie mich wiederholen: Dies sind die einzigen Funktionen, die den Texturstatus ändern. glTexEnv
ändert den Umgebungszustand; Es wirkt sich nicht auf etwas aus, das in Texturobjekten gespeichert ist.
Aktive Textur
Die Situation für Texturen ist komplexer, wiederum aus alten Gründen, die am besten nicht bekannt gegeben werden. Hier kommt ins glActiveTexture
Spiel.
Für Texturen gibt es nicht nur Ziele ( GL_TEXTURE_1D
, GL_TEXTURE_CUBE_MAP
usw.). Es gibt auch Textur - Einheiten . In Bezug auf unser C / C ++ - Beispiel haben wir Folgendes:
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;
}
Beachten Sie, dass wir jetzt nicht nur eine 2D-Liste von Object
s haben, sondern auch das Konzept eines aktuellen Objekts. Wir haben eine Funktion zum Festlegen des aktuellen Objekts, wir haben das Konzept einer maximalen Anzahl aktueller Objekte und alle unsere Objektmanipulationsfunktionen werden angepasst, um aus dem aktuellen Objekt auszuwählen.
Wenn Sie das aktuell aktive Objekt ändern, ändern Sie den gesamten Satz von Zielpositionen. Sie können also etwas binden, das in das aktuelle Objekt 0 geht, zum aktuellen Objekt 4 wechseln und ein völlig anderes Objekt ändern.
Diese Analogie mit Texturobjekten ist perfekt ... fast.
Siehe, glActiveTexture
nimmt keine ganze Zahl; es braucht einen Enumerator . Was theoretisch bedeutet, dass es alles von GL_TEXTURE0
bis nehmen kann GL_TEXTURE31
. Aber eines müssen Sie verstehen:
DAS IST FALSCH!
Die tatsächliche Reichweite, die erreicht werden glActiveTexture
kann, wird von bestimmt GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS
. Dies ist die maximale Anzahl gleichzeitiger Multitexturen, die eine Implementierung zulässt. Diese sind jeweils in verschiedene Gruppierungen für verschiedene Shader-Stufen unterteilt. Auf Hardware der GL 3.x-Klasse erhalten Sie beispielsweise 16 Vertex-Shader-Texturen, 16 Fragment-Shader-Texturen und 16 Geometrie-Shader-Texturen. Daher GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS
wird 48 sein.
Es gibt jedoch keine 48 Enumeratoren. Deshalb glActiveTexture
braucht man nicht wirklich Enumeratoren. Die richtige Art zu telefonieren glActiveTexture
ist wie folgt:
glActiveTexture(GL_TEXTURE0 + i);
wo i
ist eine Zahl zwischen 0 und GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS
.
Rendern
Was hat das alles mit dem Rendern zu tun?
Wenn Sie Shader verwenden, stellen Sie Ihre Sampler-Uniformen auf eine Texturbildeinheit ein ( glUniform1i(samplerLoc, i)
wo i
sich die Bildeinheit befindet). Das ist die Nummer, mit der Sie verwendet haben glActiveTexture
. Der Sampler wählt das Ziel basierend auf dem Sampler-Typ aus. Also wird ein sampler2D
Wille aus dem GL_TEXTURE_2D
Ziel auswählen . Dies ist ein Grund, warum Sampler unterschiedliche Typen haben.
Das klingt verdächtig, als könnten Sie zwei GLSL-Sampler mit unterschiedlichen Typen verwenden, die dieselbe Texturbildeinheit verwenden. Aber du kannst nicht; OpenGL verbietet dies und gibt beim Rendern einen Fehler aus.
GL_TEXTURE0 + i
- Ich wollte die Aufzählungswerte überprüfen, um festzustellen, ob dies gültig ist oder nicht. Und der letzte Absatz - wusste nicht, ob das legal ist oder nicht. Ausgezeichnet! Ich setze ein Lesezeichen für alle Ihre Antworten, damit ich wieder darauf verweisen kann.