public float Sample3D(float x, float y, float z) { var stretchOffset = (x + y + z) * STRETCH_3D; var xs = x + stretchOffset; var ys = y + stretchOffset; var zs = z + stretchOffset; var xsb = NoiseUtil.FastFloor(xs); var ysb = NoiseUtil.FastFloor(ys); var zsb = NoiseUtil.FastFloor(zs); var squishOffset = (xsb + ysb + zsb) * SQUISH_3D; var dx0 = x - (xsb + squishOffset); var dy0 = y - (ysb + squishOffset); var dz0 = z - (zsb + squishOffset); var xins = xs - xsb; var yins = ys - ysb; var zins = zs - zsb; var inSum = xins + yins + zins; var hash = (int)(yins - zins + 1) | (int)(xins - yins + 1) << 1 | (int)(xins - zins + 1) << 2 | (int)inSum << 3 | (int)(inSum + zins) << 5 | (int)(inSum + yins) << 7 | (int)(inSum + xins) << 9; var c = lookup3D[hash]; var value = 0.0; while (c != null) { var dx = dx0 + c.dx; var dy = dy0 + c.dy; var dz = dz0 + c.dz; var attn = 2 - dx * dx - dy * dy - dz * dz; if (attn > 0) { var px = xsb + c.xsb; var py = ysb + c.ysb; var pz = zsb + c.zsb; var i = perm3D[(perm[(perm[px & 0xFF] + py) & 0xFF] + pz) & 0xFF]; var valuePart = gradients3D[i] * dx + gradients3D[i + 1] * dy + gradients3D[i + 2] * dz; attn *= attn; value += attn * attn * valuePart; } c = c.Next; } return((float)(value * NORM_3D)); }
public float Sample2D(float x, float y) { var stretchOffset = (x + y) * STRETCH_2D; var xs = x + stretchOffset; var ys = y + stretchOffset; var xsb = NoiseUtil.FastFloor(xs); var ysb = NoiseUtil.FastFloor(ys); var squishOffset = (xsb + ysb) * SQUISH_2D; var dx0 = x - (xsb + squishOffset); var dy0 = y - (ysb + squishOffset); var xins = xs - xsb; var yins = ys - ysb; var inSum = xins + yins; var hash = (int)(xins - yins + 1) | (int)(inSum) << 1 | (int)(inSum + yins) << 2 | (int)(inSum + xins) << 4; var c = lookup2D[hash]; var value = 0.0; while (c != null) { var dx = dx0 + c.dx; var dy = dy0 + c.dy; var attn = 2 - dx * dx - dy * dy; if (attn > 0) { var px = xsb + c.xsb; var py = ysb + c.ysb; var i = perm2D[(perm[px & 0xFF] + py) & 0xFF]; var valuePart = gradients2D[i] * dx + gradients2D[i + 1] * dy; attn *= attn; value += attn * attn * valuePart; } c = c.Next; } return((float)(value * NORM_2D)); }
/** * Generate overlapping cubic lattices for 3D Re-oriented BCC noise. * Lookup table implementation inspired by DigitalShadow. * It was actually faster to narrow down the points in the loop itself, * than to build up the index with enough info to isolate 4 points. */ private double Noise3_BCC(double xr, double yr, double zr) { // Get base and offsets inside cube of first lattice. int xrb = NoiseUtil.FastFloor(xr), yrb = NoiseUtil.FastFloor(yr), zrb = NoiseUtil.FastFloor(zr); double xri = xr - xrb, yri = yr - yrb, zri = zr - zrb; // Identify which octant of the cube we're in. This determines which cell // in the other cubic lattice we're in, and also narrows down one point on each. int xht = (int)(xri + 0.5), yht = (int)(yri + 0.5), zht = (int)(zri + 0.5); int index = (xht << 0) | (yht << 1) | (zht << 2); // Point contributions double value = 0; LatticePoint3D c = LOOKUP_3D[index]; while (c != null) { double dxr = xri + c.dxr, dyr = yri + c.dyr, dzr = zri + c.dzr; double attn = 0.5 - dxr * dxr - dyr * dyr - dzr * dzr; if (attn < 0) { c = c.NextOnFailure; } else { int pxm = (xrb + c.xrv) & PMASK, pym = (yrb + c.yrv) & PMASK, pzm = (zrb + c.zrv) & PMASK; Grad3 grad = permGrad3[perm[perm[pxm] ^ pym] ^ pzm]; double extrapolation = grad.dx * dxr + grad.dy * dyr + grad.dz * dzr; attn *= attn; value += attn * attn * extrapolation; c = c.NextOnSuccess; } } return(value); }
/** * 2D Simplex noise base. * Lookup table implementation inspired by DigitalShadow. */ private double Noise2_Base(double xs, double ys) { double value = 0; // Get base points and offsets int xsb = NoiseUtil.FastFloor(xs), ysb = NoiseUtil.FastFloor(ys); double xsi = xs - xsb, ysi = ys - ysb; // Index to point list int index = (int)((ysi - xsi) / 2 + 1); double ssi = (xsi + ysi) * -0.211324865405187; double xi = xsi + ssi, yi = ysi + ssi; // Point contributions for (int i = 0; i < 3; ++i) { LatticePoint2D c = LOOKUP_2D[index + i]; double dx = xi + c.dx, dy = yi + c.dy; double attn = 0.5 - dx * dx - dy * dy; if (attn <= 0) { continue; } int pxm = (xsb + c.xsv) & PMASK, pym = (ysb + c.ysv) & PMASK; Grad2 grad = permGrad2[perm[pxm] ^ pym]; double extrapolation = grad.dx * dx + grad.dy * dy; attn *= attn; value += attn * attn * extrapolation; } return(value); }
public float Sample4D(float x, float y, float z, float w) { var stretchOffset = (x + y + z + w) * STRETCH_4D; var xs = x + stretchOffset; var ys = y + stretchOffset; var zs = z + stretchOffset; var ws = w + stretchOffset; var xsb = NoiseUtil.FastFloor(xs); var ysb = NoiseUtil.FastFloor(ys); var zsb = NoiseUtil.FastFloor(zs); var wsb = NoiseUtil.FastFloor(ws); var squishOffset = (xsb + ysb + zsb + wsb) * SQUISH_4D; var dx0 = x - (xsb + squishOffset); var dy0 = y - (ysb + squishOffset); var dz0 = z - (zsb + squishOffset); var dw0 = w - (wsb + squishOffset); var xins = xs - xsb; var yins = ys - ysb; var zins = zs - zsb; var wins = ws - wsb; var inSum = xins + yins + zins + wins; var hash = (int)(zins - wins + 1) | (int)(yins - zins + 1) << 1 | (int)(yins - wins + 1) << 2 | (int)(xins - yins + 1) << 3 | (int)(xins - zins + 1) << 4 | (int)(xins - wins + 1) << 5 | (int)inSum << 6 | (int)(inSum + wins) << 8 | (int)(inSum + zins) << 11 | (int)(inSum + yins) << 14 | (int)(inSum + xins) << 17; var c = lookup4D[hash]; var value = 0.0; while (c != null) { var dx = dx0 + c.dx; var dy = dy0 + c.dy; var dz = dz0 + c.dz; var dw = dw0 + c.dw; var attn = 2 - dx * dx - dy * dy - dz * dz - dw * dw; if (attn > 0) { var px = xsb + c.xsb; var py = ysb + c.ysb; var pz = zsb + c.zsb; var pw = wsb + c.wsb; var i = perm4D[(perm[(perm[(perm[px & 0xFF] + py) & 0xFF] + pz) & 0xFF] + pw) & 0xFF]; var valuePart = gradients4D[i] * dx + gradients4D[i + 1] * dy + gradients4D[i + 2] * dz + gradients4D[i + 3] * dw; attn *= attn; value += attn * attn * valuePart; } c = c.Next; } return((float)(value * NORM_4D)); }
/** * 4D OpenSimplex2F noise base. * Current implementation not fully optimized by lookup tables. * But still comes out slightly ahead of Gustavson's Simplex in tests. */ private double Noise4_Base(double xs, double ys, double zs, double ws) { double value = 0; // Get base points and offsets int xsb = NoiseUtil.FastFloor(xs), ysb = NoiseUtil.FastFloor(ys), zsb = NoiseUtil.FastFloor(zs), wsb = NoiseUtil.FastFloor(ws); double xsi = xs - xsb, ysi = ys - ysb, zsi = zs - zsb, wsi = ws - wsb; // If we're in the lower half, flip so we can repeat the code for the upper half. We'll flip back later. double siSum = xsi + ysi + zsi + wsi; double ssi = siSum * 0.309016994374947; // Prep for vertex contributions. bool inLowerHalf = (siSum < 2); if (inLowerHalf) { xsi = 1 - xsi; ysi = 1 - ysi; zsi = 1 - zsi; wsi = 1 - wsi; siSum = 4 - siSum; } // Consider opposing vertex pairs of the octahedron formed by the central cross-section of the stretched tesseract double aabb = xsi + ysi - zsi - wsi, abab = xsi - ysi + zsi - wsi, abba = xsi - ysi - zsi + wsi; double aabbScore = System.Math.Abs(aabb), ababScore = System.Math.Abs(abab), abbaScore = System.Math.Abs(abba); // Find the closest point on the stretched tesseract as if it were the upper half int vertexIndex, via, vib; double asi, bsi; if (aabbScore > ababScore && aabbScore > abbaScore) { if (aabb > 0) { asi = zsi; bsi = wsi; vertexIndex = 0b0011; via = 0b0111; vib = 0b1011; } else { asi = xsi; bsi = ysi; vertexIndex = 0b1100; via = 0b1101; vib = 0b1110; } } else if (ababScore > abbaScore) { if (abab > 0) { asi = ysi; bsi = wsi; vertexIndex = 0b0101; via = 0b0111; vib = 0b1101; } else { asi = xsi; bsi = zsi; vertexIndex = 0b1010; via = 0b1011; vib = 0b1110; } } else { if (abba > 0) { asi = ysi; bsi = zsi; vertexIndex = 0b1001; via = 0b1011; vib = 0b1101; } else { asi = xsi; bsi = wsi; vertexIndex = 0b0110; via = 0b0111; vib = 0b1110; } } if (bsi > asi) { via = vib; double temp = bsi; bsi = asi; asi = temp; } if (siSum + asi > 3) { vertexIndex = via; if (siSum + bsi > 4) { vertexIndex = 0b1111; } } // Now flip back if we're actually in the lower half. if (inLowerHalf) { xsi = 1 - xsi; ysi = 1 - ysi; zsi = 1 - zsi; wsi = 1 - wsi; vertexIndex ^= 0b1111; } // Five points to add, total, from five copies of the A4 lattice. for (int i = 0; i < 5; ++i) { // Update xsb/etc. and add the lattice point's contribution. LatticePoint4D c = VERTICES_4D[vertexIndex]; xsb += c.xsv; ysb += c.ysv; zsb += c.zsv; wsb += c.wsv; double xi = xsi + ssi, yi = ysi + ssi, zi = zsi + ssi, wi = wsi + ssi; double dx = xi + c.dx, dy = yi + c.dy, dz = zi + c.dz, dw = wi + c.dw; double attn = 0.5 - dx * dx - dy * dy - dz * dz - dw * dw; if (attn > 0) { int pxm = xsb & PMASK, pym = ysb & PMASK, pzm = zsb & PMASK, pwm = wsb & PMASK; Grad4 grad = permGrad4[perm[perm[perm[pxm] ^ pym] ^ pzm] ^ pwm]; double ramped = grad.dx * dx + grad.dy * dy + grad.dz * dz + grad.dw * dw; attn *= attn; value += attn * attn * ramped; } // Maybe this helps the compiler/JVM/LLVM/etc. know we can end the loop here. Maybe not. if (i == 4) { break; } // Update the relative skewed coordinates to reference the vertex we just added. // Rather, reference its counterpart on the lattice copy that is shifted down by // the vector <-0.2, -0.2, -0.2, -0.2> xsi += c.xsi; ysi += c.ysi; zsi += c.zsi; wsi += c.wsi; ssi += c.ssiDelta; // Next point is the closest vertex on the 4-simplex whose base vertex is the aforementioned vertex. double score0 = 1.0 + ssi * (-1.0 / 0.309016994374947); // Seems slightly faster than 1.0-xsi-ysi-zsi-wsi vertexIndex = 0b0000; if (xsi >= ysi && xsi >= zsi && xsi >= wsi && xsi >= score0) { vertexIndex = 0b0001; } else if (ysi > xsi && ysi >= zsi && ysi >= wsi && ysi >= score0) { vertexIndex = 0b0010; } else if (zsi > xsi && zsi > ysi && zsi >= wsi && zsi >= score0) { vertexIndex = 0b0100; } else if (wsi > xsi && wsi > ysi && wsi > zsi && wsi >= score0) { vertexIndex = 0b1000; } } return(value); }