纹理混合遇到的问题 pre-multiplying OpenGL Android iOS

Alpha-blending pre-multiplying of texture OpenGL Android iOS

问题

在进行 OpenGL 纹理混合的过程中,遇到樂一个诡异的现象,两个纹理混合的效果出人所料: 将一个白色渐变的 logo 加在另一张图片上,这个 logo 是由外向里逐渐增加透明度的,也就是最外围的透明度为0,而中心的透明度接近 1,也就是完全不透明,实心。那么预期的效果希望是在底图上加一个白色的朦胧的效果,然而实际得到的效果很让人意外,出现樂一片淡淡的黑色!

考察纹理混合的做法,在 shader 中编码如下:

vec4 main_color = texture(rgbTexture, v_TexCoord);
vec4 logo_color = texture(logo_texture, v_TexCoord);
color_out = mix(main_color, logo_color, logo_color.a);

因为logo图片是带有透明度,根据其透明度与原图进行混合,理应能够得到我们想要的结果。在 debug 过程中我尝试不进行混合,直接将logo绘制在图片上,发现logo还是有渐变效果,发现:

logo 的 RGB 数据和原始图片的 RGB 不同 此处存在 pre-multiplying.

pre-multiplying:Android 平台在加载一张位图的时候,会自动做一个操作,将 RGB 的值乘上 alpha 值,重新保存。用公式表示如下:

If you use OpenGL ES 2.0, pre-multiplying the output of your fragment shader is extremely simple:
color.rgb *= color.a

回头考察我的混合的方式,在 RGB 数据已经被做过一次 pre-multiplying 的情况下,再乘一个 alpha: RGB_new = RGB * alpha * alpha 然后再和底图的颜色加起来,显然出错樂。比如在白色的透明度为0.5的地方,原来的 RGB 为255,这种奇怪的算法得到的结果就是 63.75,接近黑色樂。这就是出现黑色的原因樂。

解决

解决思路两个:

  1. 不做 pre-multiplying
  2. 混合時考虑到前面的情况,不再乘上 alpha

第一种方式的话,在 Android 平台上,加载一个 bitmap 時,可以设置 BitmapFactory.Options 的参数 inPremultiplied 如下:

inPremultiplied

added in API level 19

boolean inPremultiplied

If true (which is the default), the resulting bitmap will have its color channels pre-multipled by the alpha channel.

This should NOT be set to false for images to be directly drawn by the view system or through a Canvas. The view system and Canvas assume all drawn images are pre-multiplied to simplify draw-time blending, and will throw a RuntimeException when un-premultiplied are drawn.

This is likely only useful if you want to manipulate raw encoded image data, e.g. with RenderScript or custom OpenGL.

This does not affect bitmaps without an alpha channel.

Setting this flag to false while setting inScaled to true may result in incorrect colors.

See also:

hasAlpha()
isPremultiplied()
inScaled

但是在iOS 平台的话,只有一个 是否压缩png文件的开关,一般来说是选择压缩以节省空间的,我目前还没有找到靠谱的解决方案。

选择另一个方案的话,需要在混合的时候更改一下计算方式,将原来计算方式改成如下:

vec4 main_color = texture(rgbTexture, v_TexCoord);
vec4 logo_color = texture(logo_texture, v_TexCoord);
color_out = main_color * (1.0f - logo_color.a) + logo_color;

和原来的相比,用OpenGL 的表述方式,原来做法是:(SRC_ALPHA, ONE_MINUS_SRC_ALPHA) 考虑pre-multiplying的话:(ONE, ONE_MINUS_SRC_ALPHA)

问题得到完美解决。

参考资料:

Android: bitmaps, textures and pre-multiplied pixels

图片Premultiplied Alpha到底是干嘛用的

https://gamedev.stackexchange.com/questions/53638/android-loading-bitmaps-without-premultiplied-alpha-opengl-es-2-0

