风格化水面实现笔记
演示视频https://youtu.be/Z8lJ-8gI7V0
一些实现细节
Base Color
传入三个颜色值:深海色,浅海色和波峰色
根据海床深度在深海色和浅海色之间插值,
再根据波峰高度(disp map)在上一步得到的颜色和波峰色之间插值
法线
在造型得到disp map的同时算一张对应的normal map,渲染时需要用到这个normal,否则geometry虽然改了但是渲染的结果是平的。
在这个基础上加上两张水面细节bump map,以不同的方向进行uv流动。tiling也要不同。
bump map的scale根据水面离相机的远近变化,越远越小。这样做一是因为远的地方没必要加细节法线,二来可以缓解大范围normal map tiling的视觉重复感。
三个深度
海床深度:从上到下,由正交相机捕捉到的深度值海面在相机视角的深度 surfaceDepth
[*]海床在相机视角的深度 sceneDepth
sceneDepth - surfaceDepth得到光路在水中travel的距离
反射
根据当前相机位置,找到关于海平面的平面对称点,生成一个反射相机,记录renderTexture。
//这个反射相机只看见特定layer和天空盒。近处的石头如果用这种方法反射会出问题,可以不让反摄像机看见近处的石头,反正近处反射弱。
在渲染水面时采样这张renderTexture,采样的坐标受到世界空间的法线扰动。
采样得到的颜色跟base color相乘,比例可调。
折射
折射用GrabPass实现,采样坐标受到切线空间的法线扰动,
然后把采样得到的折射颜色值和BaseColor根据之前算出的waterTravelDistance插值。travel距离短,能看到水底,距离长,不能看到水底。
用这样的方法实现折射的好处是,整个shader可以是opaque的,半透明的部分用这个方法代替。
根据fresnel结合反射和折射
一个trick:接近岸边的部分专门降低了反射率,提升了折射率。这样可以让水体和岸边更好的融合,视觉上不会显得突兀。
Wave Foam
在生成disp map的时候可以根据mesh的曲张程度(jacobian >1, <1)来决定哪里生成浮沫。
生成的浮沫需要流动(uv流动),需要随时间消散,需要二值化来达到卡通的效果。
浮沫整体强度在接近岸边的时候下调,避免突兀。
Coast Foam
利用之前算出来的waterTravelDistance,这个值很小的地方就是接近岸边的地方(不一定是岸,也可以是泡在水里的石头等等)
//这个方法的不足之处在于,浮沫区域的宽度会受到近岸除海床的斜率的影响。斜率很小则浮沫区域很宽,斜率很大则浮沫区域很窄。
使用sin函数和一张noise贴图叠加,并且进行二值化,最终得到白色的岸边浮沫。
浮沫整体强度也受到fresnel值的影响。脚下的浮沫看起来淡,远处比较强。(参考原神)(大概是因为这样的浮沫在近处看很丑吧)
这里用的fresnel的值和之前混合折射反射用的fresnel值不一样。这个值计算的时候,法线使用(0,1, 0)而非实际法线。否则在波浪大的时候,浮沫强度忽明忽暗,效果不好。
风格化高光Specular项
使用phong shading的公式计算,但是用到的法线是特殊的法线。
特殊法线由实际法线和(0, 1, 0)根据srufaceDepth插值而来。这样远处的specular就会更聚拢,近处更分散/受扰动更大。
根据一个threshold进行二值化,以达到风格化的效果。
这个specular项加在reflection项上参与fresnel混合,这样近岸处更加柔和。
焦散caustic
一张voronoi噪声用两个不同的流动速度和方向进行采样,并用min混合。
用unity projector把混合结果投影在terrain上海拔低于0的部分
接近海拔0的地方做渐隐,离相机过远的地方做渐隐。
潮湿沙地
同样使用unity projector在terrain上海拔低于0的部分投下淡淡的黑色。
用sin函数扰动边界并且在边界处blur。
页:
[1]