namespace WebmrAPI.Utils { public class Perlin2D : BaseRandom { byte[] _mTable = new byte[1024]; public Perlin2D(int seed = 0) : base(seed) { Generate(_mTable); } private double[] GetPseudoRandomGradientVector(int x, int y) { int v = (int)(((x * 1836311903) ^ (y * 2971215073) + 4807526976) & 1023); v = _mTable[v] & 3; switch (v) { case 0: return new double[] { 1, 0 }; case 1: return new double[] { -1, 0 }; case 2: return new double[] { 0, 1 }; default: return new double[] { 0, -1 }; } } static double QunticCurve(double t) { return t * t * t * (t * (t * 6 - 15) + 10); } static double Lerp(double a, double b, double t) { return a + (b - a) * t; } static double Dot(double[] a, double[] b) { return a[0] * b[0] + a[1] * b[1]; } public double Noise(double fx, double fy) { int left = (int)System.Math.Floor(fx); int top = (int)System.Math.Floor(fy); double pointInQuadX = fx - left; double pointInQuadY = fy - top; double[] topLeftGradient = GetPseudoRandomGradientVector(left, top); double[] topRightGradient = GetPseudoRandomGradientVector(left + 1, top); double[] bottomLeftGradient = GetPseudoRandomGradientVector(left, top + 1); double[] bottomRightGradient = GetPseudoRandomGradientVector(left + 1, top + 1); double[] distanceToTopLeft = { pointInQuadX, pointInQuadY }; double[] distanceToTopRight = { pointInQuadX - 1, pointInQuadY }; double[] distanceToBottomLeft = { pointInQuadX, pointInQuadY - 1 }; double[] distanceToBottomRight = { pointInQuadX - 1, pointInQuadY - 1 }; double tx1 = Dot(distanceToTopLeft, topLeftGradient); double tx2 = Dot(distanceToTopRight, topRightGradient); double bx1 = Dot(distanceToBottomLeft, bottomLeftGradient); double bx2 = Dot(distanceToBottomRight, bottomRightGradient); pointInQuadX = QunticCurve(pointInQuadX); pointInQuadY = QunticCurve(pointInQuadY); double tx = Lerp(tx1, tx2, pointInQuadX); double bx = Lerp(bx1, bx2, pointInQuadX); double tb = Lerp(tx, bx, pointInQuadY); return tb; } public double Noise(double fx, double fy, int octaves, double persistence = 0.5) { double amplitude = 1; double max = 0; double result = 0; while (octaves-- > 0) { max += amplitude; result += Noise(fx, fy) * amplitude; amplitude *= persistence; fx *= 2; fy *= 2; } return result / max; } } }