creater关于blend,关于预乘premultiply alpha,关于图片白边灰边的几点疑问

上图
这张图中心圆和右上角不透明度为50%的圆使用flashcc2015绘制,左上角圆和左下角不透明度为50%的圆使用pscc2017绘制。在ccc中的表现如下(一下混合因子仅对源的改变,目标因子均为ONE_MINUS_SRC_ALPHA)
1.src_alpha:


2.one:

换图,由原图做预乘处理后的效果如下,同样做两种混合模式的测试

1.src_alpha:

2.one:

以上测试基于V1.2 Bug 图片周围出现一圈白边是什么情况中开发团队的解释
读取图像信息发现两款软件对于透明通道的处理不太一致,参考unity一篇问答Alpha is Transparency灰边的问题是因为纹理缩放边缘插值计算导致,cocos2d—x中精灵的blend源默认应该是one,(因为手动设置src-alpha会有灰边,设置one没有变化,未具体考证,有误还请指正)
那么。。。问题来了,如何正确设置混合模式或者需要修改那些参数才能使纹理正常且准确的渲染,我不认为将全部素材做预乘然后全部设置one是个理智的解决方案,还请团队相关大大解释一下ccc对于这部分的设置和原理,以及这样做的出于什么考虑,为何要和cocos2d-x不同?one more question,为何编辑器中混合模式的组合是无法正确显示的,比如zero zero,是因为web的缺陷吗?

5赞

确实,这一点很早就提过,2dx会对没有预乘的图片加载的时候会做一次预乘,然后混合时用one,creator默认alpha混合,所以导致很多地方会出现灰色的轮廓,必需手动设置用one才不会有。
帮顶,希望看到更详细的解答

1赞

手动设置one的后果就是半透明以及透明像素显示错误,除非手动将图片资源处理成预乘模式,再使用one混合,这个问题比较少见应该,ps在绘制半透明区域好像是多绘制了一个像素,所以,显示无误,flash就尴尬了,撇开绘图工具本身不说,导出的png文件是无辜的,最终渲染有问题总归是底层处理的问题,既然cocos2d-x么有这个问题,那么官方基于什么考虑更换了处理方式,为何许久没有启动对于预乘模式的重构,很迷,很刺激

两位分析的都挺深入的,关于引擎中设计的表述也都是正确的。

Cocos2d-x 中的设置更加智能,默认对图片进行 WebGL 预乘,如果发现贴图是已经预乘过的,那么 Sprite 就使用 ONE 作为 blend src,否则使用 SRC_ALPHA。这里带来的问题是,贴图切换,用户手动修改 Blend function 的冲突,cocos2d-x 在切换贴图的时候,会自动根据贴图的预乘属性重新设置 Blend function,而不管用户是否手动修改过,这里就有潜在的 bug 可能。

除此之外,图片是否预乘还决定了 opacityModifyRGB 的值,如果用户随意修改这个值也会造成效果的问题。

我们比较介意的是,这里耦合了 blend function 和预乘两者的逻辑。在做 Creator 的时候,我们希望让用户更自由得选择是否对贴图进行 GL 预乘,以及选择使用什么样的 blend function。在之后的版本中,会扩展 Texture 的 inspector,让用户选择是否自动对贴图进行 GL 预乘。

2赞

十分感谢pan大耐心详细的回复,临近新年也和cocos各位大大在论坛忙碌答疑,由衷感谢
but
几点疑问
1.cocos2d-x,默认webgl预乘是什么意思,不是很了解二者关系,2d-x应该是无脑预乘了所有纹理然后丢给opengl
2.png本身不具备预乘属性,合图预乘也只是对应plist文件里描述的一个键值,“发现贴图是否预乘”是如何发现并智能处理的
结论:同意cocos团队对于混合方式和预乘属性的理解,自由的组合有助于开发者在不同场景下的灵活应用,在编辑器中给纹理添加预乘属性也是很有必要的,设计同unity的alpha is transparency属性。由于开发者很难自主决定绘图工具,对图片像素的特殊处理也由个人能力决定,基于目前版本的简单解决方案:
-----对于灰边情况,请使用工具将图片手动转成预乘文件,导入编辑器选择源混合方式为ONE。

最后预祝ccc各位大大新春快乐

对,2d-x 会无脑对所有 png 图片进行程序预乘(即便图片已经被美术工具预乘过了),然后 2d-x 会给 png 贴图设置预乘属性

