001/******************************************************************************* 002 * This software is provided as a supplement to the authors' textbooks on digital 003 * image processing published by Springer-Verlag in various languages and editions. 004 * Permission to use and distribute this software is granted under the BSD 2-Clause 005 * "Simplified" License (see http://opensource.org/licenses/BSD-2-Clause). 006 * Copyright (c) 2006-2016 Wilhelm Burger, Mark J. Burge. All rights reserved. 007 * Visit http://imagingbook.com for additional details. 008 *******************************************************************************/ 009 010package imagingbook.pub.noise.perlin; 011 012import imagingbook.lib.math.Matrix; 013import imagingbook.pub.noise.hashing.HashFun; 014 015/** 016 * Gradient (Perlin) noise implementation. 017 * This class implements an N-dimensional Perlin noise generator. 018 */ 019public class PerlinNoiseGenNd extends PerlinNoiseGen { 020 021 final int N; // dimensionality, default 1 022 final int K; // number of hypercube vertices, default 2 023 final int[][] Q; // vertex coordinates of the unit hypercube 024 025 public PerlinNoiseGenNd(int N, double f_min, double f_max, double persistence, HashFun hf) { 026 super(f_min, f_max, persistence, hf); 027 this.N = N; 028 this.K = (int) Math.pow(2, N); // number of hypercube vertices 029 this.Q = new int[K][N]; // vertices of the unit hypercube 030 for (int j = 0; j < K; j++) { 031 Q[j] = vertex(j, N); 032 } 033 } 034 035 /** 036 * N-dim combined (multi-frequency) Perlin noise function. 037 * @param X Interpolation position X (N-dimensional). 038 * @return The value of the combined Perlin 039 * noise function for the N-dimensional position X. 040 */ 041 public double NOISE(double[] X) { 042 double sum = 0; 043 for (int i = 0; i < F.length; i++) { // for all frequencies 044 sum = sum + A[i] * noise(Matrix.multiply(F[i], X)); 045 } 046 return sum; 047 } 048 049 /** 050 * 2D elementary (single-frequency) Perlin noise function. 051 * @param X Interpolation position X (N-dimensional). 052 * @return The value of the elementary Perlin 053 * noise function for the N-dimensional position X. 054 */ 055 public double noise(double[] X) { 056 int[] P0 = Matrix.floor(X); // origin of hypercube around X 057 058 // get the 2^N gradient vectors for all hypercube corners: 059 double[][] G = new double[K][N]; 060 for(int j=0; j<K; j++) { 061 G[j] = gradient(Matrix.add(P0,Q[j])); // gradient vector at cube corner j 062 } 063 064 double[] X01 = Matrix.subtract(X,P0); // X01[k] are in [0,1] 065 066 // get the 2^N gradient values at all vertices for position X 067 double[] W = new double[K]; 068 for (int j = 0; j < K; j++) { 069 W[j] = Matrix.dotProduct(G[j], Matrix.subtract(X01, Q[j])); 070 } 071 072 return interpolate(X01, W, 0); 073 } 074 075 /** 076 * @param p discrete position. 077 * @return A pseudo-random gradient vector for 078 * the discrete lattice point p (N-dimensional). 079 */ 080 double[] gradient(int[] p) { 081 if (p.length == 2) { 082 return gradient(p[0],p[1]); 083 } 084 // hash() always returns a new double[], g[i] in [0,1] 085 double[] g = hashFun.hash(p); // STILL TO BE DONE!!! 086 for (int i=0; i<g.length; i++) { 087 g[i] = 2.0 * g[i] - 1; 088 } 089 return g; 090 } 091 092 /** 093 * Local interpolation function. 094 * @param X01 Interpolation position in [0,1]^N 095 * @param WW A vector of length 2^(N-d) with 096 * the tangent values for the hypercube corners. 097 * @param k The interpolation dimension (axis). 098 * @return The interpolated noise value at position X01. 099 */ 100 double interpolate(double[] X01, double[] WW, int k) { 101 if (WW.length == 1) { // (d == N) 102 return WW[0]; // done, end of recursion 103 } 104 else { // d < N 105 double x01 = X01[k]; // select dimension d of vector X 106 double s = this.s(x01); // blending function 107 int M = WW.length/2; 108 double[] W = new double[M]; // W is half the length of WW 109 for (int i=0; i<M; i++) { 110 double wa = WW[2*i]; 111 double wb = WW[2*i+1]; 112 W[i] = (1-s)*wa + s*wb; // the actual interpolation 113 } 114 return interpolate(X01, W, k+1); 115 } 116 } 117 118 /** 119 * @param j Vertex number (0..2^N-1) 120 * @param N Dimension of the hypercube 121 * @return The coordinate vector for vertex j of the N-dimensional 122 * hypercube. 123 */ 124 private int[] vertex(int j, int N) { 125 int[] v = new int[N]; 126 // copy the bit representation of j into v, 127 // v[0] is the most significant bit 128 for (int k = 0; k < N; k++) { 129 v[k] = j & 0x00000001; // select least significant bit (bit 0) 130 j = j >>> 1; // j <- j/2 131 } 132 return v; 133 } 134 135 136 137 138 // from 2D example 139 double[] gradient(int i, int j) { 140 double[] g = hashFun.hash(i,j); // hash() always returns a new double[] 141 g[0] = 2.0 * g[0] - 1; 142 g[1] = 2.0 * g[1] - 1; 143 return g; 144 } 145 146// private int Power2(int k) { 147// return 1 << k; 148// } 149 150}