Diferencias y relación entre glActiveTexture y glBindTexture


De lo que deduzco, glActiveTexture establece la "unidad de textura"activa. Cada unidad de textura puede tener múltiples objetivos de textura (generalmente GL_TEXTURE_1D, 2D, 3D o CUBE_MAP).

Si entiendo correctamente, tienes que llamar a glActiveTexture para establecer la unidad de textura primero (inicializada a GL_TEXTURE0), y luego enlazar (uno o más) "objetivos de textura" a esa unidad de textura?

El número de unidades de textura disponibles depende del sistema. Veo enumeraciones de hasta 32 en mi biblioteca. Supongo que esto esencialmente significa que puedo tener el menor de los límites de mi GPU (que creo que es 16 8) y 32 texturas en la memoria de la GPU en cualquier momento? Supongo que hay un límite adicional que no exceda la memoria máxima de mi GPU (supuestamente 1 GB).

¿Estoy entendiendo correctamente la relación entre los objetivos de textura y las unidades de textura? Digamos que me permiten 16 unidades y 4 objetivos cada uno, ¿eso significa que hay espacio para 16 * 4 = 64 objetivos, o no funciona así?

A continuación, normalmente desea cargar un textura. Puede hacer esto a través de glTexImage2D. El primer argumento de los cuales es un objetivo de textura. Si esto funciona como glBufferData, a continuación, esencialmente vinculamos el "handle" / "texture name" al destino de textura, y luego cargamos los datos de textura en ese destino, y por lo tanto los asociamos indirectamente con ese destino.

¿Qué pasa con glTexParameter? Tenemos que enlazar un objetivo de textura, y luego elegir ese mismo objetivo de nuevo como el primer argumento? O no es necesario que el objetivo de textura esté enlazado mientras tengamos el ¿unidad de textura activa correcta?

glGenerateMipmap opera en un objetivo también...¿ese objetivo aún tiene que estar vinculado al nombre de la textura para que tenga éxito?

Entonces, cuando queremos dibujar nuestro objeto con una textura en él, tenemos que ambos elegir una unidad de textura activa, y luego un objetivo de textura? ¿O elegimos una unidad de textura, y luego podemos tomar datos de cualquiera de los 4 objetivos asociados con esa unidad? Esta es la parte que realmente me confunde.

Author: Community, 2012-01-15

4 answers

Todo sobre los Objetos OpenGL

El modelo estándar para objetos OpenGL es el siguiente.

Los objetos tienen estado. Piensa en ellos como un struct. Así que podrías tener un objeto definido así:

struct Object
{
    int count;
    float opacity;
    char *name;
};

El objeto tiene ciertos valores almacenados en él 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; Se referiría directamente a un instancia del objeto, obtener la pieza particular de estado que desea cambiar, y empujar un valor en él.

En OpenGL, no hacer esto.

Por razones heredadas que es mejor dejar 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 llamadas glBind* tienen un parámetro "target". Esto representa diferentes ubicaciones en el contexto OpenGL donde se pueden enlazar objetos de ese tipo. Por ejemplo, puede enlazar un objeto framebuffer para leer (GL_READ_FRAMEBUFFER) o para escribir (GL_DRAW_FRAMEBUFFER). Esto afecta a cómo OpenGL usa el búfer. Esto es lo que representa el parámetro loc anterior.

Las texturas son especiales porque cuando primero las vinculas a un objetivo, obtienen información especial. Cuando se une por primera vez una textura como GL_TEXTURE_2D, se en realidad están estableciendo 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 fue enlazada primero como GL_TEXTURE_2D, debe siempre enlazarla como GL_TEXTURE_2D; intentar enlazarla como GL_TEXTURE_1D dará lugar a un error (mientras se ejecuta).

Una vez que el objeto está enlazado, su estado puede ser cambiado. Esto se hace a través de funciones genéricas específicas para que objeto. También toman una ubicación que representa qué objeto modificar.

En C / C++, esto se ve como:

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 sucede que está en el valor actualmente enlazado loc.

Para los objetos de textura, las principales funciones de cambio de estado de textura son glTexParameter. Las únicas otras funciones que cambian el estado de textura son glTexImage funciones y sus variaciones (glCompressedTexImage, glCopyTexImage, el reciente glTexStorage). Las distintas versiones SubImage cambian el contenido de la textura, pero técnicamente no cambian su estado . Las funciones Image asignan el almacenamiento de texturas y establecen el formato de la textura; las funciones SubImage simplemente copian píxeles. Eso no se considera el estado de la textura.

Permítanme repetir: estas son las solo funciones que modifican el estado de textura. glTexEnv modifica el estado del entorno; no afecta a nada almacenado en la textura objeto.

Textura activa

La situación para las texturas es más compleja, de nuevo por razones heredadas que es mejor dejar sin revelar. Aquí es donde glActiveTexture entra.

Para las texturas, no hay solo objetivos (GL_TEXTURE_1D, GL_TEXTURE_CUBE_MAP, etc). También hay texture units . En términos de nuestro ejemplo de 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;
}

Observe que ahora, no solo tenemos una lista 2D de Object s, sino que también tenemos el concepto de un objeto actual. Tenemos un 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. Así que puede enlazar algo que entra en el objeto actual 0, cambiar al objeto actual 4, y estará modificando un objeto completamente diferente.

Esta analogía con los objetos de textura es perfecta... Casi.

Véase, glActiveTextureno toma un entero; toma un enumerador. Lo que en teoría significa que puede tomar cualquier cosa de GL_TEXTURE0 a 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. Ese es el número máximo de multitexturas simultáneas que permite una implementación. Estos se dividen en diferentes grupos para diferentes etapas de sombreado. Para ejemplo, en la LG 3.hardware de clase x, obtienes 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 que glActiveTexture realmente no toma enumeradores. La correcta forma 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.

Rendering

Entonces, ¿qué tiene que ver todo esto con el renderizado?

Cuando usando shaders, usted establece sus uniformes sampler a una unidad de imagen de textura (glUniform1i(samplerLoc, i), donde i es la unidad de imagen). Eso representa el número que usaste con glActiveTexture. El muestreador elegirá el objetivo basado en el tipo de muestreador. Así que un sampler2D escogerá del objetivo GL_TEXTURE_2D. Esta es una de las razones por las que los muestreadores tienen diferentes tipos.

Ahora esto suena sospechosamente como si pudieras tener dos samplers 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.

 217
Author: Nicol Bolas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-07 13:44:10

¡Lo intentaré! Todo esto no es tan complicado, solo una cuestión de términos, espero que me aclare.


Puede crear aproximadamente tantos Objetos de textura como memoria disponible en su sistema. Estos objetos contienen los datos reales (texels) de sus texturas, junto con los parámetros, proporcionados por glTexParameter (ver FAQ).

Cuando se crea, debe asignar un Destino de textura a un objeto de textura, que representa el tipo de la textura (GL_TEXTURE_2D, GL_TEXTURE_3D, GL_TEXTURE_CUBE, ...).

Estos dos elementos, texture object y texture target representan los datos de textura. Volveremos con ellos más tarde.

Unidades de textura

Ahora, OpenGL proporciona una matriz de unidades de textura, que se pueden usar simultáneamente mientras se dibuja. El tamaño de la matriz depende del sistema OpenGL, el suyo tiene 8.

Puede enlazar un objeto de textura a una unidad de textura para usar la textura dada durante el dibujo.

En un mundo simple y fácil, para dibujar con una textura dada, se uniría un objeto de textura a la unidad de textura, y se haría (pseudocódigo):

glTextureUnit[0] = textureObject

Como GL es una máquina de estados, por desgracia, no funciona de esta manera. Suponiendo que nuestro textureObject tiene datos para el objetivo de textura GL_TEXTURE_2D, expresaremos la asignación anterior como:

glActiveTexture(GL_TEXTURE0);                   // select slot 0 of the texture units array
glBindTexture(GL_TEXTURE_2D, textureObject);    // do the binding

