Premultiplied Alpha 这个概念做游戏开发的人都不会不知道。Xcode 的工程选项里有一项 Compress PNG Files,会对 PNG 进行 Premultiplied Alpha,Texture Packer 中也有Premultiplied Alpha 的选项。那么问题来了,Premultiplied Alpha 是什么呢?我被这个问题困惑了很久,之前搜到过 Nvidia的这篇文章,其实说的很清楚,只是当时有很多相关概念没搞清楚,所以没看懂。直到前几天读《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=αsCs+(1−αs)CdCo=αsCs+(1−αs)Cd

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

Co=(255,0,0)⋅0.6+(255,255,255)⋅(1−0.6)=(255,102,102)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−αs)CdCo=Cs′+(1−αs)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)((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)((255,0,0,1)+(0,25,0,0.1))⋅0.5=(127,25,0,0.55)

从上面的图里第三个颜色是没有 Premultiplied Alpha 的混合结果,对比第四个 Premultiplied Alpha 后颜色的结果,显然第四个颜色更符合直觉,第三个颜色太绿了,因为绿色通道没有乘以透明度,所以在线性插值的时候占了过大的权重。

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

纹理处理

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

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

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

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

原文地址:http://boundary.cc/2015/07/why-premultiplied-alpha/

图片Alpha预乘的作用[转]的更多相关文章

  1. alpha预乘

    将(r,g,b,a)变为(r*a,g*a,b*a,a)的操作称为alpha预乘. 对于alpha预乘的图片,应使用(One,OneMinusSrcAlpha)进行混合. 使用alpha预乘方式混合出来 ...

  2. 图片本地预览 flash html5

    dataURI 一种能够在页面嵌入外部资源的URI方案.能够降低图片或者样式表的http请求数量,提高效率. ie8把dataURI 的属性值限制在32k以内. 图片本地预览: 由于安全原因,通过fi ...

  3. iOS HTML图片本地预览

    引言 相信用过苹果手机的童鞋,会发现很多新闻类的应用,都可以实现HTML图片本地预览,那么这是如何实现的呢?本文将深入阐述其中的原理. 关于此功能,我还实现了一个DEMO,大家可以点击此访问更详细内容 ...

  4. 图像处理术语解释:什么是PRGBA和Alpha预乘(Premultiplied Alpha )

    ☞ ░ 前往老猿Python博文目录 ░ Alpha预乘(Premultiplied Alpha)和PRGBA 一般来说四通道图像数据保存的都是ARGB或RGBA,其R.G.B值还没有进行任何透明化处 ...

  5. 图像处理术语解释:灰度、色相、饱和度、亮度、明度、阿尔法通道、HSL、HSV、RGBA、ARGB和PRGBA以及Premultiplied Alpha(Alpha预乘)等基础概念详解

    ☞ ░ 前往老猿Python博文目录 ░ 一.引言 由于老猿以前没接触过图像处理,在阅读moviepy代码时,对类的有些处理方法代码看不懂是什么含义,为此花了4天时间查阅了大量资料,并加以自己的理解和 ...

  6. jQuery Lightbox图片放大预览

    简介:jQuery Lightbox图片放大预览代码是一款可以在用户点击页面中的小图片时,将该图片的高清版本以Lightbox的方式放大显示在页面的中间,提高用户的体验度. 效果展示 http://h ...

  7. js实现FileUpload选择图片后预览功能

    当asp.net的FileUpload选择一个图片后不需要上传就能显示出图片的预览功能, 代码: <%@ Page Language="C#" AutoEventWireup ...

  8. Android 举例说明自己的定义Camera图片和预览,以及前后摄像头切换

    如何调用本地图片,并调用系统拍摄的图像上一博文解释(http://blog.csdn.net/a123demi/article/details/40003695)的功能. 而本博文将通过实例实现自己定 ...

  9. 巧用weui.gallery(),点击图片后预览图片

    要在页面需要加载的JS文件: <script src="../js/libs/weui.min.js"></script> 可以去weui的文档中下载,这是 ...

随机推荐

  1. resolve和reject不会终结Promise的参数函数的执行

  2. Linux下安装jdk&Jmeter

    一.在Linux上部署一个jdk以及Jmeter   tips1:Linux安装tar.gz文件到路径 tar -zxvf 软件包名.tar.gz -C 路径 比如我的jdk-8u131-linux- ...

  3. 查看加密的vba代码

    查看加密的vba代码,可以使用这个工具,excel文件里面的宏代码一览无余. https://files.cnblogs.com/files/laoxia/PVP.zip

  4. Redis hash结构

    1. select 更换命名空间 select 1 2. 设置hash,key为mp,键为name 值为zhangsan  hexists判断hash的key是否存在 3. 获得map中键为name的 ...

  5. Hanlp自然语言处理工具的使用演练

    Hanlp是由一系列模型与算法组成的工具包,目标是普及自然语言处理在生产环境中的应用.Hanlp具备功能完善.性能高效.架构清洗.语料时新.可自定义的特点:提供词法分析(中文分词.磁性标注.命名实体识 ...

  6. 【转】Python metaclass

    转自: http://ju.outofmemory.cn/entry/32434 在回答了 yield关键字和 decorator的问题之后,我更明白了,我决定非常详细地回答这个问题. 读前警告:这个 ...

  7. HDFS管理工具HDFS Explorer

    HDFS Explorer是一个在windows上管理HDFS系统的工具,支持上传.下载.重命.复制.移动和删除等. 一.下载地址 CSDN下载地址:http://download.csdn.net/ ...

  8. SpringBoot+Maven 多模块项目的构建、运行、打包

    SpringBoot+Maven 多模块项目的构建.运行.打包 https://blog.csdn.net/zekeTao/article/details/79413919

  9. centos添加额外测源,解决:No package openvpn available.

    centos添加额外测源,解决:No package openvpn available. ##添加额外的repositories,安装openvpn yum install epel-release ...

  10. ML: 降维算法-LDA

    判别分析(discriminant analysis)是一种分类技术.它通过一个已知类别的“训练样本”来建立判别准则,并通过预测变量来为未知类别的数据进行分类.判别分析的方法大体上有三类,即Fishe ...