/// <summary> /// Returns Perlin noise at a point in 2D /// </summary> /// <returns>Perlin Noise value</returns> /// <param name="x">The x coordinate.</param> /// <param name="x">The y coordinate.</param> /// <param name="z">The z coordinate.</param> public override float Noise3D(float x, float y, float z) { int ix0 = 0, iy0 = 0, iz0 = 0, ix1 = 0, iy1 = 0, iz1 = 0; float fx0 = 0, fy0 = 0, fz0 = 0, fx1 = 0, fy1 = 0, fz1 = 0; float s, t, r; //Interpolation ratio variables float nb0, nb1, na0, na1, n0, n1; //Noise interpolation variables HashNoise2D(x, y, out ix0, out ix1, out fx0, out fx1, out iy0, out iy1, out fy0, out fy1); r = NoiseUtil.PerlinFade(fx0); //Fade the ratio variables t = NoiseUtil.PerlinFade(fy0); s = NoiseUtil.PerlinFade(fy0); nb0 = NoiseUtil.Gradient3D(hash_perm[ix0 + hash_perm[iy0 + hash_perm[iz0]]], fx0, fy0, fz0); //Interpolate along 8 corners nb1 = NoiseUtil.Gradient3D(hash_perm[ix0 + hash_perm[iy0 + hash_perm[iz1]]], fx1, fy0, fz0); na0 = NoiseUtil.LERP(nb0, nb1, r); nb0 = NoiseUtil.Gradient3D(hash_perm[ix0 + hash_perm[iy1 + hash_perm[iz0]]], fx0, fy1, fz0); nb1 = NoiseUtil.Gradient3D(hash_perm[ix0 + hash_perm[iy1 + hash_perm[iz1]]], fx1, fy1, fz0); na1 = NoiseUtil.LERP(nb0, nb1, r); n0 = NoiseUtil.LERP(na0, na1, t); nb0 = NoiseUtil.Gradient3D(hash_perm[ix1 + hash_perm[iy0 + hash_perm[iz0]]], fx0, fy0, fz1); nb1 = NoiseUtil.Gradient3D(hash_perm[ix1 + hash_perm[iy0 + hash_perm[iz1]]], fx1, fy0, fz1); na0 = NoiseUtil.LERP(nb0, nb1, r); nb0 = NoiseUtil.Gradient3D(hash_perm[ix1 + hash_perm[iy1 + hash_perm[iz0]]], fx0, fy1, fz1); nb1 = NoiseUtil.Gradient3D(hash_perm[ix1 + hash_perm[iy1 + hash_perm[iz1]]], fx1, fy1, fz1); na1 = NoiseUtil.LERP(nb0, nb1, r); n1 = NoiseUtil.LERP(na0, na1, t); return(0.936f * NoiseUtil.LERP(n0, n1, s)); //Interpolate along two noise values }
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 Noise2D(float x, float y) { //returns a noise value between -0.75 and 0.75 int ix0, iy0, ix1, iy1; float fx0, fy0, fx1, fy1, s, t, nx0, nx1, n0, n1; ix0 = (int)Mathf.Floor(x); // Integer part of x iy0 = (int)Mathf.Floor(y); // Integer part of y 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 = NoiseUtil.FADE(fy0); s = NoiseUtil.FADE(fx0); nx0 = NoiseUtil.GRAD2(m_perm[ix0 + m_perm[iy0]], fx0, fy0); nx1 = NoiseUtil.GRAD2(m_perm[ix0 + m_perm[iy1]], fx0, fy1); n0 = NoiseUtil.LERP(t, nx0, nx1); nx0 = NoiseUtil.GRAD2(m_perm[ix1 + m_perm[iy0]], fx1, fy0); nx1 = NoiseUtil.GRAD2(m_perm[ix1 + m_perm[iy1]], fx1, fy1); n1 = NoiseUtil.LERP(t, nx0, nx1); return(0.507f * NoiseUtil.LERP(s, n0, n1)); }
/// <summary> /// Calculates Value noise in 3 dimensions /// </summary> /// <returns>Noise value</returns> /// <param name="x">The x coordinate.</param> /// <param name="y">The y coordinate.</param> /// <param name="z">The z coordinate.</param> public override float Noise3D(float x, float y, float z) { int ix0 = 0, iy0 = 0, iz0 = 0, ix1 = 0, iy1 = 0, iz1 = 0; float tx = 0, ty = 0, tz = 0; float tf = 0; //Trash Variables HashNoise3D(x, y, z, out ix0, out ix0, out tx, out tf, out iy0, out iy1, out ty, out tf, out iz0, out iz1, out tz, out tf); int h0 = hash_perm[ix0]; //Hash values to interpolate between int h1 = hash_perm[ix1]; int h00 = hash_perm[h0 + iy0]; int h10 = hash_perm[h1 + iy0]; int h01 = hash_perm[h0 + iy1]; int h11 = hash_perm[h1 + iy1]; int h000 = hash_perm[h00 + iz0]; int h100 = hash_perm[h10 + iz0]; int h010 = hash_perm[h01 + iz0]; int h110 = hash_perm[h11 + iz0]; int h001 = hash_perm[h00 + iz1]; int h101 = hash_perm[h10 + iz1]; int h011 = hash_perm[h01 + iz1]; int h111 = hash_perm[h11 + iz1]; NoiseUtil.PerlinFade(tx); NoiseUtil.PerlinFade(ty); NoiseUtil.PerlinFade(tz); return(NoiseUtil.LERP( //Takes the hash of ix then shifts it by iy, then by iz, and computes ratio from the new hash NoiseUtil.LERP(NoiseUtil.LERP(h000, h100, tx), NoiseUtil.LERP(h010, h110, tx), ty), NoiseUtil.LERP(NoiseUtil.LERP(h001, h101, tx), NoiseUtil.LERP(h011, h111, tx), ty), tz) * (1f / (hashMask - 1))); }
/// <summary> /// Returns Perlin noise at a point in 1D /// </summary> /// <returns>Perlin Noise value</returns> /// <param name="x">The x coordinate.</param> public override float Noise1D(float x) { int ix0 = 0, ix1 = 0; float fx0 = 0, fx1 = 0; float s, n0, n1; //Noise interpolation variables HashNoise1D(x, out ix0, out ix1, out fx0, out fx1); s = NoiseUtil.PerlinFade(fx0); //Fade the ratio variable n0 = NoiseUtil.Gradient1D(hash_perm[ix0], fx0); //Interpolate the two points n1 = NoiseUtil.Gradient1D(hash_perm[ix1], fx1); return(0.188f * NoiseUtil.LERP(n0, n1, s)); //Interpolate along two noise values }
/// <summary> /// Calculates Value noise in 1 dimension /// </summary> /// <returns>Noise value</returns> /// <param name="x">The x coordinate.</param> public override float Noise1D(float x) { int i0 = 0, i1 = 0; float t = 0; float tf = 0; //Trash Variables HashNoise1D(x, out i0, out i1, out t, out tf); int h0 = hash_perm[i0]; //Hash values to interpolate between int h1 = hash_perm[i1]; NoiseUtil.PerlinFade(t); return(NoiseUtil.LERP(h0, h1, t) * (1f / (hashMask - 1))); //Ratio of the hash to the maximum value (hashMask-1) }
protected World(string saveName, string levelName, string seed) { _noiseUtil = new NoiseUtil((Seed = seed).GetHashCode()); _noiseUtil.SetFractalType(NoiseUtil.FractalType.FBM); LevelName = levelName; SaveRoot = $"./"; ChunkData = new ChunkDataManager <RegionStaticImpl <ChunkPos>, ChunkPos>( $"{SaveRoot}{Dimension}/region", new RegionInfo <ChunkPos>(new[] { 12, 12 }, 2 * Chunk.ChunkSize * Chunk.ChunkHeight * Chunk.ChunkSize), RegionStaticImpl <ChunkPos> .Ctor, ChunkPos.Ctor); }
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)); }
protected float Noise3D(float x, float y, float z) { //returns a noise value between -1.5 and 1.5 int ix0, iy0, ix1, iy1, iz0, iz1; float fx0, fy0, fz0, fx1, fy1, fz1; float s, t, r; float nxy0, nxy1, nx0, nx1, n0, n1; ix0 = (int)Mathf.Floor(x); // Integer part of x iy0 = (int)Mathf.Floor(y); // Integer part of y iz0 = (int)Mathf.Floor(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 = NoiseUtil.FADE(fz0); t = NoiseUtil.FADE(fy0); s = NoiseUtil.FADE(fx0); nxy0 = NoiseUtil.GRAD3(m_perm[ix0 + m_perm[iy0 + m_perm[iz0]]], fx0, fy0, fz0); nxy1 = NoiseUtil.GRAD3(m_perm[ix0 + m_perm[iy0 + m_perm[iz1]]], fx0, fy0, fz1); nx0 = NoiseUtil.LERP(r, nxy0, nxy1); nxy0 = NoiseUtil.GRAD3(m_perm[ix0 + m_perm[iy1 + m_perm[iz0]]], fx0, fy1, fz0); nxy1 = NoiseUtil.GRAD3(m_perm[ix0 + m_perm[iy1 + m_perm[iz1]]], fx0, fy1, fz1); nx1 = NoiseUtil.LERP(r, nxy0, nxy1); n0 = NoiseUtil.LERP(t, nx0, nx1); nxy0 = NoiseUtil.GRAD3(m_perm[ix1 + m_perm[iy0 + m_perm[iz0]]], fx1, fy0, fz0); nxy1 = NoiseUtil.GRAD3(m_perm[ix1 + m_perm[iy0 + m_perm[iz1]]], fx1, fy0, fz1); nx0 = NoiseUtil.LERP(r, nxy0, nxy1); nxy0 = NoiseUtil.GRAD3(m_perm[ix1 + m_perm[iy1 + m_perm[iz0]]], fx1, fy1, fz0); nxy1 = NoiseUtil.GRAD3(m_perm[ix1 + m_perm[iy1 + m_perm[iz1]]], fx1, fy1, fz1); nx1 = NoiseUtil.LERP(r, nxy0, nxy1); n1 = NoiseUtil.LERP(t, nx0, nx1); return(0.936f * NoiseUtil.LERP(s, n0, n1)); }
protected float Noise1D(float x) { //returns a noise value between -0.5 and 0.5 int ix0, ix1; float fx0, fx1; float s, n0, n1; ix0 = (int)Mathf.Floor(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 = NoiseUtil.FADE(fx0); n0 = NoiseUtil.GRAD1(m_perm[ix0], fx0); n1 = NoiseUtil.GRAD1(m_perm[ix1], fx1); return(0.188f * NoiseUtil.LERP(s, n0, n1)); }
/// <summary> /// Returns Perlin noise at a point in 2D /// </summary> /// <returns>Perlin Noise value</returns> /// <param name="x">The x coordinate.</param> /// <param name="x">The y coordinate.</param> public override float Noise2D(float x, float y) { int ix0 = 0, iy0 = 0, ix1 = 0, iy1 = 0; float fx0 = 0, fy0 = 0, fx1 = 0, fy1 = 0; float s, t, na0, na1, n0, n1; //Noise interpolation variables HashNoise2D(x, y, out ix0, out ix1, out fx0, out fx1, out iy0, out iy1, out fy0, out fy1); t = NoiseUtil.PerlinFade(fx0); //Fade the ratio variables s = NoiseUtil.PerlinFade(fy0); na0 = NoiseUtil.Gradient2D(hash_perm[ix0 + hash_perm[iy0]], fx0, fy0); //Interpolate along 4 corners na1 = NoiseUtil.Gradient2D(hash_perm[ix1 + hash_perm[iy0]], fx1, fy0); n0 = NoiseUtil.LERP(na0, na1, t); na0 = NoiseUtil.Gradient2D(hash_perm[ix0 + hash_perm[iy1]], fx0, fy1); na1 = NoiseUtil.Gradient2D(hash_perm[ix1 + hash_perm[iy1]], fx1, fy1); n1 = NoiseUtil.LERP(na0, na1, t); // return NoiseUtil.LERP(n0,n1,s); //Interpolate along two noise values return(0.507f * NoiseUtil.LERP(n0, n1, s) * sqr2); }
public World(string saveName, string levelName, int seed) { _noiseUtil = new NoiseUtil(Seed = seed); _noiseUtil.SetFractalType(NoiseUtil.FractalType.FBM); LevelName = levelName; SaveRoot = $"{SharpCraft.Instance.GameFolderDir}/saves/{saveName}/"; ChunkData = new ChunkDataManager <RegionStaticImpl <ChunkPos>, ChunkPos>( $"{SaveRoot}{_dimension}/region", new RegionInfo <ChunkPos>(new[] { 12, 12 }, 2 * Chunk.ChunkSize * Chunk.ChunkHeight * Chunk.ChunkSize), RegionStaticImpl <ChunkPos> .Ctor, ChunkPos.Ctor); _worldLut = new WorldLut(); foreach (var block in BlockRegistry.AllBlocks()) { _worldLut.Put(block.UnlocalizedName); } }
/// <summary> /// Creates the chunk metadata by constructing the unrealized blocks. They will later be realized (i.e. Meshes will be /// created). /// </summary> /// <returns></returns> private MyBlock[,,] createChunkMetadata() { MyBlock[,,] chunkMetadata = new MyBlock[chunkSize, chunkSize, chunkSize]; for (int z = 0; z < chunkSize; z++) { for (int y = 0; y < chunkSize; y++) { for (int x = 0; x < chunkSize; x++) { Vector3 position = new Vector3(x, y, z); Vector3 worldPosition = position + chunkGameObject.transform.position; chunkMetadata[x, y, z] = new MyBlock( NoiseUtil.GetBlockAt(worldPosition), position, chunkGameObject.gameObject ); } } } return(chunkMetadata); }
/** * 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); }
private void GenerateMesh(out Mesh mesh, out Mesh meshDebug) { mesh = new Mesh(); meshDebug = new Mesh { vertices = carrierMesh.vertices, triangles = carrierMesh.triangles, uv = carrierMesh.uv }; Vector3 particleAverageNormal = Vector3.zero; for (int i = 0; i < particleMesh.vertexCount; i++) { particleAverageNormal += particleMesh.normals[i]; } particleAverageNormal.Normalize(); var numTriangles = carrierMesh.triangles.Length / 3; CombineInstance[] combine = new CombineInstance[numParticles]; for (int i = 0; i < numParticles; i++) { var particle = new Mesh { vertices = particleMesh.vertices, triangles = particleMesh.triangles, colors = particleMesh.colors, normals = particleMesh.normals, tangents = particleMesh.tangents, uv = particleMesh.uv, }; int triangleIndex = carrierSampling == CarrierSampling.Random ? Random.Range(0, numTriangles) : (int)Mathf.Lerp(0, numTriangles, i / (float)numParticles); var vertexIndex0 = carrierMesh.triangles[triangleIndex * 3 + 0]; var vertexIndex1 = carrierMesh.triangles[triangleIndex * 3 + 1]; var vertexIndex2 = carrierMesh.triangles[triangleIndex * 3 + 2]; var a = carrierMesh.vertices[vertexIndex0]; var b = carrierMesh.vertices[vertexIndex1]; var c = carrierMesh.vertices[vertexIndex2]; var p = GetRandomPositionWithinTriangle(a, b, c); p = Vector3.Scale(p, carrierScale); var triangleNormal = (carrierMesh.normals[vertexIndex0] + carrierMesh.normals[vertexIndex1] + carrierMesh.normals[vertexIndex2]).normalized; var triangleTangent = (carrierMesh.tangents[vertexIndex0] + carrierMesh.tangents[vertexIndex1] + carrierMesh.tangents[vertexIndex2]).normalized; if (Random.value <= offsetAlongNormalFraction) { p += triangleNormal * offsetAlongNormal; } var up = Vector3.Cross(triangleNormal, triangleTangent); var rotation = Quaternion.LookRotation(-triangleNormal, up); // Random rotation for particle clouds. rotation = Quaternion.RotateTowards(rotation, Random.rotationUniform, particleRotationRange); // Rotation bias for billboard meshes. var biasTowards = Quaternion.Euler(biasTowardRotation); rotation = Quaternion.RotateTowards(rotation, biasTowards, 180f * particleRotationBias); // Give the particle a random forward rotation. rotation *= Quaternion.AngleAxis(360f * Random.value, particleAverageNormal); var scaleVariance = Random.Range(1f - particleScaleVariance, 1f); var particleTransform = Matrix4x4.Translate(p) * Matrix4x4.Rotate(rotation) * Matrix4x4.Scale(particleScale * scaleVariance) * Matrix4x4.identity; var combineInstance = new CombineInstance { mesh = particle, transform = particleTransform }; combine[i] = combineInstance; } mesh.CombineMeshes(combine, true, true); // Calculate normals. { var normals = new Vector3[mesh.vertexCount]; for (int i = 0; i < normals.Length; i++) { int vertexIndex = oneNormalPerParticle ? i - i % particleMesh.vertexCount : i; var v = mesh.vertices[vertexIndex].normalized; Vector3 noise = Vector3.zero; if (noiseEnabled) { var nv = v * noiseFrequency; var nx = NoiseUtil.Fbm(Hash.Float(noiseSeed, 0u, -1000, 1000), nv.x, noiseOctaves); var ny = NoiseUtil.Fbm(Hash.Float(noiseSeed, 1u, -1000, 1000), nv.y, noiseOctaves); var nz = NoiseUtil.Fbm(Hash.Float(noiseSeed, 2u, -1000, 1000), nv.z, noiseOctaves); noise = Vector3.Scale(new Vector3(nx, ny, nz), noiseScale) / 0.75f * noiseAmplitude; } normals[i] = (v + noise).normalized; } mesh.normals = normals; } }
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); }