目的:

解析,改进,批评一个国外免费透明水面Shader,进一步了解Shader背后的物理原理。

参考:

菲涅尔反射

分析:

我将原水面Shader一再简化,从中抽取最主要的部分,忽略细枝末节,并改掉缺陷,指出不足。

简化版:

1.造型

其中,顶点偏移,也就是波的造型,是用贴图制造的,一目了然:

就是一张高度图经过4方向扰动,乘以波高度。然后它再乘上顶点法线在世界坐标系上的Z轴高度,这个莫名奇妙的操作会使得Normal朝上的顶点的波高更加高,而偏的更加低。我认为编者脑子里也不清楚,所以我修改了,直接乘以(0,0,1)。如果你的高度图只有b通道,这个(0,0,1)都不用乘。

2.Fresnel_Function

再观原材质图,你一定会注意到我们的主角,一个叫Fresnel_Function的节点。

UE4这样起名字,也真是大言不惭,一会我们会说到。

这个节点,涉及到一个现象,菲涅尔效应。国外一般不称为效应,搜索Fresnel equations

现象倒是很简单:

对着玻璃看,越斜着看,它反射越多,越不透明,越像镜子;

正着看,反射越少,就越透明。

我们在生活中常常见到过这种现象:

(我怀疑夏天远方道路反光,也是这个原因)

总之,这是个在各个材质上都很普遍发生的现象,包括水面。

如果说我们之前的不透明水面本质就是镜子,那我们这次的透明水面本质就是玻璃。

真正的Fresnel方程比较复杂,可脱胎于麦克斯韦电磁学方程

对于透明物体:

然而UE4的Fresnel_Function节点的方程并不根据实际。它利用视线与平面越垂直,反射越少这一点,进行了粗略模拟。这个方程也是图形学中常见的:

其中V向量是像素点到相机位置的向量,也就是光照模型中常见的View向量,与法线N起点一致。power用来控制效果,显然由于1-V·N在[0,1]间,power越大,那么越垂直于N的V的F才越大。在下图中,也就是当power越来越大,黑色会扩大,而白环会减少,慢慢收缩到最边缘那些法线十分垂直于视线的顶点上(白色为1,黑色为0):

显然这个函数可以用来做边缘光等其他特效。

那么,我们回过头来看透明水波材质。它的Fresnel节点的power赋予了5,十分接近边缘:

注意:

以下简称Fresnel_Fuction(...)为Fresnel(power)。

以下称V垂直于N的情况为“垂视”

3.金属度(Metallic)

原材质给金属度设置的是0。可以理解,因为金属材质不发生菲涅尔效应,而且金属度越高,透明金属材质越丢失BaseColor。但金属度太低,水的透明和反光也就低了一个层次。看下金属度为1的水面,按需求和风格调整即可:

(油腻的反光又出现了)

4.反光度(Specular)

反光直接给1,没什么好说的。给0就失去了波光粼粼的效果。

5.粗糙度(Roughness)

回看透明水波材质。它的粗糙度被设置为:

也就是越垂视的地方粗糙度越为0,完全光滑;其他地方为0.1,也很光滑,但较边缘差了点。

对于对面,从直觉上来说是这样,而且Roughness影响反射光计算,越光滑反射越多,符合菲涅尔效应。

实际效果上对比不明显。

6.不透明度(Opacity)

越垂视,越不透明。也符合菲涅尔效应。

7.折射率(Refraction)

在介质密度不同的表明,光发生折射。从低密度到高密度,折射角小于入射角。

