package com.hphoto.image; import java.util.*; /** * Perlin Noise functions */ public class Noise{ private static Random randomGenerator = new Random(); public float evaluate(float x) { return noise1(x); } public float evaluate(float x, float y) { return noise2(x, y); } public float evaluate(float x, float y, float z) { return noise3(x, y, z); } /** * Compute turbulence using Perlin noise. * @param x the x value * @param y the y value * @param octaves number of octaves of turbulence * @return turbulence value at (x,y) */ public static float turbulence2(float x, float y, float octaves) { float t = 0.0f; for (float f = 1.0f; f <= octaves; f *= 2) t += Math.abs(noise2(f * x, f * y)) / f; return t; } /** * Compute turbulence using Perlin noise. * @param x the x value * @param y the y value * @param octaves number of octaves of turbulence * @return turbulence value at (x,y) */ public static float turbulence3(float x, float y, float z, float octaves) { float t = 0.0f; for (float f = 1.0f; f <= octaves; f *= 2) t += Math.abs(noise3(f * x, f * y, f * z)) / f; return t; } private final static int B = 0x100; private final static int BM = 0xff; private final static int N = 0x1000; static int[] p = new int[B + B + 2]; static float[][] g3 = new float[B + B + 2][3]; static float[][] g2 = new float[B + B + 2][2]; static float[] g1 = new float[B + B + 2]; static boolean start = true; private static float sCurve(float t) { return t * t * (3.0f - 2.0f * t); } /** * Compute 1-dimensional Perlin noise. * @param x the x value * @return noise value at x in the range -1..1 */ public static float noise1(float x) { int bx0, bx1; float rx0, rx1, sx, t, u, v; if (start) { start = false; init(); } t = x + N; bx0 = ((int)t) & BM; bx1 = (bx0+1) & BM; rx0 = t - (int)t; rx1 = rx0 - 1.0f; sx = sCurve(rx0); u = rx0 * g1[p[bx0]]; v = rx1 * g1[p[bx1]]; return 2.3f*lerp(sx, u, v); } /** * Compute 2-dimensional Perlin noise. * @param x the x coordinate * @param y the y coordinate * @return noise value at (x,y) */ public static float noise2(float x, float y) { int bx0, bx1, by0, by1, b00, b10, b01, b11; float rx0, rx1, ry0, ry1, q[], sx, sy, a, b, t, u, v; int i, j; if (start) { start = false; init(); } t = x + N; bx0 = ((int)t) & BM; bx1 = (bx0+1) & BM; rx0 = t - (int)t; rx1 = rx0 - 1.0f; t = y + N; by0 = ((int)t) & BM; by1 = (by0+1) & BM; ry0 = t - (int)t; ry1 = ry0 - 1.0f; i = p[bx0]; j = p[bx1]; b00 = p[i + by0]; b10 = p[j + by0]; b01 = p[i + by1]; b11 = p[j + by1]; sx = sCurve(rx0); sy = sCurve(ry0); q = g2[b00]; u = rx0 * q[0] + ry0 * q[1]; q = g2[b10]; v = rx1 * q[0] + ry0 * q[1]; a = lerp(sx, u, v); q = g2[b01]; u = rx0 * q[0] + ry1 * q[1]; q = g2[b11]; v = rx1 * q[0] + ry1 * q[1]; b = lerp(sx, u, v); return 1.5f*lerp(sy, a, b); } /** * Compute 3-dimensional Perlin noise. * @param x the x coordinate * @param y the y coordinate * @param y the y coordinate * @return noise value at (x,y,z) */ public static float noise3(float x, float y, float z) { int bx0, bx1, by0, by1, bz0, bz1, b00, b10, b01, b11; float rx0, rx1, ry0, ry1, rz0, rz1, q[], sy, sz, a, b, c, d, t, u, v; int i, j; if (start) { start = false; init(); } t = x + N; bx0 = ((int)t) & BM; bx1 = (bx0+1) & BM; rx0 = t - (int)t; rx1 = rx0 - 1.0f; t = y + N; by0 = ((int)t) & BM; by1 = (by0+1) & BM; ry0 = t - (int)t; ry1 = ry0 - 1.0f; t = z + N; bz0 = ((int)t) & BM; bz1 = (bz0+1) & BM; rz0 = t - (int)t; rz1 = rz0 - 1.0f; i = p[bx0]; j = p[bx1]; b00 = p[i + by0]; b10 = p[j + by0]; b01 = p[i + by1]; b11 = p[j + by1]; t = sCurve(rx0); sy = sCurve(ry0); sz = sCurve(rz0); q = g3[b00 + bz0]; u = rx0 * q[0] + ry0 * q[1] + rz0 * q[2]; q = g3[b10 + bz0]; v = rx1 * q[0] + ry0 * q[1] + rz0 * q[2]; a = lerp(t, u, v); q = g3[b01 + bz0]; u = rx0 * q[0] + ry1 * q[1] + rz0 * q[2]; q = g3[b11 + bz0]; v = rx1 * q[0] + ry1 * q[1] + rz0 * q[2]; b = lerp(t, u, v); c = lerp(sy, a, b); q = g3[b00 + bz1]; u = rx0 * q[0] + ry0 * q[1] + rz1 * q[2]; q = g3[b10 + bz1]; v = rx1 * q[0] + ry0 * q[1] + rz1 * q[2]; a = lerp(t, u, v); q = g3[b01 + bz1]; u = rx0 * q[0] + ry1 * q[1] + rz1 * q[2]; q = g3[b11 + bz1]; v = rx1 * q[0] + ry1 * q[1] + rz1 * q[2]; b = lerp(t, u, v); d = lerp(sy, a, b); return 1.5f*lerp(sz, c, d); } public static float lerp(float t, float a, float b) { return a + t * (b - a); } private static void normalize2(float v[]) { float s = (float)Math.sqrt(v[0] * v[0] + v[1] * v[1]); v[0] = v[0] / s; v[1] = v[1] / s; } static void normalize3(float v[]) { float s = (float)Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); v[0] = v[0] / s; v[1] = v[1] / s; v[2] = v[2] / s; } private static int random() { return randomGenerator.nextInt() & 0x7fffffff; } private static void init() { int i, j, k; for (i = 0; i < B; i++) { p[i] = i; g1[i] = (float)((random() % (B + B)) - B) / B; for (j = 0; j < 2; j++) g2[i][j] = (float)((random() % (B + B)) - B) / B; normalize2(g2[i]); for (j = 0; j < 3; j++) g3[i][j] = (float)((random() % (B + B)) - B) / B; normalize3(g3[i]); } for (i = B-1; i >= 0; i--) { k = p[i]; p[i] = p[j = random() % B]; p[j] = k; } for (i = 0; i < B + 2; i++) { p[B + i] = p[i]; g1[B + i] = g1[i]; for (j = 0; j < 2; j++) g2[B + i][j] = g2[i][j]; for (j = 0; j < 3; j++) g3[B + i][j] = g3[i][j]; } } /** * Returns the minimum and maximum of a number of random values * of the given function. This is useful for making some stab at * normalising the function. */ /* public static float[] findRange(Function1D f, float[] minmax) { if (minmax == null) minmax = new float[2]; float min = 0, max = 0; // Some random numbers here... for (float x = -100; x < 100; x += 1.27139) { float n = f.evaluate(x); min = Math.min(min, n); max = Math.max(max, n); } minmax[0] = min; minmax[1] = max; return minmax; } */ /** * Returns the minimum and maximum of a number of random values * of the given function. This is useful for making some stab at * normalising the function. */ /* public static float[] findRange(Function2D f, float[] minmax) { if (minmax == null) minmax = new float[2]; float min = 0, max = 0; // Some random numbers here... for (float y = -100; y < 100; y += 10.35173) { for (float x = -100; x < 100; x += 10.77139) { float n = f.evaluate(x, y); min = Math.min(min, n); max = Math.max(max, n); } } minmax[0] = min; minmax[1] = max; return minmax; } */ }