我正在阅读以下声明。有时我会引用
OpenGL 4.5核心规范中的内容进行辩论。这些内容并不特定于GL 4.5,我选择它只是因为这是最新版本。
1. 将两个纹理绑定到同一纹理单元是不可能的。
如果我说"false",可能会误导人。确切的陈述是“将两个纹理绑定到同一纹理单元的相同目标是不可能的”。技术上说,您可以说将2D纹理和3D纹理绑定到同一单元。但是您不能在同一绘制调用中同时使用两者。请注意,这是一个动态错误条件,取决于您将采样器uniform设置为什么值。从GL规范的第7.10节“采样器”中引用:
不允许将不同采样器类型的变量指向程序对象内的相同纹理图像单元。此情况仅能在下一个触发着色器调用的渲染命令中检测到,并且将生成一个INVALID_OPERATION
错误。
因此,GL将在您尝试绘制某些东西(或以其他方式触发着色器调用)时检测到此错误条件,而您配置了该着色器,使得两个采样器uniform引用同一单元的不同目标。但在之前不是错误。如果您暂时将两个uniform都设置为相同的值,但不尝试在该状态下进行绘制,则永远不会生成错误。
2. 将两个采样器绑定到相同的纹理单元是不可能的。
您可能指的是
采样器对象(与GLSL中的“sampler”类型相对),因此这是正确的。
3. 将一个纹理绑定到两个不同的纹理单元是不可能的。
假的。您可以将相同的纹理对象绑定到所有可用的单元。但是,这是一个非常无用的操作。在固定功能管道的时代,有一些极端情况下这是有限制使用的。例如,我曾看到有人将相同的纹理绑定两次,并使用寄存器组合器将两个纹理相乘,因为他需要某种平方运算。但是,使用着色器,您可以对纹理进行一次采样,然后对结果进行任何操作,因此没有用例留下。
4. 将一个采样器绑定到两个不同的纹理单元是不可能的。
假的。可以通过多个纹理单元引用单个采样器对象。您只需为每个需要的采样状态创建采样器对象,无需创建冗余采样器对象。
5. 应用程序应清楚地知道将哪种采样器类型传递给哪个统一变量。
6. 着色器程序必须确保将采样器作为正确类型的统一变量使用。
我不太确定您在这里究竟要求什么。着色器中的采样器变量选择纹理目标,并且还必须与您想要使用的纹理对象的内部数据格式匹配(例如,对于isampler
或usampler
,您需要非规范化的整数纹理格式,否则结果是未定义的)。
但是我不知道“将哪种采样器类型传递给哪个统一变量”在这里意味着什么。就GL客户端而言,不透明的采样器统一变量只是可以设置为要使用的纹理单元索引的东西,而且可以通过glUniform1i
等方式以整数形式进行设置。没有将“采样器类型”传递给统一变量。
7. 纹理单元的数量足够大。让每个加载到应用程序的网格占用尽可能多的纹理单元。
通常情况下不是这样。 GL 4.5规范中定义的GL_MAX_TEXTURE_IMAGE_UNITS
(它定义了片段着色器可以访问多少个不同的纹理单元)仅为16。(每个着色器阶段都有单独的限制,因此有GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS
,GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS
等等。在当前规范中,它们都必须至少为16。)
通常情况下,您需要在绘制调用之间切换纹理。使用数组纹理和纹理地图可能允许进一步减少所需状态切换的数量(最终减少绘制调用次数)。
非常现代的GPU还支持GL_ARB_bindless_texture,它完全绕过了“纹理单元”间接层,并允许着色器通过某些不透明句柄直接引用纹理对象(这基本上归结为引用底层虚拟GPU内存地址)。但是,该功能尚未成为OpenGL标准的一部分。
8. 一些采样器参数是纹理参数的重复。它们将覆盖纹理参数设置。
是的。传统上,GL中没有单独的采样器对象。相反,过滤或包裹模式等采样器状态是纹理对象本身的一部分。但现代硬件不是这样工作的,因此采样器对象API已被引入作为
GL_ARB_sampler_objects
扩展(现在是GL的核心功能)。如果将采样器对象绑定到纹理单元,则其设置将覆盖纹理对象中存在的采样器状态。
9. 一些采样器参数与着色器程序中的采样器描述重复。着色器程序的描述将覆盖采样器参数。
我不确定您的意思是什么。着色器程序定义了什么“采样器描述”?只有uniform的声明和可能通过
layout(binding=...)
进行初始化。然而,那只是初始值。客户端可以随时通过将uniform设置为另一个值来更新它,因此它实际上并没有“覆盖”任何内容。但我不确定您是否是这个意思。