首页 > 解决方案 > 将柏林噪声多次应用于平面/球体

问题描述

一般来说,我对 Perlin 噪声和 pv.sample_function 有一些疑问。

  1. 您将如何将 Perlin 噪声应用于球体?我想要一个有点变形的球体。
  2. 您可以多次将 Perlin 噪声应用于网格(球体/平面)吗?我想有一架飞机,上面有一些粗糙的“波浪”和高细节的噪音(因此有大波浪,里面有小波浪)。
  3. 频率中的第三个参数究竟是做什么的?在玩了一些值之后,我没有注意到它是如何影响噪音的。

这是我想应用于一架飞机的两种不同频率/柏林噪声。此外,它还显示了他们分别创建的平面。

def smooth_and_plot(sampled : pv.core.grid.UniformGrid):
    mesh = sampled.warp_by_scalar('scalars')
    mesh = mesh.extract_surface()

    # clean and smooth a little to reduce perlin noise artifacts
    mesh = mesh.smooth(n_iter=100, inplace=True, relaxation_factor=0.07)
    mesh.plot()


def gravel_plane():
    freq = [180, 180, 50]
    noise = pv.perlin_noise(0.2, freq, (0, 0, 0))
    sampled = pv.sample_function(noise,
                                 bounds=(-10, 2, -10, 10, -10, 10),
                                 dim=(500, 500, 1))

    smooth_and_plot(sampled)


def bumpy_plane():
    freq = [0.5, 0.7, 0]
    noise = pv.perlin_noise(0.5, freq, (-10, -10, -10))
    sampled = pv.sample_function(noise,
                                 bounds=(-10, 2, -10, 10, -10, 10),
                                 dim=(500, 500, 1))

    smooth_and_plot(sampled)

标签: python3dperlin-noisepyvista

解决方案


出于教学原因,让我以相反的顺序回答您的问题。

  1. 频率中的第三个参数究竟是做什么的?在玩了一些值之后,我没有注意到它是如何影响噪音的。

您没有看到效果,因为您正在查看 2d 样本,并沿第三轴更改行为。三个频率分别指定沿 x、y 和 z 轴的噪声粒度。换句话说,生成的隐函数是三个变量的标量函数。只是您的采样将维数降低到 2。

就空间量而言,频率可能是一个令人惊讶的量,但它的工作方式与时间相同。时间频率高意味着振荡周期短,时间频率低意味着振荡周期长。高空间频率意味着短波长,低空间频率意味着长波长。具体来说,波长和频率成反比。

因此,当您开始沿 z 轴切片时,您会看到第三个频率的效果:

import pyvista as pv

freq = [0.5, 0.5, 2]
noise = pv.perlin_noise(0.5, freq, (0, 0, 0))
noise_cube = pv.sample_function(noise,
                                bounds=(-10, 10, -10, 10, -10, 10),
                                dim=(200, 200, 200))
noise_cube.slice_orthogonal(-9, -9, -9).plot()

Perlin 噪声的三个正交切片,沿 z 显示较小的波长

如您所见,xy平面中的斑点是圆形的,因为两个平面内频率相等。但是在两个垂直平面中,斑点都被拉长了:它们在 z 方向上更平坦。这是因为沿 z 轴的频率大四倍,导致波长小四倍。这将导致具有大约 4:1 纵横比的随机 blob。

  1. 您可以多次将 Perlin 噪声应用于网格(球体/平面)吗?我想有一架飞机,上面有一些粗糙的“波浪”和高细节的噪音(因此有大波浪,里面有小波浪)。

您的代码片段中发生的所有事情都是在预定义的矩形网格上对函数进行采样,并将结果值作为标量存储在网格上。如果你想叠加两个函数,你所要做的就是将两个这样的函数调用的标量相加。这会有点浪费,因为您要生成两次相同的网格(并丢弃其中一个副本),但从开发的角度来看,这是最不费力的解决方案:

def bumpy_gravel_plane():
    bounds = (-10, 2, -10, 10, -10, 10)
    dim = (500, 500, 1)

    freq = [180, 180, 50]
    noise = pv.perlin_noise(0.2, freq, (0, 0, 0))
    sampled_gravel = pv.sample_function(noise, bounds=bounds, dim=dim)

    freq = [0.5, 0.7, 0]
    noise = pv.perlin_noise(0.5, freq, (-10, -10, -10))
    sampled_bumps = pv.sample_function(noise, bounds=bounds, dim=dim)

    sampled = sampled_gravel
    sampled['scalars'] += sampled_bumps['scalars']

    smooth_and_plot(sampled)

带有大尺寸凹凸和短尺寸颗粒纹理的网格屏幕截图

  1. 您将如何将 Perlin 噪声应用于球体?我想要一个有点变形的球体。

生成 2d 纹理并将其应用于球体的通常解决方案在这里不起作用,因为噪声不是周期性的,所以你不能像那样轻易地关闭它。但如果你仔细想想,生成的 Perlin 噪声是一个 3d 函数。您可以直接在您的球体上对这个 3d 函数进行采样!

有一个小问题:我认为你不能只用 pyvista 做到这一点。我们将不得不稍微弄脏我们的手,我的意思是使用一种简单的vtk方法(即EvaluateFunction()噪音)。生成您的球体,然后在其点上查询您选择的噪声函数。如果您希望结果看起来对称,则必须沿所有三个笛卡尔轴设置相同的频率:

def bumpy_sphere(R=10):
    freq = [0.5, 0.5, 0.5]
    noise = pv.perlin_noise(0.5, freq, (0, 0, 0))
    sampled = pv.Sphere(radius=R, phi_resolution=100, theta_resolution=100)
    # query the noise at each point manually
    sampled['scalars'] = [noise.EvaluateFunction(point) for point in sampled.points]

    smooth_and_plot(sampled)

具有 Perlin 噪声表面翘曲和标量的球体


推荐阅读