[UnityShader学习笔记]水体效果#1——折射与反射

学习unity shader有一段时间了,打算开始陆续整理归纳一下技术要点,也方便日后的复习和参考。

第一个总结做水体效果。对于初学者来说,水体包含的知识点相对而言是比较多的,这里就以冯乐乐大佬的《Unity Shader入门精要》这本书中的内容为起点,逐步深入完善水面效果。

书中包含的内容有:

1.通过CubeMap生成环境纹理,计算水面反射

2.使用GrabPass获取屏幕的渲染纹理,模拟水面折射

3.用Frenel公式混合反射与折射颜色

后续个人完善内容:

1.基于Gerstner公式增加顶点动画实现波浪起伏

2.利用深度纹理实现浪花效果及调整水面到水底的可见度

3.利用噪声扰动实现伪焦散效果

4.使用ShaderGraph实现上述(Gerstner波以外)的效果

最终效果图如下(请无视场景里其它乱七八糟的东西x):


最终效果图



第一篇就简单介绍和回顾一下书里有的内容,有兴趣的朋友非常推荐买一本自己看看,写的非常详细。

首先为水面准备一张切线空间的法线贴图(随便百度一下就有,想自己做可以了解一下substance designer):



法线贴图

通常会使用一张平面网格作为水体网格,因此要达到真实世界水面的波澜起伏的效果,需要修改表面法线(即与模型上某点的切线垂直的向量)。在切线空间中,若不对法线加以扰动,法线方向就为(0,0,1),对x,y增加偏移量之后法线方向便会产生改变(这也是为什么切线空间法线贴图都是蓝色调的原因)。之后x,y的偏移量还可用于对渲染纹理采样的偏移模拟水下扭曲的效果。

利用对法线贴图采样得到的法线向量参与光照计算,可得如下效果:


增加法线贴图后的平面网格

表面起伏感就出来了,但是从侧面看其实还是个平面。追求真实感的话还需增加顶点动画。

之后就是水面的折射了,透过水面可以看到水下的物体。这部分效果通过对屏幕渲染纹理采样实现。

需要注意的是设置水面网格的渲染队列,需为Transparent,这样才能保证深度深于水面的物体正确的被渲染到纹理中。

利用屏幕坐标对渲染纹理采样,可看到水下物体(被水体平面遮挡的物体):


通过渲染纹理采样实现透明效果

然后是水面的反射。

基本原理是放一个空物体在水面中心,之后通过脚本在空物体位置设置一个临时相机,并将这个临时相机拍摄到的环境图存到一张cubemap里。之后利用水面的反射方向对这张cubemap进行采样。


cubemap反射效果

由于这个场景里只有个skybox,所以反射基本是天蓝色。

基本模块介绍完了,之后就是引入时间变量让法线贴图“动”起来了,计算公式如下:

法线贴图动态采样

此处采用两个相反方向的采样来达到水面波光粼粼的效果。

随后使用法线的xy偏移对渲染纹理的采样uv做扰动,实现水下扭曲效果。

水下折射扭曲效果

最后将上述所有代码组合起来,并使用菲涅尔系数对反射和折射颜色进行插值,便能达到一个基本的水面效果:


最终基本水面效果

到这部分源代码在作者的github都有上传:https://github.com/candycat1992/Unity_Shaders_Book/blob/master/Assets/Shaders/Chapter15/Chapter15-WaterWave.shader



下一篇介绍利用深度纹理实现浪花效果及调整水面到水底的可见度。

你可能感兴趣的:([UnityShader学习笔记]水体效果#1——折射与反射)