glActiveTexture 和 glBindTexture 的区别和关系 [英] Differences and relationship between glActiveTexture and glBindTexture

查看:34
本文介绍了glActiveTexture 和 glBindTexture 的区别和关系的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

据我所知,glActiveTexture 设置了活动的纹理单元".每个纹理单元可以有多个纹理目标(通常是 GL_TEXTURE_1D、2D、3D 或 CUBE_MAP).

From what I gather, glActiveTexture sets the active "texture unit". Each texture unit can have multiple texture targets (usually GL_TEXTURE_1D, 2D, 3D or CUBE_MAP).

如果我理解正确,你必须先调用glActiveTexture来设置纹理单元(初始化为GL_TEXTURE0),然后你绑定(一个或多个)纹理目标"到那个纹理单元?

If I understand correctly, you have to call glActiveTexture to set the texture unit first (initialized to GL_TEXTURE0), and then you bind (one or more) "texture targets" to that texture unit?

可用纹理单元的数量取决于系统.我在我的库中看到了多达 32 个的枚举.我想这基本上意味着我可以在任何时候在 GPU 内存中拥有 GPU 的限制(我认为是 16 8)和 32 个纹理中的较小者?我想还有一个额外的限制,即我不超过 GPU 的最大内存(应该是 1 GB).

The number of texture units available is system dependent. I see enums for up to 32 in my library. I guess this essentially means I can have the lesser of my GPU's limit (which I think is 16 8) and 32 textures in GPU memory at any one time? I guess there's an additional limit that I don't exceed my GPU's maximum memory (supposedly 1 GB).

我是否正确理解了纹理目标和纹理单元之间的关系?假设我允许每个单位有 16 个单位和 4 个目标,这是否意味着有空间容纳 16*4=64 个目标,还是不能这样工作?

Am I understanding the relationship between texture targets and texture units correctly? Let's say I'm allowed 16 units and 4 targets each, does that mean there's room for 16*4=64 targets, or does it not work like that?

接下来,您通常要加载纹理.您可以通过 glTexImage2D 执行此操作.其中的第一个参数是纹理目标.如果这个 glBufferData 一样工作,那么我们本质上绑定了句柄"/纹理名称"到纹理目标,然后将纹理数据加载到该目标中,从而间接将其与该句柄关联.

Next you typically want to load a texture. You can do this via glTexImage2D. The first argument of which is a texture target. If this works like glBufferData, then we essentially bind the "handle"/"texture name" to the texture target, and then load the texture data into that target, and thus indirectly associate it with that handle.

glTexParameter 怎么样?我们必须绑定一个纹理目标,然后再次选择相同的目标作为第一个参数?还是只要我们有正确的活动纹理单元就不需要绑定纹理目标?

What about glTexParameter? We have to bind a texture target, and then choose that same target again as the first argument? Or does the texture target not need to be bound as long as we have the correct active texture unit?

glGenerateMipmap 也对目标进行操作...该目标仍必须绑定到纹理名称才能成功?

glGenerateMipmap operates on a target too...that target has to still be bound to the texture name for it to succeed?

然后,当我们想要绘制带有纹理的对象时,我们是否必须两者选择一个活动纹理单元,然后选择一个纹理目标?还是我们选择一个纹理单元,然后我们可以从与该单元关联的 4 个目标中的任何一个获取数据?这是真正让我感到困惑的部分.

Then when we want to draw our object with a texture on it, do we have to both choose an active texture unit, and then a texture target? Or do we choose a texture unit, and then we can grab data from any of the 4 targets associated with that unit? This is the part that's really confusing me.

推荐答案

关于 OpenGL 对象的全部

OpenGL 对象的标准模型如下.

All About OpenGL Objects

The standard model for OpenGL objects is as follows.

对象有状态.将它们视为 struct.所以你可能有一个这样定义的对象:

Objects have state. Think of them as a struct. So you might have an object defined like this:

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

该对象存储了某些值,并且具有状态.OpenGL 对象也有状态.

The object has certain values stored in it and it has state. OpenGL objects have state too.

在 C/C++ 中,如果你有一个 Object 类型的实例,你会改变它的状态如下:obj.count = 5; 你会直接引用一个对象的实例,获取您要更改的特定状态,然后将值推入其中.

