本系列学习资料来源,Ben Cloward的油管空间,B站的搬运翻译
接下来的这个系列是一组新的关于水的shader
先来看看水吧
原视频地址,内有本节的贴图链接
首先我们需要一个较好看的水的法线贴图,去goole上搜一搜
我们使用的法线图如下
使用一个叫做panner的节点来滚动纹理,传入一个速度的变量以后,得到这种效果
但是这样存在一些问题
它移动的很快,真实的水的运动是很混乱的,但目前动的太统一了
我们把panner节点的输出接到UV上,在前面使用世界位置投影,让水只在XY平面有
可以看到我们现在是在对角线上移动,因为我们的Speed同时作用了UV
于是进行改动,可以把Speed连出来的常量改成二维向量
我们如果多次复制以上这一组合,那么就可以在涟漪中制造一些混乱
也就是多次采样法线图,朝着不同方向滚动,进行叠加
我们再把Z补上,使用的是自动算Z的这个节点
看着很像水,不过,在本节中不涉及反射折射透明度,只专注于涟漪的实现
除了波纹,我们还可以再复制一组法线,调慢速度制造慢一点的波浪
甚至我们还可以把之前写雨滴涟漪的方法放进来
下一节,我们尝试水的深度颜色和深度透明度
在进入这节之前,我们可以先看看最终的完整的水的着色器会是什么效果
我们会有涟漪,有水深,有折射有反射,这就是我们的目标
下面第一件事,在上一节shader基础上,选择混合模式为半透明
接下来我们就要来解决深度问题
有两个因素会影响水的不透明度,一个是我们看水面的角度,一个是水的深度
所以我们需要有一种方式去测量水深
下面介绍第一种方式
该方式有几个节点可以用到,SceneDepth和PixelDepth
我们用一张图来辅助理解这两个节点在干什么
Scene Depth返回从相机方向开始,到场景最近的一个像素。会忽略透明物体
Pixel Depth返回从相机到这个半透明水面的距离
两者相减得到一个新矢量,也就得到了一种深度
我们简单的获取蓝色的向量,做一个除法和幂次操作
构建一个小的场景,围一个范围,里面摆些演示,摆上一个面片附加我们的shader,可以看到效果
表现了一些深度近似值,从有一点黑,到变得纯白
这就是我们需要的数据,我们可以根据这个来创建蒙版
但是存在一些奇怪的现象
以下是我们垂直看的效果
然后这是我们水平看的效果
我们的角度越水平,相减得到的向量越大,越不透明
计算的深度是深紫色的深度,然而浅色的深度才是真正的深度
我们怎么计算实际的深度呢?
因为之前的两个depth,引擎都帮我们算好了值,所以我们来相除,得到比例
通过相机位置减去世界位置,得到Pixel depth的向量值,乘以比例得到Screen depth的向量值,两个向量相减,拿到Z的差距,也就是深度了(原视频的做法我无法理解,于是用自己的方法了)
可以看到用自己的方法“水深”也是不变的
影响水的透明度的因素还有看水面的角度,我们会使用Fresnel节点
我们更改根节点的光照方式,然后连上法线,在结果乘上一个深度衰减来柔和边缘
哦,还有一点,我们做的是不透明度,所以最后要连回不透明度
可以看到深度达成了
为了更好的表现反射和折射,我们把此前的链接都断开,只是给一个粗糙度常数为0
我们的场景反射了天空,但是,岩石的反射呢?
这就要涉及UE4中反射的实现方式,反射是很复杂的,一般来说在UE4中有5种不同的实现方式,UE4中许多场景都是采用多种反射方式组合使用
这里介绍其中三种
第一种就是天空盒,正如图上所示,但是如果我们要反射更近的局部对象呢?
也就是Light Probe光照探针
在默认的场景中,这个图标的名字是球体反射捕获,它做的事情,是从这一点开始,捕获一个cubemap,然后将该cubemap用于创建反射
我们创建一个探针,可以看到效果
这样很方便偏移,只要捕捉一次立方体贴图就可以拿来反射
但是还是有问题的,因为这只是从探针那个点来说是正确的,一但移开就有错误
因此探针反射,虽然便宜但也有缺点,只是比单纯用天空盒好些
第三种方法是屏幕空间反射
关于这个方法就要回到shader的根节点上,勾上红框中的选择
效果很好,但是屏幕空间反射只能用屏幕数据,一但不在屏幕内的物体就看不到了
我们可以三个一起用,同时先把雨水的涟漪去掉,调低一点水面的波纹
但是还有问题,这个石头太完整了,缺失了折射效果
这在根节点的设置中也有
这一节没有对材质节点做很大修改,主要是设置方面
在这节中,我们会为我们的水加上几何波
我们现在是有水的波纹,但是它很小,并且观察交接处只是僵硬的连在一起
所以我们这节要做的是就是给水面添加动画
但是,回到之前的shader,我们发现水面交界处有这种绿线,看着很奇怪
这是深度渐变节点造成的
我们小作修改
我们注意到,这个折射效果各处都一样
我们希望在水的边缘处减少折射的效果,这时候深度渐变节点又可以派上用处
接下来我们正式可以进入本节几何动画的内容了,我们用线框模式查看场景,可以看到我们所用的水面,其线框是很稀疏的,三角形不多
如果就这样进行几何移动,我们会有很粗糙的动画效果,我们进入shader的根节点,设置曲面细分,这样就能方便对顶点进行动画处理
但细分之后其实性能消耗也更昂贵,要注意谨慎控制这个值
所以我们为了更好的控制细分,我们一般会使用相机和表面的距离来减少曲面细分乘数,越远,三角形越少。似乎有些偏题,所以这次我们只用一个常数0.5
到这里,我们终于可以开始操作几何了,通常的我们会使用这个
但因为使用了曲面细分而不是真实网格,我们会操作这个东西
我们会使用数学公式来模拟海浪,也就是Gerstner公式
关于Gerstner方法,这里找到了几篇很不错的博客
水面的简单渲染 – Gerstner波
Gerstner 水波详解
大意如下,一般的波动效果,诸如sin函数,只是顶点y坐标在时间函数下上下波动,顶点根本没有发生水平移动。
但是实际的水不仅仅只有表面。下面还有更多的水。
当表面的水向下移动时,其下方的水会怎么运动?当表面向上移动时,什么填充了其下面的空间?
事实证明,表面点不仅向上和向下移动,而且也向前和向后移动。
它们有一半的时间与波一起移动,而另一半则沿相反的方向移动。表面以下的水也是如此,但越深,运动就越少。
下图为正弦波与Gerstner波
Gerstner波以参数方程的形式给出:
自变量为p,参数Q、D、A用来控制形状。Q控制波峰的尖锐度,D控制波长,A为振幅。
我们直接在材质编辑器中开始做(说实话后面它这么连到最后实现这个波,我是不明觉厉的,求大神细细理论分析,我爬了.jpg)
以下节点连到世界场景位移中
开始动起来了,是很像水,但是还缺少一些东西
Gerstner算法的一部分是进行坡度控制,但是我们现在还没有添加,所以看起来这个运动是非常平滑的
Gerstner算法能让我们有控制波峰尖锐与否,以及波浪是否陡峭的能力,于是我们接着实现
同时调整一下数据,让其更尖锐,效果更明显
但这样确实真的不像水,我们还有几件事没做
首先我们改变了表面的形状,但是我们却没有改变法线,所以就会感觉虽然动起来很像波,但是看着还是光照很平坦的样子
调整一下数值
这样很不错,但是现实中不只是有一种波在动,而是很多不同的波在传播
于是我们想要构建材质函数,来通过多次调用,可控地实现这个功能
将gerstner的方法进行材质函数的构建
回到原来的shader,我们构建三组不同的波进行叠加
这样看去就不那么具有重复性了
本期的视频地址,内有本节用到的贴图链接
在制作之前,首先我们看看真实生活中的样子是什么样的
现实中,当我们进入水下
太阳照耀着水面,水面的涟漪扭曲着光照,把这些光照变成非常酷炫的样子
我们在UE中使用实现的方式,会是贴花(decal)
贴花(decal)在游戏里面是运用的比较多的,因为他可以简单的把图片运用不同的叠加方式绘制到另一个物体的表面,比如说游戏中的脏迹,脚印,弹孔和血迹等,都是贴花的效果。
我们使用decal的原因,是我们想要这些焦散的效果投射到水下的所有东西上,但是又不想要去该shader
如下图,在绿框内的所有物体都会附上焦散效果
下面我们开始做
新建一个材质球,在其根节点进行设置
这是我们用到的纹理
这里有这么个软件可以用来创造这种图案 下载地址
亮纹处模糊的效果如何实现?在ps中,蓝通道向左移动1像素,红通道向右移动1像素
我们开始连节点
主要思路是,进行世界坐标投影,保证三个方向都能得到正确的焦散结果
而后根据一组法线纹理作出扰动,去扰动两组运动速度不同的焦散纹理,进行叠加
两组纹理和扰动
可以看到,在三个方向都获得了很好的投影效果
将其放到水中,调节一下参数
非常酷炫
本节视频地址,内有所使用的贴图链接
在这一节,我们要在26节水的着色器基础上加一些泡沫
一般来说,水的泡沫发生在与其他物体相撞很迅速的时候
在自己做的小场景,加上泡沫可能不太合理,不过我们也依旧试着做做。
我们首先用到一个泡沫贴图,它的三个通道图片如下,三种不同数量的泡沫
我们通过这些,要做的是让泡沫在某些区域变厚,其他区域变薄
因为泡沫它不是可以均匀混合的东西,它是致密的或者稀薄的,所以有三个mask,分别是薄中厚
接下来还有一个渐变图,依然是三个通道
泡沫出现表示为在左边是黑的,然后根据消失速度的不同,设置渐变
用来控制泡沫的数量
我们在使用纹理时,需要用到一个引擎自带的材质函数,右键func,选择MaterialFunctionCall,按照如下寻找到这个函数
该材质函数作用是,采样一个纹理四次,每次进行不同的位移,然后叠加起来,造成混乱
其内部是这样子的
为了控制泡沫出现的地方,我们会使用之前用过的深度图,让泡沫只在边缘出现
divide连出来的是这里
颜色这么设置
泡沫的应该是不透明的,也就是输出结果连到add
结果会是这样
这是一种用法,我们只用深度添加泡沫
但是我们也可以自己绘制mask,让mask投影在世界坐标下,去控制渐变图的UV
我们也可以在Gerstner的波峰的地方加入泡沫,通过数学计算,去控制渐变图的UV
这一节我们要做FlowMapping
什么是FlowMapping?
我们此前做了水的shader,也有涟漪,但是这些涟漪(ripples)没有一个主要的方向,它只是泛泛的涟漪
但是如果我们想要制造一条溪流呢?他们有特定的流动方向,或者我们想要精确定义方向的时候该怎么办呢?
这时候,FlowMap就可以做到这一点,我们可以绘制一个纹理,其中每个像素都代表了流向,然后我们在shader中用它来移动涟漪。
我们可以用一个叫做FlowMap Painter的程序来绘制它,软件地址在这里
绘制个圈圈
转换成方向向量图
看看运动线
然后我们选择 Bake to Texture 即可获得纹理,导入UE4,我们来构建我们的FlowMap Shader
UE4自带了一些相关的FlowMap的函数去使用,但是我们本节的目的是了解其背后的数学原理
简单示例,可以看到这种扭曲效果带来的影响
我们加入时间的影响,同时用锯齿波来进行时间动画的制作
测试的效果如下
在shader中使用
断开原来的Normal和世界场景偏移
得到效果
这是一种通用的FlowMap的使用方式,在实际使用中,我们更可能使用顶视图观察场景
进行截图之后PS裁剪处理,导入之前的FlowMapPainter,输入路径即可叠加
这样我们就能根据实际场景,自己画自己的FlowMap