glTexImage2D 何时发生钳位

Posted

技术标签:

【中文标题】glTexImage2D 何时发生钳位【英文标题】:glTexImage2D When Exactly Does Clamping Happen 【发布时间】:2014-02-02 22:37:22 【问题描述】:

我见过 (several) (semi)-(related) (posts) (about) 这个,但没有人直接回答以下问题:

glTexImage.D 究竟何时将输入值钳制为 [0,1]?

文档似乎暗示它总是会这样做(除了 GL_DEPTH_STENCIL 可能的例外,我似乎记得它是不允许的,尽管文档不支持这一点)。这就是我目前在我的代码中处理它的方式。

其他链接来源似乎表明,当数据转换为标准化颜色格式时,数据被精确钳制,或者仅在图像格式为整数时才被钳制。为了证实这一点,我测试了一个 GL_RGBAF32 内部格式:负浮点数据被限制为 0,而正数据根本不被限制。

然后是(所有组合)无符号/有符号规范化/非规范化整数内部格式。

那么,什么时候像素解包,特别是glTexImage.D,钳位数据?我对GL_((R|RG|RGB|RGBA)((8|16|32)(|I|UI|_SNORM)|(16F|32F))|DEPTH_COMPONENT(16|24|32))(即所有颜色浮点和整数纹理,以及所有深度纹理)特别感兴趣,但可能应该解决所有内部格式。

【问题讨论】:

【参考方案1】:

从技术上讲,它不需要夹紧任何东西。

定义此行为的一个地方是像素传输操作。换句话说,如果内部格式和您传输到纹理中的数据格式不同,那么可能会发生很多有趣的事情,包括缩放/钳制到某个范围。如果您正确匹配内部格式和像素传输格式,您可以避免图像数据的隐式标准化和钳位,因为不需要转换。

当然,像素传输只是钳位的一种来源。在 GL4.3 中,您可以在多个纹理对象之间共享底层数据存储,并使用 texture views 更改兼容图像类的内部格式(例如任何 32 位纹理格式)。例如,这可用于在采样时将 UNORM 图像数据重新解释为 SNORM。


我可能应该解释一下GL_RGB8 之类的东西是定点的……更具体地说,它是无符号归一化(UNORM)。如果您要使用GL_RGBA 作为像素传输格式和GL_UNSIGNED_BYTE 作为数据类型将图像数据传输到GL_RGBA32F 图像,GL 会将其解释为从GL_RGBA8(源格式)到GL_RGBA32F(内部格式)。

在 GLES 中,您必须始终匹配这些格式,因为像素传输转换未定义。但是,在桌面 GL 中,此示例将仅生成 [0.0, 1.0] 范围内的值。如果您希望范围为 [-1.0, 1.0],则需要使用 SNORM 格式。

如果您尝试从具有不同内部格式和目标格式的纹理中读取,它也可以反过来工作。如果您想在纹理中输入/输出正确的值,则需要避免像素传输转换。


OpenGL 4.4 Core Profile Specification - 8.5 纹理图像规范 - pp. 183

8.4.4.2 转换为浮点数

此步骤仅适用于浮点组件组。它不在索引或整数分量上执行。对于同时包含组件和索引的组,例如GL_DEPTH_STENCIL,不会转换索引。

组中的每个元素都转换为浮点值。对于无符号或有符号整数元素,方程 2.12.2 分别是用过。

该规范稍后会进一步阐明所有类别的图像数据的这种行为:

OpenGL 4.4 Core Profile Specification - 8.5 纹理图像规范 - pp. 184

按照部分 8.4.4中的描述将所选组传输到GL,然后钳制到内部格式的可表示范围.如果纹理的内部格式是有符号或无符号整数,则组件被限制为 [-2n-1, 2n-1 - 1] 或 [0, 2n - 1],其中 n 是每个分量的位数.对于颜色分量组,如果纹理的内部格式是有符号或无符号归一化定点,则分量被钳制为 [-1, 1] 或 [0 1]。对于深度组件组,深度值被限制为 [0, 1]。否则,不会修改值。模板索引值被 2n - 1 屏蔽,其中 n 是内部格式分辨率中的模板位数(见下文)。如果基本内部格式是GL_DEPTH_STENCIL 并且格式不是GL_DEPTH_STENCIL,则模板索引纹理组件的值未定义。

【讨论】:

以上是关于glTexImage2D 何时发生钳位的主要内容,如果未能解决你的问题,请参考以下文章

最大钳位电压和额定钳位电压

C++ 库中有任何内置的钳位方法吗?

这个函数有啥作用?与钳位值有关吗?

钳位幅度不适用于 RigidBody.Velocity

python 钳位价值

glTexImage2D() 函数访问冲突错误