OPENGLES 绘制纹理带黑圈pre-multiplying
1. 问题
在进行 OpenGL 纹理混合的过程中,遇到一个诡异的现象,两个纹理混合的效果出人所料: 将一个ALPHA渐变的【胡须】加在另一张图片上,这个 【胡须】是由外向里逐渐增加透明度的,也就是最外围的透明度为0,而中心的透明度接近 1,也就是完全不透明,实心。那么预期的效果希望是在底图上加一个朦胧的效果,然而实际得到的效果很让人意外,出现一片淡淡的黑色!(如下图中的胡须旁边的黑色。)

2. 原因
shader:
vec4 main_color = texture(rgbTexture, v_TexCoord);
vec4 huxu_color = texture(huxu_texture, v_TexCoord);
vec4 color_out = mix(main_color, huxu_color, huxu_color.a);
因为【胡须】图片是带有透明度,根据其透明度与原图进行混合,理应能够得到我们想要的结果。在 debug 过程中我尝试不进行混合,直接将【胡须】绘制在图片上,发现【胡须】还是有渐变效果,发现:
【胡须】的 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,接近黑色。这就是出现黑色的原因。
3. 解决方案
解决思路有2个
不做 pre-multiplying
混合時考虑到前面的情况,不再乘上 alpha
第一种方案:
android 加载方法:加载图片时 设置 BitmapFactory.Options.inPremultiplied = false;
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 上木有这种接口。
第二种方案:
vec4 main_color = texture(rgbTexture, v_TexCoord);
vec4 huxu_color = texture(huxu_texture, v_TexCoord);
vec4 color_out = main_color * (1.0 - huxu_color.a) + huxu_color;
和原来的相比,用OpenGL 的表述方式,原来做法是:(SRC_ALPHA, ONE_MINUS_SRC_ALPHA) 考虑pre-multiplying的话:(ONE, ONE_MINUS_SRC_ALPHA)
参考资料:
https://plus.google.com/+ChetHaase/posts/ef6Deey6xKA
OPENGLES 绘制纹理带黑圈pre-multiplying的更多相关文章
- 2.x最终照着教程,成功使用OpenGL ES 绘制纹理贴图,添加了灰度图
在之前成功绘制变色的几何图形之后,今天利用Openg ES的可编程管线绘制出第一张纹理. 学校时候不知道OpenGL的重要性,怕晦涩的语法.没有跟老师学习OpenGL的环境配置,现在仅仅能利用coco ...
- Cocos2D绘制纹理的一般方法
如果你想在通常情况下绘制纹理,最简单的方法是在CCSprite的子类中实现.否则你将不得不自己创建一个CCRenderState对象传递给blend模式,着色器以及(可选的)纹理给CCRenderer ...
- android openGL ES2 一切从绘制纹理開始
纹理.在openGL中,能够理解为载入到显卡显存中的图片.Android设备在2.2開始支持openGL ES2.0.从前都是ES1.0 和 ES1.1的版本号.简单来说,openGL ES是为了嵌入 ...
- Unity3D学习笔记2——绘制一个带纹理的面
目录 1. 概述 2. 详论 2.1. 网格(Mesh) 2.1.1. 顶点 2.1.2. 顶点索引 2.2. 材质(Material) 2.2.1. 创建材质 2.2.2. 使用材质 2.3. 光照 ...
- 【百度地图API】批量地址解析与批量反地址解析(带商圈数据)
原文:[百度地图API]批量地址解析与批量反地址解析(带商圈数据) 摘要:因为地址解析的webserives方式还没有开通,所以先用JS版本的地址解析接口来批量获取地址解析数据吧,同时还能得到商圈的数 ...
- iOS OpenGL ES简单绘制纹理
OpenGL 中任何复杂的图形都是由点,线 和三角形组成的. 那么一个矩形 就需要有两个三角形组成. 纹理, 可以理解为一张图片, 我么可以将整张or部分图片绘制到圆形, 矩形等目标图形中. 下图表示 ...
- 解决 cocos2dx iOS/mac 设置纹理寻址模式后纹理变黑的问题
sprite:getTexture():setTexParameters(gl.LINEAR,gl.LINEAR,gl.REPEAT,gl.REPEAT) 在安卓设备上,设置了纹理自定义寻址模式,纹理 ...
- 用NetworkX生成并绘制(带权)无向图
NetworkX是一个非常强大的网络科学工具,它封装了图的数据结构和许多经典图算法,也内置了许多可视化函数可供调用. 1. 随机图生成 最经典的随机图当属我们在上一篇博客<Erdos-Renyi ...
- 带A圈的秘密
真嗒安全策略的罗罗,,害的我和其他的不一样.
随机推荐
- PE格式第七讲,重定位表
PE格式第七讲,重定位表 作者:IBinary出处:http://www.cnblogs.com/iBinary/版权所有,欢迎保留原文链接进行转载:) 一丶何为重定位(注意,不是重定位表格) 首先, ...
- Javascript之pixi框架学习
pixi 创建渲染器(renderer) 创建一个可以播放动画的区域,相当于(canvas). var renderer = PIXI.autoDetectRenderer(512, 512); do ...
- 开始Java8之旅(四) --四大函数接口
前言 Java8中函数接口有很多,大概有几十个吧,具体究竟是多少我也数不清,所以一开始看的时候感觉一脸懵逼,不过其实根本没那么复杂,毕竟不应该也没必要把一个东西设计的很复杂. 几个单词 在学习 ...
- php环境搭建工具推荐
楼楼最近由于一系列原因,使用了几款php环境搭建工具,安装配置方便,所以在这里推荐一下.第一款是XAMPP(网址http://www.xampps.com/),软件包原来的名字是 LAMPP,但是为了 ...
- 【转】NOR Flash擦写和原理分析
1. NOR FLASH 的简单介绍 NOR FLASH 是很常见的一种存储芯片,数据掉电不会丢失.NOR FLASH支持Execute On Chip,即程序可以直接在FLASH片内执行(这意味着存 ...
- 使用bitset实现毫秒级查询(二)
在上一篇中我们了解了bitset索引的基本用法,本篇开始学习bitset索引更新及一些复杂查询. 1.bitset索引更新 因为我们的数据是在系统启动时全部加载进内存,所以当数据库数据发生变化时要 ...
- 关于tarjan算法的空间优化
最近随着对tarjan算法理解的加深,我发现用另外一种途径实现tarjan的方法,且可以省去DFN数组,大大节省了空间.经过大量测试,已经无误.以下将分阶段阐述进行优化的过程. 第一阶段 下面来说一下 ...
- apache+php+mysql运行环境
建议Apache2.4+php5.6+mysql5.5+phpmyadmin4.4.4 参考: http://jingyan.baidu.com/article/fcb5aff797ec41edaa4 ...
- json_encode()中文不转码
php使用json_encode()把数组转换为json的时候,总会把中文进行转码,转码后从json数据上我们无法看出其中的中文文字.php5.4以后,当json_encode()的第二个参数赋值为J ...
- PHP的取整函数
PHP的取整函数有四个,分别是ceil.floor.round和intval,下面对它们进行一一介绍: 1. ceil(x):向上舍入为最接近的整数. 返回不小于 x 的下一个整数,x 如果有小数部分 ...