1.前言
最近尝试了一下吃水线效果,发现网上只有几个展示效果和介绍思路的视频和文章。在作者厚脸皮的提问和各位大佬的耐心解答下,经历了许多挫折,犯了很多傻,最后终于实现了。
我写这篇文章是为了记录一下这两周的学习过程,同时给各位有这方面想法的朋友提供一些拙见,权当抛砖引玉,还请各位大佬多多担待,有什么问题请务必指出,我一定好好听取。
我做的是较为基础的效果,还有很多的问题,需要优化,后面会有专门一栏讲讲我这个实现方式的弊端。
下面是我参考过的文章
Boat attack吃水线效果开发:
https://zhuanlan.zhihu.com/p/697302545
Unity 吃水线(waterline)效果分析:
https://zhuanlan.zhihu.com/p/697364253
非常感谢这两位大佬。
2.原理讲解
想要实现吃水线效果,我们就必须得到水下的mask。
其中,重要的有两个部分,一个是相机近裁面上的世界坐标,一个是水面的高度,我们只需要得到这两个坐标的y轴进行比对,就能得到水下的mask了。
水下的mask
近裁面的世界坐标,我们通过c#端传入相机的四个角,通过screenUV的插值即可得到。
水面的高度,我采用的做法是从水面的正上方用正交相机往下拍一张rt,这个rt记录的是用深度图重建出来的水面世界坐标,将这张rt传入shader,通过我们之前的相机近裁面的世界坐标的xz轴采样,就可以得到水面在相机近裁面上的高度。
3.代码解析
1.近裁面世界坐标
在c#端,我们ViewportToWorldPoint函数获取到正交俯视相机的四个角的世界坐标,将其作为数组传入我们的shader中,同时传入我们正交相机的大小为后面的世界uv作准备。
传入shader后,通过对屏幕uv来进行插值,即可得到近裁面上的世界坐标。
为什么要这么做呢,其实是个简单的数学问题,可以理解为将相机的四个角的坐标分别对应屏幕UV的(0,0),(0,1),(1,0),(1,1)四个坐标,然后通过lerp来补齐其中缺失的坐标,正好对应我们近裁面的世界坐标。
因为我这里使用的是后处理shader,所以直接用i.uv替代,等效于screenUV。
2.水面的高度
在水面的正上方摆一个俯视的正交相机,这个正交相机只渲染水面,其他的要剔除。
重新建立一个新的后处理shader,给我们的正交相机,记住要完全覆盖水面,不然会出错。
同时创建一个512x512的rt赋给我们的正交相机作为结果输出。(大小自己定,正方形就行)
开启正交相机的深度模式,然后在shader中通过深度图重建水面世界坐标。
获取vp矩阵的逆矩阵
声明
线性深度
与透视相机不同的是,我们的正交相机实际上是一个长方体,所以我们不需要做透视除法,也不需要将深度线性化,因为正交相机的深度本身是线性的。
将屏幕空间转化到ndc空间,在乘以我们的两个逆矩阵,即可得到世界坐标。
想要更详细的重建世界坐标方法可以看看其他大佬的文章
【UnityShader】从深度图重建世界坐标(1):
https://zhuanlan.zhihu.com/p/547213235
重建成功后将世界坐标输出即可。
这时候我们就会看到我们的rt会随着水面高度变化而变化,那么就算成功了。
如果没有看到变化,看看自己的水面是不是比0低,如果是就把水面高度抬高至大于1,具体原因会在后面的问题中讲到。
随水波变化而变化的rt
3.比对两者获得水下mask
回到我们第一个创建的后处理shader,将这水面高度rt传入。
将这个rt通过我们近裁面的世界坐标的xz轴进行采样,世界坐标的uv要除以我们正交相机的size的两倍,这样才能变成正常的uv(正交相机的size一格对应的是2m)。
然后将我们的近裁面的y轴和水面高度的y轴进行比对,得到水下的mask。
最后得到的结果
4.最后
我们已经完成了最关键的一步,接下来只需要按照自己的想法对这个mask进行处理就好了,比如通过边缘检测找出吃水线,对水下加上焦散和雾效等等。
我这里是简单参考了一下ABZU的ramp深度效果。
4.效果展示
5.其中的问题
1.由于我们的水面高度是通过rt传入shader的,受到rt的rgb只有0到1的限制,我们的水面高度只有在大于0的时候才能被正确记录(也就是说水面不能摆的比0低)。
比0低后的rt
2.如果只是用相机近裁面的世界坐标xz轴采样的话,对于水的位置就有特殊要求,不能做到动态变化。
水面的transform信息,水面就是一个普通的plane
6.结尾
由于这个效果网上并没有很多资料,我也是边尝试边做的,所以其中涉及的脚本和不必要的操作较多,为了不影响观感,这里已经尽量将重要的部分给挑出来了。
对于没有完整放上代码,希望各位大佬可以谅解(因为实在太多了。。。)
有什么缺失的部分,可以联系留言,我会及时补上。
其中的问题也会在我找到方法后也会及时更新,如果大佬有好的解决方案,还请不吝赐教,真的非常感谢!!!
放上莫斯提马美图
-
米哈游 ZZZ 绝区零 渲染细节新发现 网友发现《黑神话:悟空》误将钢筋扫描至游戏中,如何评价游戏场景实景扫描这样的做法?是怎么办到的?
-
收藏转发,GPU、CPU、内存等150+游戏开发性能分析优化干货合集! -
Unity3D游戏开发中100+效果的实现和源码大全 - 收藏起来肯定用得着 -
非广告!6年老号福利,描边、景深、泛光、投影等60+游戏后处理效果实现合集!
鸣谢:感谢作者的授权转载,欢迎大家投稿,一起分享交流游戏开发技术。
作者:陈酒十里醇香
原文:https://zhuanlan.zhihu.com/p/744793928
关注【游戏开发技术教程】
游戏开发技术、技巧、教程和资源,答疑解惑,内推面试


