2

我正在为 Mac OS >= 10.6 编写一个应用程序,它从磁盘加载的图像创建 OpenGL 纹理。

首先,我将图像加载到 NSImage 中。然后我从图像中获取 NSBitmapImageRep 并使用 glTexImage2D 将像素数据加载到纹理中。

对于 RGB 或 RGBA 图像,它可以完美运行。我可以传入 3 字节/像素的 RGB 或 4 字节的 RGBA,并创建一个 4 字节/像素的 RGBA 纹理。

然而,我刚刚让一个测试员给我发了一张似乎有 ARGB 字节顺序的 JPEG 图像(在佳能 EOS 50D 上拍摄,不确定它是如何导入的)。

我在这个线程上找到了一个帖子:(http://www.cocoabuilder.com/archive/cocoa/12782-coregraphics-over-opengl.html)这表明我将GL_BGRA的格式参数指定为glTexImage2D,并且类型为GL_UNSIGNED_INT_8_8_8_8_REV。

这似乎合乎逻辑,并且似乎应该有效,但事实并非如此。我得到不同但仍然错误的颜色值。

我编写了“swizzling”(手动字节交换)代码,将 ARGB 图像数据洗牌到一个新的 RGBA 缓冲区中,但是这种逐字节的混合对于大图像来说会很慢。

我也想了解如何使这项工作“以正确的方式”。

将 ARGB 数据加载到 RGBA OpenGL 纹理中的技巧是什么?

我当前对 xxx 的调用如下所示:

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, newWidth, newHeight, 0, format, GL_UNSIGNED_BYTE, pixelBuffer);

其中是 RGB 或 RGBA。

我尝试使用:

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, newWidth, newHeight, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, pixelBuffer);

当我的图像代表报告它是“alpha first”顺序时。

作为第二个问题,我还读到大多数显卡的“本机”格式是 GL_BGRA,因此以该格式创建纹理会导致更快的纹理绘制。纹理绘制的速度比加载纹理的速度更重要,因此预先将数据“混合”为 BGRA 格式是值得的。我尝试通过指定 GL_RGBA 的“内部格式”来要求 OpenGL 创建 BGRA 纹理,但这会导致图像完全变黑。我对文档的解释使我期望 glTexImage2D 会在读取数据时对数据进行字节交换,如果源格式和内部格式不同,但是当我尝试指定“内部格式”时,我得到一个 OpenGL 错误 0x500 (GL_INVALID_ENUM) GL_RGBA。我错过了什么?

4

4 回答 4

4

我不知道将 ARGB 数据直接加载到纹理中的方法,但是有比仅在 CPU 上进行调配更好的解决方法。你可以在 GPU 上非常有效地做到这一点:

  1. 将 ARGB 数据加载到临时 RGBA 纹理中。
  2. 使用此纹理绘制一个全屏四边形,同时使用简单的像素着色器渲染到目标纹理中。
  3. 继续加载其他资源,无需停止 GPU 管道。

像素着色器示例:

#version 130
uniform sampler2DRect unit_in;
void main() {
    gl_FragColor = texture( unit_in, gl_FragCoord.xy ).gbar;
}
于 2011-02-10T16:32:26.640 回答
1

你用OpenGL渲染它,对吧?如果您想以简单的方式做到这一点,您可以让像素着色器实时调整颜色。这对于显卡来说完全没有问题,它们是用来做更复杂的事情的:)。

您可以使用这样的着色器:

uniform sampler2D image;
void main()
{
    gl_FragColor = texture2D(image, gl_FragCoord.xy).gbar;
}

如果您不了解着色器,请在此处阅读此 tut:http ://www.lighthouse3d.com/opengl/glsl/

于 2011-02-10T17:08:03.460 回答
1

这个问题很老,但如果其他人正在寻找这个问题,我发现了一个不严格安全但有效的解决方案。问题是每个 32 位 RGBA 值都将 A 作为第一个字节而不是最后一个字节。

NBitmapImageRep.bitmapData 为您提供了一个指向您提供给 OpenGL 作为其像素指针的第一个字节的指针。只需将 1 添加到该指针,然后以正确的顺序指向 RGB 值,最后一个像素的 A。

这样做的问题是最后一个像素将从图像末尾之外的一个字节中获取 A 值,并且 A 值都是一个像素。但就像提问者一样,我在加载 JPG 时得到了这个,所以无论如何 alpha 是无关紧要的。这似乎不会导致问题,但我不会声称它是“安全的”。

于 2015-01-28T01:50:38.233 回答
0

数据为 ARGB 格式的纹理的名称。

GLuint argb_texture;

在一个函数调用中设置 ARGB swizzle 的标记数组。

static const GLenum argb_swizzle[] =
{
   GL_GREEN, GL_BLUE, GL_ALPHA, GL_RED
};

绑定 ARGB 纹理

glBindTexture(GL_TEXTURE_2D, argb_texture);

一次调用 glTexParameteriv 设置所有四个 swizzle 参数

glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, argb_swizzle);

我知道这项工作,但我不确定 argb_swizzle 的顺序是否正确。如果这不正确,请纠正我。我不太清楚 argb_swizzle 中的 GL_GREEN、G​​L_BLUE、GL_ALPHA、GL_RED 是如何确定的。

正如OpenGL 编程指南所建议的:

...这是一种机制,允许您在图形硬件读取纹理数据时动态重新排列纹理数据的组件顺序。

于 2020-01-30T17:32:06.267 回答