将 GLubyte* 转换为 GLuint* 用于 alpha 纹理 Opengl 3.0 / c++ / Win32
Posted
技术标签:
【中文标题】将 GLubyte* 转换为 GLuint* 用于 alpha 纹理 Opengl 3.0 / c++ / Win32【英文标题】:convert GLubyte* to GLuint* for alpha texturing Opengl 3.0 / c++ / Win32 【发布时间】:2015-05-09 12:39:26 【问题描述】:我的目标是使纹理的像素值 100% 透明,如果它与设置的 RGB 颜色完全匹配。我的程序使用 24 位 .bmp 图像,我知道它不包含第四个通道(除了填充),所以我一直在尝试想出一个好方法来促进添加 alpha 通道以执行基本透明度。
我了解如何计算实际 alpha 值并正确设置混合函数,但是当我尝试将第四个值添加到 GLubyte RGB 三元组时遇到了障碍,让我相信该格式根本不支持α。所以我有一个想法,将纹理数据从字节手动转换为 32 位无符号整数,但我在执行时遇到了问题。在我看来(从看书)内部像素格式 GL_UNSIGNED_INT 每个像素需要四个 32 位整数,但是当我通过将 0.0-1.0 字节值钳制到最大范围来转换字节时,我的程序不会启动无符号整数。
我不想给我答案,但我真的很感激朝着正确的方向前进。我是否在正确的轨道上转换为每像素 4 个整数,或者有没有办法让 alpha 与我忽略的字节数据一起工作?我考虑过使用 GL_UNSIGNED_INT_8888 格式,但我想尽可能避免移位。
【问题讨论】:
您在尝试添加GLubyte
格式的alpha 时遇到了什么问题?真的不应该有什么。您只需每个 texel 有 4 个字节,之前每个 texel 有 3 个字节,并将格式指定为 RGBA 而不是 RGB。
【参考方案1】:
GL_UNSIGNED_INT
不是“内部像素格式”。那实际上是像素传输数据类型。
多年来,GL 中的内部格式一直是个谜,您必须请求组件的数量,但除此之外别无其他。现在(GL3+)你必须使用明确大小的内部格式,比如GL_RGB8
,这样就可以排除大部分猜测。但是,您仍然可以假设 GL_RGB8
将被驱动程序用额外的 8 位填充,以便每种颜色都以 2 的幂边界开始。因此GL_RGB8
与GL_RGBA8
具有相同的存储要求,两者之间的唯一区别是GL_RGB8
具有所有不透明像素。
当您使用GL_UNSIGNED_INT
作为像素传输的数据类型时,这意味着 GL 会将您的输入图像数据解释为具有 32 位(无符号)每颜色分量(每像素 12 字节)。您不希望这样,您目前每个像素有 3 个无符号 8 位分量,因此 GL_UNSIGNED_BYTE
是合适的(每像素 3 个字节)。 添加第 4 个组件不会改变各个组件的大小。
关于GL_UNSIGNED_INT_8_8_8_8
,如果您尝试上传RGBA 图像,这实际上与GL_UNSIGNED_BYTE
略有不同。这就是所谓的打包数据类型; 4 个组件封装在与GL_UNSIGNED_INT
相同的封装中,每个组件都是 8 位的。还有GL_UNSIGNED_INT_8_8_8_8_REV
,它更有用——它告诉GL在像素传输期间反转颜色分量,如果你只指定GL_UNSIGNED_BYTE
作为数据类型,这是你无法做到的。 GL_UNSIGNED_INT_8_8_8_8[_REV]
解决了 CPU 字节顺序问题,在 little-endian CPU 上,GL_UNSIGNED_INT_8_8_8_8_REV
等效于 GL_UNSIGNED_BYTE
。
请记住,GL 要求图像的每一行都以 4 字节边界开始。
如果您有一个宽度不能被 4 整除的每像素 24 位图像,那么您的数据将会错位,并且 GL 会错误地解压它。要解决这个问题,您可以将解包对齐设置为 1-byte(默认为 4),如下所示:
glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
.bmp 文件格式已经填充了每一行的末尾以满足 4 字节对齐,这只是我想指出的完整性。
【讨论】:
至于您的问题的其余部分,您正在寻找颜色键透明度。您可以预处理数据以插入 alpha 组件,也可以使用片段着色器来完成。我会亲自对数据进行预处理,因为RGB
图像在 GPU 上无论如何都会填充到RGBA
,所以你不妨使用否则浪费的内存。
至少在如今流行的小端架构上,我相信8_8_8_8_REV
相当于BYTE
。 8_8_8_8
是字节交换的那个。
如果您查看规范(例如 3.3 规范中的第 131 页),第一个组件位于 _REV
格式的位 0-7 中。如果主机格式是小端,那也是UNSIGNED_BYTE
的第一个字节。在任何 Intel 机器上试一试,你会发现 GL_UNSIGNED_BYTE
和 GL_UNSIGNED_INT_8_8_8_8_REV
产生相同的结果。
@RetoKoradi:啊,是的。你说得对,我在想别的。受GL_UNPACK_SWAP_BYTES
影响的是多字节组件格式(例如GL_UNSIGNED_SHORT
)。【参考方案2】:
它应该是直截了当的,不需要任何技巧。有两种方法可以实现您所需要的。第一个解决方案是简单地将 bmp 加载为正常的 RGB 数据,然后为 alpha 通道分配一个额外 30% 大小的新缓冲区,并且对于您复制的每 3 个字节,添加一个表示您想要的 alpha 值的字节。然后在上传到 OpenGL 设备时,声明它是 GL_RGBA 而不是 GL_RGB,同时保持格式为 GL_UNSIGNED_BYTE。这样,您可以在加载时将数据从 3 个通道转换为 4 个通道。第二种解决方案是在片段着色器中执行片段丢弃,因为丢弃与 100% 透明相同。由于您知道要丢弃哪种颜色,您可以使用统一或任何其他方式将这些 rgb 值传递给着色器,然后片段着色器可以检查并相应地丢弃。您甚至不必担心此解决方案中的 Alpha 通道。
【讨论】:
以上是关于将 GLubyte* 转换为 GLuint* 用于 alpha 纹理 Opengl 3.0 / c++ / Win32的主要内容,如果未能解决你的问题,请参考以下文章