回忆初高中物理,折射率定律。国外更一般叫成斯涅尔定律(Snell's Law)

由于真空密度最低,或者说真空光速最快,所以所有的材质折射率都大于1。

从真空射入某材质:

透明水波Shader认为越垂视,折射率越高,这是对的。首先直觉上,越弯曲的玻璃,折射越厉害。

其次,你可以认为空气与水折射率不变,当入射角变大,那么折射率一定要变大。

或者你可以认为折射率=c/v,在垂视的地方,光路更长,相当于v更小,所以折射率更大了。

8.风格化法线

你可能会发现我们这个水波像是三角透明玻璃组成的,十分风格化。放大之后是这样的:

原因是这个透明水波Shader的法线。

图中用了一个函数称为Shine_func,打开后发现实现十分简单,效果也和迪厅反光球一样:

关键是DDX和DDY是什么?

这个蛋疼的起名让我一开始以为是二阶导数,但明显不对。经过搜索我发现它就是屏幕空间x方向偏导数和y方向偏导数。

问题在于为什么结果它是这样的,而不是我们之前那么顺滑的连续函数。

以DDX为例,就是检查当前像素点(Pixel)在屏幕水平方向上离得最近的左右两个顶点(Vertex),计算从左顶点到右顶点的空间向量,再归一化。

我将这个结果赋予BaseColor,这样看的准一点。

当屏幕向右是世界系y方向时,其值偏向为(0,0,1)。因为屏幕上的顶点从左到右,顶点向y轴方向变化(注意左下角世界坐标系的方向):

当我大致面朝(1,1,0)方向:

注意到方块红面由于在往屏幕右方向走时,顶点世界位置x增大(导数大于0),y不变(导数为0),而z变小(导数为负,负数clamp后为0),其ddx为(1,0,0)

方块上面由于在往屏幕右方向走时,顶点的x,y方向都有增加且一样,ddx为(1,1,0)

当我的屏幕右方向更接近x轴时,方块黄面开始变红:

尽管我们的相机位置一直在变,同一个顶点的DDX和DDY也在变,但其都保持在切平面上,叉乘出来也一定是法线方向。

这里可以看出UE4材质系统的2个缺点:

1.明明与真正的WP无关,但却必须引用这个节点,给读者以误导

2.程序执行顺序对用户不清楚。这里的WP明显是已经经过WPOffset以后的WP了。WPOffset中的WP节点和这里的WP节点明明一样,出来的值却不一样,若不是我们知晓渲染管线流程,就会被搞得怀疑人生。

9.问题一:法线

上面看出来了,叉乘出来的法线应该属于世界坐标系,但我们的材质默认是切线空间法线。原材质连这个都没注意到,所以我说编者脑子不清楚

你可能记得,材质有个选项可以修改。但因为一个蛋疼的原因,我们不得不手动计算,之后会讲到。我们需要手动将世界坐标系的法线转到切线坐标系。

(上图从左到右分别是原法线,编者原材质水波法线,和我修改后的法线。我猜由于透明水波既没什么阴影,水波的折射是否正确也很难有人看出来,所以这个问题没人注意。)

所幸UE4有节点轻松解决坐标系转换:

10.问题二:折射

看到没有,球下方边缘有很奇怪的折射。

本来是水面折射,怎么会和球有关?既然有“屏幕空间反射”,那么这个折射是不是也是基于屏幕空间算的,然后出的问题呢?

在材质detail中搜索Refraction,我们发现引擎提供2种算法,默认算法是这样的:

简单地来说它警告你不要用于像水面一样的大面积折射面。关于为什么会有这个bug它也没说细说,只说这个是物理模拟。

我选择第二种:

它说这个折射是个假模拟,值给1就是没折射,2就是offset为1的折射。这个offset是啥意思它也没说清楚。还告诉我们必须用切线空间法线,这就是为什么我们之前要手动转换。

蛋疼吗?蛋疼。UE4辣鸡吗?辣鸡。

我更改"折射"为:

因为这个假折射率要比较大,折射效果才明显。没办法,谁叫真折射有Bug呢?咱目前这种情况,就是我写本系列教程的缘由,了解原理,运用原理,避免这种情况。因为弱势,所以被牵着鼻子走,不知道在干什么。很不幸,我因为辣鸡,又碰上了这种情况,成为了一个"能用就行"的乞讨者。

以后有机会尝试改写引擎代码,改写这个折射。

结语:

本篇解析,改进,批评一个国外免费透明水面Shader,对简单的物理和材质系统进行初步了解。

由于能力的不足,在折射问题上最终又成为了一个被拦在原理和实现之外的人。之后提升自己的能力,改变这一状况。

水波模拟系列到此告一段落。

Chango的数学Shader世界(七)水波模拟-透明水面,菲涅尔(Fresnel)效应相关推荐

  1. Unity shader Note :高级纹理(CubeMap反射折射菲涅尔,Rendermap镜子玻璃,程序纹理)

    1.Cubemap–反射折射 使用脚本来创建Cubemap ①通过Camera.RenderToCubemap 把任意位置观察到的场景图制作成一张Cubemap之中 ②脚本使用自定义编译窗体的命令 – ...

  2. Chango的数学Shader世界(八)光盘模拟-各向异性,光栅衍射

    目的: 参考<GPU Gems>,在UE4中尝试以重现光盘Shader,并对书中的方法进行解析,改进,批评. 参考: <GPU Gems> 观察: 我越来越意识到观察现实的重要 ...

  3. Chango的数学Shader世界(九)流体模拟-散度,梯度,二阶导与拉普拉斯

    目的: 参考<GPU Gems>,在UE4中尝试重现2D流体模拟. 本节试图结合场论知识粗略理解Navier–Stokes equations. 参考: <GPU Gems> ...

  4. Chango的数学Shader世界(十四)细线间断,发光闪烁,TAA削弱处理

    目的: 减少游戏中的细线因屏幕分辨率不足和算法采样不足问题,导致的间断,以及相对的自发光闪烁.解决了此问题也附带解决了因TAA导致的细线自发光微弱的问题. 对比视频:https://www.bilib ...

  5. Chango的数学Shader世界(十五)油画Shader-技术分析,教程纠错

    目的: 实现油画后期Shader,探究教程中技术细节,指出错误. 参考: 搜索ue4 paint filter. UE4.21后整合自定义usf 观察: 油画的特点:成块的色块,但又保持清晰的边缘. ...

  6. Unity Shader 水多种元素的实现(反射、折射、菲涅尔、深浅、浪花/泡沫、水波、可交互)

    综合效果 经过各元素叠加 和 程序的审美调参 后的综合效果 交互的水波与边缘浪花的合并需要优化一下 反射 两种方案: cubeMap 以水面对称设一个摄像机 cubeMap 实现:反射探针生成Cube ...

  7. Unity Shader:实现菲涅尔+色散效果的环境映射以及相关原理解析

    文章目录 1,色散在光学中的原理 2,反射的数学计算方法以及用它实现环境映射 3,折射的原理以及色散的实现 4,菲涅尔效果 5,拥有菲涅尔与色散效果的环境映射 1,色散在光学中的原理 复色光 --现实 ...

  8. Unity Shader:实现菲涅尔+色散效果以及相关原理解析

    1,色散在光学中的原理  2,反射的原理以及环境映射的实现  3,折射的原理以及色散的实现  4,菲涅尔效果  5,将菲涅尔与色散效果增加到环境映射中 1,色散在光学中的原理 复色光  --现实生活中 ...

  9. unity shader 菲涅尔效果

    老样子,还是先上效果图: 菲涅尔效果的原理大家可以自己去百度看看,网上有很多,这里就不多说了,我们直接看如何实现这个效果 实现思路: 1.求得视角方向,法线方向(世界空间下) 2.根据菲涅尔效果的公式 ...

最新文章

  1. 使用verdaccio 搭建npm私有仓库
  2. 如何将usb摄像头连接到虚拟机vmware ubuntu系统上?
  3. 洛谷-P2801 教主的魔法 分块
  4. json web token没有哪个成分_SpringBoot 2.1.4集成JWT实现token验证
  5. js html5是什么意思,javascript是什么意思
  6. DAY09 NETWORK Cisco简单不同网络主机通信
  7. Android控件——HorizontalScrollView使用(一)
  8. 电子商城战略分析(采用定性与定量分析方法)
  9. 【Linux】imx6ull Kernel 源码下载和编译环境配置
  10. 42张动图带你走进神奇的物理世界,超震撼!
  11. 植物大战僵尸数据修改总结
  12. 【JS】日期Date如何格式化为年月日yyyy-MM-dd hh:mm:ss
  13. windows下域名解析及修改hosts文件不起作用的问题解决
  14. 再读《谁动了我的奶酪》
  15. java基础(适合零基础)持续更新
  16. OPENHPC搭建集群
  17. AI 编程“神器”国产化!华为耗时 8 个月,这个能用中文生成代码的模型诞生了...
  18. OSS Browser的使用
  19. Windows 命令
  20. c#和数据库技术基础之程序设计集散地-数据库

热门文章

  1. c# image转换为bitmap_WPF将BitmapImage图片对象转换为Bitmap图片对象
  2. android加固和multidex,Android Multidex正确使用方式(你可能也会遇到的坑)
  3. 数据库中 码、候选码、主码 的区别
  4. 服务器与交换机连接及校园网搭建方案
  5. Kingfisher基本入门介绍
  6. java web工程中使用帆软报表生成报表
  7. QML charts 鼠标动态跟随数值(十字交叉定位)
  8. PMP——项目的定义以及特点
  9. 最新消息!微信正在内测批量删除好友功能,附内测链接!
  10. Pycharm上传,更新本地代码到GitHub(常见问题及解决)