Skip to content

Instantly share code, notes, and snippets.

@jackmott
Last active November 3, 2016 17:03
Show Gist options
  • Save jackmott/38a26cd2934c23a161490044e64170c6 to your computer and use it in GitHub Desktop.
Save jackmott/38a26cd2934c23a161490044e64170c6 to your computer and use it in GitHub Desktop.
SIMD Perlin C#
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Numerics;
using System.Runtime.CompilerServices;
namespace FastNoise
{
public struct NoiseOutput
{
public float[] RawNoise;
//min and max values to be used for normalizing, if you wish
public float Min;
public float Max;
public NoiseOutput(float[] rawNoise, float min, float max)
{
RawNoise = rawNoise;
Min = min;
Max = max;
}
}
public class NoiseMaker
{
[DllImport("FastNoise")]
private static unsafe extern float* GetSphereSurfaceNoiseSIMD(int width, int height, int octaves, float lacunarity, float frequency, float gain, float offset, int fractalType, int noiseType, float* outMin, float* outMax);
[DllImport("FastNoise")]
private static unsafe extern void CleanUpNoiseSIMD(float* resultArray);
public enum FractalType { FBM, TURBULENCE, RIDGE, PLAIN };
public enum NoiseType { PERLIN, SIMPLEX };
// public Color[] Gradient;
private struct Settings
{
public int Octaves;
public float Lacunarity;
public float Gain;
public float Offset;
public float Frequency;
public NoiseType NoiseType;
public FractalType FractalType;
}
private Settings settings;
public NoiseMaker(int octaves, float lacunarity, float gain, float offset, float frequency, FractalType fractalType, NoiseType noiseType)
{
SetNoiseSettings(octaves, lacunarity, gain, offset, frequency, fractalType, noiseType);
}
public void SetNoiseSettings(int octaves, float lacunarity, float gain, float offset, float frequency, FractalType fractalType, NoiseType noiseType)
{
settings.Octaves = octaves;
settings.Lacunarity = lacunarity;
settings.Gain = gain;
settings.Offset = offset;
settings.Frequency = frequency;
settings.NoiseType = noiseType;
settings.FractalType = fractalType;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static float FADE(float t)
{
return (t * t * t * (t * (t * 6f - 15f) + 10f));
}
static readonly Vector<float> S6f = new Vector<float>(6.0f);
static readonly Vector<float> S15f = new Vector<float>(16.0f);
static readonly Vector<float> S10f = new Vector<float>(10.0f);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static Vector<float> FADESIMD(Vector<float> t)
{
return (t * t * t * (t * (t * S6f - S15f) + S10f));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static float LERP(float t, float a, float b)
{
return ((a) + (t) * ((b) - (a)));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static Vector<float> LERPSIMD(Vector<float> t, Vector<float> a, Vector<float> b)
{
return ((a) + (t) * ((b) - (a)));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static Vector<float> FLOORSIMD(Vector<float> f)
{
Vector<float> ft = (Vector<float>)((Vector<int>)f);
return ft - Vector.BitwiseAnd(Vector.LessThan<float>(f, ft), Vector<float>.One);
}
//---------------------------------------------------------------------
// Static data
/*
* Permutation table. This is just a random jumble of all numbers 0-255,
* repeated twice to avoid wrapping the index at 255 for each lookup.
* This needs to be exactly the same for all instances on all platforms,
* so it's easiest to just keep it as static explicit data.
* This also removes the need for any initialisation of this class.
*
* Note that making this an int[] instead of a char[] might make the
* code run faster on platforms with a high penalty for unaligned single
* byte addressing. Intel x86 is generally single-byte-friendly, but
* some other CPUs are faster with 4-aligned reads.
* However, a char[] is smaller, which avoids cache trashing, and that
* is probably the most important aspect on most architectures.
* This array is accessed a *lot* by the noise functions.
* A vector-valued noise over 3D accesses it 96 times, and a
* float-valued 4D noise 64 times. We want this to fit in the cache!
*/
static byte[] perm = {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,
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
};
//---------------------------------------------------------------------
/*
* Helper functions to compute gradients-dot-residualvectors (1D to 4D)
* Note that these generate gradients of more than unit length. To make
* a close match with the value range of classic Perlin noise, the final
* noise values need to be rescaled. To match the RenderMan noise in a
* statistical sense, the approximate scaling values (empirically
* determined from test renderings) are:
* 1D noise needs rescaling with 0.188
* 2D noise needs rescaling with 0.507
* 3D noise needs rescaling with 0.936
* 4D noise needs rescaling with 0.87
* Note that these noise functions are the most practical and useful
* signed version of Perlin noise. To return values according to the
* RenderMan specification from the SL noise() and pnoise() functions,
* the noise values need to be scaled and offset to [0,1], like this:
* float SLnoise = (noise3(x,y,z) + 1.0) * 0.5;
*/
float grad1(int h, float x)
{
h = h & 15;
float grad = 1.0f + (h & 7); // Gradient value 1.0, 2.0, ..., 8.0
if ((h & 8) == 1)
grad = -grad; // and a random sign for the gradient
return (grad * x); // Multiply the gradient with the distance
}
float grad2(int h, float x, float y)
{
h = h & 7; // Convert low 3 bits of hash code
float u = h < 4 ? x : y; // into 8 simple gradient directions,
float v = h < 4 ? y : x; // and compute the dot product with (x,y).
if ((h & 1) == 1)
u = -u;
float n = 2.0f * v;
if ((h & 2) == 1)
n = -2.0f * v;
return u + n;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float grad3(int h, float x, float y, float z)
{
h = h & 15; // Convert low 4 bits of hash code into 12 simple
float u = h < 8 ? x : y; // gradient directions, and compute dot product.
float v = h < 4 ? y : h == 12 || h == 14 ? x : z; // Fix repeats at h = 12 to 15
if ((h & 1) != 0)
u = -u;
if ((h & 2) != 0)
v = -v;
return u + v;
}
static readonly Vector<int> S15 = new Vector<int>(15);
static readonly Vector<int> S14 = new Vector<int>(14);
static readonly Vector<int> S12 = new Vector<int>(12);
static readonly Vector<int> S8 = new Vector<int>(8);
static readonly Vector<int> S4 = new Vector<int>(4);
static readonly Vector<int> S2 = new Vector<int>(2);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector<float> grad3SIMD(Vector<int> h, Vector<float> x, Vector<float> y, Vector<float> z)
{
h = Vector.BitwiseAnd(h, S15);
Vector<int> h1 = Vector.Equals(Vector<int>.Zero, Vector.BitwiseAnd(h, Vector<int>.One));
Vector<int> h2 = Vector.Equals(Vector<int>.Zero, Vector.BitwiseAnd(h, S2));
Vector<float> u = Vector.ConditionalSelect(Vector.LessThan(h, S8), x, y);
Vector<int> orh = Vector.BitwiseOr(Vector.Equals(h, S12), Vector.Equals(h, S14));
Vector<float> xorz = Vector.ConditionalSelect(orh, x, z);
Vector<float> v = Vector.ConditionalSelect(Vector.LessThan(h, S4), y, xorz);
u = Vector.ConditionalSelect(h1, u, Vector<float>.Zero - u);
v = Vector.ConditionalSelect(h2, v, Vector<float>.Zero - v);
return u + v;
}
float grad4(int h, float x, float y, float z, float t)
{
h = h & 31; // Convert low 5 bits of hash code into 32 simple
float u = h < 24 ? x : y; // gradient directions, and compute dot product.
float v = h < 16 ? y : z;
float w = h < 8 ? z : t;
if ((h & 1) == 1)
u = -u;
if ((h & 2) == 1)
v = -v;
if ((h & 4) == 1)
w = -w;
return u + v + w;
}
//---------------------------------------------------------------------
/** 1D float Perlin noise, SL "noise()"
*/
public float noise1(float x)
{
int ix0, ix1;
float fx0, fx1;
float s;
float n0, n1;
ix0 = x > 0 ? (int)x : (int)x - 1; //FASTFLOOR(x); // Integer part of x
fx0 = x - ix0; // Fractional part of x
fx1 = fx0 - 1.0f;
ix1 = (ix0 + 1) & 0xff;
ix0 = ix0 & 0xff; // Wrap to 0..255
s = FADE(fx0);
n0 = grad1(perm[ix0], fx0);
n1 = grad1(perm[ix1], fx1);
return 0.188f * (LERP(s, n0, n1));
}
//---------------------------------------------------------------------
/** 1D float Perlin periodic noise, SL "pnoise()"
*/
public float pnoise1(float x, int px)
{
int ix0, ix1;
float fx0, fx1;
float s;
float n0, n1;
ix0 = x > 0 ? (int)x : (int)x - 1; //FASTFLOOR(x); // Integer part of x
fx0 = x - ix0; // Fractional part of x
fx1 = fx0 - 1.0f;
ix1 = ((ix0 + 1) % px) & 0xff; // Wrap to 0..px-1 *and* wrap to 0..255
ix0 = (ix0 % px) & 0xff; // (because px might be greater than 256)
s = FADE(fx0);
n0 = grad1(perm[ix0], fx0);
n1 = grad1(perm[ix1], fx1);
return 0.188f * (LERP(s, n0, n1));
}
//---------------------------------------------------------------------
/** 2D float Perlin noise.
*/
public float noise2(float x, float y)
{
int ix0, iy0, ix1, iy1;
float fx0, fy0, fx1, fy1;
float s, t;
float nx0, nx1, n0, n1;
ix0 = (x > 0) ? (int)x : (int)(x - 1);
iy0 = (y > 0) ? (int)y : (int)(y - 1);
fx0 = x - ix0; // Fractional part of x
fy0 = y - iy0; // Fractional part of y
fx1 = fx0 - 1.0f;
fy1 = fy0 - 1.0f;
ix1 = (ix0 + 1) & 0xff; // Wrap to 0..255
iy1 = (iy0 + 1) & 0xff;
ix0 = ix0 & 0xff;
iy0 = iy0 & 0xff;
t = FADE(fy0);
s = FADE(fx0);
nx0 = grad2(perm[ix0 + perm[iy0]], fx0, fy0);
nx1 = grad2(perm[ix0 + perm[iy1]], fx0, fy1);
n0 = LERP(t, nx0, nx1);
nx0 = grad2(perm[ix1 + perm[iy0]], fx1, fy0);
nx1 = grad2(perm[ix1 + perm[iy1]], fx1, fy1);
n1 = LERP(t, nx0, nx1);
return 0.507f * (LERP(s, n0, n1));
}
//---------------------------------------------------------------------
/** 2D float Perlin periodic noise.
*/
public float pnoise2(float x, float y, int px, int py)
{
int ix0, iy0, ix1, iy1;
float fx0, fy0, fx1, fy1;
float s, t;
float nx0, nx1, n0, n1;
ix0 = (x > 0) ? (int)x : (int)(x - 1);
iy0 = (y > 0) ? (int)y : (int)(y - 1);
fx0 = x - ix0; // Fractional part of x
fy0 = y - iy0; // Fractional part of y
fx1 = fx0 - 1.0f;
fy1 = fy0 - 1.0f;
ix1 = ((ix0 + 1) % px) & 0xff; // Wrap to 0..px-1 and wrap to 0..255
iy1 = ((iy0 + 1) % py) & 0xff; // Wrap to 0..py-1 and wrap to 0..255
ix0 = (ix0 % px) & 0xff;
iy0 = (iy0 % py) & 0xff;
t = (fy0 * fy0 * fy0 * (fy0 * (fy0 * 6 - 15) + 10));
s = (fx0 * fx0 * fx0 * (fx0 * (fx0 * 6 - 15) + 10));
nx0 = grad2(perm[ix0 + perm[iy0]], fx0, fy0);
nx1 = grad2(perm[ix0 + perm[iy1]], fx0, fy1);
n0 = LERP(t, nx0, nx1);
nx0 = grad2(perm[ix1 + perm[iy0]], fx1, fy0);
nx1 = grad2(perm[ix1 + perm[iy1]], fx1, fy1);
n1 = LERP(t, nx0, nx1);
return ((0.446f * (LERP(s, n0, n1))) + .5f);
}
static int[] a = new int[Vector<float>.Count];
static int[] b = new int[Vector<float>.Count];
static int[] c = new int[Vector<float>.Count];
static int[] d = new int[Vector<float>.Count];
static int[] e = new int[Vector<float>.Count];
static int[] f = new int[Vector<float>.Count];
static int[] g = new int[Vector<float>.Count];
static int[] h = new int[Vector<float>.Count];
static readonly Vector<int> S255 = new Vector<int>(255);
static readonly Vector<float> SCALE = new Vector<float>(0.935f);
public static Vector<float> noise3SIMD(Vector<float> x, Vector<float> y, Vector<float> z)
{
Vector<int> ix0 = (Vector<int>)FLOORSIMD(x);
Vector<int> iy0 = (Vector<int>)FLOORSIMD(y);
Vector<int> iz0 = (Vector<int>)FLOORSIMD(z);
Vector<float> fx0 = x - (Vector<float>)ix0;
Vector<float> fy0 = y - (Vector<float>)iy0;
Vector<float> fz0 = z - (Vector<float>)iz0;
Vector<float> fx1 = fx0 - Vector<float>.One;
Vector<float> fy1 = fy0 - Vector<float>.One;
Vector<float> fz1 = fz0 - Vector<float>.One;
Vector<int> ix1 = Vector.BitwiseAnd(ix0 + Vector<int>.One, S255);
Vector<int> iy1 = Vector.BitwiseAnd(iy0 + Vector<int>.One, S255);
Vector<int> iz1 = Vector.BitwiseAnd(iz0 + Vector<int>.One, S255);
ix0 = Vector.BitwiseAnd(ix0, S255);
iy0 = Vector.BitwiseAnd(iy0, S255);
iz0 = Vector.BitwiseAnd(iz0, S255);
Vector<float> r = FADESIMD(fz0);
Vector<float> t = FADESIMD(fy0);
Vector<float> s = FADESIMD(fx0);
unsafe
{
fixed(int* ap = a, bp = b, cp = c, dp = d, ep = e, fp = f, gp = g, hp = h)
{
fixed(byte* permp = perm)
{
for (int i = 0; i < Vector<float>.Count; i++)
{
int x0 = ix0[i];
int y0 = iy0[i];
int z0 = iz0[i];
int x1 = ix1[i];
int y1 = iy1[i];
int z1 = iz1[i];
byte pz1 = permp[z1];
byte pz0 = permp[z0];
byte y00 = permp[y0 + pz0];
byte y01 = permp[y0 + pz1];
byte y10 = permp[y1 + pz0];
byte y11 = permp[y1 + pz1];
ap[i] = permp[x0 + y00];
bp[i] = permp[x0 + y01];
cp[i] = permp[x0 + y10];
dp[i] = permp[x0 + y11];
ep[i] = permp[x1 + y00];
fp[i] = permp[x1 + y01];
gp[i] = permp[x1 + y10];
hp[i] = permp[x1 + y11];
}
}
}
}
Vector<int> nxy0i = new Vector<int>(a, 0);
Vector<int> nxy1i = new Vector<int>(b, 0);
Vector<float> nxy0 = grad3SIMD(nxy0i, fx0, fy0, fz0);
Vector<float> nxy1 = grad3SIMD(nxy1i, fx0, fy0, fz1);
Vector<float> nx0 = LERPSIMD(r, nxy0, nxy1);
nxy0i = new Vector<int>(c, 0);
nxy1i = new Vector<int>(d, 0);
nxy0 = grad3SIMD(nxy0i, fx0, fy1, fz0);
nxy1 = grad3SIMD(nxy1i, fx0, fy1, fz1);
Vector<float> nx1 = LERPSIMD(r, nxy0, nxy1);
Vector<float> n0 = LERPSIMD(t, nx0, nx1);
nxy0i = new Vector<int>(e, 0);
nxy1i = new Vector<int>(f, 0);
nxy0 = grad3SIMD(nxy0i, fx1, fy0, fz0);
nxy1 = grad3SIMD(nxy1i, fx1, fy0, fz1);
nx0 = LERPSIMD(r, nxy0, nxy1);
nxy0i = new Vector<int>(g, 0);
nxy1i = new Vector<int>(h, 0);
nxy0 = grad3SIMD(nxy0i, fx1, fy1, fz0);
nxy1 = grad3SIMD(nxy1i, fx1, fy1, fz1);
nx1 = LERPSIMD(r, nxy0, nxy1);
Vector<float> n1 = LERPSIMD(t, nx0, nx1);
return LERPSIMD(s, n0, n1) * SCALE;
}
//---------------------------------------------------------------------
/** 3D float Perlin noise.
*/
public static float noise3(float x, float y, float z)
{
int ix0, iy0, iz0, ix1, iy1, iz1;
float fx0, fy0, fz0, fx1, fy1, fz1;
float s, t, r;
float nxy0, nxy1, nx0, nx1, n0, n1;
ix0 = x > 0 ? (int)x : (int)x - 1; //FASTFLOOR(x); // Integer part of x
iy0 = y > 0 ? (int)y : (int)y - 1; //FASTFLOOR(y); // Integer part of y
iz0 = z > 0 ? (int)z : (int)z - 1; //FASTFLOOR(z); // Integer part of z
fx0 = x - ix0; // Fractional part of x
fy0 = y - iy0; // Fractional part of y
fz0 = z - iz0; // Fractional part of z
fx1 = fx0 - 1.0f;
fy1 = fy0 - 1.0f;
fz1 = fz0 - 1.0f;
ix1 = (ix0 + 1) & 0xff; // Wrap to 0..255
iy1 = (iy0 + 1) & 0xff;
iz1 = (iz0 + 1) & 0xff;
ix0 = ix0 & 0xff;
iy0 = iy0 & 0xff;
iz0 = iz0 & 0xff;
r = FADE(fz0);
t = FADE(fy0);
s = FADE(fx0);
nxy0 = grad3(perm[ix0 + perm[iy0 + perm[iz0]]], fx0, fy0, fz0);
nxy1 = grad3(perm[ix0 + perm[iy0 + perm[iz1]]], fx0, fy0, fz1);
nx0 = LERP(r, nxy0, nxy1);
nxy0 = grad3(perm[ix0 + perm[iy1 + perm[iz0]]], fx0, fy1, fz0);
nxy1 = grad3(perm[ix0 + perm[iy1 + perm[iz1]]], fx0, fy1, fz1);
nx1 = LERP(r, nxy0, nxy1);
n0 = LERP(t, nx0, nx1);
nxy0 = grad3(perm[ix1 + perm[iy0 + perm[iz0]]], fx1, fy0, fz0);
nxy1 = grad3(perm[ix1 + perm[iy0 + perm[iz1]]], fx1, fy0, fz1);
nx0 = LERP(r, nxy0, nxy1);
nxy0 = grad3(perm[ix1 + perm[iy1 + perm[iz0]]], fx1, fy1, fz0);
nxy1 = grad3(perm[ix1 + perm[iy1 + perm[iz1]]], fx1, fy1, fz1);
nx1 = LERP(r, nxy0, nxy1);
n1 = LERP(t, nx0, nx1);
return LERP(s, n0, n1) * .936f;
}
//---------------------------------------------------------------------
/** 3D float Perlin periodic noise.
*/
public float pnoise3(float x, float y, float z, int px, int py, int pz)
{
int ix0, iy0, iz0, ix1, iy1, iz1;
float fx0, fy0, fz0, fx1, fy1, fz1;
float s, t, r;
float nxy0, nxy1, nx0, nx1, n0, n1;
ix0 = x > 0 ? (int)x : (int)x - 1; //FASTFLOOR(x); // Integer part of x
iy0 = y > 0 ? (int)y : (int)y - 1; //FASTFLOOR(y); // Integer part of y
iz0 = z > 0 ? (int)z : (int)z - 1; //FASTFLOOR(z); // Integer part of z
fx0 = x - ix0; // Fractional part of x
fy0 = y - iy0; // Fractional part of y
fz0 = z - iz0; // Fractional part of z
fx1 = fx0 - 1.0f;
fy1 = fy0 - 1.0f;
fz1 = fz0 - 1.0f;
ix1 = ((ix0 + 1) % px) & 0xff; // Wrap to 0..px-1 and wrap to 0..255
iy1 = ((iy0 + 1) % py) & 0xff; // Wrap to 0..py-1 and wrap to 0..255
iz1 = ((iz0 + 1) % pz) & 0xff; // Wrap to 0..pz-1 and wrap to 0..255
ix0 = (ix0 % px) & 0xff;
iy0 = (iy0 % py) & 0xff;
iz0 = (iz0 % pz) & 0xff;
r = FADE(fz0);
t = FADE(fy0);
s = FADE(fx0);
nxy0 = grad3(perm[ix0 + perm[iy0 + perm[iz0]]], fx0, fy0, fz0);
nxy1 = grad3(perm[ix0 + perm[iy0 + perm[iz1]]], fx0, fy0, fz1);
nx0 = LERP(r, nxy0, nxy1);
nxy0 = grad3(perm[ix0 + perm[iy1 + perm[iz0]]], fx0, fy1, fz0);
nxy1 = grad3(perm[ix0 + perm[iy1 + perm[iz1]]], fx0, fy1, fz1);
nx1 = LERP(r, nxy0, nxy1);
n0 = LERP(t, nx0, nx1);
nxy0 = grad3(perm[ix1 + perm[iy0 + perm[iz0]]], fx1, fy0, fz0);
nxy1 = grad3(perm[ix1 + perm[iy0 + perm[iz1]]], fx1, fy0, fz1);
nx0 = LERP(r, nxy0, nxy1);
nxy0 = grad3(perm[ix1 + perm[iy1 + perm[iz0]]], fx1, fy1, fz0);
nxy1 = grad3(perm[ix1 + perm[iy1 + perm[iz1]]], fx1, fy1, fz1);
nx1 = LERP(r, nxy0, nxy1);
n1 = LERP(t, nx0, nx1);
return 0.936f * (LERP(s, n0, n1));
}
//---------------------------------------------------------------------
/** 4D float Perlin noise.
*/
public float noise4(float x, float y, float z, float w)
{
int ix0, iy0, iz0, iw0, ix1, iy1, iz1, iw1;
float fx0, fy0, fz0, fw0, fx1, fy1, fz1, fw1;
float s, t, r, q;
float nxyz0, nxyz1, nxy0, nxy1, nx0, nx1, n0, n1;
ix0 = x > 0 ? (int)x : (int)x - 1; //FASTFLOOR(x); // Integer part of x
iy0 = y > 0 ? (int)y : (int)y - 1; //FASTFLOOR(y); // Integer part of y
iz0 = z > 0 ? (int)z : (int)z - 1; //FASTFLOOR(z); // Integer part of z
iw0 = w > 0 ? (int)w : (int)w - 1; //FASTFLOOR(w); // Integer part of w
fx0 = x - ix0; // Fractional part of x
fy0 = y - iy0; // Fractional part of y
fz0 = z - iz0; // Fractional part of z
fw0 = w - iw0; // Fractional part of w
fx1 = fx0 - 1.0f;
fy1 = fy0 - 1.0f;
fz1 = fz0 - 1.0f;
fw1 = fw0 - 1.0f;
ix1 = (ix0 + 1) & 0xff; // Wrap to 0..255
iy1 = (iy0 + 1) & 0xff;
iz1 = (iz0 + 1) & 0xff;
iw1 = (iw0 + 1) & 0xff;
ix0 = ix0 & 0xff;
iy0 = iy0 & 0xff;
iz0 = iz0 & 0xff;
iw0 = iw0 & 0xff;
q = FADE(fw0);
r = FADE(fz0);
t = FADE(fy0);
s = FADE(fx0);
nxyz0 = grad4(perm[ix0 + perm[iy0 + perm[iz0 + perm[iw0]]]], fx0, fy0, fz0, fw0);
nxyz1 = grad4(perm[ix0 + perm[iy0 + perm[iz0 + perm[iw1]]]], fx0, fy0, fz0, fw1);
nxy0 = LERP(q, nxyz0, nxyz1);
nxyz0 = grad4(perm[ix0 + perm[iy0 + perm[iz1 + perm[iw0]]]], fx0, fy0, fz1, fw0);
nxyz1 = grad4(perm[ix0 + perm[iy0 + perm[iz1 + perm[iw1]]]], fx0, fy0, fz1, fw1);
nxy1 = LERP(q, nxyz0, nxyz1);
nx0 = LERP(r, nxy0, nxy1);
nxyz0 = grad4(perm[ix0 + perm[iy1 + perm[iz0 + perm[iw0]]]], fx0, fy1, fz0, fw0);
nxyz1 = grad4(perm[ix0 + perm[iy1 + perm[iz0 + perm[iw1]]]], fx0, fy1, fz0, fw1);
nxy0 = LERP(q, nxyz0, nxyz1);
nxyz0 = grad4(perm[ix0 + perm[iy1 + perm[iz1 + perm[iw0]]]], fx0, fy1, fz1, fw0);
nxyz1 = grad4(perm[ix0 + perm[iy1 + perm[iz1 + perm[iw1]]]], fx0, fy1, fz1, fw1);
nxy1 = LERP(q, nxyz0, nxyz1);
nx1 = LERP(r, nxy0, nxy1);
n0 = LERP(t, nx0, nx1);
nxyz0 = grad4(perm[ix1 + perm[iy0 + perm[iz0 + perm[iw0]]]], fx1, fy0, fz0, fw0);
nxyz1 = grad4(perm[ix1 + perm[iy0 + perm[iz0 + perm[iw1]]]], fx1, fy0, fz0, fw1);
nxy0 = LERP(q, nxyz0, nxyz1);
nxyz0 = grad4(perm[ix1 + perm[iy0 + perm[iz1 + perm[iw0]]]], fx1, fy0, fz1, fw0);
nxyz1 = grad4(perm[ix1 + perm[iy0 + perm[iz1 + perm[iw1]]]], fx1, fy0, fz1, fw1);
nxy1 = LERP(q, nxyz0, nxyz1);
nx0 = LERP(r, nxy0, nxy1);
nxyz0 = grad4(perm[ix1 + perm[iy1 + perm[iz0 + perm[iw0]]]], fx1, fy1, fz0, fw0);
nxyz1 = grad4(perm[ix1 + perm[iy1 + perm[iz0 + perm[iw1]]]], fx1, fy1, fz0, fw1);
nxy0 = LERP(q, nxyz0, nxyz1);
nxyz0 = grad4(perm[ix1 + perm[iy1 + perm[iz1 + perm[iw0]]]], fx1, fy1, fz1, fw0);
nxyz1 = grad4(perm[ix1 + perm[iy1 + perm[iz1 + perm[iw1]]]], fx1, fy1, fz1, fw1);
nxy1 = LERP(q, nxyz0, nxyz1);
nx1 = LERP(r, nxy0, nxy1);
n1 = LERP(t, nx0, nx1);
return 0.87f * (LERP(s, n0, n1));
}
//---------------------------------------------------------------------
/** 4D float Perlin periodic noise.
*/
public float pnoise4(float x, float y, float z, float w,
int px, int py, int pz, int pw)
{
int ix0, iy0, iz0, iw0, ix1, iy1, iz1, iw1;
float fx0, fy0, fz0, fw0, fx1, fy1, fz1, fw1;
float s, t, r, q;
float nxyz0, nxyz1, nxy0, nxy1, nx0, nx1, n0, n1;
ix0 = x > 0 ? (int)x : (int)x - 1; //FASTFLOOR(x); // Integer part of x
iy0 = y > 0 ? (int)y : (int)y - 1; //FASTFLOOR(y); // Integer part of y
iz0 = z > 0 ? (int)z : (int)z - 1; //FASTFLOOR(z); // Integer part of z
iw0 = w > 0 ? (int)w : (int)w - 1; //FASTFLOOR(w); // Integer part of w
fx0 = x - ix0; // Fractional part of x
fy0 = y - iy0; // Fractional part of y
fz0 = z - iz0; // Fractional part of z
fw0 = w - iw0; // Fractional part of w
fx1 = fx0 - 1.0f;
fy1 = fy0 - 1.0f;
fz1 = fz0 - 1.0f;
fw1 = fw0 - 1.0f;
ix1 = ((ix0 + 1) % px) & 0xff; // Wrap to 0..px-1 and wrap to 0..255
iy1 = ((iy0 + 1) % py) & 0xff; // Wrap to 0..py-1 and wrap to 0..255
iz1 = ((iz0 + 1) % pz) & 0xff; // Wrap to 0..pz-1 and wrap to 0..255
iw1 = ((iw0 + 1) % pw) & 0xff; // Wrap to 0..pw-1 and wrap to 0..255
ix0 = (ix0 % px) & 0xff;
iy0 = (iy0 % py) & 0xff;
iz0 = (iz0 % pz) & 0xff;
iw0 = (iw0 % pw) & 0xff;
q = FADE(fw0);
r = FADE(fz0);
t = FADE(fy0);
s = FADE(fx0);
nxyz0 = grad4(perm[ix0 + perm[iy0 + perm[iz0 + perm[iw0]]]], fx0, fy0, fz0, fw0);
nxyz1 = grad4(perm[ix0 + perm[iy0 + perm[iz0 + perm[iw1]]]], fx0, fy0, fz0, fw1);
nxy0 = LERP(q, nxyz0, nxyz1);
nxyz0 = grad4(perm[ix0 + perm[iy0 + perm[iz1 + perm[iw0]]]], fx0, fy0, fz1, fw0);
nxyz1 = grad4(perm[ix0 + perm[iy0 + perm[iz1 + perm[iw1]]]], fx0, fy0, fz1, fw1);
nxy1 = LERP(q, nxyz0, nxyz1);
nx0 = LERP(r, nxy0, nxy1);
nxyz0 = grad4(perm[ix0 + perm[iy1 + perm[iz0 + perm[iw0]]]], fx0, fy1, fz0, fw0);
nxyz1 = grad4(perm[ix0 + perm[iy1 + perm[iz0 + perm[iw1]]]], fx0, fy1, fz0, fw1);
nxy0 = LERP(q, nxyz0, nxyz1);
nxyz0 = grad4(perm[ix0 + perm[iy1 + perm[iz1 + perm[iw0]]]], fx0, fy1, fz1, fw0);
nxyz1 = grad4(perm[ix0 + perm[iy1 + perm[iz1 + perm[iw1]]]], fx0, fy1, fz1, fw1);
nxy1 = LERP(q, nxyz0, nxyz1);
nx1 = LERP(r, nxy0, nxy1);
n0 = LERP(t, nx0, nx1);
nxyz0 = grad4(perm[ix1 + perm[iy0 + perm[iz0 + perm[iw0]]]], fx1, fy0, fz0, fw0);
nxyz1 = grad4(perm[ix1 + perm[iy0 + perm[iz0 + perm[iw1]]]], fx1, fy0, fz0, fw1);
nxy0 = LERP(q, nxyz0, nxyz1);
nxyz0 = grad4(perm[ix1 + perm[iy0 + perm[iz1 + perm[iw0]]]], fx1, fy0, fz1, fw0);
nxyz1 = grad4(perm[ix1 + perm[iy0 + perm[iz1 + perm[iw1]]]], fx1, fy0, fz1, fw1);
nxy1 = LERP(q, nxyz0, nxyz1);
nx0 = LERP(r, nxy0, nxy1);
nxyz0 = grad4(perm[ix1 + perm[iy1 + perm[iz0 + perm[iw0]]]], fx1, fy1, fz0, fw0);
nxyz1 = grad4(perm[ix1 + perm[iy1 + perm[iz0 + perm[iw1]]]], fx1, fy1, fz0, fw1);
nxy0 = LERP(q, nxyz0, nxyz1);
nxyz0 = grad4(perm[ix1 + perm[iy1 + perm[iz1 + perm[iw0]]]], fx1, fy1, fz1, fw0);
nxyz1 = grad4(perm[ix1 + perm[iy1 + perm[iz1 + perm[iw1]]]], fx1, fy1, fz1, fw1);
nxy1 = LERP(q, nxyz0, nxyz1);
nx1 = LERP(r, nxy0, nxy1);
n1 = LERP(t, nx0, nx1);
return 0.87f * (LERP(s, n0, n1));
}
public float pfbm2(float x, float y, int px, int py, int octaves, float alpha, float omega)
{
float sum = 0f;
float a = 1;
float b = 1;
for (int i = 1; i <= octaves; i++)
{
sum += (1f / a) * pnoise2(x * b, y * b, px, py);
a *= alpha;
b *= omega;
}
return 1.0f;
//return Mathf.Clamp(sum * (1f - (1f / alpha)) * 1.4f, 0, 1);
}
public float fbm2(float x, float y, int octaves, float alpha, float omega)
{
float sum = 0f;
float a = 1;
float b = 1;
for (int i = 1; i <= octaves; i++)
{
sum += (1f / a) * noise2(x * b, y * b);
a *= alpha;
b *= omega;
}
return 1.0f;
//return Mathf.Clamp(sum * (1f - (1f / alpha)) * 1.4f, 0, 1);
}
//private static float[] fmb3Offset = new float[] {0f, 0f, .0737f, .1189f, .1440f, .1530f};
//private static float[] fmb3Scale = new float[] {0f, 1.066f, .8584f, .8120f, .8083f, .8049f };
private static float[] fmb3Offset = new float[] { 0f, 0f, .0737f, .1189f, .1440f, .1530f };
private static float[] fmb3Scale = new float[] { 0f, 1.066f, .8584f, .8120f, .8083f, .8049f };
public float fbm3(float x, float y, float z, int octaves, float lacunarity, float gain)
{
float sum = 0f;
float frequency = 1;
float amplitude = 1;
for (int i = 0; i < octaves; i++)
{
sum += frequency * noise3(x * amplitude, y * amplitude, z * amplitude);
frequency /= lacunarity;
amplitude *= gain;
}
sum = (sum - fmb3Offset[octaves]) * fmb3Scale[octaves];
//clamp it
if (sum > 1) sum = 1;
if (sum < 0) sum = 0;
//look it up in the gradient and return the color
return 1.0f;
// return Gradient[(int)(sum * (Gradient.Length - 1))];
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment