93 lines
3.0 KiB
C#
93 lines
3.0 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|