【问题标题】:OpenGL ES (IPhone) alpha blending looks weirdOpenGL ES (iPhone) alpha 混合看起来很奇怪
【发布时间】:2013-09-12 03:37:50
【问题描述】:

我正在用 Opengl ES 为 iPhone 编写游戏,但遇到了 alpha 混合问题:

我正在使用glBlendFunc(Gl.GL_SRC_ALPHA, Gl.GL_ONE_MINUS_SRC_ALPHA) 来实现 alpha 混合,并尝试用多个“层”组成一个场景,这样我就可以单独移动它们而不是使用静态图像。我在 photoshop 中创建了一个预览,然后尝试在 iphone 中实现相同的结果,但是当我将纹理与半透明区域混合时会显示黑色光晕。

我附上了一张图片。左边是iphone的截图,右边是我在photoshop中构图时的样子。该图像由渐变和带有羽化边缘的沙子图像组成。

这是预期的行为吗?有什么办法可以避免黑边?

谢谢。

编辑:我正在上传包含沙子的 png 部分。完整的 png 为 512x512 并且还有其他图像。

我正在使用以下代码加载图像:

NSString *path = [NSString stringWithUTF8String:filePath];
NSData *texData = [[NSData alloc] initWithContentsOfFile:path];
UIImage *image = [[UIImage alloc] initWithData:texData];
if (image == nil) NSLog(@"ERROR LOADING TEXTURE IMAGE");

GLuint width = CGImageGetWidth(image.CGImage);
GLuint height = CGImageGetHeight(image.CGImage);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
void *imageData = malloc( height * width * 4 );
CGContextRef context = CGBitmapContextCreate( imageData, width, height, 8, 4 * width, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big );
CGColorSpaceRelease( colorSpace );
CGContextClearRect( context, CGRectMake( 0, 0, width, height ) );
CGContextTranslateCTM( context, 0, height - height );
CGContextDrawImage( context, CGRectMake( 0, 0, width, height ), image.CGImage );

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

CGContextRelease(context);

free(imageData);
[image release];
[texData release];

【问题讨论】:

    标签: iphone opengl-es alphablending


    【解决方案1】:

    我需要回答我自己的问题:

    我无法使用 ImageIO 框架使其工作,因此我将 libpng 源添加到我的项目并使用它加载图像。它现在完美无缺,但我必须解决以下问题:

    图像已加载并在模拟器中显示正常,但在真实设备上根本没有加载。我在网上发现正在发生的事情是 PNG 图像格式文件中的像素排序从 RGBA 转换为 BGRA,并且颜色值也通过压缩实用程序“pngcrush”预乘以 alpha 通道值(出于设备特定的效率原因,在使用 UIKit 界面进行编程时)。

    该实用程序还会重命名文件的标题,使 libpng 无法使用新的 PNG 文件。当 PNG 文件部署到 iPhone 上时,这些更改会自动完成。虽然这对 UIKit 来说很好,但 libpng(和其他非 Apple 库)通常无法读取这些文件。

    简单的解决方案是:

    1. 使用不同的扩展名重命名您的 PNG 文件。
    2. 适用于您的 iPhone -device- build 添加以下用户自定义设置:

      IPHONE_OPTIMIZE_OPTIONS | -skip-PNGs

    我做了第二个,它现在可以在模拟器和设备上完美运行。

    【讨论】:

      【解决方案2】:

      您的屏幕截图和 Photoshop 模型表明图像的颜色通道正在与 Alpha 通道进行预乘。

      【讨论】:

      • Irpetrich:我上传了源图像和我用来加载它的代码片段。你是对的,这就是它的样子,但是为什么/在哪里预乘颜色通道?
      • 它们被相乘是因为这是 iPhone 的 GPU 处理得最好的格式——所有 PNG 在使用 UIImage 读取时都会转换为预乘 RGBA。您可以使用新的公共 ImageIO 框架或简单地将您的 Alpha 通道存储在单独的图像中来解决此问题。
      【解决方案3】:

      我不知道您的原始源图像是什么样的,但对我来说它看起来融合正确。使用混合模式,您将在图层之间获得闷热的混合。

      photoshop 版本看起来每个图层都有适当的透明度,但没有混合。如果您不想明确设置像素 alpha,我想您可以尝试使用 glAlphaFunc。

      --- 与下面注释相关的代码(删除 alpha 预乘)---

      int pixelcount = width * height;
      unsigned char* off = pixeldata;
      for (int pi=0; pi<pixelcount; ++pi)
      {
          unsigned char alpha = off[3];
          if( alpha!=255 && alpha!=0 )
          {
              off[0] = ((int)off[0])*255/alpha;
              off[1] = ((int)off[1])*255/alpha;
              off[2] = ((int)off[2])*255/alpha;
          }
          off += 4;
      }
      

      【讨论】:

      • 我上传了原始源图片。背景是一个形状。为什么你说我的混合模式会在图层之间产生闷热的混合?
      • 在看到原始源图像后,您并没有像我想的那样做。我认为问题在于 API 正在预乘 alpha。您可以通过使用混合模式 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA) 来快速解决此问题。我知道这是 iphone API 的烦恼之一。
      • 使用 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA) 不会让我使用 glColor 更改图像的整体 alpha。
      • 加载后,您可能必须手动从图像中删除 RGA * alpha 乘法。不得不这样做真是糟透了。我将编辑上面的答案以更好地说明我的意思。
      • 除以 alpha 是如何工作的?整数除法是有​​损的。
      【解决方案4】:

      我知道这篇文章很古老,但是我遇到了同样的问题,在尝试了一些解决方案并苦恼了几天后,我发现您可以使用以下混合参数解决预乘 RGBA png 问题;

      glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
      

      在我的例子中,GL_ONE 参数替换了 GL_SRC_ALPHA 参数。

      我现在可以使用没有灰色 alpha 边缘效果的 RGBA PNG,这让我的字形文本看起来很糟糕。

      编辑: 好的,还有一件事,对于淡入淡出等(在代码中设置 alpha 通道),您需要在如上所述设置混合时手动预乘,像这样;

      glColor4f(r*a, g*a, b*a, a);
      

      【讨论】:

      • 谢谢!确实好多了!
      猜你喜欢
      • 1970-01-01
      • 2013-11-16
      • 1970-01-01
      • 1970-01-01
      • 2011-06-13
      • 2014-03-04
      • 1970-01-01
      • 2021-07-02
      • 1970-01-01
      相关资源
      最近更新 更多