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到底是干嘛用的的更多相关文章

  1. Premultiplied Alpha

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

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

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

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

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

  4. loadView在App启动时到底都干了些什么?

    loadView在App启动时到底都干了些什么? 查阅苹果官方文档如下: 1. 当你访问一个ViewController的view属性时,如果此时view的值是nil,那么,ViewControlle ...

  5. Python类中的self到底是干啥的

    Python类中的self到底是干啥的 Python编写类的时候,每个函数参数第一个参数都是self,一开始我不管它到底是干嘛的,只知道必须要写上.后来对Python渐渐熟悉了一点,再回头看self的 ...

  6. package-lock.json到底是干嘛的?(转载)

    package-lock.json到底是干嘛的? https://mp.weixin.qq.com/s/NaVVljKrQAFmHMdbkaYmPg## nvm-windows https://git ...

  7. 途牛与十八好汉撕X又言和 到底想干啥?

    到底想干啥?" title="途牛与十八好汉撕X又言和 到底想干啥?"> 天下大势,合久必分,分久必合.很多看起来热闹哄哄的"劳燕分飞"事件,最 ...

  8. mac上做透明图片, png, alpha

    现在OS X中自带的[预览]功能十分强大,我们甚至可以通过预览来直接制作一些透明效果的PNG图片,当做图片素材(例如图标)使用.这里要用到的是[预览]中的“即时Alpha”工具. -首先我们要使用预览 ...

  9. Zookeeper到底是干嘛的

    在Zookeeper的官网上有这么一句话:ZooKeeper is a centralized service for maintaining configuration information, n ...

随机推荐

  1. JVM——垃圾回收资格的判定

    一:判断一个对象是否已死 1:引用数算法:给对象加个引用计数器,被引用时加一,引用失效减一,在任何时刻一直为0的就说明不会被使用,但是由于一种情况的存在,导致这种算法不被JVM所考虑,在两个对象相互引 ...

  2. 洛谷 P2384 最短路题解

    题目背景 狗哥做烂了最短路,突然机智的考了Bosh一道,没想到把Bosh考住了...你能帮Bosh解决吗? 他会给你100000000000000000000000000000000000%10金币w ...

  3. selenium与webdriver驱动与firefox、 chrome匹配版本

    一.Chrome python3 selenium3.11.0(直接pip安装即可) chromedriver_win32:2.38 Chrome版本: 65.0.3325.146(正式版本)(32 ...

  4. windows 上运行 sslocal 提示 libcrypto(OpenSSL) not found 解决办法

    1.下载最新版ss客户端,使用pip安装的并不是最新版,去github下载最新版安装 2.安装openssl客户端 OpenSSL for Windows:https://wiki.openssl.o ...

  5. P1197 [JSOI2008]星球大战[并查集+图论]

    题目来源:洛谷 题目描述 很久以前,在一个遥远的星系,一个黑暗的帝国靠着它的超级武器统治着整个星系. 某一天,凭着一个偶然的机遇,一支反抗军摧毁了帝国的超级武器,并攻下了星系中几乎所有的星球.这些星球 ...

  6. CORS 跨域 node |XMLHttpRequest 跨域提交数据 node

    node服务端 app.post('/getdata',function(req,res,next){ req.setEncoding('utf8'); res.setHeader('Access-C ...

  7. Haskell语言学习笔记(95)Semiring

    semirings 模块 semirings 模块需要安装 $ cabal install semirings Installed semirings-0.2.0.1 Prelude> :m + ...

  8. KM模板 最大权匹配(广搜版) Luogu P1559 运动员最佳匹配问题

    KM板题: #include <bits/stdc++.h> using namespace std; inline void read(int &num) { char ch; ...

  9. 【BZOJ4237】 稻草人 CDQ分治+单调栈

    ## 题目描述 JOI村有一片荒地,上面竖着N个稻草人,村民们每年多次在稻草人们的周围举行祭典. 有一次,JOI村的村长听到了稻草人们的启示,计划在荒地中开垦一片田地.和启示中的一样,田地需要满足以下 ...

  10. tensorflow2.0 学习(二)

    线性回归问题 # encoding: utf-8 import numpy as np import matplotlib.pyplot as plt data = [] for i in range ...