You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
218 lines
6.2 KiB
218 lines
6.2 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: noise() primitives. |
|
// |
|
//=====================================================================================// |
|
|
|
#include <math.h> |
|
#include "basetypes.h" |
|
#include <memory.h> |
|
#include "tier0/dbg.h" |
|
#include "mathlib/mathlib.h" |
|
#include "mathlib/vector.h" |
|
#include "mathlib/noise.h" |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include "tier0/memdbgon.h" |
|
|
|
// generate high quality noise based upon "sparse convolution". HIgher quality than perlin noise, |
|
// and no direcitonal artifacts. |
|
|
|
#include "noisedata.h" |
|
|
|
#define N_IMPULSES_PER_CELL 5 |
|
#define NORMALIZING_FACTOR 1.0 |
|
|
|
//(0.5/N_IMPULSES_PER_CELL) |
|
|
|
static inline int LatticeCoord(float x) |
|
{ |
|
return ((int) floor(x)) & 0xff; |
|
} |
|
|
|
static inline int Hash4D(int ix, int iy, int iz, int idx) |
|
{ |
|
int ret=perm_a[ix]; |
|
ret=perm_b[(ret+iy) & 0xff]; |
|
ret=perm_c[(ret+iz) & 0xff]; |
|
ret=perm_d[(ret+idx) & 0xff]; |
|
return ret; |
|
} |
|
|
|
#define SQ(x) ((x)*(x)) |
|
|
|
static float CellNoise( int ix, int iy, int iz, float xfrac, float yfrac, float zfrac, |
|
float (*pNoiseShapeFunction)(float) ) |
|
{ |
|
float ret=0; |
|
for(int idx=0;idx<N_IMPULSES_PER_CELL;idx++) |
|
{ |
|
int coord_idx=Hash4D( ix, iy, iz, idx ); |
|
float dsq=SQ(impulse_xcoords[coord_idx]-xfrac)+ |
|
SQ(impulse_ycoords[coord_idx]-yfrac)+ |
|
SQ(impulse_zcoords[coord_idx]-zfrac); |
|
dsq = sqrt( dsq ); |
|
if (dsq < 1.0 ) |
|
{ |
|
ret += (*pNoiseShapeFunction)( 1-dsq ); |
|
} |
|
} |
|
return ret; |
|
} |
|
|
|
|
|
float SparseConvolutionNoise( Vector const &pnt ) |
|
{ |
|
return SparseConvolutionNoise( pnt, QuinticInterpolatingPolynomial ); |
|
} |
|
|
|
float FractalNoise( Vector const &pnt, int n_octaves) |
|
{ |
|
float scale=1.0; |
|
float iscale=1.0; |
|
float ret=0; |
|
float sumscale=0; |
|
for(int o=0;o<n_octaves;o++) |
|
{ |
|
Vector p1=pnt; |
|
p1 *= scale; |
|
ret+=iscale * SparseConvolutionNoise( p1 ); |
|
sumscale += iscale; |
|
scale *= 2.0; |
|
iscale *= 0.5; |
|
} |
|
return ret * ( 1.0/sumscale ); |
|
} |
|
|
|
float Turbulence( Vector const &pnt, int n_octaves) |
|
{ |
|
float scale=1.0; |
|
float iscale=1.0; |
|
float ret=0; |
|
float sumscale=0; |
|
for(int o=0;o<n_octaves;o++) |
|
{ |
|
Vector p1=pnt; |
|
p1 *= scale; |
|
ret+=iscale * fabs ( 2.0*( SparseConvolutionNoise( p1 )-.5 ) ); |
|
sumscale += iscale; |
|
scale *= 2.0; |
|
iscale *= 0.5; |
|
} |
|
return ret * ( 1.0/sumscale ); |
|
} |
|
|
|
#ifdef MEASURE_RANGE |
|
float fmin1=10000000.0; |
|
float fmax1=-1000000.0; |
|
#endif |
|
|
|
float SparseConvolutionNoise(Vector const &pnt, float (*pNoiseShapeFunction)(float) ) |
|
{ |
|
// computer integer lattice point |
|
int ix=LatticeCoord(pnt.x); |
|
int iy=LatticeCoord(pnt.y); |
|
int iz=LatticeCoord(pnt.z); |
|
|
|
// compute offsets within unit cube |
|
float xfrac=pnt.x-floor(pnt.x); |
|
float yfrac=pnt.y-floor(pnt.y); |
|
float zfrac=pnt.z-floor(pnt.z); |
|
|
|
float sum_out=0.; |
|
|
|
for(int ox=-1; ox<=1; ox++) |
|
for(int oy=-1; oy<=1; oy++) |
|
for(int oz=-1; oz<=1; oz++) |
|
{ |
|
sum_out += CellNoise( ix+ox, iy+oy, iz+oz, |
|
xfrac-ox, yfrac-oy, zfrac-oz, |
|
pNoiseShapeFunction ); |
|
} |
|
#ifdef MEASURE_RANGE |
|
fmin1=min(sum_out,fmin1); |
|
fmax1=max(sum_out,fmax1); |
|
#endif |
|
return RemapValClamped( sum_out, .544487, 9.219176, 0.0, 1.0 ); |
|
} |
|
|
|
|
|
// Improved Perlin Noise |
|
// The following code is the c-ification of Ken Perlin's new noise algorithm |
|
// "JAVA REFERENCE IMPLEMENTATION OF IMPROVED NOISE - COPYRIGHT 2002 KEN PERLIN" |
|
// as available here: http://mrl.nyu.edu/~perlin/noise/ |
|
|
|
float NoiseGradient(int hash, float x, float y, float z) |
|
{ |
|
int h = hash & 15; // CONVERT LO 4 BITS OF HASH CODE |
|
float u = h<8 ? x : y; // INTO 12 GRADIENT DIRECTIONS. |
|
float v = h<4 ? y : (h==12||h==14 ? x : z); |
|
return ((h&1) == 0 ? u : -u) + ((h&2) == 0 ? v : -v); |
|
} |
|
|
|
int NoiseHashIndex( int i ) |
|
{ |
|
static int s_permutation[] = |
|
{ |
|
151,160,137,91,90,15, |
|
131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23, |
|
190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33, |
|
88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166, |
|
77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244, |
|
102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196, |
|
135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123, |
|
5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42, |
|
223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9, |
|
129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228, |
|
251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107, |
|
49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254, |
|
138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180 |
|
}; |
|
|
|
return s_permutation[ i & 0xff ]; |
|
} |
|
|
|
float ImprovedPerlinNoise( Vector const &pnt ) |
|
{ |
|
float fx = floor(pnt.x); |
|
float fy = floor(pnt.y); |
|
float fz = floor(pnt.z); |
|
|
|
int X = (int)fx & 255; // FIND UNIT CUBE THAT |
|
int Y = (int)fy & 255; // CONTAINS POINT. |
|
int Z = (int)fz & 255; |
|
|
|
float x = pnt.x - fx; // FIND RELATIVE X,Y,Z |
|
float y = pnt.y - fy; // OF POINT IN CUBE. |
|
float z = pnt.z - fz; |
|
|
|
float u = QuinticInterpolatingPolynomial(x); // COMPUTE FADE CURVES |
|
float v = QuinticInterpolatingPolynomial(y); // FOR EACH OF X,Y,Z. |
|
float w = QuinticInterpolatingPolynomial(z); |
|
|
|
int A = NoiseHashIndex( X ) + Y; // HASH COORDINATES OF |
|
int AA = NoiseHashIndex( A ) + Z; // THE 8 CUBE CORNERS, |
|
int AB = NoiseHashIndex( A + 1 ) + Z; |
|
int B = NoiseHashIndex( X + 1 ) + Y; |
|
int BA = NoiseHashIndex( B ) + Z; |
|
int BB = NoiseHashIndex( B + 1 ) + Z; |
|
|
|
float g0 = NoiseGradient(NoiseHashIndex(AA ), x , y , z ); |
|
float g1 = NoiseGradient(NoiseHashIndex(BA ), x-1, y , z ); |
|
float g2 = NoiseGradient(NoiseHashIndex(AB ), x , y-1, z ); |
|
float g3 = NoiseGradient(NoiseHashIndex(BB ), x-1, y-1, z ); |
|
float g4 = NoiseGradient(NoiseHashIndex(AA+1), x , y , z-1 ); |
|
float g5 = NoiseGradient(NoiseHashIndex(BA+1), x-1, y , z-1 ); |
|
float g6 = NoiseGradient(NoiseHashIndex(AB+1), x , y-1, z-1 ); |
|
float g7 = NoiseGradient(NoiseHashIndex(BB+1), x-1, y-1, z-1 ); |
|
|
|
// AND ADD BLENDED RESULTS FROM 8 CORNERS OF CUBE |
|
float g01 = Lerp( u, g0, g1 ); |
|
float g23 = Lerp( u, g2, g3 ); |
|
float g45 = Lerp( u, g4, g5 ); |
|
float g67 = Lerp( u, g6, g7 ); |
|
float g0123 = Lerp( v, g01, g23 ); |
|
float g4567 = Lerp( v, g45, g67 ); |
|
|
|
return Lerp( w, g0123,g4567 ); |
|
}
|
|
|