纹理混合遇到的问题 pre-multiplying OpenGL Android iOS的更多相关文章

  1. Unity3d之Shader编程:子着色器、通道与标签的写法 & 纹理混合

    一.子着色器 Unity中的每一个着色器都包含一个subshader的列表,当Unity需要显示一个网格时,它能发现使用的着色器,并提取第一个能运行在当前用户的显示卡上的子着色器. 我们知道,子着色器 ...

  2. 【浅墨Unity3D Shader编程】之三 光之城堡篇:子着色器、通道与标签的写法 & 纹理混合

    本系列文章由@浅墨_毛星云 出品,转载请注明出处.   文章链接:http://hpw123.net/a/C__/kongzhitaichengxu/2014/1117/120.html 作者:毛星云 ...

  3. Direct2D开发:纹理混合

    转载请注明出处:http://www.cnblogs.com/Ray1024 一.概述 我们都知道Direct2D可以加载并显示图片,但是不知道你有没有想过,这个2D的图形引擎可以进行纹理混合吗?如果 ...

  4. UnityShader之固定管线命令Combine纹理混合【Shader资料4】

    Combine,纹理混合. 我们先看圣典上给的解释. 纹理在基本的顶点光照被计算后被应用.在着色器中通过SetTexture 命令来完成. SetTexture 命令在片面程序被使用时不会生效:这种模 ...

  5. 【Direct2D开发】 通过操作像素实现纹理混合

    转载请注明出处:http://www.cnblogs.com/Ray1024 一.概述 我们都知道Direct2D可以加载并显示图片,但是不知道你有没有想过,这个2D的图形引擎可以进行纹理混合吗?如果 ...

  6. Android H5混合开发(3):原生Android项目里嵌入Cordova

    前言 如果安卓项目已经存在了,那么如何使用Cordova做混合开发? 方案1(适用于插件会持续增加或变化的项目): 新建Cordova项目并添加Android平台,把我们的安卓项目导入Android平 ...

  7. Golang 开发移动应用的OpenGL(Android为例)的渲染管线

    golang.org/x/mobile/gl 实现的是 OpenGL ES 2 的封装. 参考:https://godoc.org/golang.org/x/mobile/gl OpenGL ES(O ...

  8. OpenGL—Android 开机动画源码分析二

    引自http://blog.csdn.net/luoshengyang/article/details/7691321/ BootAnimation类的成员函数的实现比较长,我们分段来阅读: 第三个开 ...

  9. OpenGL—Android 开机动画源码分析一

    .1 Android开机动画实现方式目前实现Android开机动画的方式主要是逐帧动画和OpenGL动画. ?逐帧动画 逐帧动画是一种常见的动画形式(Frame By Frame),其原理是在“连续的 ...

随机推荐

  1. thinkphp 面向切面编程-行为拓展

    thinkphp的CBD模式 核心保留了最关键的部分,并在重要位置设置了标签用以标记,其他功能都采用行为扩展和驱动的方式组合,开发人员可以根据自己的需要,对某个标签位置进行行为扩展或者替换,就可以方便 ...

  2. 【JAVASCRIPT】React学习- 数据流(组件通信)

    摘要 react 学习包括几个部分: 文本渲染 JSX 语法 组件化思想 数据流 一 组件通信如何实现 父子组件之间不存在继承关系 1.1 父=>子通信 父组件可以通过 this.refs.xx ...

  3. 【B2B】2015 年B2B的春天

    摘要 看看关于B2B的现状,以及行业发展近况. 现状 http://www.cyzone.cn/a/20160115/288471.html 行业发展 蓬勃发展的行业: 方兴未艾的行业: 未来的行业:

  4. [JAVASCRIPT]实现页面复制至电脑剪贴板

    一. 方法 方1: window.clipboarddata  可惜不支持chrome , chrome 下会提示找不到 clipboarddata 对象 方2: 采用国外大牛写的ZeroClipbo ...

  5. C#小爬虫,通过URL进行模拟发送接收数据

    public async Task<string> SendDataAsync(HttpMethod httpMethod, string requestUrl, HttpContent ...

  6. Java之IO流概述和File基本操作

    IO流图解 IO(in / out)流的分类 流向: 输入流  读取数据 输出流  写出数据 数据类型: 字节流 一个字节占8位, 以一个字节为单位读数据 八大数据类型所占字节数: byte(1), ...

  7. reversing.kr easy crack 之write up

    之前学逆向感觉学得一踏糊涂,这阶段好多师傅带我,一定要好好学,重新开始,认真学习. 来看打开可执行文件: 用ollydbg载入,单步执行后停到了入口点: 分析入口点,并没有加壳,于是F9执行程序,跳出 ...

  8. [POI2008]枪战Maf

    [POI2008]枪战Maf 题目 有n个人,每个人手里有一把手枪.一开始所有人都选定一个人瞄准(有可能瞄准自己).然后他们按某个顺序开枪,且任意时刻只有一个人开枪.因此,对于不同的开枪顺序,最后死的 ...

  9. Modular javascript(javascript模块化编程)

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  10. Open-Falcon第三步安装Agent (小米开源互联网企业级监控系统)

    安装Agent 每台机器上,都需要部署agent,agent会自动采集预先定义的各种采集项,每隔60秒,push到transfer. cd $WORKSPACE/agent/ mv cfg.examp ...