Flowmap是什么
用途
- 是Valve在2010年GDC中介绍的一种在求生之路2中用来实现水面流动效果的技术
- 容易实现,且运算量较小(所以到现在还在被使用)
- 使用了一张被称为flowmap的贴图,来达到控制场景中水面流向的效果
原理
- 纹理中记录了向量场信息
- Flow map上的颜色(通常为RG通道)记录该处向量场的方向(纹理采样要偏移的方向)
- 让模型上某一点表现出定量流动的特征
- 通过在shader中偏移uv再对纹理进行采样,来模拟流动效果
回顾:UV映射(纹理映射)
- UV坐标用于查找纹理的颜色值
- Unity中的uv坐标,类似于xy轴,用此uv坐标查找右边贴图的颜色值,采样会得到和贴图一模一样的结果
- 如果改变查找时的uv坐标,让每一列都有相同的uv值,那么采样结果就是右图的条纹状的结果
- 如果用同一个uv值采样的话,结果就会是同一的颜色,意味着采样纹理时使用了同一位置
实际操作
- 通过所带有的向量场信息对uv进行了一个偏移,来干扰纹理采样
- 经过flowmap发生偏移后,让原本正常的采样变成了一个扭曲的效果
- 不同软件的不同uv坐标:UE4与Unity相比,反转了绿通道,所以使用的flowmap也会发生变化。(根据不同的引擎需求进行调整)(是因为unity用的opengl的,UE4则是使用的DirectX的)
为什么要使用flowmap
-
类似UV动画,而非顶点动画。换言之,无需对模型顶点进行操作,易实现,运算开销小
-
任何和流动相关的效果都可以采用flowmap
- 液体
- 体积云运动(战神、最后生还者使用(2014GDC))
-
说到水体渲染,还有其他方案:
- FFT(快速傅里叶变换)
- Gerstner波
- 法线水等等
- 具体可以看下毛星云大佬的真实感水体渲染部分
FlowMap Shader
实现思路
- 采样flowmap获取向量场信息
- 使用向量场信息,使采样贴图时的UV随时间变化
- 对同一贴图以半周期的相位差采集两次,并线性插值,使贴图连续流动
何为流动
- 简单来说就是UV流动,根据修改采样坐标使得画面有流动效果
- 为什么不是对UV进行加法操作
- 加法是向左移动
- 以uv的(0,0)点举例,当它加一个(time,0)时该点uv坐标变成(time,0),也就是随时间增加采样了更远的点,在画面上呈现的效果为向左移动
- 类似移动的是观察贴图的窗口,将窗口像左移动,采样向右流动
flowmap流动
-
flowmap是一张能控制每个采样点流动方向的贴图
-
flowmap是使用R和G通道来存储向量信息的,这两个颜色通道的取值范围是0到1,而向量的取值范围则应该是-1到1,由此,我们需要进行一步重映射的操作
1
2
3
4//从flowmap获取流向
float3 flowDir = tex2D(_FlowMap, i.uv) * 2.0 - 1.0;
// FlowSpeed影响向量场强度,值越大,不同位置流速差越明显
flowDir *= -_FlowSpeed; -
接下来我们让重映射后的向量偏移乘上个时间,使其随时间移动
-
会发现随时间流逝,扰动效果越来越剧烈,于是做一个frac取小数的操作,使其从0到1周期变换
- 关于frac取小数的另一个理由:不取小数的话,时间一长,低端机上的特效会花掉,再往底层说,是因为浮点数的精度问题,我们知道计算机是以二进制的方式对数据进行存储,然后根据精度不同,数字变大后,更少的位数存储小数部分,导致精度缺失从而出现问题
-
取小数后,会存在1->0的突变瞬间,导致采样变形突变
-
构建两个采样差半个周期的采样,然后再对他们进行插值混合来解决这个问题(原视频有举例解释,多看几遍)
-
原理是使纹理流动一个周期重新开始时的不自然情况被另一层采样覆盖
-
应该有三角函数的方案,待查证,貌似庄懂老师课有
1
2
3
4
5
6
7
8
9// 构建周期相同,相位相差半个周期的波形函数
float phase0 = frac(_Time.y * 0.1 * _FlowTimeSpeed + 0.5);
float phase1 = frac(_Time.y * 0.1 * _FlowTimeSpeed + 1.0);
// 用波形函数周期化向量场方向,用偏移后的uv对材质进行偏移采样
half3 tex0 = tex2D(_MainTex, i.uv - flowDir.xy * phase0);
half3 tex1 = tex2D(_MainTex, i.uv - flowDir.xy * phase1);
// 构造函数计算随波形函数变化的权值,使得MainTex采样值在接近最大偏移值时有权值0,并因此消隐,构造较平滑的循环
float flowLerp = abs((0.5 - phase0) / 0.5);
fixed3 finalColor = lerp(tex0, tex1, flowLerp);
flowmap 修改法线采样
- 采样flowmap
- 得到向量场
- 构造两个相位
- 偏移UV
- 用偏移的UV采样法线(两层,并插值混合)
- 将法线用于光照计算
1 | // 使用FlowMap流动法线 |
绘制Flowmap
flowmap painter中制作
可以直接对着贴图用笔刷进行绘制flowmap操作,软件能即时看到贴图偏移后的效果。(只能用于贴图,可查看原视频制作)
下载地址:http://teckartist.com/?page_id=107
注意事项:
- 该工具获得的flowmap为线性空间下的颜色,无需gamma校正,在Unity中取消勾选sRGB选项
- flowmap在Unity中设置时,需要保证它无压缩或者高质量,并且确认色彩空间
Houdini中制作
- 主要是使用sidefx labs的插件,就会有一系列flowmap相关节点
- 学习houdini时可回顾,建议看原视频,很详细的步骤
其他工具
- Blender Flow Map Painter 插件,可直接在模型上画flowmap
参考资料
- 百人计划2.8:https://www.bilibili.com/video/BV1Zq4y157c9?p=2
- 课程PPT,有houdini操作,https://docs.qq.com/slide/DUXloeWVhV1hCTUFU
- Vlachos-SIGGRAPH10-WaterFlow
- Catlike Coding:Texture Distortion
- UnityShader入门精要
- 真实感水体渲染技术总结
- Unity Shader Graph Tutorial: Flow Maps
- 顽皮狗GDC2014(moving the heavens)
- 【完结】Unity 水、流体、波纹基础系列4篇
- UE4 —— 基于 Flowmap 实现 “燃烧溶解” 效果
- Flow Map Shader in Unity with Amplify
- 大佬笔记
- https://blog.csdn.net/qq_43210334/article/details/118031478
- https://www.yuque.com/sugelameiyoudi-jadcc/okgm7e/ulk917
- https://xzyw7.github.io/post/cPv04HHGV/
- https://www.yuque.com/liangchajun/tpdm7a/clbul0?
- https://www.yuque.com/log1024/pfgg4t/ikc0g3?
- https://blog.csdn.net/wrl780143706/article/details/119702267
作业
结合课程,实现一个流动的效果
和shader入门精要的折射与反射部分结合,搞了个怪东西(x
1 | Shader "Unity Shaders Learn/Chapter10/Glass Refraction" |
- 还想实现:
- 水体渲染
- 流动云渲染
- 燃烧物品效果