Todo sobre los objetos OpenGL
El modelo estándar para objetos OpenGL es el siguiente.
Los objetos tienen estado. Piense en ellos como a struct
. Entonces, podría tener un objeto definido de esta manera:
struct Object
{
int count;
float opacity;
char *name;
};
El objeto tiene ciertos valores almacenados y tiene estado . Los objetos OpenGL también tienen estado.
Estado cambiante
En C / C ++, si tiene una instancia de tipo Object
, cambiaría su estado de la siguiente manera: obj.count = 5;
haría referencia directa a una instancia del objeto, obtendría la pieza de estado en particular que desea cambiar y colocará un valor en ella.
En OpenGL, no haces esto.
Por razones heredadas, es mejor dejarlo sin explicar, para cambiar el estado de un objeto OpenGL, primero debe vincularlo al contexto. Esto se hace con algunos de glBind*
llamada.
El C / C ++ equivalente a esto es el siguiente:
Object *g_objs[MAX_LOCATIONS] = {NULL};
void BindObject(int loc, Object *obj)
{
g_objs[loc] = obj;
}
Las texturas son interesantes; representan un caso especial de encuadernación. Muchas glBind*
llamadas tienen un parámetro "objetivo". Esto representa diferentes ubicaciones en el contexto de OpenGL donde se pueden vincular objetos de ese tipo. Por ejemplo, puede vincular un objeto framebuffer para lectura ( GL_READ_FRAMEBUFFER
) o para escritura ( GL_DRAW_FRAMEBUFFER
). Esto afecta la forma en que OpenGL usa el búfer. Esto es lo loc
que representa el parámetro anterior.
Las texturas son especiales porque cuando las vincula por primera vez a un objetivo, obtienen información especial. Cuando vincula una textura por primera vez GL_TEXTURE_2D
, en realidad está configurando un estado especial en la textura. Estás diciendo que esta textura es una textura 2D. Y siempre será una textura 2D; Este estado no se puede cambiar nunca . Si tiene una textura que primero se unió como a GL_TEXTURE_2D
, siempre debe unirla como a GL_TEXTURE_2D
; Si intenta vincularlo, se GL_TEXTURE_1D
producirá un error (durante el tiempo de ejecución).
Una vez que el objeto está vinculado, su estado se puede cambiar. Esto se realiza mediante funciones genéricas específicas de ese objeto. También toman una ubicación que representa qué objeto modificar.
En C / C ++, esto se ve así:
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;
}
}
Observe cómo esta función establece lo que esté en el loc
valor actualmente vinculado .
Para objetos de textura, las principales funciones de cambio de estado de textura son glTexParameter
. Las únicas otras funciones que cambian de estado textura son las glTexImage
funciones y sus variaciones ( glCompressedTexImage
, glCopyTexImage
, el reciente glTexStorage
). Las diversas SubImage
versiones cambian el contenido de la textura, pero técnicamente no cambian su estado . Las Image
funciones asignan almacenamiento de textura y establecen el formato de la textura; las SubImage
funciones solo copian píxeles. Eso no se considera el estado de la textura.
Permítanme repetir: estas son las únicas funciones que modifican el estado de la textura. glTexEnv
modifica el estado del entorno; no afecta a nada almacenado en objetos de textura.
Textura activa
La situación de las texturas es más compleja, de nuevo por razones heredadas que es mejor no revelar. Aquí es donde glActiveTexture
entra.
Para texturas, no sólo no son objetivos ( GL_TEXTURE_1D
, GL_TEXTURE_CUBE_MAP
, etc). También hay unidades de textura . En términos de nuestro ejemplo C / C ++, lo que tenemos es esto:
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;
}
Tenga en cuenta que ahora, no solo tenemos una lista 2D de Object
s, sino que también tenemos el concepto de un objeto actual. Tenemos una función para establecer el objeto actual, tenemos el concepto de un número máximo de objetos actuales, y todas nuestras funciones de manipulación de objetos se ajustan para seleccionar del objeto actual.
Cuando cambia el objeto actualmente activo, cambia todo el conjunto de ubicaciones de destino. Por lo tanto, puede vincular algo que va al objeto actual 0, cambiar al objeto actual 4 y modificará un objeto completamente diferente.
Esta analogía con los objetos de textura es perfecta ... casi.
Mira, glActiveTexture
no toma un número entero; Se necesita un enumerador . Lo que en teoría significa que puede llevar cualquier cosa desde GL_TEXTURE0
hasta GL_TEXTURE31
. Pero hay una cosa que debes entender:
¡ESTO ES FALSO!
El rango real que glActiveTexture
puede tomar se rige por GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS
. Esa es la cantidad máxima de texturas múltiples simultáneas que permite una implementación. Estos se dividen en diferentes grupos para diferentes etapas de sombreado. Por ejemplo, en el hardware de clase GL 3.x, obtiene 16 texturas de sombreador de vértices, 16 texturas de sombreador de fragmentos y 16 texturas de sombreador de geometría. Por lo tanto, GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS
será 48.
Pero no hay 48 enumeradores. Es por eso glActiveTexture
que realmente no toma enumeradores. La forma correcta de llamar glActiveTexture
es la siguiente:
glActiveTexture(GL_TEXTURE0 + i);
donde i
es un número entre 0 y GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS
.
Representación
Entonces, ¿qué tiene que ver todo esto con el renderizado?
Al usar sombreadores, configura los uniformes de muestra en una unidad de imagen de textura ( glUniform1i(samplerLoc, i)
donde i
está la unidad de imagen). Eso representa el número que usaste glActiveTexture
. La muestra elegirá el objetivo en función del tipo de muestra. Entonces a sampler2D
elegirá del GL_TEXTURE_2D
objetivo. Esta es una razón por la cual los muestreadores tienen diferentes tipos.
Ahora esto suena sospechosamente como que puede tener dos muestreadores GLSL, con diferentes tipos que usan la misma unidad de imagen de textura. Pero no puedes; OpenGL prohíbe esto y le dará un error cuando intente renderizar.
GL_TEXTURE0 + i
: quería inspeccionar los valores de enumeración para ver si eso era válido o no. Y el último párrafo: no sabía si eso era legal o no. ¡Excelente! Estoy marcando todas sus respuestas para poder consultarlas nuevamente.