gpt4 book ai didi

3D Perlin 噪声分析导数

转载 作者:行者123 更新时间:2023-12-04 03:02:30 26 4
gpt4 key购买 nike

我目前正在使用 Shader Model 4 (DirectX 10 HLSL) 实现 3D Perlin 噪声凹凸贴图。生成噪声本身并不是一个大问题(周围有大量的教程和代码),但我还没有找到 3D Perlin 噪声的分析导数。

唯一考虑衍生品的网站是 Ińigo Quilez's site和一个相关的 GameDev.net discussion .问题是在第一个链接中,噪声是基于值的,而不是基于梯度的(这是我的要求),在第二个链接中,只有 2D 梯度噪声导数。

请注意,我不是在寻找数值导数,因为它们需要生成 4 个相邻的噪声样本,而且开销太大。

有没有人计算过这些导数?是否有使用它们的引用实现?

最佳答案

我今天在网上也找不到解决方案,所以我试图推导它。

首先定义了 3D Perlin 噪声的符号。

符号

假设 3D Perlin 噪声由三线性插值计算为

n = Lerp(
Lerp(
Lerp(dot000, dot100, u),
Lerp(dot010, dot110, u),
v),
Lerp(
Lerp(dot001, dot101, u),
Lerp(dot011, dot111, u),
v),
w)

哪里 u , v , w是分数坐标的五次多项式的插值因子(即改进的柏林噪声):
x0 = frac(x)
y0 = frac(y)
z0 = frac(z)
x1 = x0 - 1
y1 = y0 - 1
z1 = z0 - 1

u = x0 * x0 * x0 * (x0 * (6 * x0 - 15) + 10)
v = y0 * y0 * y0 * (y0 * (6 * y0 - 15) + 10)
w = z0 * z0 * z0 * (z0 * (6 * z0 - 15) + 10)

dot___ s 是梯度向量的点积 (gx___, gy___, gz___) s 在格点和分数坐标:
dot000 = gx000 * x0 + gy000 * y0 + gz000 * z0
dot100 = gx100 * x1 + gy100 * y0 + gz100 * z0
dot010 = gx010 * x0 + gy010 * y1 + gz010 * z0
dot110 = gx110 * x1 + gy110 * y1 + gz110 * z0
dot001 = gx001 * x0 + gy001 * y0 + gz001 * z1
dot101 = gx101 * x1 + gy101 * y0 + gz101 * z1
dot011 = gx011 * x0 + gy011 * y1 + gz011 * z1
dot111 = gx111 * x1 + gy111 * y1 + gz111 * z1

计算导数

首先,计算 u 的导数, vw
u' = 30 * x0 * x0 * (x0 - 1) * (x0 - 1)
v' = 30 * y0 * y0 * (y0 - 1) * (y0 - 1)
w' = 30 * z0 * z0 * (z0 - 1) * (z0 - 1)

通过扩展 nLerp(a, b, t) = a + (b - a) * t ,
n = dot000 
+ u(dot100 - dot000)
+ v(dot010 - dot000)
+ w(dot001 - dot000)
+ uv(dot110 - dot010 - dot100 + dot000)
+ uw(dot101 - dot001 - dot100 + dot000)
+ vw(dot011 - dot001 - dot010 + dot000)
+ uvw(dot111 - dot011 - dot101 + dot001 - dot110 + dot010 + dot100 - dot000)

然后取 n的偏导数,
nx = gx000
+ u' (dot100 - dot000)
+ u (gx100 - gx000)
+ v (gx010 - gx000)
+ w (gx001 - gx000)
+ u'v (dot110 - dot010 - dot100 + dot000)
+ uv (gx110 - gx010 - gx100 + gx000)
+ u'w (dot101 - dot001 - dot100 + dot000)
+ uw (gx101 - gx001 - gx100 - gx000)
+ vw (gx011 - gx001 - gx010 + gx000)
+ u'vw(dot111 - dot011 - dot101 + dot001 - dot110 + dot010 + dot100 - dot000)
+ uvw (gx111 - gx011 - gx101 + gx001 - gx110 + gx010 + gx100 - gx000)

,
ny = gy000
+ u (gy100 - gy000)
+ v' (dot010 - dot000)
+ v (gy010 - gy000)
+ w (gy001 - gy000)
+ uv' (dot110 - dot010 - dot100 + dot000)
+ uv (gy110 - gy010 - gy100 + gy000)
+ uw (gy101 - gy001 - gy100 + gy000)
+ v'w (dot011 - dot001 - dot010 + dot000)
+ vw (gy011 - gy001 - gy010 + gy000)
+ uv'w(dot111 - dot011 - dot101 + dot001 - dot110 + dot010 + dot100 - dot000)
+ uvw (gy111 - gy011 - gy101 + gy001 - gy110 + gy010 + gy100 - gy000)

,
nz = gz000
+ u (gz100 - gz000)
+ v (gz010 - gz000)
+ w' (dot001 - dot000)
+ w (gz001 - gz000)
+ uv (gz110 - gz010 - gz100 + gz000)
+ uw' (dot101 - dot001 - dot100 + dot000)
+ uw (gz101 - gz001 - gz100 + gz000)
+ vw' (dot011 - dot001 - dot010 + dot000)
+ vw (gz011 - gz001 - gz010 + gz000)
+ uvw'(dot111 - dot011 - dot101 + dot001 - dot110 + dot010 + dot100 - dot000)
+ uvw (gz111 - gz011 - gz101 + gz001 - gz110 + gz010 + gz100 - gz000)

然后 (nx, ny, nz)是噪声函数的梯度向量(偏导数)。

优化

一些常见的子表达式可以被分解出来,如果编译器不能处理它。例如:
uv = u * v
vw = v * w
uw = u * w
uvw = uv * w

扩展中的系数 n被多次重复使用。它们可以通过以下方式计算:
k0 = dot100 - dot000
k1 = dot010 - dot000
k2 = dot001 - dot000
k3 = dot110 - dot010 - k0
k4 = dot101 - dot001 - k0
k5 = dot011 - dot001 - k1
k6 = (dot111 - dot011) - (dot101 - dot001) - k3

导数也有相似的系数,
gxk0 = gx100 - gx000
gxk1 = gx010 - gx000
...
n的计算可以使用 k0 的扩展形式, ... k6以及。

最后的话

该解决方案已针对中心差分法进行了验证。

虽然这个解决方案看起来很笨拙,但我的实验(仅限 CPU,SSE)表明,通过这个解决方案计算这些导数只会产生大约 50% 的额外时间 计算单个 3D Perlin 噪声样本。

有限差分至少需要 300% 的额外时间(做额外 3 个样本)或 600%(做 6 个样本进行中心差分)。

因此,该解决方案在性能上更好,并且在数值上也应该更稳定。

关于3D Perlin 噪声分析导数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4297024/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com