Premultiplied Alpha

Xcode 的工程选项里有一项 Compress PNG Files,会对 PNG 进行 Premultiplied Alpha。游戏开发中会更加关注这个格式,省一些运行时计算。

Premultiplied Alpha 是什么呢?

Alpha Blending: To Pre or Not To Pre 这篇文章其实说的很清楚。还有《Real Time Rendering》

一、Alpha Blending

要搞清楚这个问题,先得理解 Alpha 通道的工作原理。

最常见的像素表示格式是 RGBA8888 即 (r, g, b, a),每个通道 8 位,0~255。例如红色 60% 透明度就是(255, 0, 0, 153),为了表示方便,alpha 通道一般记成正规化后的 0~1 的浮点数,也就是(255, 0, 0, 0.6)。而 Premultiplied Alpha 则是把 RGB 通道乘以透明度也就是(r * a, g * a, b * a, a),50% 透明红色就变成了(153, 0, 0, 0.6)。

透明通道在渲染的时候通过?Alpha Blending?产生作用,如果一个透明度为 as?的颜色 Cs 渲染到颜色 Cd 上,混合后的颜色通过以下公式计算:

Co = asCs + (1 ? as)Cd

以 60% 透明的红色渲染到白色背景为例:

Co = (255, 0, 0) * 0.6 + (255, 255, 255) *(1 ? 0.6) = (255, 102, 102)

也就是说,从视觉上(255, 0, 0, 0.6)渲染到白色背景上和(255, 102, 102)是同一个颜色。如果颜色以 Premultiplied Alpha 形式存储,也就是 Cs 已经乘以透明度了,所以混合公式变成了:

Co = Cs′ + (1 ? as)Cd

二、为什么要 Premultiplied Alpha?

Premultiplied Alpha 后的像素格式变得不直观,因为在画图的时候都是先从调色板中选出一个 RGB 颜色,再单独设置透明度,如果 RGB 乘以透明度就搞不清楚原色是什么了。从前面的 Alpha Blending 公式可以看出,Premultiplied Alpha 之后,混合的时候可以少一次乘法,这可以提高一些效率,但这并不是最主要的原因。最主要的原因是:

没有 Premultiplied Alpha 的纹理无法进行 Texture Filtering(除非使用最近邻插值)。

以最常见的 filtering 方式线性插值为例,一个宽 2px 高 1px 的图片,左边的像素是红色,右边是绿色 10% 透明度,如果把这个图片缩放到 1x1 的大小,那么缩放后 1 像素的颜色就是左右两个像素线性插值的结果,也就是把两个像素各个通道加起来除以2。如果使用没有 Premultiplied Alpha 的颜色进行插值,那么结果就是:

((255, 0, 0, 1) + (0, 255, 0, 0.1)) * 0.5 = (127, 127, 0, 0.55)

如果绿色 Premultiplied Alpha,也就是(0, 255 * 0.1, 0, 0.1),和红色混合后:

((255, 0, 0, 1) + (0, 25, 0, 0.1)) * 0.5 = (127, 25, 0, 0.55)

Premultiplied Alpha 最重要的意义是使得带透明度图片纹理可以正常的进行线性插值。这样旋转、缩放或者非整数的纹理坐标才能正常显示,否则就会像上面的例子一样,在透明像素边缘附近产生奇怪的颜色。

三、纹理处理

我们使用的 PNG 图片纹理,一般是不会 Premultiplied Alpha 的。游戏引擎在载入 PNG 纹理后会手动处理,然后再 glTexImage2D 传给 GPU,比如 Cocos2D-x 中的 CCImage::premultipliedAlpha:

void Image::premultipliedAlpha() {
    unsigned int* fourBytes = (unsigned int*)_data;
    for (int i = 0; i < _width * _height; i++) {
        unsigned char* p = _data + i * 4;
        fourBytes[i] = CC_RGB_PREMULTIPLY_ALPHA(p[0], p[1], p[2], p[3]);
    }
    _hasPremultipliedAlpha = true;
}

而 GPU 专用的纹理格式,比如 PVR、ETC 一般在生成纹理都是默认 Premultiplied Alpha 的,这些格式一般是 GPU 硬解码,引擎用 CPU 处理会很慢。

总之 glTexImage2D 传给 GPU 的纹理数据最好都是 Multiplied Alpha 的,要么在生成纹理时由纹理工具 Pre-multiplied,要么载入纹理后由游戏引擎或 UI 框架 Post-multiplied。

四、iOS 中的 Premultiplied Alpha

Core Graphics 的 CGImage.h 对图像透明度信息有如下定义

typedef CF_ENUM(uint32_t, CGImageAlphaInfo){
    // ...
    /* For example, premultiplied RGBA */
    kCGImageAlphaPremultipliedLast,
    /* For example, premultiplied ARGB */
    kCGImageAlphaPremultipliedFirst,
    // ...
};

