From 6066b9f1bada1098c7453cb454167f80dfbcb4db Mon Sep 17 00:00:00 2001 From: m0_75251201 Date: Mon, 14 Jul 2025 23:43:36 +0800 Subject: [PATCH] =?UTF-8?q?(client)=20feat:=E5=AE=9A=E4=B9=89=E6=9F=8F?= =?UTF-8?q?=E6=9E=97=E5=99=AA=E5=A3=B0=E7=94=9F=E6=88=90=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Client/Assets/Scripts/Utils/PerlinNoise.cs | 133 ++++++++++++++++++ .../Assets/Scripts/Utils/PerlinNoise.cs.meta | 3 + 2 files changed, 136 insertions(+) create mode 100644 Client/Assets/Scripts/Utils/PerlinNoise.cs create mode 100644 Client/Assets/Scripts/Utils/PerlinNoise.cs.meta diff --git a/Client/Assets/Scripts/Utils/PerlinNoise.cs b/Client/Assets/Scripts/Utils/PerlinNoise.cs new file mode 100644 index 0000000..ae052f6 --- /dev/null +++ b/Client/Assets/Scripts/Utils/PerlinNoise.cs @@ -0,0 +1,133 @@ +using System; + +namespace Utils +{ + public class PerlinNoise + { + private readonly int[] _p; // 混淆表 + + // 构造函数:初始化混淆表 + public PerlinNoise(int seed) + { + // 初始化为0-255的随机排列 + _p = new int[512]; // 混淆表加倍以方便使用 + var permutation = new int[256]; + var random = new Random(seed); + + // 填充数组为0-255 + for (var i = 0; i < 256; i++) permutation[i] = i; + + // 使用Fisher-Yates算法打乱数组 + for (var i = 0; i < 256; i++) + { + var swapIndex = random.Next(256); + var temp = permutation[i]; + permutation[i] = permutation[swapIndex]; + permutation[swapIndex] = temp; + } + + // 将打乱后的数组复制两次,生成512个元素的混淆表 + for (var i = 0; i < 256; i++) + { + _p[i] = permutation[i]; + _p[i + 256] = permutation[i]; + } + } + + // 平滑函数 (6t^5 - 15t^4 + 10t^3) + private double Fade(double t) + { + return t * t * t * (t * (t * 6 - 15) + 10); + } + + // 线性插值 + private double Lerp(double t, double a, double b) + { + return a + t * (b - a); + } + + // 计算梯度向量和距离向量的点积 + private double Grad(int hash, double x, double y, double z) + { + // 根据hash值确定使用哪个梯度向量 + // 12个梯度向量由以下组合构成:(+/-1, +/-1, 0), (+/-1, 0, +/-1), (0, +/-1, +/-1) + switch (hash & 0xF) // 取hash值的最后4位 + { + case 0x0: return x + y; + case 0x1: return -x + y; + case 0x2: return x - y; + case 0x3: return -x - y; + case 0x4: return x + z; + case 0x5: return -x + z; + case 0x6: return x - z; + case 0x7: return -x - z; + case 0x8: return y + z; + case 0x9: return -y + z; + case 0xA: return y - z; + case 0xB: return -y - z; + case 0xC: return y + x; // 这四个是重复的,但Ken Perlin的原始实现中包含它们。 + case 0xD: return -y + x; // 它们对噪声质量影响不大,但保持了表格的一致性。 + case 0xE: return y - x; + case 0xF: return -y - x; + default: return 0; // 不应该发生 + } + } + + /// + /// 为给定的(x, y, z)坐标生成3D Perlin噪声。 + /// 输出值通常在-1到1之间。 + /// + public double Noise(double x, double y, double z) + { + // 找到包含该点的单位立方体 + var X = (int)Math.Floor(x) & 255; + var Y = (int)Math.Floor(y) & 255; + var Z = (int)Math.Floor(z) & 255; + + // 找到该点在立方体内的相对x, y, z坐标 + x -= Math.Floor(x); + y -= Math.Floor(y); + z -= Math.Floor(z); + + // 计算x, y, z的平滑曲线 + var u = Fade(x); + var v = Fade(y); + var w = Fade(z); + + // 对立方体的8个角进行哈希计算 + var A = _p[X] + Y; + var AA = _p[A] + Z; + var AB = _p[A + 1] + Z; + var B = _p[X + 1] + Y; + var BA = _p[B] + Z; + var BB = _p[B + 1] + Z; + + // 获取所有8个角的哈希值 + var H000 = _p[AA]; + var H100 = _p[BA]; + var H010 = _p[AB]; + var H110 = _p[BB]; + var H001 = _p[AA + 1]; + var H101 = _p[BA + 1]; + var H011 = _p[AB + 1]; + var H111 = _p[BB + 1]; + + // 计算所有8个角的点积并插值 + double x0, x1, y0, y1; + + x0 = Lerp(u, Grad(H000, x, y, z), // (0,0,0) + Grad(H100, x - 1, y, z)); // (1,0,0) + x1 = Lerp(u, Grad(H010, x, y - 1, z), // (0,1,0) + Grad(H110, x - 1, y - 1, z)); // (1,1,0) + y0 = Lerp(v, x0, x1); + + x0 = Lerp(u, Grad(H001, x, y, z - 1), // (0,0,1) + Grad(H101, x - 1, y, z - 1)); // (1,0,1) + x1 = Lerp(u, Grad(H011, x, y - 1, z - 1), // (0,1,1) + Grad(H111, x - 1, y - 1, z - 1)); // (1,1,1) + y1 = Lerp(v, x0, x1); + + return Lerp(w, y0, y1); + } + } +} \ No newline at end of file diff --git a/Client/Assets/Scripts/Utils/PerlinNoise.cs.meta b/Client/Assets/Scripts/Utils/PerlinNoise.cs.meta new file mode 100644 index 0000000..683b578 --- /dev/null +++ b/Client/Assets/Scripts/Utils/PerlinNoise.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 76fe380e58f0420db22ca4d403d17978 +timeCreated: 1752507440 \ No newline at end of file