实时水面波动模拟的两种方式

本文介绍了两种实时水面波动模拟方法:Gerstner Waves和统计波模型。Gerstner Waves利用GPU Gems中的物理模型,通过调整参数实现不同效果。统计波模型基于傅里叶变换,通过生成随机高度场模拟逼真的海浪,并通过优化计算降低复杂度。最终,由于Crest Ocean项目的丰富资源,作者选择采用Gerstner Waves。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Crest

图片来自大名鼎鼎的Crest Ocean项目截图,其波动算法为Gerstner Waves
因为HDRP项目需要一套水,现有的水都比较简陋,所以又双叒叕在做玩具
主要是 Gerstner Waves 和 Statistical Wave Models

Gerstner Waves

1. Gerstner函数

在GPU Gems 第一部分 第一章 用物理模型进行高效水模拟 中提供了Gerstner函数:
Gerstner函数
其中 Q i Q_i Qi是控制波坡度的参数。对于单个波 i i i Q i = 0 Q_i = 0 Qi=0 会得到正常的正弦波,而 Q i = 1 / ( w i A i ) Q_i =1/ (w _i A_i) Qi=1/(wiAi) 可以给出尖峰的波形。我们可以提供可调参数到面板,使用 Q i = 1 / ( w i A i × N u m W a v e s ) Q_i =1/ (w _i A_i \times NumWaves) Qi=1/(wiAi×NumWaves) 控制波的平滑程度。
然后,我们可以通过分别对 x , y x,y x,y偏导,求出切线和副切线向量:
切线
副切线
然后 B × T B \times T B×T 得到法线方向
法线方向
其中
WA, S, C
可见,计算复杂度随着波形的数量变化;文章开头是启用了8八种波形的效果,但我们往往只需要计算坐标和法线。
实现的话只需要把公式算出来罢了

float3 GerstnerWave(float2 pos, float A, float Q, float T, float Phi, float D, out float3 normal)
{
   
    float3 outPutPos = float3(0.0f, 0.0f, 0.0f);

    float2 Dir = normalize(float2(cos(D), sin(D)));
    float Omega = (2.0f * 3.14159265f) / T;
    float WA = Omega * A;
    float Qi = Q / WA;
    float TSP = _Time.y * Phi;
    float fun1 = TSP + Omega * dot(Dir, pos);
    float cosFun1 = Qi * A * cos(fun1);
    float sinFun1 = sin(fun1);

    //P(x,y,t)
    outPutPos.x = Dir.x * cosFun1;
    outPutPos.y = A * sinFun1;
    outPutPos.z = Dir.y * cosFun1;

    //法线计算
    float2 P = float2(outPutPos.x, outPutPos.z);
    float tempValue = Omega * dot(Dir, P) + TSP;
    float cosFun2 = cos(tempValue);
    float sinFun2 = sin(tempValue);

    normal.xz = Dir * WA * cosFun2;
    normal.y = Qi * WA * sinFun1;

    return outPutPos;
}

叠加的部分,需要几次层得加几层

offsetVertex += GerstnerWave(v.vertex.xz, _A.x, _Q.x, _T.x, _Phi.x, _D.x, tempNormal);
finalNormal += tempNormal;
2. 效果

感觉很容易控制和调节,而且比较节省
在这里插入图片描述

Statistical Wave Models

1. 实用的海浪算法

基于FFT的高度场表达式
在这里插入图片描述
其中 t t t 是时间, k k k 是二维坐标,即水平坐标
在这里插入图片描述
n n n m m m 是整数,N、M是傅里叶变换的规模,必须是2的幂次方; L是网格的大小
在这里插入图片描述 在这里插入图片描述
x x x 为水平离散点坐标
在这里插入图片描述
现在,我们只剩 h ( k , t ) − \stackrel{-}{h(k,t)} h(k,t)未知了。

2. 建立随机的高度场

