Noise Library Part 1: NoiseGen.dba by The Sab31st Oct 2010 9:53
|
---|
Summary A noise generating library written by Jason Bevins and Keith Davies for C++. Translated for use with Dark Basic Pro. Description 1.1 Changes: Code ` This code was downloaded from The Game Creators ` It is reproduced here with full permission ` http://www.thegamecreators.com `This is a Dark Basic Pro adaptation of 'libnoise', a C++ `library for the generation and manipulation of coherent `noise. The following were instramental in the creation of the `C++ libnoise, and also help me greatly in gaining enough `understanding to translate the code in the first place. `Great thanks to Jason Bevins and Keith Davies for not only `creating such an awesome library, but also making it open `source and setting up an entire website to explaining the `concepts and principles behind the software. `http://libnoise.sourceforge.net/index.html `Perlin Noise — Hugo Elias's webpage contains a very good `description of Perlin noise and describes its many `applications. I based a lot of my documentation about coherent `noise from this site. This page gave me the inspiration to `create libnoise in the first place. Now that I know how to `generate Perlin noise, I will never again use cheesy `subdivision algorithms to create terrain height maps (unless `I absolutely need the speed.) `http://freespace.virgin.net/hugo.elias/models/m_perlin.htm `The Noise Machine — From the master, Ken Perlin himself. This `page contains a presentation that describes Perlin noise and `some of its variants. He won an Oscar for creating the Perlin `noise algorithm! `http://mrl.nyu.edu/~perlin/ `The Perlin noise math FAQ — A good page that describes Perlin `noise in plain English with only a minor amount of math. During `development of libnoise, I noticed that my smooth noise function `generated terrain with some "regularity" to the terrain features. `This page describes a better noise function called gradient noise. `F. Kenton "Doc Mojo" Musgrave's texturing page — This page `contains links to source code that generates ridged multfractal `noise, among other types of noise. The fractal.c source file `contains the code I used in my ridged multifractal class. Musgrave `is the creator of MojoWorld and is also one of the authors of `Texturing and Modeling: A Procedural Approach (Morgan Kaufmann, `2002. ISBN 1-55860-848-6.) `Due to the significant differences between C++ and Dark Basic, `I had to make a few changes to how functions are called. This `is mostly due to the fact that DBPro cannot create Classes. The `modules here are basically hard coded, so adding more will take `a little recoding. #include "math.dba" #include "modules.dba" #include "vectorTable.dba" `Generator ID constants #constant MOD_BILLOW 1 #constant MOD_CHECKERBOARD 2 #constant MOD_CONST 3 #constant MOD_CYLINDERS 4 #constant MOD_PERLIN 5 #constant MOD_RIDGEDMULTI 6 #constant MOD_SPHERES 7 #constant MOD_VORONOI 8 `Modifier ID constants #constant MOD_ABS 9 #constant MOD_CLAMP 10 #constant MOD_CURVE 11 #constant MOD_EXPONENT 12 #constant MOD_INVERT 13 #constant MOD_SCALEBIAS 14 #constant MOD_TERRACE 15 `Combiner ID constants #constant MOD_ADD 16 #constant MOD_MAX 17 #constant MOD_MIN 18 #constant MOD_MULTIPLY 19 #constant MOD_POWER 20 `Combiner ID constants #constant MOD_BLEND 21 #constant MOD_SELECT 22 `Transformer ID constants #constant MOD_DISPLACE 23 #constant MOD_ROTATEPOINT 24 #constant MOD_SCALEPOINT 25 #constant MOD_TRANSLATEPOINT 26 #constant MOD_TURBULENCE 27 `Model ID constants #constant MOD_PLANE 28 #constant MOD_CYLINDER 29 #constant MOD_SPHERE 30 `Interpolation Quaility constants #constant QUALITY_FAST 0 #constant QUALITY_STD 1 #constant QUALITY_BEST 2 `Seed numbers for magic random make work thing #constant X_NOISE_GEN 1619 #constant Y_NOISE_GEN 31337 #constant Z_NOISE_GEN 6971 #constant SEED_NOISE_GEN 1013 #constant SHIFT_NOISE_GEN 8 `The Module_Set Type has all the variables for all the modules, `regardless of the fact that some are only used by one module. `It seems wasteful, but it was the only way I could figure to `do it. type Module_Set moduleProcedure as integer source0 as integer source1 as integer source2 as integer source3 as integer control as integer frequency as float lacunarity as float octaveCount as integer persistence as float noiseQuality as integer seed as integer constValue as float displacement as float lowerBound as float upperBound as float controlPointCount as integer exponent as float bias as float scale as float edgeFallOff as float pointX as float pointY as float pointZ as float power as float enableDistance as boolean invertTerraces as boolean controlPointsSet as integer x1Matrix as float y1Matrix as float z1Matrix as float x2Matrix as float y2Matrix as float z2Matrix as float x3Matrix as float y3Matrix as float z3Matrix as float xAngle as float yAngle as float zAngle as float xScale as float yScale as float zScale as float xTranslation as float yTranslation as float zTranslation as float endtype `A couple of the modules use a Control Point array. Only one `of them has an input and output Value, so the Type only gets `used once. type typeControlPoint inputValue as float outputValue as float endtype `This function must be called by the parent application to `set up some basic functionality. function NoiseGen_Setup() `A count of how many modules have been created, so that `integers can be assigned. global moduleCount as integer moduleCount = 0 `An array of Module Sets. This is how I simulate the `ability to make multiple instances of modules, each `with their own set of variables. global dim module_sets() as Module_Set `Initialize the control point array for Curve and Terrace global dim ControlPoints(255, 255) as typeControlPoint global ControlPointsSetCount as integer ControlPointsSetCount = 0 `This command will build an array of Vectors. 1024 lines `of float values. That was fun to transcribe. Build_Vector_Tables() endfunction function GradientCoherentNoise3D(index as integer, x as float, y as float, z as float, seed as integer) result as float `Create a unit-length cube aligned along an integer boundary. This cube `surrounds the input point. if x > 0.0 x0 = int(x) else x0 = int(x) - 1 endif x1 = x0 + 1 if y > 0.0 y0 = int(y) else y0 = int(y) - 1 endif y1 = y0 + 1 if z > 0.0 z0 = int(z) else z0 = int(z) - 1 endif z1 = z0 + 1 `Map the difference between the coordinates of the input value and the `coordinates of the cube's outer-lower-left vertex onto an S-curve. xs as float ys as float zs as float xs = 0.0 ys = 0.0 zs = 0.0 select module_sets(index).noiseQuality case QUALITY_FAST: xs = (x - x0) ys = (y - y0) zs = (z - z0) endcase case QUALITY_STD: xs = SCurve3(x - x0) ys = SCurve3(y - y0) zs = SCurve3(z - z0) endcase case QUALITY_BEST: xs = SCurve5(x - x0) ys = SCurve5(y - y0) zs = SCurve5(z - z0) endcase endselect `Now calculate the noise values at each vertex of the cube. To generate `the coherent-noise value at the input point, interpolate these eight `noise values using the S-curve value as the interpolant (trilinear `interpolation.) n0 as float n1 as float ix0 as float ix1 as float iy0 as float iy1 as float n0 = GradientNoise3D(x, y, z, x0, y0, z0, seed) n1 = GradientNoise3D(x, y, z, x1, y0, z0, seed) ix0 = LinearInterp(n0, n1, xs) n0 = GradientNoise3D(x, y, z, x0, y1, z0, seed) n1 = GradientNoise3D(x, y, z, x1, y1, z0, seed) ix1 = LinearInterp(n0, n1, xs) iy0 = LinearInterp(ix0, ix1, ys) n0 = GradientNoise3D(x, y, z, x0, y0, z1, seed) n1 = GradientNoise3D(x, y, z, x1, y0, z1, seed) ix0 = LinearInterp(n0, n1, xs) n0 = GradientNoise3D(x, y, z, x0, y1, z1, seed) n1 = GradientNoise3D(x, y, z, x1, y1, z1, seed) ix1 = LinearInterp(n0, n1, xs) iy1 = LinearInterp(ix0, ix1, ys) result = LinearInterp(iy0, iy1, zs) endfunction result function GradientNoise3D(fx as float, fy as float, fz as float, ix as integer, iy as integer, iz as integer, seed as integer) result as float `Randomly generate a gradient vector given the integer coordinates of the `input value. This implementation generates a random number and uses it `as an index into a normalized-vector lookup table. vectorIndex = (X_NOISE_GEN * ix + Y_NOISE_GEN * iy + Z_NOISE_GEN * iz + SEED_NOISE_GEN * seed) && 0xffffffff vectorIndex = vectorIndex ~~ (vectorIndex >> SHIFT_NOISE_GEN) vectorIndex = vectorIndex && 0xff xvGradient as float yvGradient as float zvGradient as float xvGradient = vector_table(vectorIndex << 2) yvGradient = vector_table((vectorIndex << 2) + 1) zvGradient = vector_table((vectorIndex << 2) + 2) `Set up us another vector equal to the distance between the two vectors `passed to this function. xvPoint as float yvPoint as float zvPoint as float xvPoint = (fx - ix) yvPoint = (fy - iy) zvPoint = (fz - iz) `Now compute the dot product of the gradient vector with the distance `vector. The resulting value is gradient noise. Apply a scaling value `so that this noise value ranges from -1.0 to 1.0. result = ((xvGradient * xvPoint) + (yvGradient * yvPoint) + (zvGradient * zvPoint)) * 2.12 endfunction result function IntValueNoise3D(x as integer, y as integer, z as integer, seed as integer) result as integer `All constants are primes and must remain prime in order for this noise `function to work correctly. n = (X_NOISE_GEN * x + Y_NOISE_GEN * y + Z_NOISE_GEN * z + SEED_NOISE_GEN * seed) && 0x7fffffff n = (n >> 13) ~~ n result = (n * (n * n * 60493 + 19990303) + 1376312589) && 0x7fffffff endfunction result function ValueCoherentNoise3D(index as integer, x as float, y as float, z as float, seed as integer) result as float `Create a unit-length cube aligned along an ingeger boundary. This cube `surrounds the input point. if x > 0.0 x0 = int(x) else x0 = int(x) - 1 endif x1 = x0 + 1 if y > 0.0 y0 = int(y) else y0 = int(y) - 1 endif y1 = y0 + 1 if z > 0.0 z0 = int(z) else z0 = int(z) - 1 endif z1 = z0 + 1 `Map the difference between the coordinates of the input value and the `coordinates of the cube's outer-lower-left vertex onto an S-curve. xs as float ys as float zs as float xs = 0.0 ys = 0.0 zs = 0.0 select module_sets(index).noiseQuality case QUALITY_FAST: xs = (x - x0) ys = (y - y0) zs = (z - z0) endcase case QUALITY_STD: xs = SCurve3(x - x0) ys = SCurve3(y - y0) zs = SCurve3(z - z0) endcase case QUALITY_BEST: xs = SCurve5(x - x0) ys = SCurve5(y - y0) zs = SCurve5(z - z0) endcase endselect `Now calculate the noise values at each vertex of the cube. To generate `the coherent-noise value at the input point, interpolate these eight `noise values using the S-curve value as the interpolant (trilinear `interpolation.) n0 as float n1 as float ix0 as float ix1 as float iy0 as float iy1 as float n0 = ValueNoise3D(x0, y0, z0, seed) n1 = ValueNoise3D(x1, y0, z0, seed) ix0 = LinearInterp(n0, n1, xs) n0 = ValueNoise3D(x0, y1, z0, seed) n1 = ValueNoise3D(x1, y1, z0, seed) ix1 = LinearInterp(n0, n1, xs) iy0 = LinearInterp(ix0, ix1, ys) n0 = ValueNoise3D(x0, y0, z1, seed) n1 = ValueNoise3D(x1, y0, z1, seed) ix0 = LinearInterp(n0, n1, xs) n0 = ValueNoise3D(x0, y1, z1, seed) n1 = ValueNoise3D(x1, y1, z1, seed) ix1 = LinearInterp(n0, n1, xs) iy1 = LinearInterp(ix0, ix1, ys) result = LinearInterp (iy0, iy1, zs) endfunction result function ValueNoise3D(x as integer, y as integer, z as integer, seed as integer) result as float result = 1.0 - (IntValueNoise3D(x, y, z, seed) / 1073741824.0) endfunction result function SCurve3(a as float) result as float result = (a ^ 2 * (3.0 - 2.0 * a)) endfunction result function SCurve5(a as float) result as float a3 as float a4 as float a5 as float a3 = a ^ 3 a4 = a ^ 4 a5 = a ^ 5 result = (6.0 * a5) - (15.0 * a4) + (10.0 * a3) endfunction result `Module Creation. The function takes a procedural ID and `returns an integer index number, so that you can assign `it to a variable of your choosing. `i.e.: samplePerlin = Create_Module(MOD_PERLIN) function Create_Module(Modproc as integer) index as integer array insert at bottom module_sets() module_sets(moduleCount).moduleProcedure = Modproc index = moduleCount moduleCount = moduleCount + 1 module_sets(index).source0 = -1 module_sets(index).source1 = -1 module_sets(index).source2 = -1 module_sets(index).source3 = -1 module_sets(index).control = -1 Module_Setup(index) endfunction index `This is an internal function that sends the newly created `module to its appropriate setup. Even though all modules `have all the variables, only certain ones are used with `specific modules. function Module_Setup(index as integer) select module_sets(index).moduleProcedure case MOD_BILLOW: Billow_Setup(index) endcase case MOD_CONST: Const_Setup(index) endcase case MOD_CYLINDERS: Cylinders_Setup(index) endcase case MOD_PERLIN: Perlin_Setup(index) endcase case MOD_RIDGEDMULTI: RidgedMulti_Setup(index) endcase case MOD_SPHERES: Spheres_Setup(index) endcase case MOD_VORONOI: Voronoi_Setup(index) endcase case MOD_CLAMP: Clamp_Setup(index) endcase case MOD_CURVE: Curve_Setup(index) endcase case MOD_EXPONENT: Exponent_Setup(index) endcase case MOD_SCALEBIAS: ScaleBias_Setup(index) endcase case MOD_TERRACE: Terrace_Setup(index) endcase case MOD_SELECT: Select_Setup(index) endcase case MOD_ROTATEPOINT: RotatePoint_Setup(index) endcase case MOD_SCALEPOINT: ScalePoint_Setup(index) endcase case MOD_TRANSLATEPOINT: TranslatePoint_Setup(index) endcase case MOD_TURBULENCE: Turbulence_Setup(index) endcase endselect endfunction `This function allows for a universal GetValue function. It `references the specific GetValue for the type procedure `assigned to the module. function Module_GetValue(index as integer, x as float, y as float, z as float) result as float select module_sets(index).moduleProcedure case MOD_BILLOW: result = Billow_GetValue(index, x, y, z) endcase case MOD_CHECKERBOARD: result = Checkerboard_GetValue(index, x, y, z) endcase case MOD_CONST: result = Const_GetValue(index) endcase case MOD_CYLINDERS: result = Cylinders_GetValue(index, x, y, z) endcase case MOD_PERLIN: result = Perlin_GetValue(index, x, y, z) endcase case MOD_RIDGEDMULTI: result = RidgedMulti_GetValue(index, x, y, z) endcase case MOD_SPHERES: result = Spheres_GetValue(index, x, y, z) endcase case MOD_VORONOI: result = Voronoi_GetValue(index, x, y, z) endcase case MOD_ABS: result = Abs_GetValue(index, x, y, z) endcase case MOD_CLAMP: result = Clamp_GetValue(index, x, y, z) endcase case MOD_CURVE: result = Curve_GetValue(index, x, y, z) endcase case MOD_EXPONENT: result = Exponent_GetValue(index, x, y, z) endcase case MOD_INVERT: result = Invert_GetValue(index, x, y, z) endcase case MOD_SCALEBIAS: result = ScaleBias_GetValue(index, x, y, z) endcase case MOD_TERRACE: result = Terrace_GetValue(index, x, y, z) endcase case MOD_ADD: result = Add_GetValue(index, x, y, z) endcase case MOD_MAX: result = Max_GetValue(index, x, y, z) endcase case MOD_MIN: result = Min_GetValue(index, x, y, z) endcase case MOD_MULTIPLY: result = Multiply_GetValue(index, x, y, z) endcase case MOD_POWER: result = Power_GetValue(index, x, y, z) endcase case MOD_BLEND: result = Blend_GetValue(index, x, y, z) endcase case MOD_SELECT: result = Select_GetValue(index, x, y, z) endcase case MOD_DISPLACE: result = Displace_GetValue(index, x, y, z) endcase case MOD_ROTATEPOINT: result = RotatePoint_GetValue(index, x, y, z) endcase case MOD_SCALEPOINT: result = ScalePoint_GetValue(index, x, y, z) endcase case MOD_TRANSLATEPOINT: result = TranslatePoint_GetValue(index, x, y, z) endcase case MOD_TURBULENCE: result = Turbulence_GetValue(index, x, y, z) endcase endselect endfunction result `All of the Get commands. They take an index number of the `module and return the appropriate piece of data. function Get_Source0(index as integer) result as integer result = module_sets(index).source0 endfunction result function Get_Source1(index as integer) result as integer result = module_sets(index).source1 endfunction result function Get_Source2(index as integer) result as integer result = module_sets(index).source2 endfunction result function Get_Source3(index as integer) result as integer result = module_sets(index).source3 endfunction result function Get_Control(index as integer) result as integer result = module_sets(index).control endfunction result function Get_Frequency(index as integer) result as float result = module_sets(index).frequency endfunction result function Get_Lacunarity(index as integer) result as float result = module_sets(index).lacunarity endfunction result function Get_OctaveCount(index as integer) result as integer result = module_sets(index).octaveCount endfunction result function Get_Persistence(index as integer) result as float result = module_sets(index).persistence endfunction result function Get_NoiseQuality(index as integer) result as integer result = module_sets(index).noiseQuality endfunction result function Get_Seed(index as integer) result as integer result = module_sets(index).seed endfunction result function Get_ConstValue(index as integer) result as float result = module_sets(index).constValue endfunction result function Get_Displacement(index as integer) result as float result = module_sets(index).displacement endfunction result function Get_LowerBound(index as integer) result as float result = module_sets(index).lowerBound endfunction result function Get_UpperBound(index as integer) result as float result = module_sets(index).upperBound endfunction result function Get_Exponent(index as integer) result as float result = module_sets(index).exponent endfunction result function Get_Bias(index as integer) result as float result = module_sets(index).bias endfunction result function Get_Scale(index as integer) result as float result = module_sets(index).scale endfunction result function Get_EdgeFallOff(index as integer) result as float result = module_sets(index).edgeFallOff endfunction result function Get_PointX(index as integer) result as float result = module_sets(index).pointX endfunction result function Get_PointY(index as integer) result as float result = module_sets(index).pointY endfunction result function Get_PointZ(index as integer) result as float result = module_sets(index).pointZ endfunction result function Get_Power(index as integer) result as float result = module_sets(index).power endfunction result function Get_EnableDistance(index as integer) result as boolean result = module_sets(index).enableDistance endfunction result function Get_InvertTerraces(index as integer) result as boolean result = module_sets(index).invertTerraces endfunction result `All of the Set commands. They take the index number of the `Module and a piece of data to assign to the variable. function Set_Source0(index as integer, s as integer) module_sets(index).source0 = s endfunction function Set_Source1(index as integer, s as integer) module_sets(index).source1 = s endfunction function Set_Source2(index as integer, s as integer) module_sets(index).source2 = s endfunction function Set_Source3(index as integer, s as integer) module_sets(index).source3 = s endfunction function Set_Control(index as integer, c as integer) module_sets(index).control = c endfunction function Set_Frequency(index as integer, freq as float) module_sets(index).frequency = freq endfunction function Set_Lacunarity(index as integer, lac as float) module_sets(index).lacunarity = lac endfunction function Set_OctaveCount(index as integer, oct as integer) module_sets(index).octaveCount = oct endfunction function Set_Persistence(index as integer, per as float) module_sets(index).persistence = per endfunction function Set_NoiseQuality(index as integer, qual as integer) module_sets(index).noiseQuality = qual endfunction function Set_Seed(index as integer, seed as integer) module_sets(index).seed = seed endfunction function Set_ConstValue(index as integer, value as float) module_sets(index).constValue = value endfunction function Set_Displacement(index as integer, dis as float) module_sets(index).displacement = dis endfunction function Set_LowerBound(index as integer, lb as float) module_sets(index).lowerBound = lb endfunction function Set_UpperBound(index as integer, ub as float) module_sets(index).upperBound = ub endfunction function Set_Bounds(index as integer, lb as float, ub as float) module_sets(index).lowerBound = lb module_sets(index).upperBound = ub endfunction function Set_Exponent(index as integer, ex as float) module_sets(index).exponent = ex endfunction function Set_Bias(index as integer, bias as float) module_sets(index).bias = bias endfunction function Set_Scale(index as integer, scale as float) module_sets(index).scale = scale endfunction function Set_EdgeFallOff(index as integer, fo as float) module_sets(index).edgeFallOff = fo endfunction function Set_PointX(index as integer, px as float) module_sets(index).pointx = px endfunction function Set_PointY(index as integer, py as float) module_sets(index).pointy = py endfunction function Set_PointZ(index as integer, pz as float) module_sets(index).pointz = pz endfunction function Set_ScaleXYZ(index as integer, x as float, y as float, z as float) ScalePoint_SetXYZ(index, x, y, z) endfunction function Set_AnglesXYZ(index as integer, x as float, y as float, z as float) RotatePoint_SetAngles(index, x, y, z) endfunction function Set_TranslateXYZ(index as integer, x as float, y as float, z as float) TranslatePoint_SetXYZ(index, x, y, z) endfunction function Set_Power(index as integer, pow as float) module_sets(index).power = pow endfunction function Set_EnableDistance(index as integer, d as boolean) module_sets(index).enableDistance = d endfunction function Set_InvertTerraces(index as integer, i as boolean) module_sets(index).invertTerraces = i endfunction function ExceptionInvalidParam(index as integer) set current bitmap 0 cls set cursor 0, 0 print "A parameter in module " + str$(index) + " is not set correctly." print "Press any key to exit the program." wait key end endfunction function ExceptionNoModule(index as integer) set current bitmap 0 cls set cursor 0, 0 print "A source or control module is missing in module " + str$(index) + "." print "Press any key to exit the program." wait key end endfunction function ExceptionOutOfMemory(index as integer) set current bitmap 0 cls set cursor 0, 0 print "Argh, you have managed to use up all of your computers memory!" print "This problem occured while processing module " + str$(index) + "." print "Press any key to exit the program." wait key end endfunction function ExceptionUnknown(index as integer) set current bitmap 0 cls set cursor 0, 0 print "Something unexpected happen in module " + str$(index) + "." print "no more clues to give you. Good luck." print "Press any key to exit the program." wait key end endfunction |