在开发自定义渲染管线的过程中,若用中间渲染目标对UI[addScene(SceneFlags.BLEND|SceneFlags.UI)+addRenderTarget(中间渲染目标名称)]进行后处理,且在UI中使用了遮罩(cc.Mask)的话,遮罩会变成纯白色直接渲染到中间渲染目标上而不是起遮罩作用,而直接渲染到屏幕上不会出现这种问题,请问这是BUG还是有什么其它原因导致的?
更为详细的描述:
伪代码:
pass.addRenderTarget(中间渲染目标名称,LoadOp.CLEAR, StoreOp.STORE, this._clearColor);
……
pass.addQueue(QueueHint.BLEND)
.addScene(camera,SceneFlags.BLEND | SceneFlags.UI);
导致Mask渲染问题如下:
Mask开启:
Mask关闭得到正常的效果:
而列表需要Mask的遮罩效果必须存在。
那么如何解决Mask渲染不正确的问题?
官方看到了能否及时告知下是否是引擎底层问题?
有复现demo吗?
暂时没有,这是直接写在项目的开发代码中。不过这是必现的,只要addRenderTarget的目标不是RenderWindow,Mask就会被渲染成纯白色。
这个问题和中间渲染目标的alpha通道有些关系。
可以用SpectorJS查下中间渲染目标的结果是否符合预期。
然后把中间渲染目标绘制到屏幕的shader,可能也需要做一些调整,看看alpha blend的选项是否正确。
就是在使用SpectorJS查看后发现中间渲染目标的绘制有问题,且只有Mask的那一次draw被画了纯白色。
该代码下其它透明UI在中间渲染目标上的渲染效果,是正常透明混合的,包括带着这个遮罩的list。
我把UI画到中间渲染目标上的渲染通道用的是default,应该是用系统自带的UI Shader直接绘制的,这样直接绘制到屏幕是正确的,渲染到中间目标时就是错误的(在绘制到中间目标的那一次Draw就出现了问题,而不是最后从中间目标输出到屏幕时出现问题)。所以我现在怀疑是否是中间渲染目标和渲染屏幕在底层上有差异,需要做一些额外的设置之类的?毕竟在注册资源时一个是通过addRenderWindow注册的,一个是通过addRenderTarget注册的。
我们这边查一下。纯白的那次,可能没绑定贴图,用了默认的白色贴图。
我抽空做了个问题复现demo,demo里的Canvas下的ScrollPane上挂有Mask。在demo的UI Camera里把PPLSetting中的test效果勾上,然后材质用test.mtl,用SpectorJS观察即可看到问题。对于Test开启前后的唯一区别就是:开启test后,UI Camera先渲染到中间渲染目标上再通过后处理shader采样渲染到屏幕上,此时可在SpectorJS观察到屏幕被染白。开启test去掉Mask后的效果一切正常。
demo链接:https://store.cocos.com/app/preview/7072
我这里好像没法从商店看到。有zip包吗?
有的,但是没法在帖子里上传,怎么发你?
大佬还有在看吗?麻烦及时回复一下
cc.Mask会用到Stencil Test,需要绑定DepthStencil。cc.Mask会预先绘制白色全屏Quad:
- 绑定了DepthStencil,这时Stencil Test会失败(预期行为),画面呈黑色。
- 不绑定DepthStencil,通过了Stencil Test,画面呈白色。
输出到Window时,framebuffer自带DepthStencil,所以没有问题。
输出到自定义RenderTarget时,需要提供DepthStencil。可以自己创建一个,或者复用别的流程中的DepthStencil。但是注意:
- 这个DepthStencil不能是Window framebuffer自带的DepthStencil。
- 如果绑定了Window framebuffer的DepthStencil,输出结果是未定义的。
- 上述限制由图形API引起,引擎无法处理。
解决了,感谢大佬解答!

