3D角色遮挡住UI的实现,关于Stencil Buffer,描边,以及其他
我这么懒的人能会写这篇博客,主因是这个需求对我造成的大量伤害~~~
起因
最近服务器AI的工作刚刚阶段性完成,马上被策划拉过去做一个渲染的效果,需求是这样的:在游戏中被选中敌人是有一个红色描边的,同时会有一个感知箭头(一个UI提示图表),现在这两个都会显示在主角上面。现象如下
前面的这个怪物X假设为主角(原谅我只能拿以前项目的资源了,那公司黄了应该不会来找我吧~~),更远处的那个是怪物,白色格子是一个UI 图片,现在均可以渲染在主角上面,影响视觉感受。希望主角可以挡住描边以及特定UI。
这里要先提前说一下描边的实现,目前主要的描边实现方式有几种
(1)有的是渲染在角色上的,即对角色模型根据法线方向或者offset进行外扩,实现描边
(2) 类似于posteffect的方式,用一个摄像机单独渲染需要描边角色,然后对得到的rendertexture进行模糊放大,再cut off掉原图进而得到描边的rendertexture,然后合并到场景摄像机上面渲染即可。
(3) 根据模型法线方向以及view 方向进行计算,叠加颜色实现边缘光的效果。
项目现在的是第二种方法,后面代码部分会有展示,另外几种方式大家如果感兴趣可以自行google下,相关的帖子很多。
坑坑坑,biu
于是乎~~这需求就是要某个3D角色可以盖住UI以及这个描边图呗。其实在最初的需求中是没有挡住描边的,所以我的第一个想法是利用Stencil Buffer。订制主角和UI的Shader,主角会写入特定的stencilValue,UI在这个值下不会通过stencil test,代码如下:
UI部分
Stencil
{
Ref [_StencilValue]
Comp NotEqual
//Pass [_StencilOp]
//ReadMask [_StencilReadMask]
//WriteMask [_StencilWriteMask]
}
主角部分
Stencil{
Ref[_StencilValue]
Comp Always
Pass replace
}
这样就应该是OK了!!(这里推荐一篇Stencil Buffer相关的博客:)在测试场景中,角色成功挡住了UI图标。然而,,在运行时,,并没有效果。。。Orz。。
经过测试,涉及stencil buffer的代码并没有问题。那么,只有一个可能是模板缓存被清掉。
谁偷走了我的Stencil Buffer?
上面提到过,我们的描边实现是posteffect的方式做的,在OnRenderImage中做了很多处理。在OnRenderImage中实现功能必然会使用到Graphics.Blits这个方法,类似代码:
void OnRenderImage(RenderTexture src, RenderTexture dest )
{
Graphics.Blits(src,dest);
}
经过排查发现,注释掉上面代码之后效果恢复正常。
这是为什么呢!!!让我们看看官方的解释:
真是悲剧!描边兄给我挖了一个小坑。
解决方案
后续过程中,我把描边输出的RenderTexture输出到了Ugui中的一个Raw Image单独渲染,而不是在主摄像机中使用OnRenderImage方法把这张图渲染在摄像机中。这个描边图片同样使用UI订制的那个材质球,这样就会被主角挡住了。
下面会分享一个展示项目,包含了所有细节。
后续应该会优化描边中的blur shader,现在锯齿效果有点严重,可能会考虑下使用描边中第一种实现方式,那样效率应该会高上不少。
第一次分享博客哈,感觉写的丑的话大家就点赞鼓励下吧!
项目下载:http://pan.baidu.com/s/1bpiaqWv