【问题标题】:OpenGL texture terminology/conceptual confusionOpenGL纹理术语/概念混淆
【发布时间】:2015-08-17 20:03:29
【问题描述】:

我找到了很多资源,这些资源可以告诉您键入什么内容才能在屏幕上显示纹理,但希望对 openGL API “在做什么”以及术语的所有差异有更高层次的概念性理解“意思”。

我将尽我所能解释我所了解的内容,但希望有任何更正/添加,或指向我可以进一步阅读的资源的指针(以及我找到的文档的说明)实际的 API 调用只是在圈子中引用自己并且在概念上缺乏)。

glGenTextures- 这实际上不会为显卡上的纹理数据分配任何内存(您只需告诉它“您希望它生成多少”纹理,因此它对大小...),而是设置了一种“名称”,以便您可以一致地引用给定的纹理(我一直认为它是一种“分配指针”)。

glBindTexture- 使用在glGenTexture 中生成的“名称”来指定“我们现在正在讨论此纹理以供将来的 API 调用,直至另行通知”,此外,我们正在指定一些有关该纹理的元数据“指针”我们已经分配说它指向(/将指向)的纹理是GL_TEXTURE_2D..._3D或其他类型。 (是我一个人,还是奇怪的是这个调用有这两个看似完全不同的功能?)

glTexParameter- 设置有关当前“绑定”纹理的其他指定元数据。 (我喜欢这个 API,因为它看起来很容易解释,并且可以让你明确地设置元数据......但我想知道为什么让 OpenGL 知道它是一个 GL_TEXTURE_2D 不是这个调用的一部分,而不是之前的调用?特别是因为你有指定它是一个GL_TEXTURE_2D 无论如何你每次调用它?为什么你必须这样做?)

glTexImage2D- 为显卡上纹理的实际数据分配内存(并可选择上传)。它进一步指定了一些关于应该如何读取的元数据:它的宽度、高度、格式(GL_RGBGL_RGBA 等...)。再说一遍,为什么我再次必须指定它是GL_TEXTURE_2D,而我在之前的所有调用中都这样做了?另外,我想我可以理解为什么这包括一些元数据(而不是将所有纹理元数据调用卸载到glTexParameter,因为这些是非常基本/非可选的信息位,但也有一些奇怪的参数似乎他们应该'没有成功?哦,好吧......)

glActiveTexture- 这是我真的不明白的一点......所以我猜显卡只能有有限数量的“纹理单元”......什么是纹理单元?是不是只能有 N 个纹理缓冲区?还是只有 N 个纹理指针?或者(这是我最好的猜测......)给定的绘图调用只能主动读取 N 个指针?一旦我明白了,我必须在哪里/多久指定一次“活动纹理”? glBindTexture 是否将绑定的纹理与当前活动的纹理相关联?还是反过来(绑定,然后设置为活动)?或者上传/分配显卡内存可以做到吗?

sampler2D- 现在我们开始讨论 glsl 的东西......所以,采样器是可以从着色器中引用纹理的东西。我可以通过glGetUniformLocation 获取它的位置,所以我可以设置采样器引用的纹理——这是否对应于“活动纹理”?所以如果我想谈谈我指定为GL_TEXTURE0 的纹理,我会打电话给glUniform1i(location_of_sampler_uniform,0)?还是那两个不同的东西?

我想这就是我得到的全部......如果我明显缺少一些直觉或什么,请告诉我!谢谢!

【问题讨论】:

  • 纹理单元是一个非常以硬件为中心的概念。考虑它的最简单方法是处理一组纹理计算的 GPU 上的“处理器”。它是通过纹理处理硬件的众多途径之一。在大多数情况下,您不需要使用 glActiveTexture(),因为从您的角度来看它应该是无缝的。将 glActiveTexture() 包含在 API 中的原因是允许您进行特定于硬件的优化,例如将所有纹理保存在单个纹理单元上,但即使您不访问它,GL 驱动程序应该为您处理纹理管理。
  • @Phildo: 可能这个diagram 有点帮助。
  • @stix:如果我不需要使用 glActiveTexture,我如何为我的统一 sampler2D 指定它应该引用的纹理?我应该将 int 值设置为 glGenTextures 生成的 int 吗? @derhass:这确实有帮助-谢谢!但我仍然觉得我错过了完整的画面......
  • 我试图在这里详细回答一些术语:stackoverflow.com/questions/30960403/…

标签: opengl glsl


【解决方案1】:

让我为回答相当于一堵巨大的文字墙而道歉。我不知道如何以一种不那么令人讨厌的方式来格式化它;)

glGenTextures

这实际上不会为图形卡上的纹理数据分配任何内存(您只需告诉它“您希望它生成多少”纹理,因此它对大小一无所知...... ),而是设置了一种“名称”,以便您可以一致地引用给定的纹理(我一直认为它是一种“分配指针”)。

您或多或少可以将其视为“分配指针”。它真正做的是在纹理集中保留一个名称(句柄)。此时根本没有分配任何内容,基本上它只是标记 GL 说“你不能再分配这个名字了”。 (稍后会详细介绍)


