home *** CD-ROM | disk | FTP | other *** search
- /*---------------------------------------------------------------\
- | Name: NOISE.C |
- | Author: Charles Congdon |
- | Created: 09/23/92 |
- | Last Updated: 11/04/92 |
- | |
- | Purpose: |
- | Implements 3D Perlin noise functions, support for the |
- | Worley 3D noise interface, etc. The noise function itself is |
- | from Graphics Gems II, page 396 - the rest guesswork and |
- | intentional changes of my own. |
- | Greg Ward is the author of the Graphics Gems II code |
- | reproduced here. |
- \---------------------------------------------------------------*/
-
- #define INITNOISE 1
-
- #include "t3dlib.h"
- #include "noise.h"
-
- /*--------------------------------------\
- | 3D Noise function supporting cast |
- \--------------------------------------*/
- #define HERMITE(p0,p1,r0,r1,t,t5,var32,tt) ((p0)*(1.0 - (var32)) + \
- (p1)*(var32) + \
- (r0)*((t5)-(tt)+(t)) + \
- (r1)*(t5) )
-
- /*-----------------------------------------------------------------\
- | The following assumes a 32-bit two's compliment architecture |
- \-----------------------------------------------------------------*/
- #define FRANDM(s,s1) (s) = ((s)<<13) ^ (s); \
- (s) = ((s)*((s)*(s)*15731+789221) + 1376312589)&0x7fffffff; \
- (s1) = ((double)1.0 - (double)(s) / (double)1073741824.0)
-
- double frand (register SLONG s)
- {
- double s1;
-
- s = (s<<13)^s;
- s = (s*(s*s*15731 + 789221) + 1376312589) & 0x7fffffff;
- s1 = (double)1.0 - (double)((ULNG)s) / (double)1073741824.0;
- return (s1);
- }
-
- /*-----------------------------------------------------------\
- | Noise function interpolator - optimized as best as I can |
- | without completely re-writing (tempting). |
- \-----------------------------------------------------------*/
- void ninterp(double f[4], short int i, register short int n)
- {
- register SLONG x, y, z;
- register SLONG s1;
- register double t; /* Stack those floating point registers ! */
- register double tt;
- register double t5;
- register double var32;
- register double ttt;
- register double f0[4], f1[4];
-
- if (n == 0)
- {
- /*----------------------------------------\
- | At zero, just return lattice value. |
- \----------------------------------------*/
- x = xlim[0][i&1];
- y = xlim[1][(i>>1)&1];
- z = xlim[2][i>>2];
-
- s1 = (SLONG) (((SLONG)67)*x + ((SLONG)59)*y + ((SLONG)71)*z);
- FRANDM(s1, t);
-
- s1 = (SLONG) (((SLONG)73)*x + ((SLONG)79)*y + ((SLONG)83)*z);
- FRANDM(s1, tt);
-
- s1 = (SLONG) (((SLONG)89)*x + ((SLONG)97)*y + ((SLONG)101)*z);
- FRANDM(s1, t5);
-
- s1 = (SLONG) (((SLONG)103)*x + ((SLONG)107)*y + ((SLONG)109)*z);
- FRANDM(s1, var32);
-
- f[0] = t;
- f[1] = tt;
- f[2] = t5;
- f[3] = var32;
- return;
- }
-
- n--; /* Decrease order */
- ninterp(f0, i, n); /* Compute first half */
- ninterp(f1, (short int) (i | (1<<n)), n); /* Compute second half */
-
- #ifdef CONSUME_MY_CPU
- /*----------------------------------------------------------------\
- | Use Hermite interpolation for tangent vector direction and |
- | its magnitude. |
- \----------------------------------------------------------------*/
- t = xarg[n];
- tt = t * t;
- ttt = tt * t;
- t5 = ttt - tt;
- var32 = tt + tt + tt - ttt - ttt;
-
- f[0] = HERMITE(f0[0], f1[0], f0[n], f1[n], t, t5, var32, tt);
- f[1] = HERMITE(f0[1], f1[1], f0[n], f1[n], t, t5, var32, tt);
- f[2] = HERMITE(f0[2], f1[2], f0[n], f1[n], t, t5, var32, tt);
- f[3] = HERMITE(f0[3], f1[3], f0[n], f1[n], t, t5, var32, tt);
-
- #else /* CONSUME_MY_CPU */
- /*----------------------------------------------------\
- | Use linear interpolation to find tangent vector |
- \----------------------------------------------------*/
- t = xarg[n];
- tt = (double)1.0 - t;
- f[0] = tt * f0[0] + t * f1[0];
- f[1] = tt * f0[1] + t * f1[1];
- f[2] = tt * f0[2] + t * f1[2];
-
- tt = t * t;
- ttt = tt * t;
- t5 = ttt - tt;
- var32 = tt + tt + tt - ttt - ttt;
-
- /*--------------------------------------------------------\
- | And Hermite interpolation for the vector magnitude. |
- \--------------------------------------------------------*/
-
- f[3] = HERMITE(f0[3], f1[3], f0[n], f1[n], t, t5, var32, tt);
- #endif /* CONSUME_MY_CPU */
-
- }
-
- /*--------------------------------------------------------------------\
- | Here is a recursive implementation of the Perlin Noise Function |
- | as found in Graphics Gems II, page 396. It varies randomly |
- | between 1 and -1 with an autocorollation distance of about |
- | 1. It also appears to have no pronounced harmonics. |
- \--------------------------------------------------------------------*/
- double Noise3D(vector point, vector noisev)
- {
- static double f[4];
- register double floored;
- register double pnt;
-
-
- /*------------------------\
- | Define the unit cube. |
- \------------------------*/
- pnt = point[0]; /* Stuff the floating point registers */
- floored = floor(pnt);
- #ifdef FLOOR_ERROR
- if (pnt < (double) 0.0)
- floored = floored - (double)1.0;
- #endif
- xlim[0][0] = (SLONG)floored;
- xlim[0][1] = xlim[0][0] + (SLONG)1;
- xarg[0] = pnt - floored;
-
- pnt = point[1];
- floored = floor(pnt);
- #ifdef FLOOR_ERROR
- if (pnt < (double) 0.0)
- floored = floored - (double)1.0;
- #endif
- xlim[1][0] = (SLONG)floored;
- xlim[1][1] = xlim[1][0] + (SLONG)1;
- xarg[1] = pnt - floored;
-
- pnt = point[2];
- floored = floor(pnt);
- #ifdef FLOOR_ERROR
- if (pnt < (double) 0.0)
- floored = floored - (double)1.0;
- #endif
- xlim[2][0] = (SLONG)floored;
- xlim[2][1] = xlim[2][0] + (SLONG)1;
- xarg[2] = pnt - floored;
-
- ninterp(f, 0, 3); /* Now interpolate the between the random values
- at the unit cube's lattice points */
-
- noisev[0] = f[0]; /* Return the noise vector */
- noisev[1] = f[1];
- noisev[2] = f[2];
-
- return(f[3]); /* And the noise value */
- }
-
- /*------------------------------------------------------------\
- | My partial implementation of the Worley Fractal Noise |
- | function. Steve uses float[6] for input and output |
- | vectors, for reasons I cannot fathom. |
- | I return the vector magnitude as well, where his seems |
- | not to. No big deal. If it serves the purpose, who needs |
- | anything more... |
- \------------------------------------------------------------*/
- double wfractalval3(vector in, double Initial_scale, double NumScales,
- double Scale_Ratio, double Amplitude_Ratio,
- double Time_Ratio, double Time, vector out)
- { /* wfractval3 */
- register double sratio1;
- register double scaleaccum;
- register double ampaccum;
- register double ampl;
- register vector naccum;
- register vector inval;
- register vector outval;
- register short int i;
- register double valaccum;
-
- double randseed;
- unsigned long int seedint;
- short int seed[3];
- static short int *pseed;
- short int axisrot;
- short int iterations;
- double dummynoise;
- double noisecent[IIMAX_SCALES][3];
- static double noisecent0[IIMAX_SCALES][3];
- static double axisgoal[IIMAX_SCALES][3];
-
-
- /*---------------------------------\
- | Do a little pre-calculation. |
- \---------------------------------*/
- ampl = Amplitude_Ratio;
- sratio1 = 1.0 / Scale_Ratio;
-
- scaleaccum = 1.0 / Initial_scale; /* Fit initial scale into unit cube */
- ampaccum = 1.0;
-
- /*-----------------------------------\
- | Get info from NumScales value. |
- \-----------------------------------*/
- if (NumScales < 0.0)
- {
- axisrot = 1;
- NumScales = fabs(NumScales);
- }
- else
- {
- axisrot = 0;
- }
-
- /*--------------------------------------------------\
- | Get the random number generator's seed and the |
- | number of iterations. |
- \--------------------------------------------------*/
-
- randseed = floor(NumScales);
- iterations = (short int) randseed;
-
- if (iterations > IIMAX_SCALES) /* Enforce scale limits */
- iterations = (short int) IIMAX_SCALES;
- if (iterations < (short int)0)
- iterations = (short int)0;
-
- if (randseed != NumScales)
- {
- randseed = NumScales - randseed;
- }
- else
- {
- randseed = 0.0;
- }
-
-
- /*-----------------------------------------------------------\
- | Initialize the random number generator and noise values. |
- \-----------------------------------------------------------*/
- if (Noiseinit == 0)
- { /* Noiseinit */
- /*--------------------------------------------------------\
- | If you do not have rand48-type functions (which SAS |
- | claim to be from the AT&T Unix System V run-time |
- | library), modify the below to play with frand above. |
- \--------------------------------------------------------*/
- seedint = (unsigned long int) (2032353798 * randseed);
- seed[0] = seedint >> 16;
- seed[1] = seedint - (seed[0] << 16);
- seed[2] = 0x330E;
- pseed = seed48(seed);
-
- /*---------------------------------------\
- | Randomly displace the axes centers - |
- | sorta - starting position of centers |
- | is not as important as where they |
- | move in subsequent frames. |
- \---------------------------------------*/
- noisecent0[0][0] = erand48(pseed) * Initial_scale;
- noisecent0[0][1] = erand48(pseed) * Initial_scale;
- noisecent0[0][2] = erand48(pseed) * Initial_scale;
- for (i = 1; i < iterations; i++)
- {
- noisecent0[i][0] = noisecent0[0][0];
- noisecent0[i][1] = noisecent0[0][1];
- noisecent0[i][2] = noisecent0[0][2];
- }
-
- /*-------------------------------------------------------\
- | Now figure out how the axis for each noise "center" |
- | is going to move. |
- \-------------------------------------------------------*/
- if (Time > 0.0)
- { /* move noise vector */
- /*-----------------------------------------------\
- | Create a random vector of the proper scale |
- \-----------------------------------------------*/
- axisgoal[0][0] = erand48(pseed);
- axisgoal[0][1] = erand48(pseed);
- axisgoal[0][2] = erand48(pseed);
- normalze(Initial_scale, axisgoal[0], axisgoal[0]);
- if (axisrot == 1)
- { /* Move each axis individually */
- dummynoise = Initial_scale * Scale_Ratio;
- for (i = 1; i < iterations; i++)
- {
- axisgoal[i][0] = erand48(pseed);
- axisgoal[i][1] = erand48(pseed);
- axisgoal[i][2] = erand48(pseed);
- normalze(dummynoise, axisgoal[i], axisgoal[i]);
- dummynoise = dummynoise * Scale_Ratio;
- }
-
- } /* Move each axis individually */
- else
- { /* All axes move together */
- dummynoise = Initial_scale * Scale_Ratio;
- for (i = 1; i < iterations; i++)
- {
- axisgoal[i][0] = axisgoal[0][0];
- axisgoal[i][1] = axisgoal[0][1];
- axisgoal[i][2] = axisgoal[0][2];
- normalze(dummynoise, axisgoal[i], axisgoal[i]);
- dummynoise = dummynoise * Scale_Ratio;
- }
- } /* All axis move together */
-
- } /* move noise vector */
- Noiseinit = 1;
- } /* Noiseinit */
-
- /*-----------------------------------------------\
- | Position the noise centers as appropriate. |
- \-----------------------------------------------*/
- if (Time > 0.0)
- { /* Move to proper frame */
- /*-----------------------------------\
- | Now move us to the proper frame. |
- | NOTE that you have to pass FRAME |
- | in from some external source. |
- \-----------------------------------*/
- dummynoise = 1.0;
- for (i = 0; i < iterations; i++)
- { /* Move to frame */
- noisecent[i][0] = noisecent0[i][0] +
- (Frame/Time) * axisgoal[i][0] * dummynoise;
- noisecent[i][1] = noisecent0[i][1] +
- (Frame/Time) * axisgoal[i][1] * dummynoise;
- noisecent[i][2] = noisecent0[i][2] +
- (Frame/Time) * axisgoal[i][2] * dummynoise;
- dummynoise = dummynoise * Time_Ratio;
- } /* Move to frame */
- } /* Move to proper frame */
- else
- { /* Frame 0 if Time == 0.0 */
- for (i = 0; i < iterations; i++)
- {
- noisecent[i][0] = noisecent0[i][0];
- noisecent[i][1] = noisecent0[i][1];
- noisecent[i][2] = noisecent0[i][2];
- }
- } /* Frame 0 if Time == 0.0 */
-
- /*---------------------------------\
- | OK, sum up the noise values. |
- \---------------------------------*/
- valaccum = 0.0;
- naccum[0] = 0.0;
- naccum[1] = 0.0;
- naccum[2] = 0.0;
- for (i = 0; i < iterations; i++)
- {
- inval[0] = scaleaccum * in[0] + noisecent[i][0];
- inval[1] = scaleaccum * in[1] + noisecent[i][1];
- inval[2] = scaleaccum * in[2] + noisecent[i][2];
- dummynoise = Noise3D(inval, outval);
- valaccum = valaccum + ampaccum * dummynoise;
- naccum[0] = naccum[0] + ampaccum * outval[0];
- naccum[1] = naccum[1] + ampaccum * outval[1];
- naccum[2] = naccum[2] + ampaccum * outval[2];
- scaleaccum = scaleaccum * sratio1; /* Scale scaling factor */
- ampaccum = ampaccum * ampl; /* Amplitude scaling factor */
- }
-
- out[0] = naccum[0];
- out[1] = naccum[1];
- out[2] = naccum[2];
- return(valaccum);
- } /* wfractval3 */
-
- /*-----------------------------------------------\
- | Vector normalization to the desired scale. |
- \-----------------------------------------------*/
- void normalze(double scale, vector in, vector out)
- { /* normalze */
- double n;
-
- n = sqrt(in[0]*in[0] + in[1]*in[1] + in[2]*in[2]);
- if (n != 0.0)
- {
- n = scale / n;
- out[0] = n * in[0];
- out[1] = n * in[1];
- out[2] = n * in[2];
- }
- else
- {
- out[0] = in[0];
- out[1] = in[1];
- out[2] = in[2];
- }
- } /* normalze */
-
- /*--------------------------------------------------\
- | A shorthand way of using the imitation Worley |
- | noise function. |
- \--------------------------------------------------*/
-
- void NiceN3D(vector point, vector noisev, double scale, double NumScales)
- {
- wfractalval3(point, scale, NumScales , ISCALE_RATIO, IAMP_RATIO,
- ITIME_RATIO, ITIME, noisev);
- }
-
-
-
-