public class Perlin2d { public float Noise(float x, float y) { throw new NotImplementedException(); } }
x:2.5,
y:0.5
x:2,
y:0
x = 2.5 – 2 = 0.5,
y = 0.5 – 0 = 0.5
static float Lerp(float a, float b, float t) { // return a * (t - 1) + b * t; ( , ): return a + (b - a) * t; }
: 1.5
: 4.5
1.5 * 0.5 + 4.5 * (1 – 0.5) = 3
static float QunticCurve(float t) { return t * t * t * (t * (t * 6 - 15) + 10); } ... // : Lerp(a, b, QuinticCurve(t))
{ 1, 0 } { -1, 0 } { 0, 1 } { 0,-1 }
float[] GetPseudoRandomGradientVector(int x, int y) { int v = // - 0 3 x y switch (v) { case 0: return new float[]{ 1, 0 }; case 1: return new float[]{ -1, 0 }; case 2: return new float[]{ 0, 1 }; default: return new float[]{ 0,-1 }; } }
static float Dot(float[] a, float[] b) { return a[0] * b[0] + a[1] * b[1]; }
public float Noise(float fx, float fy) { // int left = (int)System.Math.Floor(fx); int top = (int)System.Math.Floor(fy); // float pointInQuadX = fx - left; float pointInQuadY = fy - top; // : float[] topLeftGradient = GetPseudoRandomGradientVector(left, top ); float[] topRightGradient = GetPseudoRandomGradientVector(left+1, top ); float[] bottomLeftGradient = GetPseudoRandomGradientVector(left, top+1); float[] bottomRightGradient = GetPseudoRandomGradientVector(left+1, top+1); // : float[] distanceToTopLeft = new float[]{ pointInQuadX, pointInQuadY }; float[] distanceToTopRight = new float[]{ pointInQuadX-1, pointInQuadY }; float[] distanceToBottomLeft = new float[]{ pointInQuadX, pointInQuadY-1 }; float[] distanceToBottomRight = new float[]{ pointInQuadX-1, pointInQuadY-1 }; // /* tx1--tx2 | | bx1--bx2 */ float tx1 = Dot(distanceToTopLeft, topLeftGradient); float tx2 = Dot(distanceToTopRight, topRightGradient); float bx1 = Dot(distanceToBottomLeft, bottomLeftGradient); float bx2 = Dot(distanceToBottomRight, bottomRightGradient); // , : pointInQuadX = QunticCurve(pointInQuadX); pointInQuadY = QunticCurve(pointInQuadY); // , : float tx = Lerp(tx1, tx2, pointInQuadX); float bx = Lerp(bx1, bx2, pointInQuadX); float tb = Lerp(tx, bx, pointInQuadY); // : return tb; }
public float Noise(float fx, float fy, int octaves, float persistence = 0.5f) { float amplitude = 1; // , "" // - persistence float max = 0; // float result = 0; // while (octaves-- > 0) { max += amplitude; result += Noise(fx, fy) * amplitude; amplitude *= persistence; fx *= 2; // ( ) fy *= 2; } return result/max; }
class Perlin2D { byte[] permutationTable; public Perlin2D(int seed = 0) { var rand = new System.Random(seed); permutationTable = new byte[1024]; rand.NextBytes(permutationTable); // } private float[] GetPseudoRandomGradientVector(int x, int y) { // - , int v = (int)(((x * 1836311903) ^ (y * 2971215073) + 4807526976) & 1023); v = permutationTable[v]&3; switch (v) { ...
class Perlin2D { byte[] permutationTable; public Perlin2D(int seed = 0) { var rand = new System.Random(seed); permutationTable = new byte[1024]; rand.NextBytes(permutationTable); } private float[] GetPseudoRandomGradientVector(int x, int y) { int v = (int)(((x * 1836311903) ^ (y * 2971215073) + 4807526976) & 1023); v = permutationTable[v]&3; switch (v) { case 0: return new float[]{ 1, 0 }; case 1: return new float[]{ -1, 0 }; case 2: return new float[]{ 0, 1 }; default: return new float[]{ 0,-1 }; } } static float QunticCurve(float t) { return t * t * t * (t * (t * 6 - 15) + 10); } static float Lerp(float a, float b, float t) { return a + (b - a) * t; } static float Dot(float[] a, float[] b) { return a[0] * b[0] + a[1] * b[1]; } public float Noise(float fx, float fy) { int left = (int)System.Math.Floor(fx); int top = (int)System.Math.Floor(fy); float pointInQuadX = fx - left; float pointInQuadY = fy - top; float[] topLeftGradient = GetPseudoRandomGradientVector(left, top ); float[] topRightGradient = GetPseudoRandomGradientVector(left+1, top ); float[] bottomLeftGradient = GetPseudoRandomGradientVector(left, top+1); float[] bottomRightGradient = GetPseudoRandomGradientVector(left+1, top+1); float[] distanceToTopLeft = new float[]{ pointInQuadX, pointInQuadY }; float[] distanceToTopRight = new float[]{ pointInQuadX-1, pointInQuadY }; float[] distanceToBottomLeft = new float[]{ pointInQuadX, pointInQuadY-1 }; float[] distanceToBottomRight = new float[]{ pointInQuadX-1, pointInQuadY-1 }; float tx1 = Dot(distanceToTopLeft, topLeftGradient); float tx2 = Dot(distanceToTopRight, topRightGradient); float bx1 = Dot(distanceToBottomLeft, bottomLeftGradient); float bx2 = Dot(distanceToBottomRight, bottomRightGradient); pointInQuadX = QunticCurve(pointInQuadX); pointInQuadY = QunticCurve(pointInQuadY); float tx = Lerp(tx1, tx2, pointInQuadX); float bx = Lerp(bx1, bx2, pointInQuadX); float tb = Lerp(tx, bx, pointInQuadY); return tb; } public float Noise(float fx, float fy, int octaves, float persistence = 0.5f) { float amplitude = 1; float max = 0; float result = 0; while (octaves-- > 0) { max += amplitude; result += Noise(fx, fy) * amplitude; amplitude *= persistence; fx *= 2; fy *= 2; } return result/max; } }
Source: https://habr.com/ru/post/265775/
All Articles