glBindTexture

使用在 glGenTexture 中生成的“名称”来指定“我们现在正在讨论这个纹理以供将来的 API 调用,直至另行通知”,此外,我们正在指定一些关于我们已分配的“指针”的元数据说明它指向(/将指向)的纹理是 GL_TEXTURE_2D 还是 ..._3D 或其他类型。 (是我一个人,还是奇怪的是这个调用有这两个看似完全不同的功能?)

如果你还记得的话,glGenTextures (...) 只保留了一个名字。此函数采用保留名称并有效地将其最终确定为纹理对象(第一次调用它)。你在这里传递的类型是不可变的,一旦你第一次绑定一个名字,它必须为每个连续的绑定使用相同的类型。

现在您终于完成了纹理对象的分配,但此时它没有数据存储——它只是一组没有数据的状态。


glTexParameter

设置有关当前“绑定”纹理的其他指定元数据。 (我喜欢这个 API,因为它看起来很容易解释,并且可以让你明确地设置元数据......但我想知道为什么让 OpenGL 知道它是 GL_TEXTURE_2D 不是 THIS 调用的一部分,而不是之前的调用?尤其是因为你必须指定每次你调用它时它都是 GL_TEXTURE_2D?为什么你必须这样做?)

我实际上不太清楚你在这里问什么——也许我对前面函数调用的解释会对你有所帮助?但你是对的,这个函数设置与纹理对象关联的状态。


glTexImage2D

为显卡上纹理的实际数据分配内存(并可选择上传)。它进一步指定了一些关于应该如何读取的元数据:它的宽度、高度、格式(GL_RGB、GL_RGBA 等......)。再说一遍,为什么我在之前的所有调用中都必须指定它是 GL_TEXTURE_2D 呢?另外,我想我可以理解为什么这包括一些元数据(而不是将所有纹理元数据调用卸载到 glTexParameter,因为这些是非常基本/非可选的信息位,但也有一些奇怪的参数看起来不应该成功了吗?哦,好吧...)

这是分配数据存储和(可选)上传纹理数据的内容(您可以在此处为数据提供 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

这是我真的不明白的一点......所以我猜显卡只能有有限数量的“纹理单元”......什么是纹理单元?是不是只能有 N 个纹理缓冲区?还是只有 N 个纹理指针?或者(这是我最好的猜测......)给定的绘图调用只能主动读取 N 个指针?一旦我明白了,我必须在哪里/多久指定一次“活动纹理”? glBindTexture 是否将绑定的纹理与当前活动的纹理相关联?还是反过来(绑定,然后设置为活动)?或者上传/分配显卡内存可以做到吗?

这是纹理绑定的额外间接级别(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 个这样的规则。

此要求允许您有足够的绑定位置来为可编程管道的每个阶段(顶点、几何、片段 -- 3.x,曲面细分控制/评估 -- 4.0)维护一组 16 种不同的纹理。大多数实现只能在单个着色器调用中使用 16 个纹理(基本上是通过),但您总共可以选择 48 个 (GL3) 或 80 个 (GL4) 位置。


sampler2D

现在我们开始讨论 glsl 的东西......所以,采样器是一种可以从着色器中引用纹理的东西。我可以通过 glGetUniformLocation 获取它的位置,所以我可以设置采样器引用的纹理 - 这是否对应于“活动纹理”?所以如果我想谈谈我指定为 GL_TEXTURE0 的纹理,我会调用 glUniform1i(location_of_sampler_uniform,0)?还是那两个不同的东西?

是的,GLSL 中的采样器存储与 GL_TEXTUREn 对应的索引,其中 n 是您分配给此制服的值。

请注意,这些不是常规制服,它们被称为opaque types(分配的值不能在运行时从着色器中更改/分配)。您不需要知道这一点,但如果出现问题,了解这一点可能会有所帮助:

   “为什么我不能在运行时为采样器动态选择纹理图像单元?” :)

在更高版本的 OpenGL 中,采样器实际上变成了state objects of their own。它们解耦了一些过去直接与纹理对象相关的状态,但与解释纹理数据的存储方式无关。解耦状态包括纹理环绕模式、最小/放大过滤器和 mipmap 级别。 Sampler 对象不存储数据。

每当您将采样器对象绑定到纹理图像单元时,就会发生这种解耦 - 这将覆盖每个纹理对象复制的上述状态。

如此有效,GLSL sampler* 既不引用纹理也不引用采样器;它引用了一个纹理图像单元(可能有一个或两个绑定到它的东西)。 GLSL 将根据声明的sampler 类型从该单元中相应地提取采样器状态和纹理数据。

【讨论】:

    猜你喜欢
    • 2021-06-03
    • 2014-03-04
    • 1970-01-01
    • 1970-01-01
    • 2014-02-12
    • 1970-01-01
    • 2016-05-08
    • 1970-01-01
    • 2021-03-19
    相关资源
    最近更新 更多