OpenGL 纹理 terminology/conceptual 混乱
OpenGL texture terminology/conceptual confusion
我找到了很多资源,它们告诉您要在屏幕上输入什么才能获得纹理,但我想更深入地了解 openGL API 是什么 "doing" 和术语的所有差异 "mean".
我将尽我所能解释我所收集的内容,但我会喜欢任何 corrections/additions,或指向我可以进一步阅读的资源的指针(以及我已经发现实际 API 调用的文档只是在圈子中引用自己并且在概念上是缺乏的)。
glGenTextures
- 这实际上不会为显卡上的纹理数据分配任何内存(您只需告诉它 "how many" 您希望它生成的纹理,所以它不会'我对大小一无所知...),而是将 "name" 放在一边,这样您就可以一致地引用给定的纹理(我一直认为它是 "allocating a pointer" 的一种)。
glBindTexture
- 使用 glGenTexture
中生成的 "name" 来指定 "we're now talking about this texture for future API calls until further notice",此外,我们正在指定一些关于 "pointer" 的元数据我们已经分配说明它指向(/将指向)的纹理是类型 GL_TEXTURE_2D
还是 ..._3D
或其他类型。 (是我一个人,还是觉得这个调用有这两个看似完全不同的功能很奇怪?)
glTexParameter
- 设置有关当前 "bound" 纹理的其他指定元数据。 (我喜欢这个 API,因为它看起来非常不言自明,并且允许您显式设置元数据......但我想知道为什么让 OpenGL 知道它是 GL_TEXTURE_2D
不是 THIS 调用的一部分,而不是以前的?特别是因为你每次调用它时都必须指定它是一个 GL_TEXTURE_2D
?为什么你必须这样做?)
glTexImage2D
- 为显卡上纹理的实际数据分配内存(并可选择上传)。它进一步指定了一些关于应该如何读取的元数据:它的宽度、高度、格式(GL_RGB
、GL_RGBA
等)。再一次,为什么我 again 必须指定它是一个 GL_TEXTURE_2D
,而我在之前的所有调用中都这样做了?另外,我想我可以理解为什么这包括一些元数据(而不是将所有纹理元数据调用卸载到 glTexParameter
因为这些是相当 fundamental/non-optional 位的信息,但也有一些奇怪的参数看起来像他们不应该晋级?哦好吧...)
glActiveTexture
-这是我真的不明白的一点……所以我猜显卡只能有有限数量的"texture units"……什么是纹理单元?是不是只能有N个纹理缓冲区?或者只有 N 个纹理指针?或者(这是我最好的猜测......)给定的绘制调用只能主动读取 N 个指针?一旦我明白了,where/how 通常我必须指定 "Active Texture"? glBindTexture
是否将绑定纹理与当前活动纹理相关联?还是相反(绑定,然后设置为活动状态)?还是 uploading/allocating 显卡内存可以做到这一点?
sampler2D
- 现在我们开始研究 glsl 的东西了……所以,采样器是一种可以从着色器中引用纹理的东西。我可以通过 glGetUniformLocation
获取它的位置,所以我可以设置采样器引用的纹理 - 这是否对应于 "Active Texture"?所以如果我想谈论我指定为 GL_TEXTURE0
的纹理,我会调用 glUniform1i(location_of_sampler_uniform,0)
?或者这两个是不同的东西?
我想这就是我的全部...如果我明显缺少一些直觉或其他东西,请告诉我!谢谢!
让我为回答了一大堆文字而道歉。我想不出如何格式化这种不那么令人讨厌的方式;)
glGenTextures
this won't actually allocate any memory for the data of a texture on the graphics card (you just tell it "how many" textures you want it to generate, so it doesn't know anything about the size...), but instead sets kind of a "name" aside so you can reference given textures consistently (I've been thinking of it as kind of "allocating a pointer").
你或多或少可以把它想象成"allocating a pointer."它真正做的是在纹理集中保留一个名称(句柄)。此时什么都没有分配,基本上它只是标记 GL 说 "you can't hand out this name anymore." (稍后详细介绍).
glBindTexture
use the "name" generated in glGenTexture to specify that "we're now talking about this texture for future API calls until further notice", and further, we're specifying some metadata about that "pointer" we've allocated saying whether the texture it points to (/will point to) is of type GL_TEXTURE_2D or ..._3D or whatever. (Is it just me, or is it weird that this call has those two seemingly totally different functionalities?)
如果您还记得的话,glGenTextures (...)
只保留了一个名称。此函数采用保留名称并有效地将其最终确定为纹理对象(第一次调用)。您在此处传递的类型是不可变的,一旦您第一次绑定名称,它必须为每个后续绑定使用相同的类型。
现在您终于完成了纹理对象的分配,但此时它还没有数据存储 -- 它只是一组没有数据的状态。
glTexParameter
sets other specified metadata about the currently "bound" texture. (I like this API as it seems pretty self explanatory and lets you set metadata explicitly... but I wonder why letting OpenGL know that it's a GL_TEXTURE_2D isn't part of THIS call, and not the previous? Especially because you have to specify that it's a GL_TEXTURE_2D every time you call this anyways? And why do you have to do that?)
其实我不太清楚你在这里问的是什么 -- 也许我对前面函数调用的解释对你有帮助?但你是对的,这个函数设置与纹理对象关联的状态。
glTexImage2D
allocates the memory for the actual data for the texture on the graphics card (and optionally uploads it). It further specifies some metadata regarding how it ought be read: its width, height, formatting (GL_RGB, GL_RGBA, etc...). Now again, why do I again have to specify that it's a GL_TEXTURE_2D when I've done it in all the previous calls? Also, I guess I can understand why this includes some metadata (rather than offloading ALL the texture metadata calls to glTexParameter as these are pretty fundamental/non-optional bits of info, but there are also some weird parameters that seem like they oughtn't have made the cut? oh well...)
这是分配数据存储和(可选)上传纹理数据的地方(您可以在此处提供 NULL
数据,然后选择稍后使用 glTexSubImage2D (...)
完成数据上传)。
您必须在此处指定纹理目标,因为有六种不同类型的纹理使用 2D 数据存储。说明这一点的最简单方法是立方体贴图。
立方体贴图的类型为 GL_TEXTURE_CUBE_MAP
,但您不能使用 GL_TEXTURE_CUBE_MAP
上传其纹理数据——那是荒谬的。相反,您在立方体贴图绑定到 GL_TEXTURE_CUBE_MAP
时调用 glTexImage2D (...)
,然后传递类似 GL_TEXTURE_CUBE_MAP_POSITIVE_X
的内容来指示您正在引用立方体贴图的 6 个 2D 面中的哪一个。
glActiveTexture
this is the bit that I really don't get... So I guess graphics cards are capable of having only a limited number of "texture units"... what is a texture unit? Is it that there can only be N texture buffers? Or only N texture pointers? Or (this is my best guess...) there can only be N pointers being actively read by a given draw call? And once I get that, where/how often to I have to specify the "Active Texture"? Does glBindTexture associate the bound texture with the currently active texture? Or is it the other way around (bind, then set active)? Or does uploading/allocating the graphics card memory do that?
这是纹理绑定的附加间接级别(GL 并不总是有多个纹理单元,您必须执行多个渲染过程才能应用多个纹理)。
引入多纹理后,绑定纹理实际上开始以这种方式工作:
glBindTexture (target, name) => ATIU.targets [target].bound = name
Where:
* ATIU is the active texture image unit
* targets is an array of all possible texture types that can be bound to this unit
* bound is the name of the texture bound to ATIU.targets [target]
自 OpenGL 3.0 以来的规则是,系统中的每个着色器阶段至少有 16 个这样的规则。
此要求允许您有足够的绑定位置来为可编程管道的每个阶段维护一组 16 个不同的纹理(顶点、几何体、片段 -- 3.x、曲面细分控制/评估 -- 4.0)。大多数实现只能在单个着色器调用中使用 16 个纹理(基本上通过),但是您总共有 48 (GL3) 或 80 (GL4) 个位置可以 select。
sampler2D
now we're getting into glsl stuff... So, a sampler is a thing that can reference a texture from within a shader. I can get its location via glGetUniformLocation, so I can set which texture that sampler is referencing- does this correspond to the "Active Texture"? So if I want to talk about the texture I've specified as GL_TEXTURE0, I'd call glUniform1i(location_of_sampler_uniform,0)? Or are those two different things?
是的,GLSL 中的采样器存储对应于 GL_TEXTUREn
的索引,其中 n 是您分配给此统一的值。
请注意,这些不是常规制服,它们被称为 opaque types(在 运行 时间的着色器中分配的值不能是 changed/assigned)。您不需要知道这一点,但如果出现问题,了解这一点可能会有所帮助:
"Why can't I dynamically select a texture image unit for my sampler at run-time?" :)
在后来的 OpenGL 版本中,采样器实际上变成了 state objects of their own。它们解耦了一些过去直接绑定到纹理对象但与解释纹理数据存储方式无关的状态。解耦状态包括纹理环绕模式、min/mag 过滤器和 mipmap 级别等内容。 采样器对象不存储任何数据。
每当您将采样器对象绑定到纹理图像单元时,就会发生这种解耦 - 这将覆盖上述由每个纹理对象复制的状态。
如此有效,GLSL sampler*
既不引用纹理也不引用采样器;它引用一个纹理图像单元(它可能绑定了其中一个或两个)。 GLSL 将根据声明的 sampler
类型相应地从该单元中提取采样器状态和纹理数据。
我找到了很多资源,它们告诉您要在屏幕上输入什么才能获得纹理,但我想更深入地了解 openGL API 是什么 "doing" 和术语的所有差异 "mean".
我将尽我所能解释我所收集的内容,但我会喜欢任何 corrections/additions,或指向我可以进一步阅读的资源的指针(以及我已经发现实际 API 调用的文档只是在圈子中引用自己并且在概念上是缺乏的)。
glGenTextures
- 这实际上不会为显卡上的纹理数据分配任何内存(您只需告诉它 "how many" 您希望它生成的纹理,所以它不会'我对大小一无所知...),而是将 "name" 放在一边,这样您就可以一致地引用给定的纹理(我一直认为它是 "allocating a pointer" 的一种)。
glBindTexture
- 使用 glGenTexture
中生成的 "name" 来指定 "we're now talking about this texture for future API calls until further notice",此外,我们正在指定一些关于 "pointer" 的元数据我们已经分配说明它指向(/将指向)的纹理是类型 GL_TEXTURE_2D
还是 ..._3D
或其他类型。 (是我一个人,还是觉得这个调用有这两个看似完全不同的功能很奇怪?)
glTexParameter
- 设置有关当前 "bound" 纹理的其他指定元数据。 (我喜欢这个 API,因为它看起来非常不言自明,并且允许您显式设置元数据......但我想知道为什么让 OpenGL 知道它是 GL_TEXTURE_2D
不是 THIS 调用的一部分,而不是以前的?特别是因为你每次调用它时都必须指定它是一个 GL_TEXTURE_2D
?为什么你必须这样做?)
glTexImage2D
- 为显卡上纹理的实际数据分配内存(并可选择上传)。它进一步指定了一些关于应该如何读取的元数据:它的宽度、高度、格式(GL_RGB
、GL_RGBA
等)。再一次,为什么我 again 必须指定它是一个 GL_TEXTURE_2D
,而我在之前的所有调用中都这样做了?另外,我想我可以理解为什么这包括一些元数据(而不是将所有纹理元数据调用卸载到 glTexParameter
因为这些是相当 fundamental/non-optional 位的信息,但也有一些奇怪的参数看起来像他们不应该晋级?哦好吧...)
glActiveTexture
-这是我真的不明白的一点……所以我猜显卡只能有有限数量的"texture units"……什么是纹理单元?是不是只能有N个纹理缓冲区?或者只有 N 个纹理指针?或者(这是我最好的猜测......)给定的绘制调用只能主动读取 N 个指针?一旦我明白了,where/how 通常我必须指定 "Active Texture"? glBindTexture
是否将绑定纹理与当前活动纹理相关联?还是相反(绑定,然后设置为活动状态)?还是 uploading/allocating 显卡内存可以做到这一点?
sampler2D
- 现在我们开始研究 glsl 的东西了……所以,采样器是一种可以从着色器中引用纹理的东西。我可以通过 glGetUniformLocation
获取它的位置,所以我可以设置采样器引用的纹理 - 这是否对应于 "Active Texture"?所以如果我想谈论我指定为 GL_TEXTURE0
的纹理,我会调用 glUniform1i(location_of_sampler_uniform,0)
?或者这两个是不同的东西?
我想这就是我的全部...如果我明显缺少一些直觉或其他东西,请告诉我!谢谢!
让我为回答了一大堆文字而道歉。我想不出如何格式化这种不那么令人讨厌的方式;)
glGenTextures
this won't actually allocate any memory for the data of a texture on the graphics card (you just tell it "how many" textures you want it to generate, so it doesn't know anything about the size...), but instead sets kind of a "name" aside so you can reference given textures consistently (I've been thinking of it as kind of "allocating a pointer").
你或多或少可以把它想象成"allocating a pointer."它真正做的是在纹理集中保留一个名称(句柄)。此时什么都没有分配,基本上它只是标记 GL 说 "you can't hand out this name anymore." (稍后详细介绍).
glBindTexture
use the "name" generated in glGenTexture to specify that "we're now talking about this texture for future API calls until further notice", and further, we're specifying some metadata about that "pointer" we've allocated saying whether the texture it points to (/will point to) is of type GL_TEXTURE_2D or ..._3D or whatever. (Is it just me, or is it weird that this call has those two seemingly totally different functionalities?)
如果您还记得的话,glGenTextures (...)
只保留了一个名称。此函数采用保留名称并有效地将其最终确定为纹理对象(第一次调用)。您在此处传递的类型是不可变的,一旦您第一次绑定名称,它必须为每个后续绑定使用相同的类型。
现在您终于完成了纹理对象的分配,但此时它还没有数据存储 -- 它只是一组没有数据的状态。
glTexParameter
sets other specified metadata about the currently "bound" texture. (I like this API as it seems pretty self explanatory and lets you set metadata explicitly... but I wonder why letting OpenGL know that it's a GL_TEXTURE_2D isn't part of THIS call, and not the previous? Especially because you have to specify that it's a GL_TEXTURE_2D every time you call this anyways? And why do you have to do that?)
其实我不太清楚你在这里问的是什么 -- 也许我对前面函数调用的解释对你有帮助?但你是对的,这个函数设置与纹理对象关联的状态。
glTexImage2D
allocates the memory for the actual data for the texture on the graphics card (and optionally uploads it). It further specifies some metadata regarding how it ought be read: its width, height, formatting (GL_RGB, GL_RGBA, etc...). Now again, why do I again have to specify that it's a GL_TEXTURE_2D when I've done it in all the previous calls? Also, I guess I can understand why this includes some metadata (rather than offloading ALL the texture metadata calls to glTexParameter as these are pretty fundamental/non-optional bits of info, but there are also some weird parameters that seem like they oughtn't have made the cut? oh well...)
这是分配数据存储和(可选)上传纹理数据的地方(您可以在此处提供 NULL
数据,然后选择稍后使用 glTexSubImage2D (...)
完成数据上传)。
您必须在此处指定纹理目标,因为有六种不同类型的纹理使用 2D 数据存储。说明这一点的最简单方法是立方体贴图。
立方体贴图的类型为 GL_TEXTURE_CUBE_MAP
,但您不能使用 GL_TEXTURE_CUBE_MAP
上传其纹理数据——那是荒谬的。相反,您在立方体贴图绑定到 GL_TEXTURE_CUBE_MAP
时调用 glTexImage2D (...)
,然后传递类似 GL_TEXTURE_CUBE_MAP_POSITIVE_X
的内容来指示您正在引用立方体贴图的 6 个 2D 面中的哪一个。
glActiveTexture
this is the bit that I really don't get... So I guess graphics cards are capable of having only a limited number of "texture units"... what is a texture unit? Is it that there can only be N texture buffers? Or only N texture pointers? Or (this is my best guess...) there can only be N pointers being actively read by a given draw call? And once I get that, where/how often to I have to specify the "Active Texture"? Does glBindTexture associate the bound texture with the currently active texture? Or is it the other way around (bind, then set active)? Or does uploading/allocating the graphics card memory do that?
这是纹理绑定的附加间接级别(GL 并不总是有多个纹理单元,您必须执行多个渲染过程才能应用多个纹理)。
引入多纹理后,绑定纹理实际上开始以这种方式工作:
glBindTexture (target, name) => ATIU.targets [target].bound = name
Where:
* ATIU is the active texture image unit
* targets is an array of all possible texture types that can be bound to this unit
* bound is the name of the texture bound to ATIU.targets [target]
自 OpenGL 3.0 以来的规则是,系统中的每个着色器阶段至少有 16 个这样的规则。
此要求允许您有足够的绑定位置来为可编程管道的每个阶段维护一组 16 个不同的纹理(顶点、几何体、片段 -- 3.x、曲面细分控制/评估 -- 4.0)。大多数实现只能在单个着色器调用中使用 16 个纹理(基本上通过),但是您总共有 48 (GL3) 或 80 (GL4) 个位置可以 select。
sampler2D
now we're getting into glsl stuff... So, a sampler is a thing that can reference a texture from within a shader. I can get its location via glGetUniformLocation, so I can set which texture that sampler is referencing- does this correspond to the "Active Texture"? So if I want to talk about the texture I've specified as GL_TEXTURE0, I'd call glUniform1i(location_of_sampler_uniform,0)? Or are those two different things?
是的,GLSL 中的采样器存储对应于 GL_TEXTUREn
的索引,其中 n 是您分配给此统一的值。
请注意,这些不是常规制服,它们被称为 opaque types(在 运行 时间的着色器中分配的值不能是 changed/assigned)。您不需要知道这一点,但如果出现问题,了解这一点可能会有所帮助:
"Why can't I dynamically select a texture image unit for my sampler at run-time?" :)
在后来的 OpenGL 版本中,采样器实际上变成了 state objects of their own。它们解耦了一些过去直接绑定到纹理对象但与解释纹理数据存储方式无关的状态。解耦状态包括纹理环绕模式、min/mag 过滤器和 mipmap 级别等内容。 采样器对象不存储任何数据。
每当您将采样器对象绑定到纹理图像单元时,就会发生这种解耦 - 这将覆盖上述由每个纹理对象复制的状态。
如此有效,GLSL sampler*
既不引用纹理也不引用采样器;它引用一个纹理图像单元(它可能绑定了其中一个或两个)。 GLSL 将根据声明的 sampler
类型相应地从该单元中提取采样器状态和纹理数据。