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.Ich werde es versuchen ! All dies ist nicht so kompliziert, nur eine Frage der Begriffe, hoffe ich werde mich klar machen.
Sie können ungefähr so viele Texturobjekte erstellen, wie in Ihrem System Speicher verfügbar ist. Diese Objekte enthalten die tatsächlichen Daten (Texel) Ihrer Texturen sowie die von glTexParameter bereitgestellten Parameter (siehe FAQ ).
Wenn erstellt wird, müssen Sie eine zuweisen Texture Ziel einem Textur - Objekt, das den Typ der Textur darstellt (
GL_TEXTURE_2D
,GL_TEXTURE_3D
,GL_TEXTURE_CUBE
, ...).Diese beiden Elemente, Texturobjekt und Texturziel, repräsentieren die Texturdaten. Wir werden später darauf zurückkommen.
Textureinheiten
Jetzt bietet OpenGL eine Reihe von Textureinheiten , die gleichzeitig beim Zeichnen verwendet werden können. Die Größe des Arrays hängt vom OpenGL-System ab, Ihr Array hat 8.
Sie können ein Texturobjekt an eine Textureinheit binden , um die angegebene Textur beim Zeichnen zu verwenden.
In einer einfachen Welt würden Sie zum Zeichnen mit einer bestimmten Textur ein Texturobjekt an die Textureinheit binden und Folgendes tun (Pseudocode):
Da der GL eine Zustandsmaschine ist, funktioniert er leider nicht auf diese Weise. Angenommen, wir
textureObject
haben Daten für dasGL_TEXTURE_2D
Texturziel, drücken wir die vorherige Zuordnung wie folgt aus:Beachten Sie, dass dies
GL_TEXTURE_2D
wirklich von der Art der Textur abhängt, die Sie binden möchten.Texturobjekte
Im Pseudocode würden Sie zum Festlegen von Texturdaten oder Texturparametern beispielsweise Folgendes tun:
OpenGL kann Texturobjekte nicht direkt manipulieren, um ihren Inhalt zu aktualisieren / einzustellen oder ihre Parameter zu ändern. Sie müssen sie zuerst an die aktive Textureinheit binden (je nachdem, um welche es sich handelt). Der entsprechende Code lautet:
Shader
Shader haben Zugriff auf alle Textureinheiten, die aktive Textur ist ihnen egal.
Sampler-Uniformen sind
int
Werte, die den Index der für den Sampler zu verwendenden Textureinheit darstellen (und nicht das zu verwendende Texturobjekt).Sie müssen also Ihre Texturobjekte an die Einheiten binden, die Sie verwenden möchten.
Der Typ des Samplers stimmt mit dem Texturziel überein, das in der Textureinheit verwendet wird:
Sampler2D
fürGL_TEXTURE_2D
usw.quelle
Stellen Sie sich die GPU wie eine Lackieranlage vor.
Es gibt eine Reihe von Tanks, die Farbstoffe an einige Lackiermaschinen liefern. In der Lackiermaschine wird der Farbstoff dann auf das Objekt aufgetragen. Diese Tanks sind die Textureinheiten
Diese Tanks können mit verschiedenen Farbstoffen ausgestattet werden. Jede Art von Farbstoff erfordert eine andere Art von Lösungsmittel. Das "Lösungsmittel" ist das Texturziel . Der Einfachheit halber ist jeder Tank an eine Lösungsmittelversorgung angeschlossen, und in jedem Tank kann jeweils nur eine Art von Lösungsmittel verwendet werden. So gibt es ein Ventil / Schalter
TEXTURE_CUBE_MAP
,TEXTURE_3D
,TEXTURE_2D
,TEXTURE_1D
. Sie können alle Farbstofftypen gleichzeitig in den Tank füllen. Da jedoch nur eine Art von Lösungsmittel eindringt, wird nur die Art der Farbstoffanpassung "verdünnt". Sie können also jede Art von Textur binden lassen, aber die Bindung mit dem "wichtigsten" Lösungsmittel wird tatsächlich in den Tank gelangen und sich mit der Art des Farbstoffs mischen, zu dem sie gehört.Und dann ist da noch der Farbstoff selbst, der aus einem Lager stammt und durch "Binden" in den Tank gefüllt wird. Das ist deine Textur.
quelle
Wenn Sie in Ihrem Shader nach 2 Texturen suchen müssen:
Für tex1 und tex2 müssen die Quellen wie folgt angegeben werden:
in der Render-Schleife:
Mit einer gl_bindtexture ist so etwas nicht möglich. Andererseits ist eine mögliche Verwendung einer Bindung in der Rendering-Schleife der Fall, wenn Sie eine Textur mit einem Inhalt im Stream (Video, Webcam) füttern:
quelle