预乘透明度(Premultiplied Alpha图像简单地说,即每个颜色分量都乘以 alpha 通道值作为结果值:

color.rgb *= color.alpha

为什么关注预乘透明度图像?微信团队因 AR 抢红包场景的 OpenGL 混色结果出错引起注意。

Premultiplied alpha is better than conventional blending for several reasons:

It works properly when filtering alpha cutouts _(see below)_

It works properly when doing image composition _(stay tuned for my next post)_

It is a superset of both conventional and additive blending. If you set alpha to zero while RGB is non zero, you get an additive blend. This can be handy for particle systems that want to smoothly transition from additive glowing sparks to dark pieces of soot as the particles age.

It plays nice with DXT compression, which only supports transparent pixels with an RGB of zero.

摘自:Premultiplied alpha

原文地址:https://www.cnblogs.com/dins/p/premultiplied-alpha.html

时间: 2024-08-06 03:37:27

Premultiplied Alpha的相关文章

pre-multiplied alpha相关(转)

原文转自http://www.cgspread.com/7677.html http://blog.csdn.net/zinking3/article/details/2260405 http://www.gimp.org/docs/plug-in/appendix-alpha.html android的Bitmap与pre-multiplied alpha相关.getPixels得到的是直通alpha的像素值,而copyPixelsFromBitmap得到的则是预乘alpha的像素值. 第二篇

premultiplied pixel formats的具体含义

Anti-aliasing problem  with  render_scanlines_compound_layered> However, I have no clue what this change means. I read about> premultiplied pixel formats here and there, but never really> understood what they are. Search in Google for "premu

Win2D 官方文章系列翻译 - 预乘 Alpha

本文为个人博客备份文章,原文地址: http://validvoid.net/win2d-premultiplied-alpha/ 在计算机绘图中有两种表示颜色值不透明度的方法.Win2D 中两种方法均有所采用.本文旨在解释两种方法之间的区别以及其各自的使用场景. 直接 Alpha (Straight alpha) 当使用直接,亦即线性 Alpha 时: RGB 值指定绘制目标的颜色 Alpha 值指定绘制目标的质密程度 在该方法中,RGB 和 Alpha 通道各自独立发挥作用.它们可以在不互相

GDI+编程小结

GDI+(Graphics Device Interface Plus图形设备接口加)是Windows XP和Windows Server 2003操作系统的子系统,也是.NET框架的重要组成部分,负责在屏幕和打印机上绘制图形图像和显示信息. GDI+不但在功能上比GDI 要强大很多,而且在代码编写方面也更简单,因此会很快成为Windows图形图像程序开发的首选. 一.              GDI+的特点和新增功能 GDI+与GDI一样,都具有设备无关性.应用程序的程序员可利用GDI+这样

CCNode Class-----Cocos2D-Swift v3.3

CCNode Class Reference Inherits from CCResponder : NSObject Conforms to CCSchedulerTarget Declared in CCNode.h Overview CCNode is the base class for all objects displayed by Cocos2D. CCNode handles transformations, can have a content size and provide

Bitmap四种属性

http://blog.csdn.net/rabbit_in_android/article/details/49967461 Bitmap: (1)     public Bitmap (int width,int height,int stride,     PixelFormat format,IntPtr scan0) 用指定的大小.像素格式和像素数据初始化 Bitmap 类的新实例. (2)     LockBits():,就是把图像的内存区域根据格式锁定,拿到那块内存的首地址.这样就

[实例]鼠标穿透窗口 &amp; 窗口渐变透明 By 小鸟喳喳叫

理论讲解请点击这里查看 ==> 传送门 注:本教程需要原料 Photoshop(我用的是CS6) 第一步:创建一个窗口(实现鼠标穿透) WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style            = CS_HREDRAW | CS_VREDRAW;    wcex.lpfnWndProc    = WndProc;    wcex.cbClsExtra        = 0;    wcex.cbWndExtr

iOS8 Core Image In Swift:更复杂的滤镜

iOS8 Core Image In Swift:自动改善图像以及内置滤镜的使用 上面那篇文章主要是Core Image的基础,只是为了说明CIImage.CIFilter.CIContext,以及基础滤镜的简单使用.在上一篇中几乎没有对滤镜进行更复杂的操作,都是直接把inputImage扔给CIFilter而已,而Core Image实际上还能对滤镜进行更加细粒度的控制,我们在新的工程中对其进行探索.为此,我重新建立了一个空的workspace,并把之前所使用的工程添加到这个workspace

流媒体 3——彩色数字图像基础

1. 视觉系统的颜色感知 颜色是视觉系统对可见光的感知结果.可见光是波长在380 nm-780 nm之间的电磁波,我们看到的大多数光不是一种波长的光,而是由许多不同波长的光组合成的.(1).眼睛本质上是一个照相机.人的视网膜(human retina)通过神经元来感知外部世界的颜色,每个神经元或者是一个对颜色敏感的锥体(cone),或者是一个对颜色不敏感的杆状体(rod).(2).红.绿和蓝三种锥体细胞对不同频率的光的感知程度不同,对不同亮度的感知程度也不同,人们可以使用数字图像处理技术来降低数