水渲染记录
工作中,经常接到水渲染的需求,项目不同,要求也不同。断断续续几年里,从简单到复杂,也弄了一些,最近索性把市面上做的比较好的一些案例拿到研究了一遍,下面是根据Unity提供的Demo BoatAttack学习后重写的效果,记录一下实现过程。
海水组成:
水面波: Gerstner Wave
Gerstner Wave是比较简单常用的一种,也能做出挺不错的效果,相关介绍各种大佬也已经说了很多,我这里就直接记录怎么使用
海浪谱公式
参数解释:Q = 尖锐参数 A = 振幅 D = 波方向 w = 2π/L(L=波长)
将公式写成代码 先在c#中模拟看效果
调整尖锐度对应变化
两个叠加
三个叠加
四个叠加并调高QA 使得海浪看起来更汹涌
再加个主浪 全部调整波长
通过对参数的控制和波的叠加可以模拟出很多环境不同的水面效果,从平静的湖面到汹涌的大海,根据自己的理解写出代码去尝试才会有更深的体会.
计算法线:
法线公式:
其中:
将球拉长 将计算出的法线朝向赋值给小球 验证法线结果
现在 波形和法线都有了!
海水渲染
按照我的片元函数书写顺序罗列篇首效果组成
1.镜反
2.法线
3.菲尼尔
4.高光
5.折射
6.焦散
7.sss
8.白沫
镜反:附加相机RT传入
//_PlaneReflectTex由外部传入
reflection += tex2D(_PlaneReflectTex,fixed2(screenUV.x,(1-screenUV.y)) ).rgb;
法线: 混合法线扰动
half2 reflectionUV = screenUV + normalWS.zx * half2(0.02, 0.15);
reflection += tex2D(_PlaneReflectTex,fixed2(reflectionUV.x,(1-reflectionUV.y)) ).rgb;
菲尼尔:
half fresnelTerm = pow(1.0 - saturate(dot(normalWS, viewDirectionWS)), 5);
reflection *= fresnelTerm;
高光: unity内置DirectBDRF
高光+阴影
高光+阴影+镜反+菲尼尔
折射:
//_CameraOpaqueTexture非透抓屏传入
half3 refraction = tex2D(_CameraOpaqueTexture,distortion).rgb;
焦散: 结合深度
折射+ 焦散
折射 焦散 深度渐变颜色
sss:
sss 折射 焦散 深度渐变颜色
以上叠加
白沫:
1.算白沫遮罩:根据上面计算的波形法线,波峰 + 海岸线 生成白沫遮罩
2.采样白沫贴图:采样白沫贴图*遮罩
3.白沫光照:主光,环境光,阴影
最终着色
船尾浪花
实时RT 白沫 + 叠加细节波影响尾浪法线