# Home    # nevrax.com   
Nevrax
Nevrax.org
#News
#Mailing-list
#Documentation
#CVS
#Bugs
#License
Docs
 
Documentation  
Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages   Search  

noise_value.cpp

Go to the documentation of this file.
00001 
00007 /* Copyright, 2001 Nevrax Ltd.
00008  *
00009  * This file is part of NEVRAX NEL.
00010  * NEVRAX NEL is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2, or (at your option)
00013  * any later version.
00014 
00015  * NEVRAX NEL is distributed in the hope that it will be useful, but
00016  * WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00018  * General Public License for more details.
00019 
00020  * You should have received a copy of the GNU General Public License
00021  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00022  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00023  * MA 02111-1307, USA.
00024  */
00025 
00026 #include "std3d.h"
00027 
00028 #include "3d/noise_value.h"
00029 #include "3d/fast_floor.h"
00030 
00031 using namespace NLMISC;
00032 
00033 namespace NL3D 
00034 {
00035 
00036 
00037 // 3 level: best quality/speed ratio.
00038 #define NL3D_NOISE_LEVEL                        3
00039 #define NL3D_NOISE_GRID_SIZE_SHIFT      5
00040 #define NL3D_NOISE_GRID_SIZE            (1<<NL3D_NOISE_GRID_SIZE_SHIFT)
00041 static  const float NL3D_OO255= 1.0f / 255;
00042 
00043 // ***************************************************************************
00044 // ***************************************************************************
00045 // ***************************************************************************
00046 
00047 // ***************************************************************************
00049 class   CRandomGrid3D
00050 {
00051 public:
00052 
00053         // generate a random grid, with same seed.
00054         CRandomGrid3D()
00055         {
00056                 //seed
00057                 srand(0);
00058 
00059                 // init the grid
00060                 for(uint z=0; z<NL3D_NOISE_GRID_SIZE; z++)
00061                 {
00062                         for(uint y=0; y<NL3D_NOISE_GRID_SIZE; y++)
00063                         {
00064                                 for(uint x=0; x<NL3D_NOISE_GRID_SIZE; x++)
00065                                 {
00066                                         uint    id= x + (y<<NL3D_NOISE_GRID_SIZE_SHIFT) + (z<<(NL3D_NOISE_GRID_SIZE_SHIFT*2));
00067                                         // take higher bits of rand gives better result.
00068                                         uint    v= rand() >> 5;
00069                                         _Texture3d[id]= v&255;
00070                                 }
00071                         }
00072                 }
00073 
00074                 // init sizes.
00075                 uint    i;
00076                 // sum of sizes must be 1, and each level must be /2.
00077                 float   sizeSum=0;
00078                 for(i=0; i<NL3D_NOISE_LEVEL; i++)
00079                 {
00080                         _Sizes[i]= 1.0f / (1<<i);
00081                         sizeSum+= _Sizes[i];
00082                 }
00083                 // normalize
00084                 for(i=0; i<NL3D_NOISE_LEVEL; i++)
00085                 {
00086                         _Sizes[i]/= sizeSum;
00087                 }
00088 
00089                 // init LevelPhases.
00090                 for(i=0; i<NL3D_NOISE_LEVEL; i++)
00091                 {
00092                         _LevelPhase[i].x= frand(NL3D_NOISE_GRID_SIZE);
00093                         _LevelPhase[i].y= frand(NL3D_NOISE_GRID_SIZE);
00094                         _LevelPhase[i].z= frand(NL3D_NOISE_GRID_SIZE);
00095                 }
00096                 // not for level 0.
00097                 _LevelPhase[0]= CVector::Null;
00098         }
00099 
00100         // x/y/z are use to lookup directly in the grid 3D.
00101         static inline float     evalNearest(const CVector &pos)
00102         {
00103                 // compute integer part.
00104                 sint    x= OptFastFloor(pos.x);
00105                 sint    y= OptFastFloor(pos.y);
00106                 sint    z= OptFastFloor(pos.z);
00107                 // index in texture.
00108                 uint    ux= x& (NL3D_NOISE_GRID_SIZE-1);
00109                 uint    uy= y& (NL3D_NOISE_GRID_SIZE-1);
00110                 uint    uz= z& (NL3D_NOISE_GRID_SIZE-1);
00111 
00112                 // read the texture.
00113                 float   turb= lookup(ux,uy,uz);
00114 
00115                 return turb*NL3D_OO255;
00116         }
00117 
00118         // x/y/z are use to lookup directly in the grid 3D.
00119         static inline float     evalBiLinear(const CVector &pos)
00120         {
00121                 // compute integer part.
00122                 sint    x= OptFastFloor(pos.x);
00123                 sint    y= OptFastFloor(pos.y);
00124                 sint    z= OptFastFloor(pos.z);
00125                 // index in texture.
00126                 uint    ux= x& (NL3D_NOISE_GRID_SIZE-1);
00127                 uint    uy= y& (NL3D_NOISE_GRID_SIZE-1);
00128                 uint    uz= z& (NL3D_NOISE_GRID_SIZE-1);
00129                 uint    ux2= (x+1)& (NL3D_NOISE_GRID_SIZE-1);
00130                 uint    uy2= (y+1)& (NL3D_NOISE_GRID_SIZE-1);
00131                 uint    uz2= (z+1)& (NL3D_NOISE_GRID_SIZE-1);
00132                 // delta.
00133                 float   dx2;
00134                 float   dy2;
00135                 float   dz2;
00136                 easeInEaseOut(dx2, pos.x-x);
00137                 easeInEaseOut(dy2, pos.y-y);
00138                 easeInEaseOut(dz2, pos.z-z);
00139                 float   dx= 1-dx2;
00140                 float   dy= 1-dy2;
00141                 float   dz= 1-dz2;
00142                 // TriLinear in texture3D.
00143                 float   turb=0;
00144                 float   dxdy= dx*dy;
00145                 turb+= lookup(ux,uy,uz)* dxdy*dz;
00146                 turb+= lookup(ux,uy,uz2)* dxdy*dz2;
00147                 float   dxdy2= dx*dy2;
00148                 turb+= lookup(ux,uy2,uz)* dxdy2*dz;
00149                 turb+= lookup(ux,uy2,uz2)* dxdy2*dz2;
00150                 float   dx2dy= dx2*dy;
00151                 turb+= lookup(ux2,uy,uz)* dx2dy*dz;
00152                 turb+= lookup(ux2,uy,uz2)* dx2dy*dz2;
00153                 float   dx2dy2= dx2*dy2;
00154                 turb+= lookup(ux2,uy2,uz)* dx2dy2*dz;
00155                 turb+= lookup(ux2,uy2,uz2)* dx2dy2*dz2;
00156 
00157                 // End!
00158                 return turb*NL3D_OO255;
00159         }
00160 
00161 
00162         // get size according to level
00163         static inline float     getLevelSize(uint level)
00164         {
00165                 return _Sizes[level];
00166         }
00167 
00168         // get an additional level phase.
00169         static inline const CVector     &getLevelPhase(uint level)
00170         {
00171                 return _LevelPhase[level];
00172         }
00173 
00174 
00175 // **************
00176 private:
00177 
00178         static  uint8           _Texture3d[NL3D_NOISE_GRID_SIZE*NL3D_NOISE_GRID_SIZE*NL3D_NOISE_GRID_SIZE];
00179         static  float           _Sizes[NL3D_NOISE_LEVEL];
00180         static  CVector         _LevelPhase[NL3D_NOISE_LEVEL];
00181 
00182 
00183         // lookup with no mod.
00184         static inline float     lookup(uint ux, uint uy, uint uz)
00185         {
00186                 uint    id= ux + (uy<<NL3D_NOISE_GRID_SIZE_SHIFT) + (uz<<(NL3D_NOISE_GRID_SIZE_SHIFT*2));
00187                 return  _Texture3d[id];
00188         }
00189 
00190         // easineasout
00191         static inline void      easeInEaseOut(float &y, float x)
00192         {
00193                 // cubic such that f(0)=0, f'(0)=0, f(1)=1, f'(1)=0.
00194                 float   x2=x*x;
00195                 float   x3=x2*x;
00196                 y= -2*x3 + 3*x2;
00197         }
00198 
00199 };
00200 
00201 
00202 uint8           CRandomGrid3D::_Texture3d[NL3D_NOISE_GRID_SIZE*NL3D_NOISE_GRID_SIZE*NL3D_NOISE_GRID_SIZE];
00203 float           CRandomGrid3D::_Sizes[NL3D_NOISE_LEVEL];
00204 CVector         CRandomGrid3D::_LevelPhase[NL3D_NOISE_LEVEL];
00205 
00206 // just to init the static arrays.
00207 static  CRandomGrid3D   NL3D_RandomGrid3D;
00208 
00209 
00210 // ***************************************************************************
00211 // ***************************************************************************
00212 // ***************************************************************************
00213 
00214 
00215 // ***************************************************************************
00216 float   CNoiseValue::evalRandom(const CVector &pos) const
00217 {
00218         return CRandomGrid3D::evalNearest(pos);
00219 }
00220 
00221 
00222 // ***************************************************************************
00223 float   CNoiseValue::noise(const CVector &pos) const
00224 {
00225         // eval "fractaly".
00226         float           turb;
00227 
00228 #if (NL3D_NOISE_LEVEL != 3)
00229         CVector         vd= pos;
00230         turb=0;
00231         for(uint level=0;level<NL3D_NOISE_LEVEL;level++)
00232         {
00233                 // Add the influence of the ith level.
00234                 turb+= CRandomGrid3D::getLevelSize(level) * 
00235                         CRandomGrid3D::evalBiLinear(vd + CRandomGrid3D::getLevelPhase(level) );
00236                 // Next level at higher frequency
00237                 vd*= 2;
00238         }
00239 #else
00240         // special case. unrolled loop.
00241         // level 0 has no phase.
00242         turb= CRandomGrid3D::getLevelSize(0) * 
00243                 CRandomGrid3D::evalBiLinear(pos);
00244         // level 1
00245         turb+= CRandomGrid3D::getLevelSize(1) * 
00246                 CRandomGrid3D::evalBiLinear(pos*2 + CRandomGrid3D::getLevelPhase(1) );
00247         // level 2
00248         turb+= CRandomGrid3D::getLevelSize(2) * 
00249                 CRandomGrid3D::evalBiLinear(pos*4 + CRandomGrid3D::getLevelPhase(2) );
00250 #endif
00251 
00252         return turb;
00253 }
00254 
00255 
00256 
00257 // ***************************************************************************
00258 CNoiseValue::CNoiseValue()
00259 {
00260         Abs= 0;
00261         Rand= 1;
00262         Frequency= 1;
00263 }
00264 
00265 
00266 // ***************************************************************************
00267 CNoiseValue::CNoiseValue(float abs, float rand, float freq)
00268 {
00269         Abs= abs;
00270         Rand= rand;
00271         Frequency= freq;
00272 }
00273 
00274 
00275 // ***************************************************************************
00276 float   CNoiseValue::eval(const CVector &posInWorld) const
00277 {
00278         // A single cube in the Grid3d correspond to Frequency==1.
00279         // So enlarging size of the grid3d do not affect the frequency aspect.
00280         return Abs + Rand * noise(posInWorld*Frequency);
00281 }
00282 
00283 
00284 // ***************************************************************************
00285 float   CNoiseValue::evalOneLevelRandom(const CVector &posInWorld) const
00286 {
00287         // A single cube in the Grid3d correspond to Frequency==1.
00288         // So enlarging size of the grid3d do not affect the frequency aspect.
00289         return Abs + Rand * evalRandom(posInWorld*Frequency);
00290 }
00291 
00292 
00293 // ***************************************************************************
00294 void    CNoiseValue::serial(IStream &f)
00295 {
00296         (void)f.serialVersion(0);
00297         f.serial(Abs);
00298         f.serial(Rand);
00299         f.serial(Frequency);
00300 }
00301 
00302 
00303 // ***************************************************************************
00304 // ***************************************************************************
00305 // ***************************************************************************
00306 
00307 
00308 // ***************************************************************************
00309 void    CNoiseColorGradient::eval(const CVector &posInWorld, CRGBAF &result) const
00310 {
00311         // test if not null grads.
00312         uint    nGrads= Gradients.size();
00313         if(nGrads==0)
00314                 return;
00315         // if only one color, easy
00316         if(nGrads==1)
00317         {
00318                 result= Gradients[0];
00319         }
00320         else
00321         {
00322                 // eval noise
00323                 float   f= NoiseValue.eval(posInWorld) * (nGrads-1);
00324                 clamp(f, 0.f, (float)(nGrads-1));
00325                 // look up in table of gradients.
00326                 uint    id= OptFastFloor(f);
00327                 clamp(id, 0U, nGrads-2);
00328                 // fractionnal part.
00329                 f= f-id;
00330                 clamp(f, 0, 1);
00331                 // interpolate the gradient.
00332                 result= Gradients[id]*(1-f) + Gradients[id+1]*f;
00333         }
00334 }
00335 
00336 // ***************************************************************************
00337 void    CNoiseColorGradient::serial(IStream &f)
00338 {
00339         (void)f.serialVersion(0);
00340         f.serial(NoiseValue);
00341         f.serialCont(Gradients);
00342 }
00343 
00344 
00345 
00346 } // NL3D