[转]图片Premultiplied Alpha到底是干嘛用的
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)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−α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)
如果绿色 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 的混合结果,对比第四个 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。
[转]图片Premultiplied Alpha到底是干嘛用的的更多相关文章
- Premultiplied Alpha
Xcode 的工程选项里有一项 Compress PNG Files,会对 PNG 进行 Premultiplied Alpha.游戏开发中会更加关注这个格式,省一些运行时计算. Premultipl ...
- 图像处理术语解释:什么是PRGBA和Alpha预乘(Premultiplied Alpha )
☞ ░ 前往老猿Python博文目录 ░ Alpha预乘(Premultiplied Alpha)和PRGBA 一般来说四通道图像数据保存的都是ARGB或RGBA,其R.G.B值还没有进行任何透明化处 ...
- 图像处理术语解释:灰度、色相、饱和度、亮度、明度、阿尔法通道、HSL、HSV、RGBA、ARGB和PRGBA以及Premultiplied Alpha(Alpha预乘)等基础概念详解
☞ ░ 前往老猿Python博文目录 ░ 一.引言 由于老猿以前没接触过图像处理,在阅读moviepy代码时,对类的有些处理方法代码看不懂是什么含义,为此花了4天时间查阅了大量资料,并加以自己的理解和 ...
- loadView在App启动时到底都干了些什么?
loadView在App启动时到底都干了些什么? 查阅苹果官方文档如下: 1. 当你访问一个ViewController的view属性时,如果此时view的值是nil,那么,ViewControlle ...
- Python类中的self到底是干啥的
Python类中的self到底是干啥的 Python编写类的时候,每个函数参数第一个参数都是self,一开始我不管它到底是干嘛的,只知道必须要写上.后来对Python渐渐熟悉了一点,再回头看self的 ...
- package-lock.json到底是干嘛的?(转载)
package-lock.json到底是干嘛的? https://mp.weixin.qq.com/s/NaVVljKrQAFmHMdbkaYmPg## nvm-windows https://git ...
- 途牛与十八好汉撕X又言和 到底想干啥?
到底想干啥?" title="途牛与十八好汉撕X又言和 到底想干啥?"> 天下大势,合久必分,分久必合.很多看起来热闹哄哄的"劳燕分飞"事件,最 ...
- mac上做透明图片, png, alpha
现在OS X中自带的[预览]功能十分强大,我们甚至可以通过预览来直接制作一些透明效果的PNG图片,当做图片素材(例如图标)使用.这里要用到的是[预览]中的“即时Alpha”工具. -首先我们要使用预览 ...
- Zookeeper到底是干嘛的
在Zookeeper的官网上有这么一句话:ZooKeeper is a centralized service for maintaining configuration information, n ...
随机推荐
- golang执行Linux和Windows命令
1. 可接收变参命令 package main import ( "fmt" "os" "os/exec" "strings&qu ...
- 25.centos7基础学习与积累-011-课前考试二-命令练习
从头开始积累centos7系统运用 大牛博客:https://blog.51cto.com/yangrong/p5 取IP地址: 6的命令:ifconfig eth0 7的命令 [root@pytho ...
- PAT甲级1012题解——选择一种合适数据存储方式能使题目变得更简单
题目分析: 本题的算法并不复杂,主要是要搞清楚数据的存储方式(选择一种合适的方式存储每个学生的四个成绩很重要)这里由于N的范围为10^6,故选择结构体来存放对应下标为学生的id(N只有2000的范围, ...
- BZOJ2523/LOJ2646 聪明的学生
BZOJ2523/LOJ2646 聪明的学生 第一道CTSC的题. 因为是思维题,所以思路就不写了.直接看代码吧. #include<bits/stdc++.h> #define M 30 ...
- linux卸载mysql误删mysql.pm
操作步骤如下 linux卸载mysql:yum remove mysql 查找mysql所有的文件并删除: 查找:find / -name mysql 删除:rm -rf xxx 误操作删除mysql ...
- 《Coderxiaoban团队》第三次作业:团队项目的原型设计
<XXX团队>第三次作业:团队项目的原型设计 项目 内容 这个作业属于哪个课程 任课教师博客主页链接 这个作业的要求在哪里 实验七 团队作业3:团队项目原型设计与开发 团队名称 Coder ...
- Python开发应用-操作excel
一. openpyxl读 95%的时间使用的是这个模块,目前excel处理的模块,只有这个还在维护 1.workBook workBook=openpyxl.load_workbook('path(. ...
- IntToBinaryString
void IntToBinaryString(int devisor,char* pBinStr) { int i; int remainder; ;i<;i++) { remainder=de ...
- (尚024)Vue_案例_交互删除
注意:本总结中最终会删除不成功 ,原因是Item.vue中方法methods单词拼写错误!!! 首先明白,删除在Item.vue中交互 1.写交互,首先写监听@click="deleteIt ...
- 为啥用DTO
0.部分参数对于开发前端的人来说是无意义的,因为传递也没有效果.所以不应该暴露给前端使用. 1.依据现有的类代码,即可方便的构造出DTO对象,而无需重新进行分析. 2.减少请求次数,大大提高效率. 3 ...