Tenga en cuenta que GL_TEXTURE_2D realmente depende del tipo de textura que desea unir.

Objetos de textura

En pseudo código, para establecer datos de textura o parámetros de textura, haría por ejemplo:

setTexData(textureObject, ...)
setTexParameter(textureObject, TEXTURE_MIN_FILTER, LINEAR)

OpenGL no puede manipular directamente objetos de textura, para actualizar/establecer su contenido o cambiar sus parámetros, primero debe vincularlos a la unidad de textura activa (lo que sea). El código equivalente se convierte en :

glBindTexture(GL_TEXTURE_2D, textureObject)       // this 'installs' textureObject in texture unit
glTexImage2D(GL_TEXTURE_2D, ...)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)

Shaders

Los shaders tienen acceso a todas las unidades de textura, no les importa textura activa.

Los uniformes del muestreador son int valores que representan el índice de la unidad de textura a usar para el muestreador (y no el objeto de textura a usar).

Por lo tanto, debe vincular sus objetos de textura a las unidades que desea usar.

El tipo del sampler hará la coincidencia con el objetivo de textura que se utiliza en la unidad de textura : Sampler2D para GL_TEXTURE_2D, y así sucesivamente...

 15
Author: rotoglup,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-23 04:38:30

Imagina la GPU como una planta de procesamiento de pintura.

Hay una serie de tanques, que entrega tinte a alguna máquina de pintura. En la máquina de pintura, el tinte se aplica al objeto. Esos tanques son las unidades de textura

Esos tanques pueden estar equipados con diferentes tipos de tinte. Cada tipo de tinte requiere algún otro tipo de disolvente. El" disolvente " es el objetivo de textura. Para mayor comodidad, cada tanque está conectado a un suministro de solvente, y solo uno tipo de disolvente se puede utilizar a la vez en cada tanque. Así que hay una válvula, interruptor TEXTURE_CUBE_MAP, TEXTURE_3D, TEXTURE_2D, TEXTURE_1D. Puede llenar todos los tipos de tinte en el tanque al mismo tiempo, pero como solo entra un tipo de disolvente, "diluirá" solo el tipo de tinte que coincida. Por lo tanto, puede tener cada tipo de textura encuadernada, pero la unión con el disolvente "más importante" en realidad irá al tanque y se mezclará con el tipo de tinte al que pertenece.

Y luego está el tinte en sí, que proviene de un almacén y se llena en el tanque "atándolo". Esa es tu textura.

 12
Author: datenwolf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-23 04:38:51

Si en tu sombreador necesitas buscar 2 texturas:

uniform sampler2D tex1;  
uniform sampler2D tex2;  

Es necesario indicar para tex1 y tex2 sus fuentes de la siguiente manera:

tex1 = gl.createTexture();  
gl.activeTexture(gl.TEXTURE3);  
gl.bindTexture(gl.TEXTURE_2D, tex1); 
gl.texParameteri(gl.TEXTURE_2D, ...);  
....


tex2 = gl.createTexture();  
gl.activeTexture(gl.TEXTURE7);  
gl.bindTexture(gl.TEXTURE_2D, tex2); 
gl.texParameteri(gl.TEXTURE_2D, ...);  
....  
var tex1Loc  = gl.getUniformLocation(your_shader,"tex1");  
var tex2Loc  = gl.getUniformLocation(your_shader,"tex2");

En el bucle de renderizado :

gl.uniform1i(tex1Loc, 3);  
gl.uniform1i(tex2Loc, 7);  
// but you can dynamically change these values

Con una gl_bindtexture, no es posible hacer tal cosa. Por otro lado, un posible uso de un bind en el bucle de renderizado, es el caso en el que alimentas una textura con un contenido en stream (video, webcam):

gl.bindTexture(gl.TEXTURE_2D, tex1);  
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, video);  
// in the render loop
 1
Author: Philippe Oceangermanique,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-07-20 19:49:58