Blender V2.61 - r43446
|
00001 00004 00005 // This file is part of Wavelet Turbulence. 00006 // 00007 // Wavelet Turbulence is free software: you can redistribute it and/or modify 00008 // it under the terms of the GNU General Public License as published by 00009 // the Free Software Foundation, either version 3 of the License, or 00010 // (at your option) any later version. 00011 // 00012 // Wavelet Turbulence is distributed in the hope that it will be useful, 00013 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 // GNU General Public License for more details. 00016 // 00017 // You should have received a copy of the GNU General Public License 00018 // along with Wavelet Turbulence. If not, see <http://www.gnu.org/licenses/>. 00019 // 00020 // Copyright 2008 Theodore Kim and Nils Thuerey 00021 // 00022 // WTURBULENCE handling 00024 // Parallelized turbulence even further. TNT matrix library functions 00025 // rewritten to improve performance. 00026 // - MiikaH 00028 00029 #include "WTURBULENCE.h" 00030 #include "INTERPOLATE.h" 00031 #include "IMAGE.h" 00032 #include <MERSENNETWISTER.h> 00033 #include "WAVELET_NOISE.h" 00034 #include "FFT_NOISE.h" 00035 #include "EIGENVALUE_HELPER.h" 00036 #include "LU_HELPER.h" 00037 #include "SPHERE.h" 00038 #include <zlib.h> 00039 #include <math.h> 00040 00041 // needed to access static advection functions 00042 #include "FLUID_3D.h" 00043 00044 #if PARALLEL==1 00045 #include <omp.h> 00046 #endif // PARALLEL 00047 00048 // 2^ {-5/6} 00049 static const float persistence = 0.56123f; 00050 00052 // constructor 00054 WTURBULENCE::WTURBULENCE(int xResSm, int yResSm, int zResSm, int amplify, int noisetype) 00055 { 00056 // if noise magnitude is below this threshold, its contribution 00057 // is negilgible, so stop evaluating new octaves 00058 _cullingThreshold = 1e-3; 00059 00060 // factor by which to increase the simulation resolution 00061 _amplify = amplify; 00062 00063 // manually adjust the overall amount of turbulence 00064 // DG - RNA-fied _strength = 2.; 00065 00066 // add the corresponding octaves of noise 00067 _octaves = (int)(log((float)_amplify) / log(2.0f) + 0.5); // XXX DEBUG/ TODO: int casting correct? - dg 00068 00069 // noise resolution 00070 _xResBig = _amplify * xResSm; 00071 _yResBig = _amplify * yResSm; 00072 _zResBig = _amplify * zResSm; 00073 _resBig = Vec3Int(_xResBig, _yResBig, _zResBig); 00074 _invResBig = Vec3(1./(float)_resBig[0], 1./(float)_resBig[1], 1./(float)_resBig[2]); 00075 _slabSizeBig = _xResBig*_yResBig; 00076 _totalCellsBig = _slabSizeBig * _zResBig; 00077 00078 // original / small resolution 00079 _xResSm = xResSm; 00080 _yResSm = yResSm; 00081 _zResSm = zResSm; 00082 _resSm = Vec3Int(xResSm, yResSm, zResSm); 00083 _invResSm = Vec3(1./(float)_resSm[0], 1./(float)_resSm[1], 1./(float)_resSm[2] ); 00084 _slabSizeSm = _xResSm*_yResSm; 00085 _totalCellsSm = _slabSizeSm * _zResSm; 00086 00087 // allocate high resolution density field 00088 _totalStepsBig = 0; 00089 _densityBig = new float[_totalCellsBig]; 00090 _densityBigOld = new float[_totalCellsBig]; 00091 00092 for(int i = 0; i < _totalCellsBig; i++) { 00093 _densityBig[i] = 00094 _densityBigOld[i] = 0.; 00095 } 00096 00097 // allocate & init texture coordinates 00098 _tcU = new float[_totalCellsSm]; 00099 _tcV = new float[_totalCellsSm]; 00100 _tcW = new float[_totalCellsSm]; 00101 _tcTemp = new float[_totalCellsSm]; 00102 00103 // map all 00104 const float dx = 1./(float)(_resSm[0]); 00105 const float dy = 1./(float)(_resSm[1]); 00106 const float dz = 1./(float)(_resSm[2]); 00107 int index = 0; 00108 for (int z = 0; z < _zResSm; z++) 00109 for (int y = 0; y < _yResSm; y++) 00110 for (int x = 0; x < _xResSm; x++, index++) 00111 { 00112 _tcU[index] = x*dx; 00113 _tcV[index] = y*dy; 00114 _tcW[index] = z*dz; 00115 _tcTemp[index] = 0.; 00116 } 00117 00118 // noise tiles 00119 _noiseTile = new float[noiseTileSize * noiseTileSize * noiseTileSize]; 00120 /* 00121 std::string noiseTileFilename = std::string("noise.wavelets"); 00122 generateTile_WAVELET(_noiseTile, noiseTileFilename); 00123 */ 00124 setNoise(noisetype); 00125 /* 00126 std::string noiseTileFilename = std::string("noise.fft"); 00127 generatTile_FFT(_noiseTile, noiseTileFilename); 00128 */ 00129 } 00130 00132 // destructor 00134 WTURBULENCE::~WTURBULENCE() { 00135 delete[] _densityBig; 00136 delete[] _densityBigOld; 00137 00138 delete[] _tcU; 00139 delete[] _tcV; 00140 delete[] _tcW; 00141 delete[] _tcTemp; 00142 00143 delete[] _noiseTile; 00144 } 00145 00147 // Change noise type 00148 // 00149 // type (1<<0) = wavelet / 2 00150 // type (1<<1) = FFT / 4 00151 // type (1<<2) = curl / 8 00153 void WTURBULENCE::setNoise(int type) 00154 { 00155 if(type == (1<<1)) // FFT 00156 { 00157 // needs fft 00158 #ifdef WITH_FFTW3 00159 std::string noiseTileFilename = std::string("noise.fft"); 00160 generatTile_FFT(_noiseTile, noiseTileFilename); 00161 #endif 00162 } 00163 else if(type == (1<<2)) // curl 00164 { 00165 // TODO: not supported yet 00166 } 00167 else // standard - wavelet 00168 { 00169 std::string noiseTileFilename = std::string("noise.wavelets"); 00170 generateTile_WAVELET(_noiseTile, noiseTileFilename); 00171 } 00172 } 00173 00174 // init direct access functions from blender 00175 void WTURBULENCE::initBlenderRNA(float *strength) 00176 { 00177 _strength = strength; 00178 } 00179 00181 // Get the smallest valid x derivative 00182 // 00183 // Takes the one-sided finite difference in both directions and 00184 // selects the smaller of the two 00186 static float minDx(int x, int y, int z, float* input, Vec3Int res) 00187 { 00188 const int index = x + y * res[0] + z * res[0] * res[1]; 00189 const int maxx = res[0]-2; 00190 00191 // get grid values 00192 float center = input[index]; 00193 float left = (x <= 1) ? FLT_MAX : input[index - 1]; 00194 float right = (x >= maxx) ? FLT_MAX : input[index + 1]; 00195 00196 const float dx = res[0]; 00197 00198 // get all the derivative estimates 00199 float dLeft = (x <= 1) ? FLT_MAX : (center - left) * dx; 00200 float dRight = (x >= maxx) ? FLT_MAX : (right - center) * dx; 00201 float dCenter = (x <= 1 || x >= maxx) ? FLT_MAX : (right - left) * dx * 0.5f; 00202 00203 // if it's on a boundary, only one estimate is valid 00204 if (x <= 1) return dRight; 00205 if (x >= maxx) return dLeft; 00206 00207 // if it's not on a boundary, get the smallest one 00208 float finalD; 00209 finalD = (fabs(dCenter) < fabs(dRight)) ? dCenter : dRight; 00210 finalD = (fabs(finalD) < fabs(dLeft)) ? finalD : dLeft; 00211 00212 return finalD; 00213 } 00214 00216 // get the smallest valid y derivative 00217 // 00218 // Takes the one-sided finite difference in both directions and 00219 // selects the smaller of the two 00221 static float minDy(int x, int y, int z, float* input, Vec3Int res) 00222 { 00223 const int index = x + y * res[0] + z * res[0] * res[1]; 00224 const int maxy = res[1]-2; 00225 00226 // get grid values 00227 float center = input[index]; 00228 float down = (y <= 1) ? FLT_MAX : input[index - res[0]]; 00229 float up = (y >= maxy) ? FLT_MAX : input[index + res[0]]; 00230 00231 const float dx = res[1]; // only for square domains 00232 00233 // get all the derivative estimates 00234 float dDown = (y <= 1) ? FLT_MAX : (center - down) * dx; 00235 float dUp = (y >= maxy) ? FLT_MAX : (up - center) * dx; 00236 float dCenter = (y <= 1 || y >= maxy) ? FLT_MAX : (up - down) * dx * 0.5f; 00237 00238 // if it's on a boundary, only one estimate is valid 00239 if (y <= 1) return dUp; 00240 if (y >= maxy) return dDown; 00241 00242 // if it's not on a boundary, get the smallest one 00243 float finalD = (fabs(dCenter) < fabs(dUp)) ? dCenter : dUp; 00244 finalD = (fabs(finalD) < fabs(dDown)) ? finalD : dDown; 00245 00246 return finalD; 00247 } 00248 00250 // get the smallest valid z derivative 00251 // 00252 // Takes the one-sided finite difference in both directions and 00253 // selects the smaller of the two 00255 static float minDz(int x, int y, int z, float* input, Vec3Int res) 00256 { 00257 const int slab = res[0]*res[1]; 00258 const int index = x + y * res[0] + z * slab; 00259 const int maxz = res[2]-2; 00260 00261 // get grid values 00262 float center = input[index]; 00263 float front = (z <= 1) ? FLT_MAX : input[index - slab]; 00264 float back = (z >= maxz) ? FLT_MAX : input[index + slab]; 00265 00266 const float dx = res[2]; // only for square domains 00267 00268 // get all the derivative estimates 00269 float dfront = (z <= 1) ? FLT_MAX : (center - front) * dx; 00270 float dback = (z >= maxz) ? FLT_MAX : (back - center) * dx; 00271 float dCenter = (z <= 1 || z >= maxz) ? FLT_MAX : (back - front) * dx * 0.5f; 00272 00273 // if it's on a boundary, only one estimate is valid 00274 if (z <= 1) return dback; 00275 if (z >= maxz) return dfront; 00276 00277 // if it's not on a boundary, get the smallest one 00278 float finalD = (fabs(dCenter) < fabs(dback)) ? dCenter : dback; 00279 finalD = (fabs(finalD) < fabs(dfront)) ? finalD : dfront; 00280 00281 return finalD; 00282 } 00283 00285 // handle texture coordinates (advection, reset, eigenvalues), 00286 // Beware -- uses big density maccormack as temporary arrays 00288 void WTURBULENCE::advectTextureCoordinates (float dtOrg, float* xvel, float* yvel, float* zvel, float *tempBig1, float *tempBig2) { 00289 00290 // advection 00291 SWAP_POINTERS(_tcTemp, _tcU); 00292 FLUID_3D::copyBorderX(_tcTemp, _resSm, 0 , _resSm[2]); 00293 FLUID_3D::copyBorderY(_tcTemp, _resSm, 0 , _resSm[2]); 00294 FLUID_3D::copyBorderZ(_tcTemp, _resSm, 0 , _resSm[2]); 00295 FLUID_3D::advectFieldMacCormack1(dtOrg, xvel, yvel, zvel, 00296 _tcTemp, tempBig1, _resSm, 0 , _resSm[2]); 00297 FLUID_3D::advectFieldMacCormack2(dtOrg, xvel, yvel, zvel, 00298 _tcTemp, _tcU, tempBig1, tempBig2, _resSm, NULL, 0 , _resSm[2]); 00299 00300 SWAP_POINTERS(_tcTemp, _tcV); 00301 FLUID_3D::copyBorderX(_tcTemp, _resSm, 0 , _resSm[2]); 00302 FLUID_3D::copyBorderY(_tcTemp, _resSm, 0 , _resSm[2]); 00303 FLUID_3D::copyBorderZ(_tcTemp, _resSm, 0 , _resSm[2]); 00304 FLUID_3D::advectFieldMacCormack1(dtOrg, xvel, yvel, zvel, 00305 _tcTemp, tempBig1, _resSm, 0 , _resSm[2]); 00306 FLUID_3D::advectFieldMacCormack2(dtOrg, xvel, yvel, zvel, 00307 _tcTemp, _tcV, tempBig1, tempBig2, _resSm, NULL, 0 , _resSm[2]); 00308 00309 SWAP_POINTERS(_tcTemp, _tcW); 00310 FLUID_3D::copyBorderX(_tcTemp, _resSm, 0 , _resSm[2]); 00311 FLUID_3D::copyBorderY(_tcTemp, _resSm, 0 , _resSm[2]); 00312 FLUID_3D::copyBorderZ(_tcTemp, _resSm, 0 , _resSm[2]); 00313 FLUID_3D::advectFieldMacCormack1(dtOrg, xvel, yvel, zvel, 00314 _tcTemp, tempBig1, _resSm, 0 , _resSm[2]); 00315 FLUID_3D::advectFieldMacCormack2(dtOrg, xvel, yvel, zvel, 00316 _tcTemp, _tcW, tempBig1, tempBig2, _resSm, NULL, 0 , _resSm[2]); 00317 } 00318 00320 // Compute the eigenvalues of the advected texture 00322 void WTURBULENCE::computeEigenvalues(float *_eigMin, float *_eigMax) { 00323 // stats 00324 float maxeig = -1.; 00325 float mineig = 10.; 00326 00327 // texture coordinate eigenvalues 00328 for (int z = 1; z < _zResSm-1; z++) { 00329 for (int y = 1; y < _yResSm-1; y++) 00330 for (int x = 1; x < _xResSm-1; x++) 00331 { 00332 const int index = x+ y *_resSm[0] + z*_slabSizeSm; 00333 00334 // compute jacobian 00335 float jacobian[3][3] = { 00336 { minDx(x, y, z, _tcU, _resSm), minDx(x, y, z, _tcV, _resSm), minDx(x, y, z, _tcW, _resSm) } , 00337 { minDy(x, y, z, _tcU, _resSm), minDy(x, y, z, _tcV, _resSm), minDy(x, y, z, _tcW, _resSm) } , 00338 { minDz(x, y, z, _tcU, _resSm), minDz(x, y, z, _tcV, _resSm), minDz(x, y, z, _tcW, _resSm) } 00339 }; 00340 00341 // ONLY compute the eigenvalues after checking that the matrix 00342 // is nonsingular 00343 sLU LU = computeLU(jacobian); 00344 00345 if (isNonsingular(LU)) 00346 { 00347 // get the analytic eigenvalues, quite slow right now... 00348 Vec3 eigenvalues = Vec3(1.); 00349 computeEigenvalues3x3( &eigenvalues[0], jacobian); 00350 _eigMax[index] = MAX3V(eigenvalues); 00351 _eigMin[index] = MIN3V(eigenvalues); 00352 maxeig = MAX(_eigMax[index],maxeig); 00353 mineig = MIN(_eigMin[index],mineig); 00354 } 00355 else 00356 { 00357 _eigMax[index] = 10.0f; 00358 _eigMin[index] = 0.1; 00359 } 00360 } 00361 } 00362 } 00363 00365 // advect & reset texture coordinates based on eigenvalues 00367 void WTURBULENCE::resetTextureCoordinates(float *_eigMin, float *_eigMax) 00368 { 00369 // allowed deformation of the textures 00370 const float limit = 2.f; 00371 const float limitInv = 1./limit; 00372 00373 // standard reset 00374 int resets = 0; 00375 const float dx = 1./(float)(_resSm[0]); 00376 const float dy = 1./(float)(_resSm[1]); 00377 const float dz = 1./(float)(_resSm[2]); 00378 00379 for (int z = 1; z < _zResSm-1; z++) 00380 for (int y = 1; y < _yResSm-1; y++) 00381 for (int x = 1; x < _xResSm-1; x++) 00382 { 00383 const int index = x+ y *_resSm[0] + z*_slabSizeSm; 00384 if (_eigMax[index] > limit || _eigMin[index] < limitInv) 00385 { 00386 _tcU[index] = (float)x * dx; 00387 _tcV[index] = (float)y * dy; 00388 _tcW[index] = (float)z * dz; 00389 resets++; 00390 } 00391 } 00392 } 00393 00395 // Compute the highest frequency component of the wavelet 00396 // decomposition 00398 void WTURBULENCE::decomposeEnergy(float *_energy, float *_highFreqEnergy) 00399 { 00400 // do the decomposition -- the goal here is to have 00401 // the energy with the high frequency component stomped out 00402 // stored in _tcTemp when it is done. _highFreqEnergy is only used 00403 // as an additional temp array 00404 00405 // downsample input 00406 downsampleXNeumann(_highFreqEnergy, _energy, _xResSm, _yResSm, _zResSm); 00407 downsampleYNeumann(_tcTemp, _highFreqEnergy, _xResSm, _yResSm, _zResSm); 00408 downsampleZNeumann(_highFreqEnergy, _tcTemp, _xResSm, _yResSm, _zResSm); 00409 00410 // upsample input 00411 upsampleZNeumann(_tcTemp, _highFreqEnergy, _xResSm, _yResSm, _zResSm); 00412 upsampleYNeumann(_highFreqEnergy, _tcTemp, _xResSm, _yResSm, _zResSm); 00413 upsampleXNeumann(_tcTemp, _highFreqEnergy, _xResSm, _yResSm, _zResSm); 00414 00415 // subtract the down and upsampled field from the original field -- 00416 // what should be left over is solely the high frequency component 00417 int index = 0; 00418 for (int z = 0; z < _zResSm; z++) 00419 for (int y = 0; y < _yResSm; y++) { 00420 for (int x = 0; x < _xResSm; x++, index++) { 00421 // brute force reset of boundaries 00422 if(z >= _zResSm - 1 || x >= _xResSm - 1 || y >= _yResSm - 1 || z <= 0 || y <= 0 || x <= 0) 00423 _highFreqEnergy[index] = 0.; 00424 else 00425 _highFreqEnergy[index] = _energy[index] - _tcTemp[index]; 00426 } 00427 } 00428 } 00429 00431 // compute velocity from energies and march into obstacles 00432 // for wavelet decomposition 00434 void WTURBULENCE::computeEnergy(float *_energy, float* xvel, float* yvel, float* zvel, unsigned char *obstacles) 00435 { 00436 // compute everywhere 00437 for (int x = 0; x < _totalCellsSm; x++) 00438 _energy[x] = 0.5f * (xvel[x] * xvel[x] + yvel[x] * yvel[x] + zvel[x] * zvel[x]); 00439 00440 FLUID_3D::copyBorderX(_energy, _resSm, 0 , _resSm[2]); 00441 FLUID_3D::copyBorderY(_energy, _resSm, 0 , _resSm[2]); 00442 FLUID_3D::copyBorderZ(_energy, _resSm, 0 , _resSm[2]); 00443 00444 // pseudo-march the values into the obstacles 00445 // the wavelet upsampler only uses a 3x3 support neighborhood, so 00446 // propagating the values in by 4 should be sufficient 00447 int index; 00448 00449 // iterate 00450 for (int iter = 0; iter < 4; iter++) 00451 { 00452 index = _slabSizeSm + _xResSm + 1; 00453 for (int z = 1; z < _zResSm - 1; z++, index += 2 * _xResSm) 00454 for (int y = 1; y < _yResSm - 1; y++, index += 2) 00455 for (int x = 1; x < _xResSm - 1; x++, index++) 00456 if (obstacles[index] && obstacles[index] != RETIRED) 00457 { 00458 float sum = 0.0f; 00459 int valid = 0; 00460 00461 if (!obstacles[index + 1] || obstacles[index + 1] == RETIRED) 00462 { 00463 sum += _energy[index + 1]; 00464 valid++; 00465 } 00466 if (!obstacles[index - 1] || obstacles[index - 1] == RETIRED) 00467 { 00468 sum += _energy[index - 1]; 00469 valid++; 00470 } 00471 if (!obstacles[index + _xResSm] || obstacles[index + _xResSm] == RETIRED) 00472 { 00473 sum += _energy[index + _xResSm]; 00474 valid++; 00475 } 00476 if (!obstacles[index - _xResSm] || obstacles[index - _xResSm] == RETIRED) 00477 { 00478 sum += _energy[index - _xResSm]; 00479 valid++; 00480 } 00481 if (!obstacles[index + _slabSizeSm] || obstacles[index + _slabSizeSm] == RETIRED) 00482 { 00483 sum += _energy[index + _slabSizeSm]; 00484 valid++; 00485 } 00486 if (!obstacles[index - _slabSizeSm] || obstacles[index - _slabSizeSm] == RETIRED) 00487 { 00488 sum += _energy[index - _slabSizeSm]; 00489 valid++; 00490 } 00491 if (valid > 0) 00492 { 00493 _energy[index] = sum / (float)valid; 00494 obstacles[index] = MARCHED; 00495 } 00496 } 00497 index = _slabSizeSm + _xResSm + 1; 00498 for (int z = 1; z < _zResSm - 1; z++, index += 2 * _xResSm) 00499 for (int y = 1; y < _yResSm - 1; y++, index += 2) 00500 for (int x = 1; x < _xResSm - 1; x++, index++) 00501 if (obstacles[index] == MARCHED) 00502 obstacles[index] = RETIRED; 00503 } 00504 index = _slabSizeSm + _xResSm + 1; 00505 for (int z = 1; z < _zResSm - 1; z++, index += 2 * _xResSm) 00506 for (int y = 1; y < _yResSm - 1; y++, index += 2) 00507 for (int x = 1; x < _xResSm - 1; x++, index++) 00508 if (obstacles[index]) 00509 obstacles[index] = 1; 00510 } 00511 00513 // Evaluate derivatives 00515 Vec3 WTURBULENCE::WVelocity(Vec3 orgPos) 00516 { 00517 // arbitrarily offset evaluation points 00518 const Vec3 p1 = orgPos + Vec3(NOISE_TILE_SIZE/2.0,0,0); 00519 const Vec3 p2 = orgPos + Vec3(0,NOISE_TILE_SIZE/2.0,0); 00520 const Vec3 p3 = orgPos + Vec3(0,0,NOISE_TILE_SIZE/2.0); 00521 00522 const float f1y = WNoiseDy(p1, _noiseTile); 00523 const float f1z = WNoiseDz(p1, _noiseTile); 00524 00525 const float f2x = WNoiseDx(p2, _noiseTile); 00526 const float f2z = WNoiseDz(p2, _noiseTile); 00527 00528 const float f3x = WNoiseDx(p3, _noiseTile); 00529 const float f3y = WNoiseDy(p3, _noiseTile); 00530 00531 Vec3 ret = Vec3( 00532 f3y - f2z, 00533 f1z - f3x, 00534 f2x - f1y ); 00535 return ret; 00536 } 00537 00539 // Evaluate derivatives with Jacobian 00541 Vec3 WTURBULENCE::WVelocityWithJacobian(Vec3 orgPos, float* xUnwarped, float* yUnwarped, float* zUnwarped) 00542 { 00543 // arbitrarily offset evaluation points 00544 const Vec3 p1 = orgPos + Vec3(NOISE_TILE_SIZE/2.0,0,0); 00545 const Vec3 p2 = orgPos + Vec3(0,NOISE_TILE_SIZE/2.0,0); 00546 const Vec3 p3 = orgPos + Vec3(0,0,NOISE_TILE_SIZE/2.0); 00547 00548 Vec3 final; 00549 final[0] = WNoiseDx(p1, _noiseTile); 00550 final[1] = WNoiseDy(p1, _noiseTile); 00551 final[2] = WNoiseDz(p1, _noiseTile); 00552 // UNUSED const float f1x = xUnwarped[0] * final[0] + xUnwarped[1] * final[1] + xUnwarped[2] * final[2]; 00553 const float f1y = yUnwarped[0] * final[0] + yUnwarped[1] * final[1] + yUnwarped[2] * final[2]; 00554 const float f1z = zUnwarped[0] * final[0] + zUnwarped[1] * final[1] + zUnwarped[2] * final[2]; 00555 00556 final[0] = WNoiseDx(p2, _noiseTile); 00557 final[1] = WNoiseDy(p2, _noiseTile); 00558 final[2] = WNoiseDz(p2, _noiseTile); 00559 const float f2x = xUnwarped[0] * final[0] + xUnwarped[1] * final[1] + xUnwarped[2] * final[2]; 00560 // UNUSED const float f2y = yUnwarped[0] * final[0] + yUnwarped[1] * final[1] + yUnwarped[2] * final[2]; 00561 const float f2z = zUnwarped[0] * final[0] + zUnwarped[1] * final[1] + zUnwarped[2] * final[2]; 00562 00563 final[0] = WNoiseDx(p3, _noiseTile); 00564 final[1] = WNoiseDy(p3, _noiseTile); 00565 final[2] = WNoiseDz(p3, _noiseTile); 00566 const float f3x = xUnwarped[0] * final[0] + xUnwarped[1] * final[1] + xUnwarped[2] * final[2]; 00567 const float f3y = yUnwarped[0] * final[0] + yUnwarped[1] * final[1] + yUnwarped[2] * final[2]; 00568 // UNUSED const float f3z = zUnwarped[0] * final[0] + zUnwarped[1] * final[1] + zUnwarped[2] * final[2]; 00569 00570 Vec3 ret = Vec3( 00571 f3y - f2z, 00572 f1z - f3x, 00573 f2x - f1y ); 00574 return ret; 00575 } 00576 00577 00579 // perform an actual noise advection step 00581 /*void WTURBULENCE::stepTurbulenceReadable(float dtOrg, float* xvel, float* yvel, float* zvel, unsigned char *obstacles) 00582 { 00583 // enlarge timestep to match grid 00584 const float dt = dtOrg * _amplify; 00585 const float invAmp = 1.0f / _amplify; 00586 float *tempBig1 = new float[_totalCellsBig]; 00587 float *tempBig2 = new float[_totalCellsBig]; 00588 float *bigUx = new float[_totalCellsBig]; 00589 float *bigUy = new float[_totalCellsBig]; 00590 float *bigUz = new float[_totalCellsBig]; 00591 float *_energy = new float[_totalCellsSm]; 00592 float *highFreqEnergy = new float[_totalCellsSm]; 00593 float *eigMin = new float[_totalCellsSm]; 00594 float *eigMax = new float[_totalCellsSm]; 00595 00596 memset(tempBig1, 0, sizeof(float)*_totalCellsBig); 00597 memset(tempBig2, 0, sizeof(float)*_totalCellsBig); 00598 memset(highFreqEnergy, 0, sizeof(float)*_totalCellsSm); 00599 memset(eigMin, 0, sizeof(float)*_totalCellsSm); 00600 memset(eigMax, 0, sizeof(float)*_totalCellsSm); 00601 00602 // prepare textures 00603 advectTextureCoordinates(dtOrg, xvel,yvel,zvel, tempBig1, tempBig2); 00604 00605 // compute eigenvalues of the texture coordinates 00606 computeEigenvalues(eigMin, eigMax); 00607 00608 // do wavelet decomposition of energy 00609 computeEnergy(_energy, xvel, yvel, zvel, obstacles); 00610 decomposeEnergy(_energy, highFreqEnergy); 00611 00612 // zero out coefficients inside of the obstacle 00613 for (int x = 0; x < _totalCellsSm; x++) 00614 if (obstacles[x]) _energy[x] = 0.f; 00615 00616 float maxVelocity = 0.; 00617 for (int z = 1; z < _zResBig - 1; z++) 00618 for (int y = 1; y < _yResBig - 1; y++) 00619 for (int x = 1; x < _xResBig - 1; x++) 00620 { 00621 // get unit position for both fine and coarse grid 00622 const Vec3 pos = Vec3(x,y,z); 00623 const Vec3 posSm = pos * invAmp; 00624 00625 // get grid index for both fine and coarse grid 00626 const int index = x + y *_xResBig + z *_slabSizeBig; 00627 const int indexSmall = (int)posSm[0] + (int)posSm[1] * _xResSm + (int)posSm[2] * _slabSizeSm; 00628 00629 // get a linearly interpolated velocity and texcoords 00630 // from the coarse grid 00631 Vec3 vel = INTERPOLATE::lerp3dVec( xvel,yvel,zvel, 00632 posSm[0], posSm[1], posSm[2], _xResSm,_yResSm,_zResSm); 00633 Vec3 uvw = INTERPOLATE::lerp3dVec( _tcU,_tcV,_tcW, 00634 posSm[0], posSm[1], posSm[2], _xResSm,_yResSm,_zResSm); 00635 00636 // multiply the texture coordinate by _resSm so that turbulence 00637 // synthesis begins at the first octave that the coarse grid 00638 // cannot capture 00639 Vec3 texCoord = Vec3(uvw[0] * _resSm[0], 00640 uvw[1] * _resSm[1], 00641 uvw[2] * _resSm[2]); 00642 00643 // retrieve wavelet energy at highest frequency 00644 float energy = INTERPOLATE::lerp3d( 00645 highFreqEnergy, posSm[0],posSm[1],posSm[2], _xResSm, _yResSm, _zResSm); 00646 00647 // base amplitude for octave 0 00648 float coefficient = sqrtf(2.0f * fabs(energy)); 00649 const float amplitude = *_strength * fabs(0.5 * coefficient) * persistence; 00650 00651 // add noise to velocity, but only if the turbulence is 00652 // sufficiently undeformed, and the energy is large enough 00653 // to make a difference 00654 const bool addNoise = eigMax[indexSmall] < 2. && 00655 eigMin[indexSmall] > 0.5; 00656 if (addNoise && amplitude > _cullingThreshold) { 00657 // base amplitude for octave 0 00658 float amplitudeScaled = amplitude; 00659 00660 for (int octave = 0; octave < _octaves; octave++) 00661 { 00662 // multiply the vector noise times the maximum allowed 00663 // noise amplitude at this octave, and add it to the total 00664 vel += WVelocity(texCoord) * amplitudeScaled; 00665 00666 // scale coefficient for next octave 00667 amplitudeScaled *= persistence; 00668 texCoord *= 2.0f; 00669 } 00670 } 00671 00672 // Store velocity + turbulence in big grid for maccormack step 00673 // 00674 // If you wanted to save memory, you would instead perform a 00675 // semi-Lagrangian backtrace for the current grid cell here. Then 00676 // you could just throw the velocity away. 00677 bigUx[index] = vel[0]; 00678 bigUy[index] = vel[1]; 00679 bigUz[index] = vel[2]; 00680 00681 // compute the velocity magnitude for substepping later 00682 const float velMag = bigUx[index] * bigUx[index] + 00683 bigUy[index] * bigUy[index] + 00684 bigUz[index] * bigUz[index]; 00685 if (velMag > maxVelocity) maxVelocity = velMag; 00686 00687 // zero out velocity inside obstacles 00688 float obsCheck = INTERPOLATE::lerp3dToFloat( 00689 obstacles, posSm[0], posSm[1], posSm[2], _xResSm, _yResSm, _zResSm); 00690 if (obsCheck > 0.95) 00691 bigUx[index] = bigUy[index] = bigUz[index] = 0.; 00692 } 00693 00694 // prepare density for an advection 00695 SWAP_POINTERS(_densityBig, _densityBigOld); 00696 00697 // based on the maximum velocity present, see if we need to substep, 00698 // but cap the maximum number of substeps to 5 00699 const int maxSubSteps = 5; 00700 maxVelocity = sqrt(maxVelocity) * dt; 00701 int totalSubsteps = (int)(maxVelocity / (float)maxSubSteps); 00702 totalSubsteps = (totalSubsteps < 1) ? 1 : totalSubsteps; 00703 totalSubsteps = (totalSubsteps > maxSubSteps) ? maxSubSteps : totalSubsteps; 00704 const float dtSubdiv = dt / (float)totalSubsteps; 00705 00706 // set boundaries of big velocity grid 00707 FLUID_3D::setZeroX(bigUx, _resBig, 0, _resBig[2]); 00708 FLUID_3D::setZeroY(bigUy, _resBig, 0, _resBig[2]); 00709 FLUID_3D::setZeroZ(bigUz, _resBig, 0, _resBig[2]); 00710 00711 // do the MacCormack advection, with substepping if necessary 00712 for(int substep = 0; substep < totalSubsteps; substep++) 00713 { 00714 FLUID_3D::advectFieldMacCormack(dtSubdiv, bigUx, bigUy, bigUz, 00715 _densityBigOld, _densityBig, tempBig1, tempBig2, _resBig, NULL); 00716 00717 if (substep < totalSubsteps - 1) 00718 SWAP_POINTERS(_densityBig, _densityBigOld); 00719 } // substep 00720 00721 // wipe the density borders 00722 FLUID_3D::setZeroBorder(_densityBig, _resBig, 0, _resBig[2]); 00723 00724 // reset texture coordinates now in preparation for next timestep 00725 // Shouldn't do this before generating the noise because then the 00726 // eigenvalues stored do not reflect the underlying texture coordinates 00727 resetTextureCoordinates(eigMin, eigMax); 00728 00729 delete[] tempBig1; 00730 delete[] tempBig2; 00731 delete[] bigUx; 00732 delete[] bigUy; 00733 delete[] bigUz; 00734 delete[] _energy; 00735 delete[] highFreqEnergy; 00736 00737 delete[] eigMin; 00738 delete[] eigMax; 00739 00740 00741 _totalStepsBig++; 00742 }*/ 00743 00744 //struct 00745 00747 // perform the full turbulence algorithm, including OpenMP 00748 // if available 00750 void WTURBULENCE::stepTurbulenceFull(float dtOrg, float* xvel, float* yvel, float* zvel, unsigned char *obstacles) 00751 { 00752 // enlarge timestep to match grid 00753 const float dt = dtOrg * _amplify; 00754 const float invAmp = 1.0f / _amplify; 00755 float *tempBig1 = (float *)calloc(_totalCellsBig, sizeof(float)); 00756 float *tempBig2 = (float *)calloc(_totalCellsBig, sizeof(float)); 00757 float *bigUx = (float *)calloc(_totalCellsBig, sizeof(float)); 00758 float *bigUy = (float *)calloc(_totalCellsBig, sizeof(float)); 00759 float *bigUz = (float *)calloc(_totalCellsBig, sizeof(float)); 00760 float *_energy = (float *)calloc(_totalCellsSm, sizeof(float)); 00761 float *highFreqEnergy = (float *)calloc(_totalCellsSm, sizeof(float)); 00762 float *eigMin = (float *)calloc(_totalCellsSm, sizeof(float)); 00763 float *eigMax = (float *)calloc(_totalCellsSm, sizeof(float)); 00764 00765 memset(_tcTemp, 0, sizeof(float)*_totalCellsSm); 00766 00767 00768 // prepare textures 00769 advectTextureCoordinates(dtOrg, xvel,yvel,zvel, tempBig1, tempBig2); 00770 00771 // do wavelet decomposition of energy 00772 computeEnergy(_energy, xvel, yvel, zvel, obstacles); 00773 00774 for (int x = 0; x < _totalCellsSm; x++) 00775 if (obstacles[x]) _energy[x] = 0.f; 00776 00777 decomposeEnergy(_energy, highFreqEnergy); 00778 00779 // zero out coefficients inside of the obstacle 00780 for (int x = 0; x < _totalCellsSm; x++) 00781 if (obstacles[x]) highFreqEnergy[x] = 0.f; 00782 00783 Vec3Int ressm(_xResSm, _yResSm, _zResSm); 00784 FLUID_3D::setNeumannX(highFreqEnergy, ressm, 0 , ressm[2]); 00785 FLUID_3D::setNeumannY(highFreqEnergy, ressm, 0 , ressm[2]); 00786 FLUID_3D::setNeumannZ(highFreqEnergy, ressm, 0 , ressm[2]); 00787 00788 00789 int threadval = 1; 00790 #if PARALLEL==1 00791 threadval = omp_get_max_threads(); 00792 #endif 00793 00794 00795 // parallel region setup 00796 // Uses omp_get_max_trheads to get number of required cells. 00797 float* maxVelMagThreads = new float[threadval]; 00798 00799 for (int i=0; i<threadval; i++) maxVelMagThreads[i] = -1.0f; 00800 00801 #if PARALLEL==1 00802 00803 #pragma omp parallel 00804 #endif 00805 { float maxVelMag1 = 0.; 00806 #if PARALLEL==1 00807 const int id = omp_get_thread_num(); /*, num = omp_get_num_threads(); */ 00808 #endif 00809 00810 // vector noise main loop 00811 #if PARALLEL==1 00812 #pragma omp for schedule(static,1) 00813 #endif 00814 for (int zSmall = 0; zSmall < _zResSm; zSmall++) 00815 { 00816 for (int ySmall = 0; ySmall < _yResSm; ySmall++) 00817 for (int xSmall = 0; xSmall < _xResSm; xSmall++) 00818 { 00819 const int indexSmall = xSmall + ySmall * _xResSm + zSmall * _slabSizeSm; 00820 00821 // compute jacobian 00822 float jacobian[3][3] = { 00823 { minDx(xSmall, ySmall, zSmall, _tcU, _resSm), minDx(xSmall, ySmall, zSmall, _tcV, _resSm), minDx(xSmall, ySmall, zSmall, _tcW, _resSm) } , 00824 { minDy(xSmall, ySmall, zSmall, _tcU, _resSm), minDy(xSmall, ySmall, zSmall, _tcV, _resSm), minDy(xSmall, ySmall, zSmall, _tcW, _resSm) } , 00825 { minDz(xSmall, ySmall, zSmall, _tcU, _resSm), minDz(xSmall, ySmall, zSmall, _tcV, _resSm), minDz(xSmall, ySmall, zSmall, _tcW, _resSm) } 00826 }; 00827 00828 // get LU factorization of texture jacobian and apply 00829 // it to unit vectors 00830 sLU LU = computeLU(jacobian); 00831 float xUnwarped[3], yUnwarped[3], zUnwarped[3]; 00832 float xWarped[3], yWarped[3], zWarped[3]; 00833 bool nonSingular = isNonsingular(LU); 00834 00835 xUnwarped[0] = 1.0f; xUnwarped[1] = 0.0f; xUnwarped[2] = 0.0f; 00836 yUnwarped[0] = 0.0f; yUnwarped[1] = 1.0f; yUnwarped[2] = 0.0f; 00837 zUnwarped[0] = 0.0f; zUnwarped[1] = 0.0f; zUnwarped[2] = 1.0f; 00838 00839 xWarped[0] = 1.0f; xWarped[1] = 0.0f; xWarped[2] = 0.0f; 00840 yWarped[0] = 0.0f; yWarped[1] = 1.0f; yWarped[2] = 0.0f; 00841 zWarped[0] = 0.0f; zWarped[1] = 0.0f; zWarped[2] = 1.0f; 00842 00843 #if 0 00844 // UNUSED 00845 float eigMax = 10.0f; 00846 float eigMin = 0.1f; 00847 #endif 00848 if (nonSingular) 00849 { 00850 solveLU3x3(LU, xUnwarped, xWarped); 00851 solveLU3x3(LU, yUnwarped, yWarped); 00852 solveLU3x3(LU, zUnwarped, zWarped); 00853 00854 // compute the eigenvalues while we have the Jacobian available 00855 Vec3 eigenvalues = Vec3(1.); 00856 computeEigenvalues3x3( &eigenvalues[0], jacobian); 00857 eigMax[indexSmall] = MAX3V(eigenvalues); 00858 eigMin[indexSmall] = MIN3V(eigenvalues); 00859 } 00860 00861 // make sure to skip one on the beginning and end 00862 int xStart = (xSmall == 0) ? 1 : 0; 00863 int xEnd = (xSmall == _xResSm - 1) ? _amplify - 1 : _amplify; 00864 int yStart = (ySmall == 0) ? 1 : 0; 00865 int yEnd = (ySmall == _yResSm - 1) ? _amplify - 1 : _amplify; 00866 int zStart = (zSmall == 0) ? 1 : 0; 00867 int zEnd = (zSmall == _zResSm - 1) ? _amplify - 1 : _amplify; 00868 00869 for (int zBig = zStart; zBig < zEnd; zBig++) 00870 for (int yBig = yStart; yBig < yEnd; yBig++) 00871 for (int xBig = xStart; xBig < xEnd; xBig++) 00872 { 00873 const int x = xSmall * _amplify + xBig; 00874 const int y = ySmall * _amplify + yBig; 00875 const int z = zSmall * _amplify + zBig; 00876 00877 // get unit position for both fine and coarse grid 00878 const Vec3 pos = Vec3(x,y,z); 00879 const Vec3 posSm = pos * invAmp; 00880 00881 // get grid index for both fine and coarse grid 00882 const int index = x + y *_xResBig + z *_slabSizeBig; 00883 00884 // get a linearly interpolated velocity and texcoords 00885 // from the coarse grid 00886 Vec3 vel = INTERPOLATE::lerp3dVec( xvel,yvel,zvel, 00887 posSm[0], posSm[1], posSm[2], _xResSm,_yResSm,_zResSm); 00888 Vec3 uvw = INTERPOLATE::lerp3dVec( _tcU,_tcV,_tcW, 00889 posSm[0], posSm[1], posSm[2], _xResSm,_yResSm,_zResSm); 00890 00891 // multiply the texture coordinate by _resSm so that turbulence 00892 // synthesis begins at the first octave that the coarse grid 00893 // cannot capture 00894 Vec3 texCoord = Vec3(uvw[0] * _resSm[0], 00895 uvw[1] * _resSm[1], 00896 uvw[2] * _resSm[2]); 00897 00898 // retrieve wavelet energy at highest frequency 00899 float energy = INTERPOLATE::lerp3d( 00900 highFreqEnergy, posSm[0],posSm[1],posSm[2], _xResSm, _yResSm, _zResSm); 00901 00902 // base amplitude for octave 0 00903 float coefficient = sqrtf(2.0f * fabs(energy)); 00904 const float amplitude = *_strength * fabs(0.5 * coefficient) * persistence; 00905 00906 // add noise to velocity, but only if the turbulence is 00907 // sufficiently undeformed, and the energy is large enough 00908 // to make a difference 00909 const bool addNoise = eigMax[indexSmall] < 2. && 00910 eigMin[indexSmall] > 0.5; 00911 if (addNoise && amplitude > _cullingThreshold) { 00912 // base amplitude for octave 0 00913 float amplitudeScaled = amplitude; 00914 00915 for (int octave = 0; octave < _octaves; octave++) 00916 { 00917 // multiply the vector noise times the maximum allowed 00918 // noise amplitude at this octave, and add it to the total 00919 vel += WVelocityWithJacobian(texCoord, &xUnwarped[0], &yUnwarped[0], &zUnwarped[0]) * amplitudeScaled; 00920 00921 // scale coefficient for next octave 00922 amplitudeScaled *= persistence; 00923 texCoord *= 2.0f; 00924 } 00925 } 00926 00927 // Store velocity + turbulence in big grid for maccormack step 00928 // 00929 // If you wanted to save memory, you would instead perform a 00930 // semi-Lagrangian backtrace for the current grid cell here. Then 00931 // you could just throw the velocity away. 00932 bigUx[index] = vel[0]; 00933 bigUy[index] = vel[1]; 00934 bigUz[index] = vel[2]; 00935 00936 // compute the velocity magnitude for substepping later 00937 const float velMag = bigUx[index] * bigUx[index] + 00938 bigUy[index] * bigUy[index] + 00939 bigUz[index] * bigUz[index]; 00940 if (velMag > maxVelMag1) maxVelMag1 = velMag; 00941 00942 // zero out velocity inside obstacles 00943 float obsCheck = INTERPOLATE::lerp3dToFloat( 00944 obstacles, posSm[0], posSm[1], posSm[2], _xResSm, _yResSm, _zResSm); 00945 if (obsCheck > 0.95) 00946 bigUx[index] = bigUy[index] = bigUz[index] = 0.; 00947 } // xyz*/ 00948 00949 #if PARALLEL==1 00950 maxVelMagThreads[id] = maxVelMag1; 00951 #else 00952 maxVelMagThreads[0] = maxVelMag1; 00953 #endif 00954 } 00955 } 00956 } // omp 00957 00958 // compute maximum over threads 00959 float maxVelMag = maxVelMagThreads[0]; 00960 #if PARALLEL==1 00961 for (int i = 1; i < threadval; i++) 00962 if (maxVelMag < maxVelMagThreads[i]) 00963 maxVelMag = maxVelMagThreads[i]; 00964 #endif 00965 delete [] maxVelMagThreads; 00966 00967 00968 // prepare density for an advection 00969 SWAP_POINTERS(_densityBig, _densityBigOld); 00970 00971 // based on the maximum velocity present, see if we need to substep, 00972 // but cap the maximum number of substeps to 5 00973 const int maxSubSteps = 25; 00974 const int maxVel = 5; 00975 maxVelMag = sqrt(maxVelMag) * dt; 00976 int totalSubsteps = (int)(maxVelMag / (float)maxVel); 00977 totalSubsteps = (totalSubsteps < 1) ? 1 : totalSubsteps; 00978 // printf("totalSubsteps: %d\n", totalSubsteps); 00979 totalSubsteps = (totalSubsteps > maxSubSteps) ? maxSubSteps : totalSubsteps; 00980 const float dtSubdiv = dt / (float)totalSubsteps; 00981 00982 // set boundaries of big velocity grid 00983 FLUID_3D::setZeroX(bigUx, _resBig, 0 , _resBig[2]); 00984 FLUID_3D::setZeroY(bigUy, _resBig, 0 , _resBig[2]); 00985 FLUID_3D::setZeroZ(bigUz, _resBig, 0 , _resBig[2]); 00986 00987 #if PARALLEL==1 00988 int stepParts = threadval*2; // Dividing parallelized sections into numOfThreads * 2 sections 00989 float partSize = (float)_zResBig/stepParts; // Size of one part; 00990 00991 if (partSize < 4) {stepParts = threadval; // If the slice gets too low (might actually slow things down, change it to larger 00992 partSize = (float)_zResBig/stepParts;} 00993 if (partSize < 4) {stepParts = (int)(ceil((float)_zResBig/4.0f)); // If it's still too low (only possible on future systems with +24 cores), change it to 4 00994 partSize = (float)_zResBig/stepParts;} 00995 #else 00996 int zBegin=0; 00997 int zEnd=_resBig[2]; 00998 #endif 00999 01000 // do the MacCormack advection, with substepping if necessary 01001 for(int substep = 0; substep < totalSubsteps; substep++) 01002 { 01003 01004 #if PARALLEL==1 01005 #pragma omp parallel 01006 { 01007 01008 #pragma omp for schedule(static,1) 01009 for (int i=0; i<stepParts; i++) 01010 { 01011 int zBegin = (int)((float)i*partSize + 0.5f); 01012 int zEnd = (int)((float)(i+1)*partSize + 0.5f); 01013 #endif 01014 FLUID_3D::advectFieldMacCormack1(dtSubdiv, bigUx, bigUy, bigUz, 01015 _densityBigOld, tempBig1, _resBig, zBegin, zEnd); 01016 #if PARALLEL==1 01017 } 01018 01019 #pragma omp barrier 01020 01021 #pragma omp for schedule(static,1) 01022 for (int i=0; i<stepParts; i++) 01023 { 01024 int zBegin = (int)((float)i*partSize + 0.5f); 01025 int zEnd = (int)((float)(i+1)*partSize + 0.5f); 01026 #endif 01027 FLUID_3D::advectFieldMacCormack2(dtSubdiv, bigUx, bigUy, bigUz, 01028 _densityBigOld, _densityBig, tempBig1, tempBig2, _resBig, NULL, zBegin, zEnd); 01029 #if PARALLEL==1 01030 } 01031 } 01032 #endif 01033 01034 if (substep < totalSubsteps - 1) 01035 SWAP_POINTERS(_densityBig, _densityBigOld); 01036 } // substep 01037 01038 free(tempBig1); 01039 free(tempBig2); 01040 free(bigUx); 01041 free(bigUy); 01042 free(bigUz); 01043 free(_energy); 01044 free(highFreqEnergy); 01045 01046 // wipe the density borders 01047 FLUID_3D::setZeroBorder(_densityBig, _resBig, 0 , _resBig[2]); 01048 01049 // reset texture coordinates now in preparation for next timestep 01050 // Shouldn't do this before generating the noise because then the 01051 // eigenvalues stored do not reflect the underlying texture coordinates 01052 resetTextureCoordinates(eigMin, eigMax); 01053 01054 free(eigMin); 01055 free(eigMax); 01056 01057 // output files 01058 // string prefix = string("./amplified.preview/density_bigxy_"); 01059 // FLUID_3D::writeImageSliceXY(_densityBig, _resBig, _resBig[2]/2, prefix, _totalStepsBig, 1.0f); 01060 //string df3prefix = string("./df3/density_big_"); 01061 //IMAGE::dumpDF3(_totalStepsBig, df3prefix, _densityBig, _resBig[0],_resBig[1],_resBig[2]); 01062 // string pbrtPrefix = string("./pbrt/density_big_"); 01063 // IMAGE::dumpPBRT(_totalStepsBig, pbrtPrefix, _densityBig, _resBig[0],_resBig[1],_resBig[2]); 01064 01065 _totalStepsBig++; 01066 }