noise.c

Go to the documentation of this file.
00001 /*                         N O I S E . C
00002  * BRL-CAD
00003  *
00004  * Copyright (c) 2004-2006 United States Government as represented by
00005  * the U.S. Army Research Laboratory.
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public License
00009  * as published by the Free Software Foundation; either version 2 of
00010  * the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful, but
00013  * WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Library General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this file; see the file named COPYING for more
00019  * information.
00020  */
00021 
00022 /** \addtogroup noise */
00023 /*@{*/
00024 /** @file noise.c
00025  *  Signed noise functions
00026  *
00027  *      - bn_noise_perlin       Robert Skinner's Perlin-style "Noise" function
00028  *      - bn_noise_vec  Vector-valued noise
00029  *
00030  *  Spectral Noise functions
00031  *
00032  *      - bn_noise_fbm  fractional Brownian motion.  Based on bn_noise_perlin
00033  *      - bn_noise_turb turbulence.  Based on bn_noise_perlin
00034  *
00035  *  These noise functions provide mostly random noise at the integer lattice
00036  *  points.  The functions should be evaluated at non-integer locations for
00037  *  their nature to be realized.
00038  *
00039  *
00040  *  @author     Lee A. Butler
00041  *  @par Contributed code from
00042  *      F. Kenton Musgrave
00043  *@n    Robert Skinner
00044  *
00045  *  @par Source -
00046  *      The U. S. Army Research Laboratory
00047  *@     Aberdeen Proving Ground, Maryland  21005-5068  USA
00048  */
00049 
00050 
00051 #ifndef lint
00052 static const char RCSid[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/libbn/noise.c,v 14.12 2006/09/04 04:42:40 lbutler Exp $ (ARL)";
00053 #endif
00054 
00055 #include "common.h"
00056 
00057 
00058 
00059 #include <stdio.h>
00060 #include <stdlib.h>
00061 #include <math.h>
00062 #include "machine.h"
00063 #include "bu.h"
00064 #include "vmath.h"
00065 #include "bn.h"
00066 
00067 
00068 
00069 /**
00070  * @brief interpolate smoothly from 0 .. 1
00071  *  SMOOTHSTEP() takes a value in the range [0:1] and provides a number
00072  * in the same range indicating the amount of (a) present in a smooth
00073  * interpolation transition between (a) and (b)
00074  */
00075 #define SMOOTHSTEP(x)   (  (x) * (x) * (3 - 2*(x))  )
00076 
00077 
00078 
00079 
00080 #define FLOOR(x)        (  (int)(x) - (  (x) < 0 && (x) != (int)(x)  )  )
00081 
00082 /**
00083  *@brief fold space to extend the domain over which we can take
00084  * noise values.
00085  *
00086  *@n x, y, z are set to the noise space location for the source point.
00087  *@n ix, iy, iz are the integer lattice point (integer portion of x,y,z)
00088  *@n fx, fy, fz are the fractional lattice distance above ix,iy,iz
00089  *
00090  * The noise function has a finite domain, which can be exceeded when
00091  * using fractal textures with very high frequencies.  This routine is
00092  * designed to extend the effective domain of the function, albeit by
00093  * introducing periodicity.     -FKM 4/93
00094  */
00095 static void
00096 filter_args(fastf_t *src, fastf_t *p, fastf_t *f, int *ip)
00097 {
00098         register int i;
00099         point_t dst;
00100         static unsigned long max2x = ~((unsigned long)0);
00101         static unsigned long max = (~((unsigned long)0)) >> 1;
00102 
00103         for (i=0 ; i < 3 ; i++) {
00104                 /* assure values are positive */
00105                 if (src[i] < 0) dst[i] = -src[i];
00106                 else dst[i] = src[i];
00107 
00108 
00109                 /* fold space */
00110                 while (dst[i] > max || dst[i]<0) {
00111                         if (dst[i] > max) {
00112                                 dst[i] = max2x - dst[i];
00113                         } else {
00114                                 dst[i] = -dst[i];
00115                         }
00116                 }
00117 
00118         }
00119 
00120         p[X] = dst[0];  ip[X] = FLOOR(p[X]);    f[X] = p[X] - ip[X];
00121         p[Y] = dst[1];  ip[Y] = FLOOR(p[Y]);    f[Y] = p[Y] - ip[Y];
00122         p[Z] = dst[2];  ip[Z] = FLOOR(p[Z]);    f[Z] = p[Z] - ip[Z];
00123 }
00124 
00125 
00126 #define MAXSIZE 267     /* 255 + 3 * (4 values) */
00127 
00128 /**
00129  * The RTable maps numbers into the range [-1..1]
00130  */
00131 static double   RTable[MAXSIZE];
00132 
00133 #define INCRSUM(m,s,x,y,z)      ((s)*(RTable[m]*0.5             \
00134                                         + RTable[m+1]*(x)       \
00135                                         + RTable[m+2]*(y)       \
00136                                         + RTable[m+3]*(z)))
00137 
00138 
00139 
00140 /**
00141  *  A heavily magic-number protected version of the hashtable.
00142  *
00143  *  This table is used to convert integers into repeatable random results
00144  *  for indicies into RTable.
00145  */
00146 struct str_ht {
00147         long    magic;
00148         char    hashTableValid;
00149         long    *hashTableMagic1;
00150         short   *hashTable;
00151         long    *hashTableMagic2;
00152         long    magic_end;
00153 };
00154 
00155 static struct str_ht ht;
00156 
00157 #define MAGIC_STRHT1    1771561
00158 #define MAGIC_STRHT2    1651771
00159 #define MAGIC_TAB1         9823
00160 #define MAGIC_TAB2       784642
00161 #define CK_HT() { \
00162         BU_CKMAG(&ht.magic, MAGIC_STRHT1, "struct str_ht ht 1"); \
00163         BU_CKMAG(&ht.magic_end, MAGIC_STRHT2, "struct str_ht ht 2"); \
00164         BU_CKMAG(ht.hashTableMagic1, MAGIC_TAB1, "hashTable Magic 1"); \
00165         BU_CKMAG(ht.hashTableMagic2, MAGIC_TAB2, "hashTable Magic 2"); \
00166         if (ht.hashTable != (short *)&ht.hashTableMagic1[1] ) \
00167                 bu_bomb("ht.hashTable changed rel ht.hashTableMagic1"); \
00168         if (ht.hashTableMagic2 != (long *)&ht.hashTable[4096] ) \
00169                 bu_bomb("ht.hashTable changed rel ht.hashTableMagic2"); \
00170 }
00171 
00172 /**
00173  * Map integer point into repeatable random number [0..4095]
00174  * We actually only use the first 8 bits of the final value extracted from
00175  * this table.  It's not quite clear that we really need this big a table.
00176  * The extra size does provide some extra randomness for intermediate results.
00177  */
00178 #define Hash3d(a,b,c) \
00179         ht.hashTable[  \
00180                 ht.hashTable[  \
00181                         ht.hashTable[(a) & 0xfff] ^ ((b) & 0xfff) \
00182                 ]  ^ ((c) & 0xfff) \
00183         ]
00184 
00185 
00186 void
00187 bn_noise_init(void)
00188 {
00189         int i, j, k, temp;
00190         int rndtabi = BN_RAND_TABSIZE - 1;
00191 
00192         bu_semaphore_acquire( BU_SEM_BN_NOISE );
00193 
00194         if (ht.hashTableValid) {
00195                 bu_semaphore_release( BU_SEM_BN_NOISE );
00196                 return;
00197         }
00198 
00199         BN_RANDSEED(rndtabi, (BN_RAND_TABSIZE-1) );
00200         ht.hashTableMagic1 = (long *) bu_malloc(
00201                 2*sizeof(long) + 4096*sizeof(short int),
00202                 "noise hashTable");
00203         ht.hashTable = (short *)&ht.hashTableMagic1[1];
00204         ht.hashTableMagic2 = (long *)&ht.hashTable[4096];
00205 
00206         *ht.hashTableMagic1 = MAGIC_TAB1;
00207         *ht.hashTableMagic2 = MAGIC_TAB2;
00208 
00209         ht.magic_end = MAGIC_STRHT2;
00210         ht.magic = MAGIC_STRHT1;
00211 
00212         for (i = 0; i < 4096; i++)
00213                 ht.hashTable[i] = i;
00214 
00215         /* scramble the hash table */
00216         for (i = 4095; i > 0; i--) {
00217                 j = (int)(BN_RANDOM(rndtabi) * 4096.0);
00218 
00219                 temp = ht.hashTable[i];
00220                 ht.hashTable[i] = ht.hashTable[j];
00221                 ht.hashTable[j] = temp;
00222         }
00223 
00224         BN_RANDSEED(k, 13);
00225 
00226         for (i = 0; i < MAXSIZE; i++)
00227                 RTable[i] = BN_RANDOM(k) * 2.0 - 1.0;
00228 
00229 
00230         ht.hashTableValid = 1;
00231 
00232         bu_semaphore_release( BU_SEM_BN_NOISE );
00233 
00234 
00235         CK_HT();
00236 }
00237 
00238 
00239 
00240 /**
00241  *@brief
00242  * Robert Skinner's Perlin-style "Noise" function
00243  *
00244  * Results are in the range [-0.5 .. 0.5].  Unlike many implementations,
00245  * this function provides random noise at the integer lattice values.
00246  * However this produces much poorer quality and should be avoided if
00247  * possible.
00248  *
00249  * The power distribution of the result has no particular shape, though it
00250  * isn't as flat as the literature would have one believe.
00251  */
00252 double
00253 bn_noise_perlin(fastf_t *point)
00254 {
00255         register int    jx, jy, jz;
00256         int ix, iy, iz; /* lower integer lattice point */
00257         double x, y, z; /* corrected point */
00258         double fx, fy, fz;      /* distance above integer lattice point */
00259         double  sx, sy, sz, tx, ty, tz;
00260         double  sum;
00261         short   m;
00262         point_t p, f;
00263         int ip[3];
00264 
00265         if (!ht.hashTableValid) bn_noise_init();
00266         else {
00267 /*              CK_HT(); */
00268         }
00269 
00270         /* IS: const fastf_t *, point_t, point_t, int[3] */
00271         /* NE: fastf_t *, fastf_t *, fastf_t *, int *    */
00272         filter_args( point, p, f, ip);
00273         ix = ip[X];
00274         iy = ip[Y];
00275         iz = ip[Z];
00276 
00277         fx = f[X];
00278         fy = f[Y];
00279         fz = f[Z];
00280 
00281         x = p[X];
00282         y = p[Y];
00283         z = p[Z];
00284 
00285         jx = ix + 1; /* (jx,jy,jz) = integer lattice point above (ix,iy,iz) */
00286         jy = iy + 1;
00287         jz = iz + 1;
00288 
00289         sx = SMOOTHSTEP(fx);
00290         sy = SMOOTHSTEP(fy);
00291         sz = SMOOTHSTEP(fz);
00292 
00293         /* the complement values of sx,sy,sz */
00294         tx = 1.0 - sx;
00295         ty = 1.0 - sy;
00296         tz = 1.0 - sz;
00297 
00298         /*
00299          *  interpolate!
00300          */
00301         /* get a repeatable random # 0..4096 & 0xFF*/
00302         m = Hash3d( ix, iy, iz ) & 0xFF;
00303         sum = INCRSUM(m,(tx*ty*tz),(x-ix),(y-iy),(z-iz));
00304 
00305         m = Hash3d( jx, iy, iz ) & 0xFF;
00306         sum += INCRSUM(m,(sx*ty*tz),(x-jx),(y-iy),(z-iz));
00307 
00308         m = Hash3d( ix, jy, iz ) & 0xFF;
00309         sum += INCRSUM(m,(tx*sy*tz),(x-ix),(y-jy),(z-iz));
00310 
00311         m = Hash3d( jx, jy, iz ) & 0xFF;
00312         sum += INCRSUM(m,(sx*sy*tz),(x-jx),(y-jy),(z-iz));
00313 
00314         m = Hash3d( ix, iy, jz ) & 0xFF;
00315         sum += INCRSUM(m,(tx*ty*sz),(x-ix),(y-iy),(z-jz));
00316 
00317         m = Hash3d( jx, iy, jz ) & 0xFF;
00318         sum += INCRSUM(m,(sx*ty*sz),(x-jx),(y-iy),(z-jz));
00319 
00320         m = Hash3d( ix, jy, jz ) & 0xFF;
00321         sum += INCRSUM(m,(tx*sy*sz),(x-ix),(y-jy),(z-jz));
00322 
00323         m = Hash3d( jx, jy, jz ) & 0xFF;
00324         sum += INCRSUM(m,(sx*sy*sz),(x-jx),(y-jy),(z-jz));
00325 
00326         return sum;
00327 
00328 }
00329 
00330 /**
00331  * Vector-valued "Noise"
00332  */
00333 void
00334 bn_noise_vec(fastf_t *point, fastf_t *result)
00335 {
00336         register int    jx, jy, jz;
00337         int ix, iy, iz;         /* lower integer lattice point */
00338         double x, y, z;         /* corrected point */
00339         double          px, py, pz, s;
00340         double          sx, sy, sz, tx, ty, tz;
00341         short           m;
00342         point_t p, f;
00343         int ip[3];
00344 
00345 
00346         if ( ! ht.hashTableValid ) bn_noise_init();
00347 
00348 
00349         /* sets:
00350          * x,y,z to range [0..maxval],
00351          * ix,iy,iz to integer portion,
00352          * fx,fy,fz to fractional portion
00353          */
00354         filter_args( point, p, f, ip);
00355         ix = ip[X];
00356         iy = ip[Y];
00357         iz = ip[Z];
00358 
00359         x = p[X];
00360         y = p[Y];
00361         z = p[Z];
00362 
00363         jx = ix+1;   jy = iy + 1;   jz = iz + 1;
00364 
00365         sx = SMOOTHSTEP(x - ix);
00366         sy = SMOOTHSTEP(y - iy);
00367         sz = SMOOTHSTEP(z - iz);
00368 
00369         /* the complement values of sx,sy,sz */
00370         tx = 1.0 - sx;
00371         ty = 1.0 - sy;
00372         tz = 1.0 - sz;
00373 
00374         /*
00375          *  interpolate!
00376          */
00377         m = Hash3d( ix, iy, iz ) & 0xFF;
00378         px = x-ix;
00379         py = y-iy;
00380         pz = z-iz;
00381         s = tx*ty*tz;
00382         result[0] = INCRSUM(m,s,px,py,pz);
00383         result[1] = INCRSUM(m+4,s,px,py,pz);
00384         result[2] = INCRSUM(m+8,s,px,py,pz);
00385 
00386         m = Hash3d( jx, iy, iz ) & 0xFF;
00387         px = x-jx;
00388         s = sx*ty*tz;
00389         result[0] += INCRSUM(m,s,px,py,pz);
00390         result[1] += INCRSUM(m+4,s,px,py,pz);
00391         result[2] += INCRSUM(m+8,s,px,py,pz);
00392 
00393         m = Hash3d( jx, jy, iz ) & 0xFF;
00394         py = y-jy;
00395         s = sx*sy*tz;
00396         result[0] += INCRSUM(m,s,px,py,pz);
00397         result[1] += INCRSUM(m+4,s,px,py,pz);
00398         result[2] += INCRSUM(m+8,s,px,py,pz);
00399 
00400         m = Hash3d( ix, jy, iz ) & 0xFF;
00401         px = x-ix;
00402         s = tx*sy*tz;
00403         result[0] += INCRSUM(m,s,px,py,pz);
00404         result[1] += INCRSUM(m+4,s,px,py,pz);
00405         result[2] += INCRSUM(m+8,s,px,py,pz);
00406 
00407         m = Hash3d( ix, jy, jz ) & 0xFF;
00408         pz = z-jz;
00409         s = tx*sy*sz;
00410         result[0] += INCRSUM(m,s,px,py,pz);
00411         result[1] += INCRSUM(m+4,s,px,py,pz);
00412         result[2] += INCRSUM(m+8,s,px,py,pz);
00413 
00414         m = Hash3d( jx, jy, jz ) & 0xFF;
00415         px = x-jx;
00416         s = sx*sy*sz;
00417         result[0] += INCRSUM(m,s,px,py,pz);
00418         result[1] += INCRSUM(m+4,s,px,py,pz);
00419         result[2] += INCRSUM(m+8,s,px,py,pz);
00420 
00421         m = Hash3d( jx, iy, jz ) & 0xFF;
00422         py = y-iy;
00423         s = sx*ty*sz;
00424         result[0] += INCRSUM(m,s,px,py,pz);
00425         result[1] += INCRSUM(m+4,s,px,py,pz);
00426         result[2] += INCRSUM(m+8,s,px,py,pz);
00427 
00428         m = Hash3d( ix, iy, jz ) & 0xFF;
00429         px = x-ix;
00430         s = tx*ty*sz;
00431         result[0] += INCRSUM(m,s,px,py,pz);
00432         result[1] += INCRSUM(m+4,s,px,py,pz);
00433         result[2] += INCRSUM(m+8,s,px,py,pz);
00434 }
00435 /*************************************************************
00436  *@brief
00437  *      Spectral Noise functions
00438  *
00439  *************************************************************
00440  *
00441  *      The Spectral Noise functions cache the values of the
00442  *      term:
00443  *@code
00444                     (-h_val)
00445                 freq
00446  *@endcode
00447  *      Which on some systems is rather expensive to compute.
00448  *
00449  *************************************************************/
00450 struct fbm_spec {
00451         long    magic;
00452         double  octaves;
00453         double  lacunarity;
00454         double  h_val;
00455         double  remainder;
00456         double  *spec_wgts;
00457 };
00458 #define MAGIC_fbm_spec_wgt 0x837592
00459 
00460 static struct fbm_spec *etbl = (struct fbm_spec *)NULL;
00461 static int etbl_next = 0;
00462 static int etbl_size = 0;
00463 
00464 #define PSCALE(_p, _s) _p[0] *= _s; _p[1] *= _s; _p[2] *= _s
00465 #define PCOPY(_d, _s) _d[0] = _s[0]; _d[1] = _s[1]; _d[2] = _s[2]
00466 
00467 
00468 
00469 static struct fbm_spec *
00470 build_spec_tbl(double h_val, double lacunarity, double octaves)
00471 {
00472         struct fbm_spec *ep;
00473         double          *spec_wgts;
00474         double          frequency;
00475         int             i;
00476 
00477         /* The right spectral weights table for these parameters has not been
00478          * pre-computed.  As a result, we compute the table now and save it
00479          * with the knowledge that we'll likely want it again later.
00480          */
00481 
00482         /* allocate storage for new tables if needed */
00483         if (etbl_next >= etbl_size) {
00484                 if (etbl_size) {
00485                         etbl_size *= 2;
00486                         etbl = (struct fbm_spec *)bu_realloc((char *)etbl,
00487                                         etbl_size*sizeof(struct fbm_spec),
00488                                         "spectral weights table");
00489                 } else
00490                         etbl = (struct fbm_spec *)bu_calloc(etbl_size = 10,
00491                                         sizeof(struct fbm_spec),
00492                                         "spectral weights table");
00493 
00494                 if (!etbl) abort();
00495         }
00496 
00497         /* set up the next available table */
00498         ep = &etbl[etbl_next];
00499         ep->magic = MAGIC_fbm_spec_wgt; ep->octaves = octaves;
00500         ep->h_val = h_val;              ep->lacunarity = lacunarity;
00501         spec_wgts = ep->spec_wgts =
00502                 (double *)bu_malloc( ((int)(octaves+1)) * sizeof(double),
00503                 "spectral weights" );
00504 
00505         /* precompute and store spectral weights table */
00506         for (frequency = 1.0, i=0 ; i < octaves ; i++) {
00507                 /* compute weight for each frequency */
00508                 spec_wgts[i] = pow(frequency, -h_val);
00509                 frequency *= lacunarity;
00510         }
00511 
00512         etbl_next++; /* saved for last in case we're running multi-threaded */
00513         return ep;
00514 }
00515 
00516 /**
00517  * The first order of business is to see if we have pre-computed
00518  * the spectral weights table for these parameters in a previous
00519  * invocation.  If not, the we compute them and save them for
00520  * possible future use
00521  */
00522 
00523 struct fbm_spec         *
00524 find_spec_wgt(double h, double l, double o)
00525 {
00526         struct fbm_spec *ep;
00527         int i;
00528 
00529 
00530         for (ep = etbl, i=0 ; i < etbl_next ; i++, ep++) {
00531                 if (ep->magic != MAGIC_fbm_spec_wgt) bu_bomb("find_spec_wgt");
00532                 if (ep->lacunarity == l && ep->h_val == h &&
00533                         ep->octaves >= o )
00534                                 return ep;
00535         }
00536 
00537         /* we didn't find the table we wanted so we've got to semaphore on
00538          * the list to wait our turn to add what we want to the table.
00539          */
00540 
00541         bu_semaphore_acquire( BU_SEM_BN_NOISE );
00542 
00543         /* We search the list one more time in case the last process to
00544          * hold the semaphore just created the table we were about to add
00545          */
00546         for (ep = etbl, i=0 ; i < etbl_next ; i++, ep++) {
00547                 if (ep->magic != MAGIC_fbm_spec_wgt) bu_bomb("find_spec_wgt");
00548                 if (ep->lacunarity == l && ep->h_val == h &&
00549                         ep->octaves >= o )
00550                                 break;
00551         }
00552 
00553         if (i >= etbl_next) ep = build_spec_tbl(h, l, o);
00554 
00555         bu_semaphore_release( BU_SEM_BN_NOISE );
00556 
00557         return (ep);
00558 }
00559 /**
00560  * @brief
00561  * Procedural fBm evaluated at "point"; returns value stored in "value".
00562  *
00563  * @param   point               location to sample noise
00564  * @param   ``h_val''           fractal increment parameter
00565  * @param   ``lacunarity''      gap between successive frequencies
00566  * @param   ``octaves''         number of frequencies in the fBm
00567  *
00568  * The spectral properties of the result are in the APPROXIMATE range [-1..1]
00569  * Depending upon the number of octaves computed, this range may be exceeded.
00570  * Applications should clamp or scale the result to their needs.
00571  * The results have a more-or-less gaussian distribution.  Typical
00572  * results for 1M samples include:
00573  *
00574  * @li  Min           -1.15246
00575  * @li  Max            1.23146
00576  * @li  Mean        -0.0138744
00577  * @li  s.d.          0.306642
00578  * @li  Var          0.0940295
00579  *
00580  * The function call pow() is relatively expensive.  Therfore, this function
00581  * pre-computes and saves the spectral weights in a table for re-use in
00582  * successive invocations.
00583  */
00584 double
00585 bn_noise_fbm(fastf_t *point, double h_val, double lacunarity, double octaves)
00586 {
00587         struct fbm_spec         *ep;
00588         double                  value, remainder, *spec_wgts;
00589         point_t                 pt;
00590         int                     i, oct;
00591 
00592         /* The first order of business is to see if we have pre-computed
00593          * the spectral weights table for these parameters in a previous
00594          * invocation.  If not, the we compute them and save them for
00595          * possible future use
00596          */
00597 
00598         ep = find_spec_wgt(h_val, lacunarity, octaves);
00599 
00600         /* now we're ready to compute the fBm value */
00601 
00602         value = 0.0;            /* initialize vars to proper values */
00603         /* copy the point so we don't corrupt the caller's version */
00604         PCOPY(pt, point);
00605 
00606         spec_wgts = ep->spec_wgts;
00607 
00608         /* inner loop of spectral construction */
00609         oct=(int)octaves; /* save repeating double->int cast */
00610         for (i=0 ; i < oct ; i++) {
00611                 value += bn_noise_perlin( pt ) * spec_wgts[i];
00612                 PSCALE(pt, lacunarity);
00613         }
00614 
00615         remainder = octaves - (int)octaves;
00616         if ( remainder ) {
00617                 /* add in ``octaves''  remainder
00618                  * ``i''  and spatial freq. are preset in loop above
00619                  */
00620             value += remainder * bn_noise_perlin( pt ) * spec_wgts[i];
00621         }
00622 
00623         return( value );
00624 
00625 } /* bn_noise_fbm() */
00626 
00627 
00628 /**
00629  * @brief
00630  * Procedural turbulence evaluated at "point";
00631  *
00632  * @return  turbulence value for point
00633  *
00634  * @param       point           location to sample noise at
00635  * @param   ``h_val''           fractal increment parameter
00636  * @param   ``lacunarity''      gap between successive frequencies
00637  * @param   ``octaves''         number of frequencies in the fBm
00638  *
00639  * The result is characterized by sharp, narrow trenches in low values and
00640  * a more fbm-like quality in the mid-high values.  Values are in the
00641  * APPROXIMATE range [0 .. 1] depending upon the number of octaves evaluated.
00642  * Typical results:
00643 @code
00644  * Min         0.00857137
00645  * Max            1.26712
00646  * Mean          0.395122
00647  * s.d.          0.174796
00648  * Var          0.0305536
00649 @endcode
00650  * The function call pow() is relatively expensive.  Therfore, this function
00651  * pre-computes and saves the spectral weights in a table for re-use in
00652  * successive invocations.
00653  */
00654 double
00655 bn_noise_turb(fastf_t *point, double h_val, double lacunarity, double octaves)
00656 {
00657         struct fbm_spec         *ep;
00658         double                  value, remainder, *spec_wgts;
00659         point_t                 pt;
00660         int                     i, oct;
00661 
00662 
00663         /* The first order of business is to see if we have pre-computed
00664          * the spectral weights table for these parameters in a previous
00665          * invocation.  If not, the we compute them and save them for
00666          * possible future use
00667          */
00668 
00669 #define CACHE_SPECTRAL_WGTS 1
00670 #ifdef CACHE_SPECTRAL_WGTS
00671 
00672         ep = find_spec_wgt(h_val, lacunarity, octaves);
00673 
00674         /* now we're ready to compute the fBm value */
00675 
00676         value = 0.0;            /* initialize vars to proper values */
00677 
00678         /* copy the point so we don't corrupt
00679          * the caller's copy of the variable
00680          */
00681         PCOPY(pt, point);
00682         spec_wgts = ep->spec_wgts;
00683 
00684         /* inner loop of spectral construction */
00685         oct=(int)octaves; /* save repeating double->int cast */
00686         for (i=0 ; i < oct ; i++) {
00687                 value += fabs(bn_noise_perlin( pt )) * spec_wgts[i];
00688                 PSCALE(pt, lacunarity);
00689         }
00690 
00691         remainder = octaves - (int)octaves;
00692         if ( remainder ) {
00693                 /* add in ``octaves''  remainder
00694                  * ``i''  and spatial freq. are preset in loop above
00695                  */
00696             value += remainder * bn_noise_perlin( pt ) * spec_wgts[i];
00697         }
00698 #else
00699         PCOPY(pt, point);
00700 
00701         value = 0.0;            /* initialize vars to proper values */
00702         frequency = 1.0;
00703 
00704         oct=(int)octaves; /* save repeating double->int cast */
00705         for (i=0 ; i < oct ; i++) {
00706                 value += fabs(bn_noise_perlin( pt )) * pow(frequency, -h_val);
00707                 frequency *= lacunarity;
00708                 PSCALE(pt, lacunarity);
00709         }
00710 
00711         remainder = octaves - (int)octaves;
00712         if ( remainder ) {
00713                 /* add in ``octaves''  remainder
00714                  * ``i''  and spatial freq. are preset in loop above
00715                  */
00716             value += remainder * bn_noise_perlin( pt ) * pow(frequency, -h_val);
00717         }
00718 #endif
00719         return( value );
00720 
00721 } /* bn_noise_turb() */
00722 
00723 /**
00724  *@brief
00725  * A ridged noise pattern
00726  *
00727  *      From "Texturing and Modeling, A Procedural Approach" 2nd ed p338
00728  */
00729 double
00730 bn_noise_ridged(fastf_t *point, double h_val, double lacunarity, double octaves, double offset)
00731 {
00732         struct fbm_spec         *ep;
00733         double                  result, weight, signal, *spec_wgts;
00734         point_t                 pt;
00735         int                     i;
00736 
00737         /* The first order of business is to see if we have pre-computed
00738          * the spectral weights table for these parameters in a previous
00739          * invocation.  If not, the we compute them and save them for
00740          * possible future use
00741          */
00742 
00743         ep = find_spec_wgt(h_val, lacunarity, octaves);
00744 
00745         /* copy the point so we don't corrupt
00746          * the caller's copy of the variable
00747          */
00748         PCOPY(pt, point);
00749         spec_wgts = ep->spec_wgts;
00750 
00751 
00752         /* get first octave */
00753         signal = bn_noise_perlin(pt);
00754 
00755         /* get absolute value of signal (this creates the ridges) */
00756         if (signal < 0.0) signal = -signal;
00757 
00758         /* invert and translate (note that "offset shoudl be ~= 1.0 */
00759         signal = offset - signal;
00760 
00761         /* square the signal, to increase "sharpness" of ridges */
00762         signal *= signal;
00763 
00764         /* assign initial value */
00765         result = signal;
00766         weight = 1.0;
00767 
00768         for (i=1 ; i < octaves ; i++ ) {
00769                 PSCALE(pt, lacunarity);
00770 
00771                 signal = bn_noise_perlin(pt);
00772 
00773                 if (signal < 0.0) signal = - signal;
00774                 signal = offset - signal;
00775 
00776                 /* weight the contribution */
00777                 signal *= weight;
00778                 result += signal * spec_wgts[i];
00779         }
00780         return result;
00781 }
00782 
00783 /**
00784  *
00785  *      From "Texturing and Modeling, A Procedural Approach" 2nd ed
00786  */
00787 
00788 double
00789 bn_noise_mf(fastf_t *point, double h_val, double lacunarity, double octaves, double offset)
00790 {
00791         double                  frequency = 1.0;
00792         struct fbm_spec         *ep;
00793         double                  result, weight, signal, *spec_wgts;
00794         point_t                 pt;
00795         int                     i;
00796 
00797         /* The first order of business is to see if we have pre-computed
00798          * the spectral weights table for these parameters in a previous
00799          * invocation.  If not, the we compute them and save them for
00800          * possible future use
00801          */
00802 
00803         ep = find_spec_wgt( h_val, lacunarity, octaves );
00804 
00805         /* copy the point so we don't corrupt
00806          * the caller's copy of the variable
00807          */
00808         PCOPY( pt, point );
00809         spec_wgts = ep->spec_wgts;
00810         offset = 1.0;
00811 
00812         result = (bn_noise_perlin(pt) + offset) * spec_wgts[0];
00813         weight = result;
00814 
00815         for (i=1 ; i < octaves ; i++) {
00816                 PSCALE(pt, lacunarity);
00817 
00818                 if (weight > 1.0) weight = 1.0;
00819 
00820                 signal = ( bn_noise_perlin(pt) + offset ) * spec_wgts[i];
00821 
00822                 signal += fabs(bn_noise_perlin( pt )) * pow(frequency, -h_val);
00823                 frequency *= lacunarity;
00824                 PSCALE(pt, lacunarity);
00825         }
00826         return result;
00827 }
00828 
00829 /*@}*/
00830 /*
00831  * Local Variables:
00832  * mode: C
00833  * tab-width: 8
00834  * c-basic-offset: 4
00835  * indent-tabs-mode: t
00836  * End:
00837  * ex: shiftwidth=4 tabstop=8
00838  */

Generated on Mon Sep 18 01:24:47 2006 for BRL-CAD by  doxygen 1.4.6