通过 glTexSubImage3d 上传纹理数据时,像素传输格式可以改变吗?

Posted

技术标签:

【中文标题】通过 glTexSubImage3d 上传纹理数据时,像素传输格式可以改变吗?【英文标题】:Can the pixel transfer format change when uploading texture data via glTexSubImage? 【发布时间】:2014-11-12 09:25:57 【问题描述】:

我面临的情况是,为了兼容性,我首先分配纹理的存储空间,然后将纹理数据上传到其中。这个想法是根据是否支持不可变存储来保持代码路径相似。

在没有不可变存储的情况下,存储通过glTexImage2D 调用分配(使用 NULL 数据指针,没有像素解包缓冲区绑定),例如:

glTexImage2D(GL_TEXTURE_2D, 0,
             GL_RGBA,                           
             width, height, 0,
             GL_RGBA,                           
             GL_UNSIGNED_BYTE,
             0);

在此之后,实际数据被上传:

glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
                width, height,
                GL_RGBA,
                GL_UNSIGNED_BYTE,
                data);

问题是:在上传时,像素传输格式可以不同于分配存储时指定的格式吗?有些驱动认为可以,有些驱动(特别是:ANGLE)认为不可以。

换句话说,这个调用应该起作用吗?

glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
                width, height,
                GL_RGBA,
                GL_FLOAT, // <-- DIFFERENT
                data);

根据我对 OpenGL 4.5 规范的解释,是的。不仅glTexSubImage2D 应该与不可变纹理一起使用(并且在glTexStorage 调用中没有指定像素传输格式); 4.5 规范在第 8.6 节(强调我的)中说:

TexSubImage*D 和 TextureSubImage*D 参数宽度、高度、深度、格式、类型和数据与对应的 TexImage*D 命令(存在这些参数)的相应参数相匹配,这意味着 它们接受相同值,含义相同。

对我来说,这意味着“它们接受相同的值集”(有效值中的任何值),而不是“它们接受传递给 glTexImage*D 的完全相同的值”。

在 OpenGL ES 2.0 规范中,措辞略有不同:

TexSubImage2D 参数宽度、高度、格式、类型和数据与 TexImage2D 的相应参数匹配,这意味着它们使用相同的值指定,并且具有相同的含义。

再一次,对我来说,这并不意味着像素传输格式必须匹配,只是接受的值来自同一个集合。


那么,我的解释正确吗?


附录

我一直在研究 OpenGL 手册页。现在当然它们不是规范的(规范是),但是 ES2/3 手册页和 OpenGL 4.5 手册页之间存在显着差异:

GLES 2:https://www.khronos.org/opengles/sdk/docs/man/xhtml/glTexImage2D.xml GLES 3:https://www.khronos.org/opengles/sdk/docs/man3/html/glTexImage2D.xhtml GL 4.5:https://www.opengl.org/sdk/docs/man/html/glTexImage2D.xhtml

请注意,在 GLES3 案例中,有这样的措辞:“internalFormat 可能是显示的未调整大小的(基本)内部格式之一,以及有效的格式和类型组合”,强烈暗示确实使用三元组来分配存储空间.

不过,GLES3 也有开箱即用的不可变存储,所以这没有任何意义...

但无论如何,这使我对glTexImage2D 的调用完全合法。然后,有问题的调用变成了glTexSubImage2D

GLES 2:https://www.khronos.org/opengles/sdk/docs/man/xhtml/glTexSubImage2D.xml GLES 3:https://www.khronos.org/opengles/sdk/docs/man3/html/glTexSubImage2D.xhtml

在那里,引用内部格式的唯一错误条件是 GLES 2 中的:

GL_INVALID_OPERATION 如果纹理数组未被先前的glTexImage2DglCopyTexImage2D 操作定义,其internalformat 匹配glTexSubImage2D格式 .

这在 GLES 3 中:

GL_INVALID_OPERATION如果之前指定的纹理数组的internalFormatformattype的组合无效则生成。见glTexImage2D

这再次意味着我的解释是正确的:传递给glTexSubImage2D 的格式+类型的组合,加上传递给glTexImage2D 的内部格式,确实是glTexImage2D 文档中列出的有效组合。

【问题讨论】:

【参考方案1】:

那么,我的解释正确吗?

一句话:是的。它被称为内部格式像素数据格式是有原因的。 ANGLE 是 OpenGL-ES 的仿真,因此遵循为此指定的规范和行为。这与您的观察一致。

【讨论】:

对不起,什么是“一致的”?我解释 OpenGL ES 2.0 规范的方式与解释 OpenGL 4.5 的方式相同——“使用相同的值”意味着“接受来自同一组的值”。所以 ANGLE 的行为在这里是有问题的。 @peppe:我必须仔细阅读 ES 规范的那部分内容。 在原帖中添加了一些内容。 @peppe:OpenGL ES 与桌面 GL 的不同之处在于它不支持像素传输期间的数据转换。您的内部格式必须与像素数据格式匹配,这就是 ES 手册页中有entire tables dedicated to matching formats 的原因。这一切都归结为简化 ES 中的实现,并且在像素传输期间转换图像格式会增加许多不必要的复杂性,这显然只在桌面 GL 中值得;) @AndonM.Coleman:这也是我最初对 ES 规范措辞的解释。

以上是关于通过 glTexSubImage3d 上传纹理数据时,像素传输格式可以改变吗?的主要内容,如果未能解决你的问题,请参考以下文章

glTexSubImage3D vs QOpenGLTexture setData

Opengl Array Texture,适用于原始数据,但不适用于图像数据

ThreeJS 为 .obj 上传多个纹理

有没有办法用纹理一次上传 obj 和 mtl 文件

如何将带有 mtl 和纹理的 obj 上传到存储桶?

正确使用 QT 包装器上传 3D 纹理