我说的“发现贴图是否预乘”就是指判断前面设置的预乘属性

大大我有个点比较迷惑:
在2dx里面我用shader混合的时候也有一圈白边。
我觉得既然用了预乘,就应该计算之后再除以color.a这样openGl才能根据颜色正确渲染
bool Image::initWithPngData(const unsigned char * data, ssize_t dataLen)里面的一段代码,是强制预乘的。

// premultiplied alpha for RGBA8888
        if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
        {
            premultipliedAlpha();
        }
        else
        {
            _hasPremultipliedAlpha = false;
        }

后来我给绑定shader的sprite设置属性setBlendFunc(BlendFunc::ALPHA_NON_PREMULTIPLIED);
const BlendFunc BlendFunc::ALPHA_NON_PREMULTIPLIED = {GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA};
就没有了一圈白边。

我在这个在线混合的网站做了试验
http://www.andersriggelsen.dk/glblendfunc.php
同样,当混合属性为{GL_ONE, GL_ONE_MINUS_SRC_ALPHA}
也会有一圈白边,勾选了Premultiply就可以正常显示。

那这一圈白边是什么原因显示的呢?
感觉预乘最多导致纹理变暗一点,但alpha是0的边界为什么会多出来白边呢?

感谢回复。。。。。。。。

1.混合不是简单的乘除法,预乘了就得除掉,没有这个道理
2.预乘纹理要对应{ONE,ONE_MINUS_ALPHA},非预乘要对应{SRC_ALPHA,ONE_MINUS_ALPHA}
3.预乘和最终效果没有必然关系,不同混合运算,最终效果自然不同
4.alpha是0乘啥都是0,它边界是啥跟它本身没关系,白边是半透明区域
4.白边问题你算一下就知道了,你贴的网站有公式,简单讲你没有预乘图片,就使用ONE作为源,相比SRC_ALPHA少乘了alpha,导致最终像素值变大了,也就是泛白了

1赞

谢谢回复。

我觉得cocos默认使用BlendFunc::ALPHA_PREMULTIPLIED是在cpu上计算混合,所以先预乘一下。
一般混合是{SRC_ALPHA,ONE_MINUS_ALPHA}交给openGL利用gpu后乘(对应预乘)处理最终的颜色。
所以预乘跟显示效果是有关系的。

最后我问的白边问题,我是觉得按理说不管预乘与否都不应该出现白边啊,因为边界的alpha是0或者是1啊。
难道我用的图片边界都有半透明?

这张图没有预乘也没有白边。。。

http://forum.cocos.com/uploads/default/original/2X/5/5e22fce09b3f9f888d802687afdf3df32456533f.png

理解不了了。。。

1.边界alpha是0或1?谁告诉你的,你自己画个没有白边的图看边缘像素?你为什么不拿有白边的图看边缘,有问题就拿有问题的东西研究,别自己画个其他的东西就得出结论
2.像素显示是一个一个矩形色块,曲线实际上也是若干直线组成,你放大图片,就会有锯齿,怎么解决锯齿问题,你画个圆,看看边缘你就知道了
3.什么cpu,gpu,什么就“什么什么了”就“所以”了,完全不知道你在说啥,别你觉得是啥就说啥,贴资料,贴数据
4.我没说预乘和最终效果没关系,我说没有必然关系,因为决定最终显示是数据,怎么算得到的数据是根本,图片本身存储数据,引擎和底层渲染处理数据,传给gpu渲染,所以我说“不同混合运算,最终效果自然不同”

使用cocos create 2.0.5 遇到同一问题,图片输出premultiply alpha 设为true勾上,sprite src blend :ONE,dst blend :ONE_MINUS_SRC_ALPHA 搞定了,感谢楼主

1赞

老哥。。。最新版本的creator,TP预乘打图,引擎设置one,图片能正常显示,但是设置节点透明度后,图片就开变亮变白而不透明,这个是有bug么

修正一下是有透明,但是会变亮变白

你是说 255 时正常,透明度低于 255 就变亮变白?

恩。。。255是正常的,低于255就变亮变白,之前看有篇帖子说这个是bug已经解决了。。。但是这边不知道为什么还是出现,我的引擎版本是2.3.0-rc1。。。。。。。。。。。。。。。。。。。。。。。

common.zip (12.1 KB)
劳烦查收一下…