在OS X上加载表面时,SDL2预乘Alpha通道?

问题描述 投票:3回答:1

我正在加载32位RGBA法线贴图纹理,在alpha通道中编码高度贴图,通过OS X Sierra上的SDL2 2.0.7和SDL2_image 2.0.2。

这些纹理中的每个像素都具有非零RGB值,编码方向法向量。 (0,0,0)(即黑色)的方向矢量无效。

然而,当我通过SDL2_image加载这样的纹理时,alpha值为0的纹理区域也会产生0的RGB值。我认为SDL可能预先乘以这些像素的alpha值?

附加是这些法线贴图纹理之一。您可以通过打开例如纹理来确认它是否有效。 GIMP并在其中一个透明区域使用颜色选择器。实际上,您会看到透明区域仍然具有蓝色(编码法线向量)的RGB颜色。

32 bit RGBA normalmap with alpha-encoded heightmap for parallax mapping

以下是一个最小的测试用例,说明了附加的PNG文件的问题:

#include <SDL_image.h>
#include <assert.h>

int main(int argc, char **argv) {

    SDL_Surface *s = IMG_Load("green3_2_nm.png");
    assert(s);

    for (int i = 0; i < s->w * s->h; i++) {
        const Uint32 *in = (Uint32 *) (s->pixels + i * s->format->BytesPerPixel);

        SDL_Color color;
        SDL_GetRGBA(*in, s->format, &color.r, &color.g, &color.b, &color.a);

        assert(color.r || color.g || color.b);
    }

    SDL_FreeSurface(s);

    return 0;
}

我正在用gcc $(pkg-config --cflags --libs sdl2_image) test.c编译这个测试用例

第15行的断言将使几行失败进入图像 - 即确切地说α值下降到0的位置。

我尝试了TGA和PNG图像格式,但SDL对它们都做了同样的事情。

这是SDL中的错误,还是我错过了什么?我很好奇人们是否也在其他平台上看到同样的问题。

===

答:Core Graphics是Apple OS X上SDL2_image的默认图像加载后端,确实预先乘以alpha - 总是。解决方案是在没有Core Graphics支持的情况下重新编译SDL2_image,而是启用libpng,libjpeg和您需要的任何其他图像编解码器:

./configure \
--disable-imageio \
--disable-png-shared \
--disable-tif-shared \
--disable-jpg-shared \
--disable-webp-shared

在我的系统上,我必须禁用Core Graphics(imageio)以及其他编解码器的共享库加载,如您所见。这产生了一个脂肪SDL2_image.so,与libpng,libjpg等静态相关..但是按预期工作。

c image sdl sdl-2
1个回答
3
投票

SDL_image是特定于平台的图像加载代码的包装器,而不是在所有平台上使用相同的图像加载器。

  • Linux:LibPNG,LibJPEG
  • macOS,iOS:核心图形
  • Windows:WinCodec

这样做的好处是可以减小SDL_image的大小,因为它不需要附带任何图像解码代码,而是可以动态地链接到已经安装在系统上的东西。但是,在macOS和iOS上,Core Graphics不支持非预乘alpha,因此SDL_image必须将其反转。

请参阅:2007年5月的mac-opengl - Re: kCGImageAlphaFirst not implemented (Was: (no subject))(来自Wayback机器):

老实说,我不希望CGBitmapContextCreate()很快支持非预乘alpha。

...

我不确定使用ImageIO + CoreGraphics是否真的被用于OpenGL应用程序的图像加载方案。

这种行为是在LibSDL bug #838 - OSX SDL darkens colours proportional to increase in alpha中发现的,并且在SDL_image changeset 240中引入了一种解决方法。

您可以看到解决方法仅仅是对alpha进行非预测,这是一个非常有损的过程。

要解决这个问题,您可以在使用LibPNG的macOS上构建自己的SDL_image版本。这应该可以通过配置实现,您不必对SDL_image代码本身进行任何更改。为此,请使用--disable-imageio选项。 SDL_image附带了自己的LibPNG代码副本,因此您无需安装LibPNG即可使其正常工作。

© www.soinside.com 2019 - 2024. All rights reserved.