Chango的数学Shader世界(二)水波模拟

23 篇文章 10 订阅
21 篇文章 5 订阅

目的:

推导出一个水波Shader,先造型,再考虑表面材质。本篇考虑造型。

参考:

《GPU Gems》

引言:

我该怎样看待数学与Shader的关系呢?

我有一个答案,那就是把数学看作你的朋友/工具,了解它的每一部分,在特效需求的每一步中你都能敏感地发现它的影子。

比如,我怎么用拼图拼成一个房子呢?

从那个尖角的特征中,你立刻想到了你的好朋友三角形,然后你发现正方形+三角形,就能解决需求:

同样的,本节的水模拟和三角函数(Sin,Cos)的关系,也被拥有数形结合能力,熟知常用数学函数的你发现了。

(注意sin和cos在频率一致的情况下形状一样,只是位置有偏差而已。之所以海浪的形状会像sin/cos,是因为真实海浪波动方程就含有这两个函数,但我们并非在物理模拟,而是用数学函数的形状“画”出我们感觉像海浪的图形)

思路:

    准备一个多顶点的平面模型,在Shader中通过调整每一个顶点z轴(高度方向)的位置,将平面转化成为一个波浪面。

本节就先使用三维空间中的Sin(x),计算得顶点z轴坐标(之后博文进一步优化)。这样,最终效果应该与上面图3的形状一致。如果你不理解3维空间中的Sin(x)为何是图3这样,将2维图形z=sin(x)如同切片一样层层迭起,这些曲线在空间中就形成了图3的波面(或者说,你拿平行于xz平面的切片去切图3,在切面上总能得到类似图2的sin曲线)。

步骤:

1.准备多顶点平面

我是用maya准备的,十分简单,你也可以用其他建模软件。我的顶点数是200*200,这样等会出来的波面会比较丝滑。过少的顶点会导致波面锯齿,甚至出现奇怪的形状。就其原理来讲,就是连续函数转离散的时候出了问题,在通信原理中,有Nyquist定理(采样定理),当网格顶点间距大于最短波长的1/2,会发生失真。没错,我们的理想函数Sin(x)就是被采样信号,我们的模型是用来采样的,这一视角十分有趣。马上我们会检视到这一定理。

2.编写Shader

在UE4的材质中,搜索world position,得出红色的Absolute World Position节点,这就是顶点原坐标,类型为float3。

在材质栏中有WorldPositionOffset。即顶点世界位置偏移。若给它(0,0,0),则顶点原封不动。

方便起见,我们将平面在世界中的z坐标置为0,并让y轴朝向我们,这样可从侧面看到波形。

显然对于原顶点(px,py,0),我们需要的偏移为(px,py,sin(px))-(px,py,0)=(0,0,sin(px))。

我们通过在Custom节点填写HLSL代码实现

float3 re;
re.x=0.0f;
re.y=0.0f;
re.z=100*sin(0.01f*OriPos.x);
return re;

然后把材质应用于平面

3.分析

细心的你会发现,我实际上用的是100*Sin(0.01*x),而不是Sin(x),为什么呢?

先说结论:100是为了加大振幅,看得更清楚。0.01是为了加大周期,即增大波长,防止Nyquist定理告诉我们会出现的失真。

加大振幅很好理解,那如果我们不加大波长呢?

这是100*Sin(x) :

这是100*Sin(0.1x),波长大了10倍:

 

可以看出,在波长特别小的情况下,图形会十分奇怪,完全没有sin(x)的样子,这时顶点间距相对太长完全不能充分取满曲线;而稍微长一点会发现,呈现出了振幅一致的周期性,但还是不够光滑。大概是这么个采样情况:

当波长过小,采样间距大于1/2波长,呈现出红色的采样状态,与原曲线相差甚远。

当波长中等,呈现出绿色采样状态,虽然锯齿明显,但已有大致形状。

下面来体会一下从正常采样到失真采样的过程吧(波长逐渐变小):

我们最后来回顾一下初高中学过的Sin/Cos函数,然后计算出为了避免失真我们的最小波长。

目的有3:

1.熟悉函数,为之后优化水波shader打好基础

2.假如你需要大小随机的波浪增加真实感,那计算出最小波长是必须的。

3.Sin/Cos在数学、Shader的世界中相当于英文中的abc字母,是最基础最常见的东西。

这里不谈Cos,因为Sin和Cos可以互相转换,本质上是一样的。

Sin(x+2\pi )=Sin(x) ,Sin(-x)=-Sin(x)

Cos(x+2\pi )=Cos(x),Cos(x)=Cos(-x)

Sin(x+\frac{\pi }{2})=Cos(x)

Cos(x-\frac{\pi }{2})=Sin(x)

A\cdot Sin(\omega\cdot x+p)

A:振幅

w:频率

p:相位

其中周期(或称波长)T有计算公式:

T=\frac{2\pi }{\omega }

更改相位p(phase),其实就是将图像左右移动

最后,材质中的HLSL代码是:

float3 re;
re.x=0.0f;
re.y=0.0f;
re.z=100*sin(2*3.14f/T*OriPos.x+p);
return re;

最后,我们来算一下最短波长。这里模型顶点的间距为10个UE单位。

"网格顶点间距不能大于最短波长的1/2"

10\leq \frac{minT}{2}

最短波长为20。

结语:

本篇实现了水波Shader的初步造型,并对实际步骤中的问题进行了分析。通过最后几张图,你会发现通过持续改变相位,可以使波浪“动起来”,而调整振幅和波长,可以带来一些波浪上的变化。

对于表面材质来说,你可能没有注意到当前的法线信息并不对。

总之,下一节会继续优化水波材质,计算法线。

  • 6
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值