水波高度场的实现是由迄今为止详细阐述的原则:具有规定形式的空间谱的高斯随机数来实现的。这是直接在傅里叶域中实现的最有效的方法。波高场的傅里叶振幅可表示为
在这里插入图片描述在这里插入图片描述
其中, ξ r \xi_r ξr ξ i \xi_i ξi 是均值为0,标准差为1的高斯分布的随机数,分布形式的不同,会导致不同的效果。
原文中提到,对大量的海洋表面波浪浮标、照片和雷达测量数据的统计分析表明,波浪高度振幅几乎是统计上显著的、独立的、高斯波动,频谱统计均值可表示为:
在这里插入图片描述
有很多经验模型模拟 P h ( k ) P_h(k) Ph(k),其中 Phillips 比较常用
在这里插入图片描述
其中 L = V 2 / g L = V^2 / g L=V2/g ,V是风速,g是重力加速度, w ^ \hat w w^是风的方向。

现在,我们有了计算 h ( x , t ) h(x,t) h(x,t)所需的所有信息。

3. 优化计算

这个计算量明显要比上面的方法大太多了,为了把计算的复杂度降下来,除了尽量分离可预计算的参数之外,FFT必须得掌握
看了几篇文章,总结就是利用单位根的性质,计算基于点值表示的多项式,然后转换回去。

1. 基于点值的多项式计算

对于多项式
A ( x ) = ∑ l = 0 n − 1 a i ⋅ x i A(x) = \sum ^{n - 1}_{l = 0} a_i \cdot x^i A(x)=l=0n1aixi
把不重合的差值节点 ( x 0 , x 1 , x 2 , . . . , x n ) (x_0,x_1,x_2,...,x_n) (x0,x1,x2,...,xn) 分别代入 A ( x ) A(x) A(x),得到 ( y 0 , y 1 , y 2 , . . . , y n ) (y_0,y_1,y_2,...,y_n) (y0,y1,y2,...,yn),这就是多项式的点值表示法
仅仅是表示方法并没有降低计算复杂度,复杂度的降低主要依赖于单位根的性质。
在单位圆中,单位根 w n k w^k_n wnk可表示为:
w n k = c o s ( 2 π ⋅ k n ) + i ⋅ s i n ( 2 π ⋅ k n ) w^k_n = cos(2\pi \cdot \cfrac{k}{n}) + i \cdot sin(2 \pi \cdot \cfrac{k}{n}) wnk=cos(2πnk)+isin(2πn

### PyCharm 打开文件显示不全的解决方案 当遇到PyCharm打开文件显示不全的情况时,可以尝试以下几种方法来解决问题。 #### 方法一:清理缓存并重启IDE 有时IDE内部缓存可能导致文件加载异常。通过清除缓存再启动程序能够有效改善此状况。具体操作路径为`File -> Invalidate Caches / Restart...`,之后按照提示完成相应动作即可[^1]。 #### 方法二:调整编辑器字体设置 如果是因为字体原因造成的内容显示问题,则可以通过修改编辑区内的文字样式来进行修复。进入`Settings/Preferences | Editor | Font`选项卡内更改合适的字号大小以及启用抗锯齿功能等参数配置[^2]。 #### 方法三:检查项目结构配置 对于某些特定场景下的源码视图缺失现象,可能是由于当前工作空间未能正确识别全部模块所引起。此时应该核查Project Structure里的Content Roots设定项是否涵盖了整个工程根目录;必要时可手动添加遗漏部分,并保存变更生效[^3]。 ```python # 示例代码用于展示如何获取当前项目的根路径,在实际应用中可根据需求调用该函数辅助排查问题 import os def get_project_root(): current_file = os.path.abspath(__file__) project_dir = os.path.dirname(current_file) while not os.path.exists(os.path.join(project_dir, '.idea')): parent_dir = os.path.dirname(project_dir) if parent_dir == project_dir: break project_dir = parent_dir return project_dir print(f"Current Project Root Directory is {get_project_root()}") ```
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值