前言
本文章仅记录自己学习当中遇到的问题,以及自己在制作效果时实现的思路,如有不正确欢迎大佬们指正。
以下为实现的最终效果图:
目录
一、平面反射Planar Reflection
要实现水面上的倒影的效果可以用平面反射原理实现,相关的文章多到数不胜数,此处推荐两个比较好的文章,如果对其背后的数学原理感兴趣,可以移步以下文章:
[Unity/URP学习]平面反射(PlanarReflection)_unity 平面反射-优快云博客
不得不看的Unity小魔术——平面反射【有点难,但很有用!】_哔哩哔哩_bilibili
简单简述一下平面反射的实现思路,我们现实里要看到一个物体,就如上图一样,需要通过反射等一系列方法,使得光线传播到眼睛(摄像机)位置。
但如此实现会比较困难,此时我们可以以平面为对称线,在平面对面实例化一个完全对称的相机,用于观看平面反射之后的结果,并将看到的画面打印成一张RenderTexture,就可以实现类似的效果了。
此处需要注意一下的是,得到的RT图需要使用屏幕空间坐标对其进行采样才可以得到正确的反色和结果。
实现效果如下,我们还可以给反射相机打印的RenderTexure做一个高斯模糊的效果,模拟水面折射产生的模糊:
图1(不加高斯模糊) 图2(加高斯模糊)
二、噪声图扰动制作水波纹效果
我们可以通过噪声图扰动现在的反射结果,来模拟水中的波纹效果(如上图)。这里讲几个扰动效果的小TIPS,可以使得扰动得到的波纹效果更加真实:
1、可以通过采样两张噪声图或者采样一张噪声图给不同属性叠加的方式,使得其随机性更高,不会让波纹看起来呈现出一定规律
2、仔细观察地平线处,可以发现我们的水波纹会有一个比较不自然的接线;并且所有波纹都是同一频率进行扰动,这样会导致结果看上去非常不自然。
我们可以通过给噪声偏移值,除以 当前点到屏幕距离 的值,这样就可以让波纹从近到远呈现一种较为平滑的过渡,并且地平线的接线问题也得以解决,得到的效果如下图:
三、BlinnPhong高光模拟阳光打在水面上的效果
为水面添加一个BlinnPhong高光效果,可以模拟出阳光打在水面上使得水面产生一定颜色变化的效果,但仍然有一些需要注意到的地方,如果我们直接为水面添加BlinnPhong高光,为高光乘以一个颜色值,就会得到以下效果:
咋一看好像效果挺好,但与噪声扰动一样,在地平线的接线处产生了非常生硬的过渡,为了消除这些过渡,我们采用与解决噪声图扰动瑕疵类似的方法,使用Shader入门精要当中计算线性雾的公式来消除最边缘的高光(最后还要把得到的值remap到(0,1)的范围)。
公式得到的效果大概如下,在距离屏幕较近的地方的值接近1,较边缘的地方则为0。
两者相乘即可得到较为平滑的高光过渡效果:
四、菲涅尔效应制作水底效果
制作水底效果前我们需要先得到水下的画面,此处我们可以通过两种方式得到水下的画面:
1、GrabPass去捕捉屏幕纹理
2、手动添加一个Texture来模拟水底的效果
此处由于我们水底下啥也没有,我们就用一张贴图来当作我们的水底,我们可以在法线空间下给视线空间一些偏移量,来制作地面与水面的偏移效果。
在现实生活当中,我们直线观察水下的场景,可以比较清楚的观察到水下的画面,而在视线与水面角度相差较小的时候,看着就没那么清晰了,这就是菲涅尔效应。
菲涅尔效应的实现网上也有较全的资料,简述一下实际上就是1-nDotv的结果。
在得到水下画面之后,我们直接将得到的Color与菲涅尔的结果相乘,就可以得到一个受菲涅尔效应影响的水底效果了。
五、提取水面扰动的高亮部分制作水面反光
太阳打在水面上会产生一些反光的效果,虽然反射天空盒加上bloom效果已经达成了类似的效果,不过我们可以通过手动实现并操纵一些属性使得它产生更好的效果。
我们将噪声图采样结果提取出,并通过power或者减去一个阈值的方式,去提取出高亮的部分,再乘以一个强度就可以得到水面反光的效果。
最后将得到的结果叠加即可,高光部分单独提取的效果如下: