Cocos开启透明画布模式后,一些具有透明度的Sprite会和背景的颜色叠加,会导致该元素的渲染异常,需要通过图片预乘和设置blend来修正渲染的效果。对游戏开发同学来说可能会陌生,为什么需要Canvas和DOM共存,以及什么场景下需要开启透明画布渲染模式
在营销活动页、数据大屏等web互动领域,前端整体的运行时需要构建在web体系上,但是业务对渲染效果有较强的诉求,所以在技术选型上一般把Canvas作为动画渲染层,DOM作为UI层,两者能力互补,渲染层一般会采取轻量的渲染引擎,比如pixi.js、babylon.js,但是在一些重效果重交互的场景也会考虑使用Cocos这种专业的游戏引擎。一般情况下Canvas层会在layers的最下层,如下图所示
![e1c15df72002f6e5552f8fc479913525.jpeg](https://img-blog.csdnimg.cn/img_convert/e1c15df72002f6e5552f8fc479913525.jpeg)
但是特效弹窗、浮层、首屏快照等场景中,也存在画布层级在DOM层级之上的情况,这个时候就需要开启Cocos的透明画布渲染模式,让底层的DOM内容能够被透出,比如下面这个游戏改用DOM图片作为背景,Canvas画布盖在DOM标签之上
![cc0569873ac30b6bf2aedb6e33d9199d.jpeg](https://img-blog.csdnimg.cn/img_convert/cc0569873ac30b6bf2aedb6e33d9199d.jpeg)
Cocos开启透明画布模式很简单,在 cc.game.run
之前设置 cc.macro.ENABLE_TRANSPARENT_CANVAS = true;
Canavs就会渲染成透明模式,这时候我们抓取一下渲染的帧图,能明确看到画布中的透明区域
![44c5549c961b28a9fce2c555c818b130.jpeg](https://img-blog.csdnimg.cn/img_convert/44c5549c961b28a9fce2c555c818b130.jpeg)
浏览器会按照元素在DOM树中的zIndex层级进行颜色计算,这个过程可以简单表达为 resultColor = canvasColor × alpha + domColor × (1 − alpha)
。一般情况下色彩混合是符合视觉预期的,但是在Cocos默认的 alpha blending 作用下,我们会遇到一些不太符合直觉的表现,比如下面这个帧图:三个带透明度的Sprite和一张普通的Sprite叠加,最后输出的buffer中三个Sprite区域会携带透明信息
![bf85aa27bbe5357d3710ec5a856941ec.jpeg](https://img-blog.csdnimg.cn/img_convert/bf85aa27bbe5357d3710ec5a856941ec.jpeg)
这样再叠加DOM标签颜色,实际的渲染效果就如下右图所示:
![b58322fb1edc0e739a132f3764cebd9e.jpeg](https://img-blog.csdnimg.cn/img_convert/b58322fb1edc0e739a132f3764cebd9e.jpeg)
需要单独把这种带透明度的Sprite的 srcBlendFactors
设置成one,同时给对应的Sprite贴图开启 Premultiplied Alpha
,这样引擎在blend的时候就能够在保留对应的Sprite透明度的同时,不会把透明输出到最后的渲染结果中。处理后的效果如下图,圈出的两个Sprite渲染结果已经符合预期
![a088c7193b1cf4c67792d36dc0f25b65.jpeg](https://img-blog.csdnimg.cn/img_convert/a088c7193b1cf4c67792d36dc0f25b65.jpeg)
剩下的就是一些代码上的处理,主要分以下这几块:
1、编辑器有blend设置面板,也可以通过代码的方式按需设置srcblendFactor为one
function setBlendFactorToOne() {
let sprite = this.node.getComponent(cc.Sprite);
let blendFunc = new cc.BlendFunc();
blendFunc.src = cc.macro.BlendFactor.ONE;
sprite.srcBlendFactor = blendFunc.src;
}
2、批量给贴图设置预乘,可能需要处理不同的场景:
项目本地的资源:在resource面板勾选Premultiplied Alpha;如果用到了静态图集,图集也要开启,不然合图后会不生效;
远程的资源图片:远程资源不参与本地构建,在拉取后需要通过代码的方式手动设置
cc.assetManager.loadRemote('https://example.com/your-image.png', (error, texture) => {
if (!error) texture.setPremutilplyAlpha(true);
})
3、如果用到了spine,在给texture开启预乘的同时,也要给skeleton设置预乘 skeleton.premutipliedAlpha = true
更
多
精
彩
融球效果(shader) 颜色滤镜 水波扩散效果(shader)