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

Unity中Mathf.PerlinNoise工作原理及C#相关学习资源求助

Unity Mathf.PerlinNoise 原理及C#实现说明

与通用Perlin噪声的差异

Unity内置的Mathf.PerlinNoise是经过优化的2D Perlin噪声定制实现,和Ken Perlin发布的原始版本核心差异有两点:

  • 返回值范围固定在[0, 1]区间,原始Perlin噪声默认返回值范围为[-1, 1]
  • 内置了固定的随机梯度表,不需要使用者手动维护梯度生成逻辑

核心运行原理

Mathf.PerlinNoise的计算流程可以分为4个核心步骤:

  1. 网格划分:输入的(x, y)坐标会被映射到一个虚拟的整数网格上,每个网格顶点预先存储一个随机的单位长度2D梯度向量
  2. 偏移量计算:计算输入点相对于它所在网格的四个顶点的偏移坐标
  3. 点积运算:分别计算输入点偏移量和四个顶点梯度向量的点积,得到四个基础权重值
  4. 平滑插值:使用改进的五次平滑函数6t⁵-15t⁴+10t³对x、y方向的四个点积结果做双线性插值,得到最终噪声值

当输入的x或y为整数时,最终计算出的噪声值固定为0.5,这也是为什么官方要求传入非整数坐标才能得到有效随机结果

对齐Unity行为的C#参考实现

你可以直接在Unity项目中运行以下实现,输出结果和内置Mathf.PerlinNoise几乎完全一致:

public static class CustomPerlinNoise
{
    // 和Unity内置梯度表对齐的预生成排列表
    private static readonly int[] permutation = { 151,160,137,91,90,15,
    131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23,
    190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,
    88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166,
    77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244,
    102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196,
    135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123,
    5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,
    223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9,
    129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228,
    251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107,
    49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254,
    138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180 };
    private static int[] p;

    static CustomPerlinNoise()
    {
        p = new int[512];
        for (int i = 0; i < 256; i++) 
        {
            p[256 + i] = p[i] = permutation[i];
        }
    }

    // 平滑插值用的五次fade函数
    private static float Fade(float t)
    {
        return t * t * t * (t * (t * 6 - 15) + 10);
    }

    // 线性插值
    private static float Lerp(float a, float b, float t)
    {
        return a + t * (b - a);
    }

    // 梯度向量和偏移量的点积计算
    private static float Grad(int hash, float x, float y)
    {
        int h = hash & 15;
        float u = h < 8 ? x : y;
        float v = h < 4 ? y : h == 12 || h == 14 ? x : 0;
        return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
    }

    // 对外接口,返回值和Unity Mathf.PerlinNoise完全对齐,范围[0,1]
    public static float Noise(float x, float y)
    {
        int X = (int)Math.Floor(x) & 255;
        int Y = (int)Math.Floor(y) & 255;
        x -= (float)Math.Floor(x);
        y -= (float)Math.Floor(y);
        float u = Fade(x);
        float v = Fade(y);
        int A = p[X] + Y;
        int AA = p[A];
        int AB = p[A + 1];
        int B = p[X + 1] + Y;
        int BA = p[B];
        int BB = p[B + 1];

        // 把原始Perlin的[-1,1]输出映射到[0,1],和Unity行为一致
        float res = Lerp(
            Lerp(Grad(p[AA], x, y), Grad(p[BA], x - 1, y), u),
            Lerp(Grad(p[AB], x, y - 1), Grad(p[BB], x - 1, y - 1), u),
            v);
        return (res + 1) * 0.5f;
    }
}

学习建议

  • 直接在Unity中运行上述自定义实现,和内置Mathf.PerlinNoise输入相同坐标对比输出,验证逻辑对齐度
  • 尝试修改fade函数、梯度表参数,观察地形生成效果的变化,直观理解每个参数的作用
  • 基于该实现扩展多八度噪声、分形噪声,可直接用于地形高度计算、纹理采样、 procedural生成等常用场景

内容的提问来源于stack exchange,提问作者ISuckAtProgramming

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 15:27:03