/*
* Copyright (c) 2009-2012 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.jme3.scene.plugins.blender.textures.generating;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.jme3.math.FastMath;
import com.jme3.scene.plugins.blender.textures.generating.TextureGeneratorMusgrave.MusgraveData;
/**
* This generator is responsible for creating various noises used to create
* generated textures loaded from blender.
* It is only used by TextureHelper.
* Take note that these functions are not thread safe.
* @author Marcin Roguski (Kaelthas)
*/
/* package */class NoiseGenerator {
private static final Logger LOGGER = Logger.getLogger(NoiseGenerator.class.getName());
// tex->stype
protected static final int TEX_PLASTIC = 0;
protected static final int TEX_WALLIN = 1;
protected static final int TEX_WALLOUT = 2;
// musgrave stype
protected static final int TEX_MFRACTAL = 0;
protected static final int TEX_RIDGEDMF = 1;
protected static final int TEX_HYBRIDMF = 2;
protected static final int TEX_FBM = 3;
protected static final int TEX_HTERRAIN = 4;
// keyblock->type
protected static final int KEY_LINEAR = 0;
protected static final int KEY_CARDINAL = 1;
protected static final int KEY_BSPLINE = 2;
// CONSTANTS (read from file)
protected static float[] hashpntf;
protected static short[] hash;
protected static float[] hashvectf;
protected static short[] p;
protected static float[][] g;
/**
* Constructor. Loads the constants needed for computations. They are exactly like the ones the blender uses. Each
* deriving class should override this method and load its own constraints.
*/
public NoiseGenerator() {
LOGGER.fine("Loading noise constants.");
InputStream is = NoiseGenerator.class.getResourceAsStream("noiseconstants.dat");
try {
ObjectInputStream ois = new ObjectInputStream(is);
hashpntf = (float[]) ois.readObject();
hash = (short[]) ois.readObject();
hashvectf = (float[]) ois.readObject();
p = (short[]) ois.readObject();
g = (float[][]) ois.readObject();
} catch (IOException e) {
LOGGER.log(Level.SEVERE, e.getLocalizedMessage(), e);
} catch (ClassNotFoundException e) {
assert false : "Constants' classes should be arrays of primitive types, so they are ALWAYS known!";
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
LOGGER.log(Level.WARNING, e.getLocalizedMessage());
}
}
}
}
protected static Map<Integer, NoiseFunction> noiseFunctions = new HashMap<Integer, NoiseFunction>();
static {
noiseFunctions.put(Integer.valueOf(0), new NoiseFunction() {
// originalBlenderNoise
public float execute(float x, float y, float z) {
return NoiseFunctions.originalBlenderNoise(x, y, z);
}
public float executeSigned(float x, float y, float z) {
return 2.0f * NoiseFunctions.originalBlenderNoise(x, y, z) - 1.0f;
}
});
noiseFunctions.put(Integer.valueOf(1), new NoiseFunction() {
// orgPerlinNoise
public float execute(float x, float y, float z) {
return 0.5f + 0.5f * NoiseFunctions.noise3Perlin(x, y, z);
}
public float executeSigned(float x, float y, float z) {
return NoiseFunctions.noise3Perlin(x, y, z);
}
});
noiseFunctions.put(Integer.valueOf(2), new NoiseFunction() {
// newPerlin
public float execute(float x, float y, float z) {
return 0.5f + 0.5f * NoiseFunctions.newPerlin(x, y, z);
}
public float executeSigned(float x, float y, float z) {
return this.execute(x, y, z);
}
});
noiseFunctions.put(Integer.valueOf(3), new NoiseFunction() {
private final float[] da = new float[4];
private final float[] pa = new float[12];
// voronoi_F1
public float execute(float x, float y, float z) {
NoiseFunctions.voronoi(x, y, z, da, pa, 1, NATURAL_DISTANCE_FUNCTION);
return da[0];
}
public float executeSigned(float x, float y, float z) {
NoiseFunctions.voronoi(x, y, z, da, pa, 1, NATURAL_DISTANCE_FUNCTION);
return 2.0f * da[0] - 1.0f;
}
});
noiseFunctions.put(Integer.valueOf(4), new NoiseFunction() {
private final float[] da = new float[4];
private final float[] pa = new float[12];
// voronoi_F2
public float execute(float x, float y, float z) {
NoiseFunctions.voronoi(x, y, z, da, pa, 1, NATURAL_DISTANCE_FUNCTION);
return da[1];
}
public float executeSigned(float x, float y, float z) {
NoiseFunctions.voronoi(x, y, z, da, pa, 1, NATURAL_DISTANCE_FUNCTION);
return 2.0f * da[1] - 1.0f;
}
});
noiseFunctions.put(Integer.valueOf(5), new NoiseFunction() {
private final float[] da = new float[4];
private final float[] pa = new float[12];
// voronoi_F3
public float execute(float x, float y, float z) {
NoiseFunctions.voronoi(x, y, z, da, pa, 1, NATURAL_DISTANCE_FUNCTION);
return da[2];
}
public float executeSigned(float x, float y, float z) {
NoiseFunctions.voronoi(x, y, z, da, pa, 1, NATURAL_DISTANCE_FUNCTION);
return 2.0f * da[2] - 1.0f;
}
});
noiseFunctions.put(Integer.valueOf(6), new NoiseFunction() {
private final float[] da = new float[4];
private final float[] pa = new float[12];
// voronoi_F4
public float execute(float x, float y, float z) {
NoiseFunctions.voronoi(x, y, z, da, pa, 1, NATURAL_DISTANCE_FUNCTION);
return da[3];
}
public float executeSigned(float x, float y, float z) {
NoiseFunctions.voronoi(x, y, z, da, pa, 1, NATURAL_DISTANCE_FUNCTION);
return 2.0f * da[3] - 1.0f;
}
});
noiseFunctions.put(Integer.valueOf(7), new NoiseFunction() {
private final float[] da = new float[4];
private final float[] pa = new float[12];
// voronoi_F1F2
public float execute(float x, float y, float z) {
NoiseFunctions.voronoi(x, y, z, da, pa, 1, NATURAL_DISTANCE_FUNCTION);
return da[1] - da[0];
}
public float executeSigned(float x, float y, float z) {
NoiseFunctions.voronoi(x, y, z, da, pa, 1, NATURAL_DISTANCE_FUNCTION);
return 2.0f * (da[1] - da[0]) - 1.0f;
}
});
noiseFunctions.put(Integer.valueOf(8), new NoiseFunction() {
private final NoiseFunction voronoiF1F2NoiseFunction = noiseFunctions.get(Integer.valueOf(7));
// voronoi_Cr
public float execute(float x, float y, float z) {
float t = 10 * voronoiF1F2NoiseFunction.execute(x, y, z);
return t > 1.0f ? 1.0f : t;
}
public float executeSigned(float x, float y, float z) {
float t = 10.0f * voronoiF1F2NoiseFunction.execute(x, y, z);
return t > 1.0f ? 1.0f : 2.0f * t - 1.0f;
}
});
noiseFunctions.put(Integer.valueOf(14), new NoiseFunction() {
// cellNoise
public float execute(float x, float y, float z) {
int xi = (int) FastMath.floor(x);
int yi = (int) FastMath.floor(y);
int zi = (int) FastMath.floor(z);
long n = xi + yi * 1301 + zi * 314159;
n ^= n << 13;
return (n * (n * n * 15731 + 789221) + 1376312589) / 4294967296.0f;
}
public float executeSigned(float x, float y, float z) {
return 2.0f * this.execute(x, y, z) - 1.0f;
}
});
}
/** Distance metrics for voronoi. e parameter only used in Minkovsky. */
protected static Map<Integer, DistanceFunction> distanceFunctions = new HashMap<Integer, NoiseGenerator.DistanceFunction>();
private static DistanceFunction NATURAL_DISTANCE_FUNCTION; // often used in noise functions, se I store it here to avoid fetching it every time
static {
distanceFunctions.put(Integer.valueOf(0), new DistanceFunction() {
// real distance
public float execute(float x, float y, float z, float e) {
return (float) Math.sqrt(x * x + y * y + z * z);
}
});
distanceFunctions.put(Integer.valueOf(1), new DistanceFunction() {
// distance squared
public float execute(float x, float y, float z, float e) {
return x * x + y * y + z * z;
}
});
distanceFunctions.put(Integer.valueOf(2), new DistanceFunction() {
// manhattan/taxicab/cityblock distance
public float execute(float x, float y, float z, float e) {
return FastMath.abs(x) + FastMath.abs(y) + FastMath.abs(z);
}
});
distanceFunctions.put(Integer.valueOf(3), new DistanceFunction() {
// Chebychev
public float execute(float x, float y, float z, float e) {
x = FastMath.abs(x);
y = FastMath.abs(y);
z = FastMath.abs(z);
float t = x > y ? x : y;
return z > t ? z : t;
}
});
distanceFunctions.put(Integer.valueOf(4), new DistanceFunction() {
// Minkovsky, preset exponent 0.5 (MinkovskyH)
public float execute(float x, float y, float z, float e) {
float d = (float) (Math.sqrt(FastMath.abs(x)) + Math.sqrt(FastMath.abs(y)) + Math.sqrt(FastMath.abs(z)));
return d * d;
}
});
distanceFunctions.put(Integer.valueOf(5), new DistanceFunction() {
// Minkovsky, preset exponent 0.25 (Minkovsky4)
public float execute(float x, float y, float z, float e) {
x *= x;
y *= y;
z *= z;
return (float) Math.sqrt(Math.sqrt(x * x + y * y + z * z));
}
});
distanceFunctions.put(Integer.valueOf(6), new DistanceFunction() {
// Minkovsky, general case
public float execute(float x, float y, float z, float e) {
return (float) Math.pow(Math.pow(FastMath.abs(x), e) + Math.pow(FastMath.abs(y), e) + Math.pow(FastMath.abs(z), e), 1.0f / e);
}
});
NATURAL_DISTANCE_FUNCTION = distanceFunctions.get(Integer.valueOf(0));
}
protected static Map<Integer, MusgraveFunction> musgraveFunctions = new HashMap<Integer, NoiseGenerator.MusgraveFunction>();
static {
musgraveFunctions.put(Integer.valueOf(TEX_MFRACTAL), new MusgraveFunction() {
public float execute(MusgraveData musgraveData, float x, float y, float z) {
float rmd, value = 1.0f, pwr = 1.0f, pwHL = (float) Math.pow(musgraveData.lacunarity, -musgraveData.h);
for (int i = 0; i < (int) musgraveData.octaves; ++i) {
value *= pwr * musgraveData.noiseFunction.executeSigned(x, y, z) + 1.0f;
pwr *= pwHL;
x *= musgraveData.lacunarity;
y *= musgraveData.lacunarity;
z *= musgraveData.lacunarity;
}
rmd = musgraveData.octaves - FastMath.floor(musgraveData.octaves);
if (rmd != 0.0f) {
value *= rmd * musgraveData.noiseFunction.executeSigned(x, y, z) * pwr + 1.0f;
}
return value;
}
});
musgraveFunctions.put(Integer.valueOf(TEX_RIDGEDMF), new MusgraveFunction() {
public float execute(MusgraveData musgraveData, float x, float y, float z) {
float result, signal, weight;
float pwHL = (float) Math.pow(musgraveData.lacunarity, -musgraveData.h);
float pwr = pwHL;
signal = musgraveData.offset - FastMath.abs(musgraveData.noiseFunction.executeSigned(x, y, z));
signal *= signal;
result = signal;
weight = 1.0f;
for (int i = 1; i < (int) musgraveData.octaves; ++i) {
x *= musgraveData.lacunarity;
y *= musgraveData.lacunarity;
z *= musgraveData.lacunarity;
weight = signal * musgraveData.gain;
if (weight > 1.0f) {
weight = 1.0f;
} else if (weight < 0.0) {
weight = 0.0f;
}
signal = musgraveData.offset - FastMath.abs(musgraveData.noiseFunction.executeSigned(x, y, z));
signal *= signal;
signal *= weight;
result += signal * pwr;
pwr *= pwHL;
}
return result;
}
});
musgraveFunctions.put(Integer.valueOf(TEX_HYBRIDMF), new MusgraveFunction() {
public float execute(MusgraveData musgraveData, float x, float y, float z) {
float result, signal, weight, rmd;
float pwHL = (float) Math.pow(musgraveData.lacunarity, -musgraveData.h);
float pwr = pwHL;
result = musgraveData.noiseFunction.executeSigned(x, y, z) + musgraveData.offset;
weight = musgraveData.gain * result;
x *= musgraveData.lacunarity;
y *= musgraveData.lacunarity;
z *= musgraveData.lacunarity;
for (int i = 1; weight > 0.001f && i < (int) musgraveData.octaves; ++i) {
if (weight > 1.0f) {
weight = 1.0f;
}
signal = (musgraveData.noiseFunction.executeSigned(x, y, z) + musgraveData.offset) * pwr;
pwr *= pwHL;
result += weight * signal;
weight *= musgraveData.gain * signal;
x *= musgraveData.lacunarity;
y *= musgraveData.lacunarity;
z *= musgraveData.lacunarity;
}
rmd = musgraveData.octaves - FastMath.floor(musgraveData.octaves);
if (rmd != 0.0f) {
result += rmd * (musgraveData.noiseFunction.executeSigned(x, y, z) + musgraveData.offset) * pwr;
}
return result;
}
});
musgraveFunctions.put(Integer.valueOf(TEX_FBM), new MusgraveFunction() {
public float execute(MusgraveData musgraveData, float x, float y, float z) {
float rmd, value = 0.0f, pwr = 1.0f, pwHL = (float) Math.pow(musgraveData.lacunarity, -musgraveData.h);
for (int i = 0; i < (int) musgraveData.octaves; ++i) {
value += musgraveData.noiseFunction.executeSigned(x, y, z) * pwr;
pwr *= pwHL;
x *= musgraveData.lacunarity;
y *= musgraveData.lacunarity;
z *= musgraveData.lacunarity;
}
rmd = musgraveData.octaves - FastMath.floor(musgraveData.octaves);
if (rmd != 0.f) {
value += rmd * musgraveData.noiseFunction.executeSigned(x, y, z) * pwr;
}
return value;
}
});
musgraveFunctions.put(Integer.valueOf(TEX_HTERRAIN), new MusgraveFunction() {
public float execute(MusgraveData musgraveData, float x, float y, float z) {
float value, increment, rmd;
float pwHL = (float) Math.pow(musgraveData.lacunarity, -musgraveData.h);
float pwr = pwHL;
value = musgraveData.offset + musgraveData.noiseFunction.executeSigned(x, y, z);
x *= musgraveData.lacunarity;
y *= musgraveData.lacunarity;
z *= musgraveData.lacunarity;
for (int i = 1; i < (int) musgraveData.octaves; ++i) {
increment = (musgraveData.noiseFunction.executeSigned(x, y, z) + musgraveData.offset) * pwr * value;
value += increment;
pwr *= pwHL;
x *= musgraveData.lacunarity;
y *= musgraveData.lacunarity;
z *= musgraveData.lacunarity;
}
rmd = musgraveData.octaves - FastMath.floor(musgraveData.octaves);
if (rmd != 0.0) {
increment = (musgraveData.noiseFunction.executeSigned(x, y, z) + musgraveData.offset) * pwr * value;
value += rmd * increment;
}
return value;
}
});
}
public static class NoiseFunctions {
public static float noise(float x, float y, float z, float noiseSize, int noiseDepth, NoiseFunction noiseFunction, boolean isHard) {
if (noiseSize != 0.0) {
noiseSize = 1.0f / noiseSize;
x *= noiseSize;
y *= noiseSize;
z *= noiseSize;
}
float result = noiseFunction.execute(x, y, z);
return isHard ? FastMath.abs(2.0f * result - 1.0f) : result;
}
public static float turbulence(float x, float y, float z, float noiseSize, int noiseDepth, NoiseFunction noiseFunction, boolean isHard) {
if (noiseSize != 0.0) {
noiseSize = 1.0f / noiseSize;
x *= noiseSize;
y *= noiseSize;
z *= noiseSize;
}
float sum = 0, t, amp = 1, fscale = 1;
for (int i = 0; i <= noiseDepth; ++i, amp *= 0.5f, fscale *= 2f) {
t = noiseFunction.execute(fscale * x, fscale * y, fscale * z);
if (isHard) {
t = FastMath.abs(2.0f * t - 1.0f);
}
sum += t * amp;
}
sum *= (float) (1 << noiseDepth) / (float) ((1 << noiseDepth + 1) - 1);
return sum;
}
private static final float[] voronoiP = new float[3];
public static void voronoi(float x, float y, float z, float[] da, float[] pa, float distanceExponent, DistanceFunction distanceFunction) {
float xd, yd, zd, d;
int xi = (int) FastMath.floor(x);
int yi = (int) FastMath.floor(y);
int zi = (int) FastMath.floor(z);
da[0] = da[1] = da[2] = da[3] = Float.MAX_VALUE;// 1e10f;
for (int i = xi - 1; i <= xi + 1; ++i) {
for (int j = yi - 1; j <= yi + 1; ++j) {
for (int k = zi - 1; k <= zi + 1; ++k) {
NoiseMath.hash(i, j, k, voronoiP);
xd = x - (voronoiP[0] + i);
yd = y - (voronoiP[1] + j);
zd = z - (voronoiP[2] + k);
d = distanceFunction.execute(xd, yd, zd, distanceExponent);
if (d < da[0]) {
da[3] = da[2];
da[2] = da[1];
da[1] = da[0];
da[0] = d;
pa[9] = pa[6];
pa[10] = pa[7];
pa[11] = pa[8];
pa[6] = pa[3];
pa[7] = pa[4];
pa[8] = pa[5];
pa[3] = pa[0];
pa[4] = pa[1];
pa[5] = pa[2];
pa[0] = voronoiP[0] + i;
pa[1] = voronoiP[1] + j;
pa[2] = voronoiP[2] + k;
} else if (d < da[1]) {
da[3] = da[2];
da[2] = da[1];
da[1] = d;
pa[9] = pa[6];
pa[10] = pa[7];
pa[11] = pa[8];
pa[6] = pa[3];
pa[7] = pa[4];
pa[8] = pa[5];
pa[3] = voronoiP[0] + i;
pa[4] = voronoiP[1] + j;
pa[5] = voronoiP[2] + k;
} else if (d < da[2]) {
da[3] = da[2];
da[2] = d;
pa[9] = pa[6];
pa[10] = pa[7];
pa[11] = pa[8];
pa[6] = voronoiP[0] + i;
pa[7] = voronoiP[1] + j;
pa[8] = voronoiP[2] + k;
} else if (d < da[3]) {
da[3] = d;
pa[9] = voronoiP[0] + i;
pa[10] = voronoiP[1] + j;
pa[11] = voronoiP[2] + k;
}
}
}
}
}
// instead of adding another permutation array, just use hash table defined above
public static float newPerlin(float x, float y, float z) {
int A, AA, AB, B, BA, BB;
float floorX = FastMath.floor(x), floorY = FastMath.floor(y), floorZ = FastMath.floor(z);
int intX = (int) floorX & 0xFF, intY = (int) floorY & 0xFF, intZ = (int) floorZ & 0xFF;
x -= floorX;
y -= floorY;
z -= floorZ;
// computing fading curves
floorX = NoiseMath.npfade(x);
floorY = NoiseMath.npfade(y);
floorZ = NoiseMath.npfade(z);
A = hash[intX] + intY;
AA = hash[A] + intZ;
AB = hash[A + 1] + intZ;
B = hash[intX + 1] + intY;
BA = hash[B] + intZ;
BB = hash[B + 1] + intZ;
return NoiseMath.lerp(floorZ, NoiseMath.lerp(floorY, NoiseMath.lerp(floorX, NoiseMath.grad(hash[AA], x, y, z), NoiseMath.grad(hash[BA], x - 1, y, z)), NoiseMath.lerp(floorX, NoiseMath.grad(hash[AB], x, y - 1, z), NoiseMath.grad(hash[BB], x - 1, y - 1, z))),
NoiseMath.lerp(floorY, NoiseMath.lerp(floorX, NoiseMath.grad(hash[AA + 1], x, y, z - 1), NoiseMath.grad(hash[BA + 1], x - 1, y, z - 1)), NoiseMath.lerp(floorX, NoiseMath.grad(hash[AB + 1], x, y - 1, z - 1), NoiseMath.grad(hash[BB + 1], x - 1, y - 1, z - 1))));
}
public static float noise3Perlin(float x, float y, float z) {
float t = x + 10000.0f;
int bx0 = (int) t & 0xFF;
int bx1 = bx0 + 1 & 0xFF;
float rx0 = t - (int) t;
float rx1 = rx0 - 1.0f;
t = y + 10000.0f;
int by0 = (int) t & 0xFF;
int by1 = by0 + 1 & 0xFF;
float ry0 = t - (int) t;
float ry1 = ry0 - 1.0f;
t = z + 10000.0f;
int bz0 = (int) t & 0xFF;
int bz1 = bz0 + 1 & 0xFF;
float rz0 = t - (int) t;
float rz1 = rz0 - 1.0f;
int i = p[bx0];
int j = p[bx1];
int b00 = p[i + by0];
int b10 = p[j + by0];
int b01 = p[i + by1];
int b11 = p[j + by1];
float sx = NoiseMath.surve(rx0);
float sy = NoiseMath.surve(ry0);
float sz = NoiseMath.surve(rz0);
float[] q = g[b00 + bz0];
float u = NoiseMath.at(rx0, ry0, rz0, q);
q = g[b10 + bz0];
float v = NoiseMath.at(rx1, ry0, rz0, q);
float a = NoiseMath.lerp(sx, u, v);
q = g[b01 + bz0];
u = NoiseMath.at(rx0, ry1, rz0, q);
q = g[b11 + bz0];
v = NoiseMath.at(rx1, ry1, rz0, q);
float b = NoiseMath.lerp(sx, u, v);
float c = NoiseMath.lerp(sy, a, b);
q = g[b00 + bz1];
u = NoiseMath.at(rx0, ry0, rz1, q);
q = g[b10 + bz1];
v = NoiseMath.at(rx1, ry0, rz1, q);
a = NoiseMath.lerp(sx, u, v);
q = g[b01 + bz1];
u = NoiseMath.at(rx0, ry1, rz1, q);
q = g[b11 + bz1];
v = NoiseMath.at(rx1, ry1, rz1, q);
b = NoiseMath.lerp(sx, u, v);
float d = NoiseMath.lerp(sy, a, b);
return 1.5f * NoiseMath.lerp(sz, c, d);
}
private static final float[] cn = new float[8];
private static final int[] b1 = new int[8];
private static final int[] b2 = new int[2];
private static final float[] xFactor = new float[8];
private static final float[] yFactor = new float[8];
private static final float[] zFactor = new float[8];
public static float originalBlenderNoise(float x, float y, float z) {
float n = 0.5f;
int ix = (int) FastMath.floor(x);
int iy = (int) FastMath.floor(y);
int iz = (int) FastMath.floor(z);
float ox = x - ix;
float oy = y - iy;
float oz = z - iz;
float jx = ox - 1;
float jy = oy - 1;
float jz = oz - 1;
float cn1 = ox * ox;
float cn2 = oy * oy;
float cn3 = oz * oz;
float cn4 = jx * jx;
float cn5 = jy * jy;
float cn6 = jz * jz;
cn1 = 1.0f - 3.0f * cn1 + 2.0f * cn1 * ox;
cn2 = 1.0f - 3.0f * cn2 + 2.0f * cn2 * oy;
cn3 = 1.0f - 3.0f * cn3 + 2.0f * cn3 * oz;
cn4 = 1.0f - 3.0f * cn4 - 2.0f * cn4 * jx;
cn5 = 1.0f - 3.0f * cn5 - 2.0f * cn5 * jy;
cn6 = 1.0f - 3.0f * cn6 - 2.0f * cn6 * jz;
cn[0] = cn1 * cn2 * cn3;
cn[1] = cn1 * cn2 * cn6;
cn[2] = cn1 * cn5 * cn3;
cn[3] = cn1 * cn5 * cn6;
cn[4] = cn4 * cn2 * cn3;
cn[5] = cn4 * cn2 * cn6;
cn[6] = cn4 * cn5 * cn3;
cn[7] = cn4 * cn5 * cn6;
b1[0] = b1[1] = hash[hash[ix & 0xFF] + (iy & 0xFF)];
b1[2] = b1[3] = hash[hash[ix & 0xFF] + (iy + 1 & 0xFF)];
b1[4] = b1[5] = hash[hash[ix + 1 & 0xFF] + (iy & 0xFF)];
b1[6] = b1[7] = hash[hash[ix + 1 & 0xFF] + (iy + 1 & 0xFF)];
b2[0] = iz & 0xFF;
b2[1] = iz + 1 & 0xFF;
xFactor[0] = xFactor[1] = xFactor[2] = xFactor[3] = ox;
xFactor[4] = xFactor[5] = xFactor[6] = xFactor[7] = jx;
yFactor[0] = yFactor[1] = yFactor[4] = yFactor[5] = oy;
yFactor[2] = yFactor[3] = yFactor[6] = yFactor[7] = jy;
zFactor[0] = zFactor[2] = zFactor[4] = zFactor[6] = oz;
zFactor[1] = zFactor[3] = zFactor[5] = zFactor[7] = jz;
for (int i = 0; i < cn.length; ++i) {
int hIndex = 3 * hash[b1[i] + b2[i % 2]];
n += cn[i] * (hashvectf[hIndex] * xFactor[i] + hashvectf[hIndex + 1] * yFactor[i] + hashvectf[hIndex + 2] * zFactor[i]);
}
if (n < 0.0f) {
n = 0.0f;
} else if (n > 1.0f) {
n = 1.0f;
}
return n;
}
}
/**
* This class is abstract to the noise functions computations. It has two methods. One calculates the Signed (with
* 'S' at the end) and the other Unsigned value.
* @author Marcin Roguski (Kaelthas)
*/
interface NoiseFunction {
/**
* This method calculates the unsigned value of the noise.
* @param x
* the x texture coordinate
* @param y
* the y texture coordinate
* @param z
* the z texture coordinate
* @return value of the noise
*/
float execute(float x, float y, float z);
/**
* This method calculates the signed value of the noise.
* @param x
* the x texture coordinate
* @param y
* the y texture coordinate
* @param z
* the z texture coordinate
* @return value of the noise
*/
float executeSigned(float x, float y, float z);
}
public static class NoiseMath {
public static float lerp(float t, float a, float b) {
return a + t * (b - a);
}
public static float npfade(float t) {
return t * t * t * (t * (t * 6.0f - 15.0f) + 10.0f);
}
public static float grad(int hash, float x, float y, float z) {
int h = hash & 0x0F;
float u = h < 8 ? x : y, v = h < 4 ? y : h == 12 || h == 14 ? x : z;
return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v);
}
public static float surve(float t) {
return t * t * (3.0f - 2.0f * t);
}
public static float at(float x, float y, float z, float[] q) {
return x * q[0] + y * q[1] + z * q[2];
}
public static void hash(int x, int y, int z, float[] result) {
result[0] = hashpntf[3 * hash[hash[hash[z & 0xFF] + y & 0xFF] + x & 0xFF]];
result[1] = hashpntf[3 * hash[hash[hash[z & 0xFF] + y & 0xFF] + x & 0xFF] + 1];
result[2] = hashpntf[3 * hash[hash[hash[z & 0xFF] + y & 0xFF] + x & 0xFF] + 2];
}
}
/**
* This interface is used for distance calculation classes. Distance metrics for voronoi. e parameter only used in
* Minkovsky.
*/
interface DistanceFunction {
/**
* This method calculates the distance for voronoi algorithms.
* @param x
* the x coordinate
* @param y
* the y coordinate
* @param z
* the z coordinate
* @param e
* this parameter used in Monkovsky (no idea what it really is ;)
* @return
*/
float execute(float x, float y, float z, float e);
}
interface MusgraveFunction {
float execute(MusgraveData musgraveData, float x, float y, float z);
}
}