zoukankan      html  css  js  c++  java
  • 真实感海洋的绘制(二):使用快速傅里叶变换加速波形计算

    真实感海洋的绘制(二):使用快速傅里叶变换加速波形计算

    其实上一篇博文所写的\(H(\vec{x},t)​\),就是二维傅里叶变换的求和式,之前的暴力计算法属于二维的离散傅里叶变换(Discrete Fourier Transform, DFT),利用二维的快速傅里叶变换(Fast Fourier Transform, FFT)可以将复杂度从\(O(n^4)​\)降低到\(O(n^2\log{n})​\)

    如果读者不熟悉FFT,强烈建议阅读《算法导论》相关章节,个人感觉没有什么资料讲得比《算法导论》更清楚了。书后习题还有关于二维FFT的思考,是本文算法正确性的理论基础。

    数学推导

    高度场

    出于数学上推导的简单和实现上的简单,我们约定\(L_x=L_y=N=M=2^k\),把方程重写为如下形式

    \[H(\vec x,t) = \sum_{\vec{k}}h(\vec k, t)e^{i\vec{k}\cdot \vec{x}} \mbox{, where } \vec{k}=(2\pi n/L,2\pi m/L), \ \vec{x}=(x, z)\\ -N/2\le n, m < N/2 \]

    \(\vec{k}\)\(\vec{x}\)带入整理得

    \[\begin{align} H(\vec{x},t)&=\sum_{n=-N/2}^{N/2 - 1}\sum_{m=-N/2}^{N/2-1}h(\vec{k},t)e^{2\pi nxi/N+2\pi mz/N} \\ &=\sum_{n=-N/2}^{N/2-1}e^{2\pi nxi/N}\sum_{m=-N/2}^{N/2-1}h(\vec{k},t)e^{2\pi mzi/N} \end{align} \]

    为了化成便于使用FFT的形式,令\(n'=n+N/2\), \(m'=m+N/2\)

    \[H(\vec{x},t)=\sum_{n'=0}^{N-1}e^{2\pi(n'-N/2)xi/N}\sum_{m'=0}^{N-1}h(\vec{k},t)e^{2\pi(m'-N/2)zi/N} \]

    其中

    \[\begin{align} e^{2\pi(n'-N/2)xi/N}&=e^{2\pi n'xi/N}e^{-\pi xi}\\ &=(-1)^x e^{2\pi n'xi/N} (\mbox{ note that }e^{\pi i}=-1, N\ge 2) \end{align} \]

    所以

    \[H(\vec{x},t)=(-1)^{x+z}\sum_{n'=0}^{N-1}e^{2\pi n'xi/N}\sum_{m'=0}^{N-1}h(\vec{k},t)e^{2\pi m'zi/N} \]

    这样已经成为了可以进行FFT的形式。这儿出现了一个\((-1)^{x+z}\),不用担心,在全部计算完之后带入即可。

    法线

    关于法线的计算有一些tricky。我们先写出之前给出的法线公式

    \[\epsilon(\vec{x},t)=\nabla H(\vec{x},t)=\sum_{\vec{k}}i\vec{k}h(\vec{k},t)e^{i\vec{k}\cdot \vec{x}}\\ \begin{align} \vec{N}(\vec{x},t)&=(0,1,0)-(\epsilon_x(\vec{x},t),0,\epsilon_z(\vec{x},t))\\ &=(-\epsilon_x(\vec{x},t),1,-\epsilon_z(\vec{x},t)) \end{align} \]

    问题在于计算\(\epsilon(\vec{x},t) = (\epsilon_x, \epsilon_z)\)。我们首先类似\(H\)的推导得到

    \[\epsilon(\vec{x},t)=(-1)^{x+z}\sum_{n'=0}^{N-1}e^{2\pi n'xi/N}\sum_{m'=0}^{N-1}i\vec{k}h(\vec{k},t)e^{2\pi m'zi/N} \]

    经过观察我们发现\(\epsilon(\vec{x},t)\)的两个方向分别只与\(\vec{k}\)的两个方向有关,那么可以写成如下形式

    \[\epsilon_x(\vec{x},t)=(-1)^{x+z}\sum_{n'=0}^{N-1}e^{2\pi n'xi/N}\sum_{m'=0}^{N-1}ik_xh(\vec{k},t)e^{2\pi m'zi/N}\\ \epsilon_z(\vec{x},t)=(-1)^{x+z}\sum_{n'=0}^{N-1}e^{2\pi n'xi/N}\sum_{m'=0}^{N-1}ik_zh(\vec{k},t)e^{2\pi m'zi/N}\\ \]

    然后分别计算即可。

    偏置量

    类似地,我们写出偏置量的公式

    \[\vec{D}(\vec{x},t)=\sum_{\vec{k}}-i\frac{\vec{k}}{|\vec{k}|} h(\vec{k},t)e^{i\vec{k}\cdot \vec{x}} \]

    和法线计算的方式完全一样得到

    \[\vec{D}(\vec{x},t)=(-1)^{x+z}\sum_{n'=0}^{N-1}e^{2\pi n'xi/N}\sum_{m'=0}^{N-1}-i\frac{\vec{k}}{|\vec{k}|}h(\vec{k},t)e^{2\pi m'zi/N} \]

    分成两个方向

    \[D_x(\vec{x},t)=(-1)^{x+z}\sum_{n'=0}^{N-1}e^{2\pi n'xi/N}\sum_{m'=0}^{N-1}-i\frac{k_x}{|\vec{k}|}h(\vec{k},t)e^{2\pi m'zi/N} \\ D_z(\vec{x},t)=(-1)^{x+z}\sum_{n'=0}^{N-1}e^{2\pi n'xi/N}\sum_{m'=0}^{N-1}-i\frac{k_z}{|\vec{k}|}h(\vec{k},t)e^{2\pi m'zi/N} \]

    这就完成了推导的工作。相信熟悉FFT的读者可以对上边的公式很容易给出一个自己的FFT计算实现。

    实现结果

    FFT

    之后的博客将会研究如何对这样的海面进行真实感渲染和光照计算。如果有时间的话,可能会探索如何把这个FFT模型移植到GPU上并行计算以实现更好的性能。

    参考文献

    1. Tessendorf, Jerry. Simulating Ocean Water. In SIGGRAPH 2002 Course Notes #9 (Simulating Nature: Realistic and Interactive Techniques), ACM Press.
    2. Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest and Clifford Stein. Introduction to Algorithms, 3rd Edition, MIT Press.
  • 相关阅读:
    HDU 5409 CRB and Graph (边双连通+DFS)
    HDU 3749 Financial Crisis (点双连通+并查集)
    POJ 1523 SPF (无向图割点)
    HDU 3639 Hawk-and-Chicken (强连通缩点+DFS)
    UVA11324 The Largest Clique (强连通缩点+DP最长路)
    HDU 3861 The King’s Problem (强连通缩点+DAG最小路径覆盖)
    ZOJ 3795 Grouping (强连通缩点+DP最长路)
    POJ 2455 Secret Milking Machine 【二分】+【最大流】
    POJ 2112 Optimal Milking (二分+最短路+最大流)
    POJ 1094 Sorting It All Out 【拓扑排序】
  • 原文地址:https://www.cnblogs.com/hehao98/p/8604163.html
Copyright © 2011-2022 走看看