/** * Copyright (c) 2003-2009, Xith3D Project Group all rights reserved. * * Portions based on the Java3D interface, Copyright by Sun Microsystems. * Many thanks to the developers of Java3D and Sun Microsystems for their * innovation and design. * * 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 the 'Xith3D Project Group' 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) A * RISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE */ package org.xith3d.utility.noise; import java.util.Random; /** * PerlinSolidNoiseGenerator.java 1.0 98/06/16 Carl Burke * * Encapsulates Perlin's method for solid noise generation. * * Copyright (c) 1998 Carl Burke. * * Adapted from copyrighted source code by Ken Perlin * and F. Kenton Musgrave to accompany: * Texturing and Modeling: A Procedural Approach * Ebert, D., Musgrave, K., Peachey, P., Perlin, K., and Worley, S. * AP Professional, September, 1994. ISBN 0-12-228760-6 * Web site: http://www.cs.umbc.edu/~ebert/book/book.html * * @author Carl Burke */ public class Noise { /************************************************************ * Noise generation (interpolation) over 1,2, and 3 dimensions ************************************************************/ /* noise functions over 1, 2, and 3 dimensions */ public static final int B = 0x100; public static final int BM = 0xff; public static final int N = 0x1000; public static final int NP = 12; /* 2^N */ public static final int NM = 0xfff; private Random rgen; private double rseed; private double[] vec; private int[] p; private double[][] g3; private double[][] g2; private double[] g1; public Noise() { rgen = new Random(); init_noise(); } public Noise( double seed ) { rgen = new Random(); setSeed( seed ); init_noise(); } public void setSeed( double s ) { rseed = s; rgen.setSeed( Double.doubleToLongBits( rseed ) ); init_noise(); } public double getSeed() { return rseed; } /************************************************************ * Methods specific to noise synthetic terrain generation ************************************************************/ /************************************************************ * Supporting/filtering methods ************************************************************/ public double bias( double a, double b ) { return Math.pow( a, Math.log( b ) / Math.log( 0.5 ) ); } public double gain( double a, double b ) { double p = Math.log( 1. - b ) / Math.log( 0.5 ); if ( a < 0.001 ) { return ( 0.0 ); } if ( a > 0.999 ) { return 1.0; } if ( a < 0.5 ) { return Math.pow( 2 * a, p ) / 2; } return 1.0 - ( Math.pow( 2 * ( 1.0 - a ), p ) / 2 ); } public double turbulence( double[] v, double freq ) { double t; if ( vec == null ) { vec = new double[ 3 ]; } for ( t = 0.; freq >= 1.; freq /= 2 ) { vec[ 0 ] = freq * v[ 0 ]; vec[ 1 ] = freq * v[ 1 ]; vec[ 2 ] = freq * v[ 2 ]; t += ( Math.abs( noise3( vec ) ) / freq ); } return t; } /************************************************************ * Initialization ************************************************************/ private void normalize2( double[] v ) // v.length == 2 { double s; s = Math.sqrt( ( v[ 0 ] * v[ 0 ] ) + ( v[ 1 ] * v[ 1 ] ) ); v[ 0 ] = v[ 0 ] / s; v[ 1 ] = v[ 1 ] / s; } private void normalize3( double[] v ) // v.length == 3 { double s; s = 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 void init_noise() { int i; int j; int k; p = new int[ B + B + 2 ]; g3 = new double[ B + B + 2 ][ 3 ]; g2 = new double[ B + B + 2 ][ 2 ]; g1 = new double[ B + B + 2 ]; for ( i = 0; i < B; i++ ) { p[ i ] = i; g1[ i ] = ( rgen.nextDouble() * 2.0 ) - 1.0; // -1.0 to 1.0 for ( j = 0; j < 2; j++ ) g2[ i ][ j ] = ( rgen.nextDouble() * 2.0 ) - 1.0; // -1.0 to 1.0 normalize2( g2[ i ] ); for ( j = 0; j < 3; j++ ) g3[ i ][ j ] = ( rgen.nextDouble() * 2.0 ) - 1.0; // -1.0 to 1.0 normalize3( g3[ i ] ); } while ( ( --i ) > 0 ) { j = (int)( rgen.nextDouble() * B ); k = p[ i ]; p[ i ] = p[ j ]; 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 ]; } } public double s_curve( double t ) { return t * t * ( 3. - ( 2. * t ) ); } public double lerp( double t, double a, double b ) { return a + ( t * ( b - a ) ); } /* #define setup(i,b0,b1,r0,r1)\ t = vec[i] + N;\ b0 = ((int)t) & BM;\ b1 = (b0+1) & BM;\ r0 = t - (int)t;\ r1 = r0 - 1.;\ */ public double noise1( double arg ) { int bx0; int bx1; double rx0; double rx1; double sx; double t; double u; double v; /* setup(0, bx0,bx1, rx0,rx1) */ t = arg + N; bx0 = ( (int)t ) & BM; bx1 = ( bx0 + 1 ) & BM; rx0 = t - (int)t; rx1 = rx0 - 1.; sx = s_curve( rx0 ); u = rx0 * g1[ p[ bx0 ] ]; v = rx1 * g1[ p[ bx1 ] ]; return lerp( sx, u, v ); } public double noise2( double[] vec ) // vec.length == 2 { int bx0; int bx1; int by0; int by1; int b00; int b10; int b01; int b11; double rx0; double rx1; double ry0; double ry1; double[] q; double sx; double sy; double a; double b; double t; double u; double v; int i; int j; /* setup(0, bx0,bx1, rx0,rx1) */ t = vec[ 0 ] + N; bx0 = ( (int)t ) & BM; bx1 = ( bx0 + 1 ) & BM; rx0 = t - (int)t; rx1 = rx0 - 1.; /* setup(1, by0,by1, ry0,ry1) */ t = vec[ 1 ] + N; by0 = ( (int)t ) & BM; by1 = ( by0 + 1 ) & BM; ry0 = t - (int)t; ry1 = ry0 - 1.; i = p[ bx0 ]; j = p[ bx1 ]; b00 = p[ i + by0 ]; b10 = p[ j + by0 ]; b01 = p[ i + by1 ]; b11 = p[ j + by1 ]; sx = s_curve( rx0 ); sy = s_curve( 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 lerp( sy, a, b ); } public double noise3( double[] vec ) // vec.length == 3 { int bx0, bx1, by0, by1, bz0, bz1, b00, b10, b01, b11; double rx0, rx1, ry0, ry1, rz0, rz1; double[] q; double sy, sz, a, b, c, d, t, u, v; int i, j; /* setup(0, bx0,bx1, rx0,rx1) */ t = vec[ 0 ] + N; bx0 = ( (int)t ) & BM; bx1 = ( bx0 + 1 ) & BM; rx0 = t - (int)t; rx1 = rx0 - 1.; /* setup(1, by0,by1, ry0,ry1) */ t = vec[ 1 ] + N; by0 = ( (int)t ) & BM; by1 = ( by0 + 1 ) & BM; ry0 = t - (int)t; ry1 = ry0 - 1.; /* setup(2, bz0,bz1, rz0,rz1) */ t = vec[ 2 ] + N; bz0 = ( (int)t ) & BM; bz1 = ( bz0 + 1 ) & BM; rz0 = t - (int)t; rz1 = rz0 - 1.; i = p[ bx0 ]; j = p[ bx1 ]; b00 = p[ i + by0 ]; b10 = p[ j + by0 ]; b01 = p[ i + by1 ]; b11 = p[ j + by1 ]; t = s_curve( rx0 ); sy = s_curve( ry0 ); sz = s_curve( 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 lerp( sz, c, d ); } public double noise( double[] vec, int len ) { switch ( len ) { case 0: return 0.0; case 1: return noise1( vec[ 0 ] ); case 2: return noise2( vec ); default: return noise3( vec ); } } }