In C/C++, if you have an instance of type Object, you would change its state as follows: obj.count = 5; You would directly reference an instance of the object, get the particular piece of state you want to change, and shove a value into it.

在 OpenGL 中,您不会这样做.

In OpenGL, you don't do this.

由于遗留原因最好不要解释,要更改 OpenGL 对象的状态,您必须首先将其绑定到上下文.这是通过一些来自 glBind* 调用完成的.

For legacy reasons better left unexplained, to change the state of an OpenGL object, you must first bind it to the context. This is done with some from of glBind* call.

与此等效的 C/C++ 如下:

The C/C++ equivalent to this is as follows:

Object *g_objs[MAX_LOCATIONS] = {NULL};    
void BindObject(int loc, Object *obj)
{
  g_objs[loc] = obj;
}

纹理很有趣;它们代表了一种特殊的绑定情况.许多 glBind* 调用都有一个目标"参数.这表示 OpenGL 上下文中可以绑定该类型对象的不同位置.例如,您可以绑定一个帧缓冲区对象用于读取 (GL_READ_FRAMEBUFFER) 或写入 (GL_DRAW_FRAMEBUFFER).这会影响 OpenGL 使用缓冲区的方式.这就是上面的 loc 参数所代表的内容.

Textures are interesting; they represent a special case of binding. Many glBind* calls have a "target" parameter. This represents different locations in the OpenGL context where objects of that type can be bound. For example, you can bind a framebuffer object for reading (GL_READ_FRAMEBUFFER) or for writing (GL_DRAW_FRAMEBUFFER). This affects how OpenGL uses the buffer. This is what the loc parameter above represents.

纹理很特别,因为当您第一次将它们绑定到目标时,它们会获得特殊信息.当您第一次将纹理绑定为 GL_TEXTURE_2D 时,您实际上是在纹理中设置特殊状态.你是说这个纹理是一个 2D 纹理.并且它总是是一个 2D 纹理;这个状态不能改变永远.如果您的纹理首先绑定为 GL_TEXTURE_2D,则必须始终将其绑定为 GL_TEXTURE_2D;尝试将其绑定为 GL_TEXTURE_1D 将导致错误(在运行时).

Textures are special because when you first bind them to a target, they get special information. When you first bind a texture as a GL_TEXTURE_2D, you are actually setting special state in the texture. You are saying that this texture is a 2D texture. And it will always be a 2D texture; this state cannot be changed ever. If you have a texture that was first bound as a GL_TEXTURE_2D, you must always bind it as a GL_TEXTURE_2D; attempting to bind it as GL_TEXTURE_1D will give rise to an error (while run-time).

一旦对象被绑定,它的状态就可以改变.这是通过特定于该对象的通用函数完成的.它们也采用代表要修改的对象的位置.

Once the object is bound, its state can be changed. This is done via generic functions specific to that object. They too take a location that represents which object to modify.

在 C/C++ 中,这看起来像:

In C/C++, this looks like:

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;
  }
}

注意这个函数如何设置当前绑定的 loc 值.

Notice how this function sets whatever happens to be in currently bound loc value.

对于纹理对象,主要的纹理状态改变函数是glTexParameter.改变纹理状态的唯一其他函数是 glTexImage 函数及其变体(glCompressedTexImageglCopyTexImage,最近的glTexStorage).各种SubImage 版本会更改纹理的内容,但在技术上不会更改其状态.Image 函数分配纹理存储并设置纹理的格式;SubImage 函数只是复制周围的像素.这不被视为纹理的状态.

For texture objects, the main texture state changing functions are glTexParameter. The only other functions that change texture state are the glTexImage functions and their variations (glCompressedTexImage, glCopyTexImage, the recent glTexStorage). The various SubImage versions change the contents of the texture, but they do not technically change its state. The Image functions allocate texture storage and set the texture's format; the SubImage functions just copy pixels around. That is not considered the texture's state.

请允许我重复一遍:这些是修改纹理状态的唯一函数.glTexEnv 修改环境状态;它不会影响存储在纹理对象中的任何内容.

Allow me to repeat: these are the only functions that modify texture state. glTexEnv modifies environment state; it doesn't affect anything stored in texture objects.

纹理的情况更加复杂,同样出于遗留原因,最好不要公开.这就是 glActiveTexture 的用武之地.

The situation for textures is more complex, again for legacy reasons best left undisclosed. This is where glActiveTexture comes in.

对于纹理,不仅仅是目标(GL_TEXTURE_1DGL_TEXTURE_CUBE_MAP 等).还有纹理单位.就我们的 C/C++ 示例而言,我们拥有的是:

For textures, there aren't just targets (GL_TEXTURE_1D, GL_TEXTURE_CUBE_MAP, etc). There are also texture units. In terms of our C/C++ example, what we have is this:

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;
}

请注意,现在我们不仅有 Object 的二维列表,而且还有当前对象的概念.我们有一个设置当前对象的函数,我们有当前对象的最大数量的概念,我们所有的对象操作函数都调整为从当前对象中选择.

Notice that now, we not only have a 2D list of Objects, but we also have the concept of a current object. We have a function to set the current object, we have the concept of a maximum number of current objects, and all of our object manipulation functions are adjusted to select from the current object.

当您更改当前活动的对象时,您将更改整个目标位置集.所以你可以绑定一些进入当前对象 0 的东西,切换到当前对象 4,并且将修改一个完全不同的对象.

When you change the currently active object, you change the entire set of target locations. So you can bind something that goes into current object 0, switch to current object 4, and will be modifying a completely different object.

这个与纹理对象的类比是完美的......几乎.

This analogy with texture objects is perfect... almost.

看,glActiveTexture 不接受整数;它需要一个枚举器.这在理论上意味着它可以接受从 GL_TEXTURE0GL_TEXTURE31 的任何内容.但是,您必须了解一件事:

See, glActiveTexture does not take an integer; it takes an enumerator. Which in theory means that it can take anything from GL_TEXTURE0 to GL_TEXTURE31. But there's one thing you must understand:

这是假的!

glActiveTexture 的实际范围由 GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 控制.这是实现允许的最大同时多纹理数.对于不同的着色器阶段,它们每个都分为不同的组.例如,在 GL 3.x 类硬件上,您将获得 16 个顶点着色器纹理、16 个片段着色器纹理和 16 个几何着色器纹理.因此,GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 将为 48.

The actual range that glActiveTexture can take is governed by GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS. That is the maximum number of simultaneous multitextures that an implementation allows. These are each divided up into different groupings for different shader stages. For example, on GL 3.x class hardware, you get 16 vertex shader textures, 16 fragment shader textures, and 16 geometry shader textures. Therefore, GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS will be 48.

但是没有 48 个枚举器.这就是 glActiveTexture 并不真正采用枚举器的原因.正确调用glActiveTexture的方法如下:

But there aren't 48 enumerators. Which is why glActiveTexture doesn't really take enumerators. The correct way to call glActiveTexture is as follows:

glActiveTexture(GL_TEXTURE0 + i);

其中 i 是一个介于 0 和 GL_MAX_COMBIED_TEXTURE_IMAGE_UNITS 之间的数字.

where i is a number between 0 and GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS.

那么所有这些与渲染有什么关系?

So what does all of this have to do with rendering?

使用着色器时,您将采样器统一设置为纹理图像单元(glUniform1i(samplerLoc, i),其中 i 是图像单元).这表示您与 glActiveTexture 一起使用的数字.采样器将根据采样器类型选择目标.所以 sampler2D 将从 GL_TEXTURE_2D 目标中选择.这是采样器具有不同类型的原因之一.

When using shaders, you set your sampler uniforms to a texture image unit (glUniform1i(samplerLoc, i), where i is the image unit). That represents the number you used with glActiveTexture. The sampler will pick the target based on the sampler type. So a sampler2D will pick from the GL_TEXTURE_2D target. This is one reason why samplers have different types.

现在这听起来很可疑,就像您可以有两个 GLSL 采样器,它们具有使用相同纹理图像单元的不同类型.但你不能;OpenGL 禁止这样做,并且在您尝试渲染时会给您一个错误.

Now this sounds suspiciously like you can have two GLSL samplers, with different types that use the same texture image unit. But you can't; OpenGL forbids this and will give you an error when you attempt to render.

这篇关于glActiveTexture 和 glBindTexture 的区别和关系的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