You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用1D Noise实现带渐变效果的点位移?

使用1D渐变噪声实现点位移的问题修复

需求与问题

  • 目标:基于覆盖整条线的1D渐变噪声驱动点的X/Y轴位移,噪声值作为-1~1的位移乘数,避免独立随机位移
  • 当前问题:设置frequency=1时,噪声出现多个波形,不符合“整条线单平滑渐变”的预期

问题根源

你使用的Perlin噪声实现中,frequency参数表示每单位输入坐标对应的噪声周期数。你的输入坐标是y轴的010区间,当`frequency=1`时,会覆盖10个完整噪声周期,因此出现多个波形。若要让整条线段对应一个平滑渐变,需要将输入坐标归一化到01区间,让整个线段仅覆盖一个噪声周期。

修复后的代码

import numpy as np
import matplotlib.pyplot as plt
import random
import math
from enum import Enum

#PerlinNoise by alexandr-gnrk
class Interp(Enum):
    LINEAR = 1
    COSINE = 2
    CUBIC = 3

class PerlinNoise():
    def __init__(self, 
            seed, amplitude=1, frequency=1, 
            octaves=1, interp=Interp.COSINE, use_fade=False):
        self.seed = random.Random(seed).random()
        self.amplitude = amplitude
        self.frequency = frequency
        self.octaves = octaves
        self.interp = interp
        self.use_fade = use_fade

        self.mem_x = dict()


    def __noise(self, x):
        # 性能优化:缓存已生成的噪声值
        if x not in self.mem_x:
            self.mem_x[x] = random.Random(self.seed + x).uniform(-1, 1)
        return self.mem_x[x]


    def __interpolated_noise(self, x):
        prev_x = int(x) # 前一个整数坐标
        next_x = prev_x + 1 # 后一个整数坐标
        frac_x = x - prev_x # 小数部分

        if self.use_fade:
            frac_x = self.__fade(frac_x)

        # 插值计算
        if self.interp is Interp.LINEAR:
            res = self.__linear_interp(
                self.__noise(prev_x), 
                self.__noise(next_x),
                frac_x)
        elif self.interp is Interp.COSINE:
            res = self.__cosine_interp(
                self.__noise(prev_x), 
                self.__noise(next_x),
                frac_x)
        else:
            res = self.__cubic_interp(
                self.__noise(prev_x - 1), 
                self.__noise(prev_x), 
                self.__noise(next_x),
                self.__noise(next_x + 1),
                frac_x)

        return res


    def get(self, x):
        frequency = self.frequency
        amplitude = self.amplitude
        result = 0
        for _ in range(self.octaves):
            result += self.__interpolated_noise(x * frequency) * amplitude
            frequency *= 2
            amplitude /= 2

        return result


    def __linear_interp(self, a, b, x):
        return a + x * (b - a)


    def __cosine_interp(self, a, b, x):
        x2 = (1 - math.cos(x * math.pi)) / 2
        return a * (1 - x2) + b * x2


    def __cubic_interp(self, v0, v1, v2, v3, x):
        p = (v3 - v2) - (v0 - v1)
        q = (v0 - v1) - p
        r = v2 - v0
        s = v1
        return p * x**3 + q * x**2 + r * x + s


    def __fade(self, x):
        # 仅线性插值时生效的平滑过渡函数
        return (6 * x**5) - (15 * x**4) + (10 * x**3)

# 原始线段:x固定为10,y从0到10的20个点
x = np.linspace(10, 10, 20)
y = np.linspace(0, 10, 20)

seed = 10

# 初始化噪声生成器,参数不变
gen_x = PerlinNoise(seed=seed, amplitude=5, frequency=1, octaves=1, interp=Interp.CUBIC, use_fade=True)

# 核心修改:将y坐标归一化到0-1区间,让整条线段对应一个噪声周期
normalized_y = y / np.max(y)
noise_x = np.array([gen_x.get(pos) for pos in normalized_y])

# 绘制对比图
fig, ax = plt.subplots(1)
ax.set_aspect("equal")
ax.plot(x, y, linewidth=2, color="k")
ax.scatter(x, y, s=20, zorder=4, color="k")
ax.plot(x+noise_x, y, linewidth=2, color="blue")
ax.scatter(x+noise_x, y, s=80, zorder=4, color="red")
plt.show()

修复效果

修改后,整条线段的点会基于一个平滑的1D噪声渐变进行位移:

  • frequency=1对应整个线段覆盖一个完整的噪声周期
  • 噪声值在-1~1之间变化,最终位移量由amplitude控制(示例中为5,即最大位移±5个单位)
  • 完全符合“基于覆盖整条线的渐变噪声驱动位移”的需求

内容的提问来源于stack exchange,提问作者Dr. Pontchartrain

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 12:25:14