diff options
Diffstat (limited to 'intern/smoke/intern/WTURBULENCE.cpp')
-rw-r--r-- | intern/smoke/intern/WTURBULENCE.cpp | 259 |
1 files changed, 123 insertions, 136 deletions
diff --git a/intern/smoke/intern/WTURBULENCE.cpp b/intern/smoke/intern/WTURBULENCE.cpp index a1b2aaf30f2..db7a1b55afa 100644 --- a/intern/smoke/intern/WTURBULENCE.cpp +++ b/intern/smoke/intern/WTURBULENCE.cpp @@ -81,9 +81,25 @@ WTURBULENCE::WTURBULENCE(int xResSm, int yResSm, int zResSm, int amplify, int no _densityBig = new float[_totalCellsBig]; _densityBigOld = new float[_totalCellsBig]; + // allocate high resolution velocity field. Note that this is only + // necessary because we use MacCormack advection. For semi-Lagrangian + // advection, these arrays are not necessary. + _tempBig1 = _tempBig2 = + _bigUx = _bigUy = _bigUz = NULL; + _tempBig1 = new float[_totalCellsBig]; + _tempBig2 = new float[_totalCellsBig]; + _bigUx = new float[_totalCellsBig]; + _bigUy = new float[_totalCellsBig]; + _bigUz = new float[_totalCellsBig]; + for(int i = 0; i < _totalCellsBig; i++) { _densityBig[i] = - _densityBigOld[i] = 0.; + _densityBigOld[i] = + _bigUx[i] = + _bigUy[i] = + _bigUz[i] = + _tempBig1[i] = + _tempBig2[i] = 0.; } // allocate & init texture coordinates @@ -92,6 +108,10 @@ WTURBULENCE::WTURBULENCE(int xResSm, int yResSm, int zResSm, int amplify, int no _tcW = new float[_totalCellsSm]; _tcTemp = new float[_totalCellsSm]; + // allocate & init energy terms + _energy = new float[_totalCellsSm]; + _highFreqEnergy = new float[_totalCellsSm]; + // map all const float dx = 1./(float)(_resSm[0]); const float dy = 1./(float)(_resSm[1]); @@ -105,8 +125,15 @@ WTURBULENCE::WTURBULENCE(int xResSm, int yResSm, int zResSm, int amplify, int no _tcV[index] = y*dy; _tcW[index] = z*dz; _tcTemp[index] = 0.; + _energy[index] = 0.; } + // allocate eigenvalue arrays + _eigMin = new float[_totalCellsSm]; + _eigMax = new float[_totalCellsSm]; + for(int i=0; i < _totalCellsSm; i++) + _eigMin[i] = _eigMax[i] = 0.; + // noise tiles _noiseTile = new float[noiseTileSize * noiseTileSize * noiseTileSize]; /* @@ -127,12 +154,23 @@ WTURBULENCE::~WTURBULENCE() { delete[] _densityBig; delete[] _densityBigOld; + delete[] _bigUx; + delete[] _bigUy; + delete[] _bigUz; + delete[] _tempBig1; + delete[] _tempBig2; + delete[] _tcU; delete[] _tcV; delete[] _tcW; delete[] _tcTemp; + delete[] _eigMin; + delete[] _eigMax; delete[] _noiseTile; + + delete[] _energy; + delete[] _highFreqEnergy; } ////////////////////////////////////////////////////////////////////// @@ -277,34 +315,34 @@ static float minDz(int x, int y, int z, float* input, Vec3Int res) // handle texture coordinates (advection, reset, eigenvalues), // Beware -- uses big density maccormack as temporary arrays ////////////////////////////////////////////////////////////////////// -void WTURBULENCE::advectTextureCoordinates (float dtOrg, float* xvel, float* yvel, float* zvel, float *tempBig1, float *tempBig2) { +void WTURBULENCE::advectTextureCoordinates (float dtOrg, float* xvel, float* yvel, float* zvel) { // advection SWAP_POINTERS(_tcTemp, _tcU); FLUID_3D::copyBorderX(_tcTemp, _resSm); FLUID_3D::copyBorderY(_tcTemp, _resSm); FLUID_3D::copyBorderZ(_tcTemp, _resSm); FLUID_3D::advectFieldMacCormack(dtOrg, xvel, yvel, zvel, - _tcTemp, _tcU, tempBig1, tempBig2, _resSm, NULL); + _tcTemp, _tcU, _tempBig1, _tempBig2, _resSm, NULL); SWAP_POINTERS(_tcTemp, _tcV); FLUID_3D::copyBorderX(_tcTemp, _resSm); FLUID_3D::copyBorderY(_tcTemp, _resSm); FLUID_3D::copyBorderZ(_tcTemp, _resSm); FLUID_3D::advectFieldMacCormack(dtOrg, xvel, yvel, zvel, - _tcTemp, _tcV, tempBig1, tempBig2, _resSm, NULL); + _tcTemp, _tcV, _tempBig1, _tempBig2, _resSm, NULL); SWAP_POINTERS(_tcTemp, _tcW); FLUID_3D::copyBorderX(_tcTemp, _resSm); FLUID_3D::copyBorderY(_tcTemp, _resSm); FLUID_3D::copyBorderZ(_tcTemp, _resSm); FLUID_3D::advectFieldMacCormack(dtOrg, xvel, yvel, zvel, - _tcTemp, _tcW, tempBig1, tempBig2, _resSm, NULL); + _tcTemp, _tcW, _tempBig1, _tempBig2, _resSm, NULL); } ////////////////////////////////////////////////////////////////////// // Compute the eigenvalues of the advected texture ////////////////////////////////////////////////////////////////////// -void WTURBULENCE::computeEigenvalues(float *_eigMin, float *_eigMax) { +void WTURBULENCE::computeEigenvalues() { // stats float maxeig = -1.; float mineig = 10.; @@ -349,7 +387,7 @@ void WTURBULENCE::computeEigenvalues(float *_eigMin, float *_eigMax) { ////////////////////////////////////////////////////////////////////// // advect & reset texture coordinates based on eigenvalues ////////////////////////////////////////////////////////////////////// -void WTURBULENCE::resetTextureCoordinates(float *_eigMin, float *_eigMax) +void WTURBULENCE::resetTextureCoordinates() { // allowed deformation of the textures const float limit = 2.f; @@ -380,7 +418,7 @@ void WTURBULENCE::resetTextureCoordinates(float *_eigMin, float *_eigMax) // Compute the highest frequency component of the wavelet // decomposition ////////////////////////////////////////////////////////////////////// -void WTURBULENCE::decomposeEnergy(float *_energy, float *_highFreqEnergy) +void WTURBULENCE::decomposeEnergy() { // do the decomposition -- the goal here is to have // the energy with the high frequency component stomped out @@ -416,7 +454,7 @@ void WTURBULENCE::decomposeEnergy(float *_energy, float *_highFreqEnergy) // compute velocity from energies and march into obstacles // for wavelet decomposition ////////////////////////////////////////////////////////////////////// -void WTURBULENCE::computeEnergy(float *_energy, float* xvel, float* yvel, float* zvel, unsigned char *obstacles) +void WTURBULENCE::computeEnergy(float* xvel, float* yvel, float* zvel, unsigned char *obstacles) { // compute everywhere for (int x = 0; x < _totalCellsSm; x++) @@ -475,7 +513,7 @@ void WTURBULENCE::computeEnergy(float *_energy, float* xvel, float* yvel, float* } if (valid > 0) { - _energy[index] = sum / (float)valid; + _energy[index] = sum / valid; obstacles[index] = MARCHED; } } @@ -500,9 +538,9 @@ void WTURBULENCE::computeEnergy(float *_energy, float* xvel, float* yvel, float* Vec3 WTURBULENCE::WVelocity(Vec3 orgPos) { // arbitrarily offset evaluation points - const Vec3 p1 = orgPos + Vec3(NOISE_TILE_SIZE/2.0,0,0); - const Vec3 p2 = orgPos + Vec3(0,NOISE_TILE_SIZE/2.0,0); - const Vec3 p3 = orgPos + Vec3(0,0,NOISE_TILE_SIZE/2.0); + const Vec3 p1 = orgPos + Vec3(NOISE_TILE_SIZE/2,0,0); + const Vec3 p2 = orgPos + Vec3(0,NOISE_TILE_SIZE/2,0); + const Vec3 p3 = orgPos + Vec3(0,0,NOISE_TILE_SIZE/2); const float f1y = WNoiseDy(p1, _noiseTile); const float f1z = WNoiseDz(p1, _noiseTile); @@ -526,9 +564,9 @@ Vec3 WTURBULENCE::WVelocity(Vec3 orgPos) Vec3 WTURBULENCE::WVelocityWithJacobian(Vec3 orgPos, float* xUnwarped, float* yUnwarped, float* zUnwarped) { // arbitrarily offset evaluation points - const Vec3 p1 = orgPos + Vec3(NOISE_TILE_SIZE/2.0,0,0); - const Vec3 p2 = orgPos + Vec3(0,NOISE_TILE_SIZE/2.0,0); - const Vec3 p3 = orgPos + Vec3(0,0,NOISE_TILE_SIZE/2.0); + const Vec3 p1 = orgPos + Vec3(NOISE_TILE_SIZE/2,0,0); + const Vec3 p2 = orgPos + Vec3(0,NOISE_TILE_SIZE/2,0); + const Vec3 p3 = orgPos + Vec3(0,0,NOISE_TILE_SIZE/2); Vec3 final; final[0] = WNoiseDx(p1, _noiseTile); @@ -559,40 +597,24 @@ Vec3 WTURBULENCE::WVelocityWithJacobian(Vec3 orgPos, float* xUnwarped, float* yU return ret; } - ////////////////////////////////////////////////////////////////////// // perform an actual noise advection step ////////////////////////////////////////////////////////////////////// void WTURBULENCE::stepTurbulenceReadable(float dtOrg, float* xvel, float* yvel, float* zvel, unsigned char *obstacles) { - // enlarge timestep to match grid - const float dt = dtOrg * _amplify; - const float invAmp = 1.0f / _amplify; - float *tempBig1 = new float[_totalCellsBig]; - float *tempBig2 = new float[_totalCellsBig]; - float *bigUx = new float[_totalCellsBig]; - float *bigUy = new float[_totalCellsBig]; - float *bigUz = new float[_totalCellsBig]; - float *_energy = new float[_totalCellsSm]; - float *highFreqEnergy = new float[_totalCellsSm]; - float *eigMin = new float[_totalCellsSm]; - float *eigMax = new float[_totalCellsSm]; - - memset(tempBig1, 0, sizeof(float)*_totalCellsBig); - memset(tempBig2, 0, sizeof(float)*_totalCellsBig); - memset(highFreqEnergy, 0, sizeof(float)*_totalCellsSm); - memset(eigMin, 0, sizeof(float)*_totalCellsSm); - memset(eigMax, 0, sizeof(float)*_totalCellsSm); - - // prepare textures - advectTextureCoordinates(dtOrg, xvel,yvel,zvel, tempBig1, tempBig2); + // enlarge timestep to match grid + const float dt = dtOrg * _amplify; + const float invAmp = 1.0f / _amplify; + + // prepare textures + advectTextureCoordinates(dtOrg, xvel,yvel,zvel); // compute eigenvalues of the texture coordinates - computeEigenvalues(eigMin, eigMax); + computeEigenvalues(); // do wavelet decomposition of energy - computeEnergy(_energy, xvel, yvel, zvel, obstacles); - decomposeEnergy(_energy, highFreqEnergy); + computeEnergy(xvel, yvel, zvel, obstacles); + decomposeEnergy(); // zero out coefficients inside of the obstacle for (int x = 0; x < _totalCellsSm; x++) @@ -627,7 +649,7 @@ void WTURBULENCE::stepTurbulenceReadable(float dtOrg, float* xvel, float* yvel, // retrieve wavelet energy at highest frequency float energy = INTERPOLATE::lerp3d( - highFreqEnergy, posSm[0],posSm[1],posSm[2], _xResSm, _yResSm, _zResSm); + _highFreqEnergy, posSm[0],posSm[1],posSm[2], _xResSm, _yResSm, _zResSm); // base amplitude for octave 0 float coefficient = sqrtf(2.0f * fabs(energy)); @@ -636,8 +658,8 @@ void WTURBULENCE::stepTurbulenceReadable(float dtOrg, float* xvel, float* yvel, // add noise to velocity, but only if the turbulence is // sufficiently undeformed, and the energy is large enough // to make a difference - const bool addNoise = eigMax[indexSmall] < 2. && - eigMin[indexSmall] > 0.5; + const bool addNoise = _eigMax[indexSmall] < 2. && + _eigMin[indexSmall] > 0.5; if (addNoise && amplitude > _cullingThreshold) { // base amplitude for octave 0 float amplitudeScaled = amplitude; @@ -659,21 +681,21 @@ void WTURBULENCE::stepTurbulenceReadable(float dtOrg, float* xvel, float* yvel, // If you wanted to save memory, you would instead perform a // semi-Lagrangian backtrace for the current grid cell here. Then // you could just throw the velocity away. - bigUx[index] = vel[0]; - bigUy[index] = vel[1]; - bigUz[index] = vel[2]; + _bigUx[index] = vel[0]; + _bigUy[index] = vel[1]; + _bigUz[index] = vel[2]; // compute the velocity magnitude for substepping later - const float velMag = bigUx[index] * bigUx[index] + - bigUy[index] * bigUy[index] + - bigUz[index] * bigUz[index]; + const float velMag = _bigUx[index] * _bigUx[index] + + _bigUy[index] * _bigUy[index] + + _bigUz[index] * _bigUz[index]; if (velMag > maxVelocity) maxVelocity = velMag; // zero out velocity inside obstacles float obsCheck = INTERPOLATE::lerp3dToFloat( obstacles, posSm[0], posSm[1], posSm[2], _xResSm, _yResSm, _zResSm); if (obsCheck > 0.95) - bigUx[index] = bigUy[index] = bigUz[index] = 0.; + _bigUx[index] = _bigUy[index] = _bigUz[index] = 0.; } // prepare density for an advection @@ -681,23 +703,24 @@ void WTURBULENCE::stepTurbulenceReadable(float dtOrg, float* xvel, float* yvel, // based on the maximum velocity present, see if we need to substep, // but cap the maximum number of substeps to 5 - const int maxSubSteps = 5; + const int maxSubSteps = 25; + const int maxVel = 5; maxVelocity = sqrt(maxVelocity) * dt; - int totalSubsteps = (int)(maxVelocity / (float)maxSubSteps); + int totalSubsteps = (int)(maxVelocity / (float)maxVel); totalSubsteps = (totalSubsteps < 1) ? 1 : totalSubsteps; totalSubsteps = (totalSubsteps > maxSubSteps) ? maxSubSteps : totalSubsteps; const float dtSubdiv = dt / (float)totalSubsteps; // set boundaries of big velocity grid - FLUID_3D::setZeroX(bigUx, _resBig); - FLUID_3D::setZeroY(bigUy, _resBig); - FLUID_3D::setZeroZ(bigUz, _resBig); + FLUID_3D::setZeroX(_bigUx, _resBig); + FLUID_3D::setZeroY(_bigUy, _resBig); + FLUID_3D::setZeroZ(_bigUz, _resBig); // do the MacCormack advection, with substepping if necessary for(int substep = 0; substep < totalSubsteps; substep++) { - FLUID_3D::advectFieldMacCormack(dtSubdiv, bigUx, bigUy, bigUz, - _densityBigOld, _densityBig, tempBig1, tempBig2, _resBig, NULL); + FLUID_3D::advectFieldMacCormack(dtSubdiv, _bigUx, _bigUy, _bigUz, + _densityBigOld, _densityBig, _tempBig1, _tempBig2, _resBig, NULL); if (substep < totalSubsteps - 1) SWAP_POINTERS(_densityBig, _densityBigOld); @@ -709,20 +732,17 @@ void WTURBULENCE::stepTurbulenceReadable(float dtOrg, float* xvel, float* yvel, // reset texture coordinates now in preparation for next timestep // Shouldn't do this before generating the noise because then the // eigenvalues stored do not reflect the underlying texture coordinates - resetTextureCoordinates(eigMin, eigMax); - - delete[] tempBig1; - delete[] tempBig2; - delete[] bigUx; - delete[] bigUy; - delete[] bigUz; - delete[] _energy; - delete[] highFreqEnergy; - - delete[] eigMin; - delete[] eigMax; + resetTextureCoordinates(); - + // output files + /* + string prefix = string("./amplified.preview/density_bigxy_"); + FLUID_3D::writeImageSliceXY(_densityBig, _resBig, _resBig[2]/2, prefix, _totalStepsBig, 1.0f); + //string df3Prefix = string("./df3/density_big_"); + //IMAGE::dumpDF3(_totalStepsBig, df3Prefix, _densityBig, _resBig[0],_resBig[1],_resBig[2]); + string pbrtPrefix = string("./pbrt/density_big_"); + IMAGE::dumpPBRT(_totalStepsBig, pbrtPrefix, _densityBig, _resBig[0],_resBig[1],_resBig[2]); + */ _totalStepsBig++; } @@ -732,42 +752,20 @@ void WTURBULENCE::stepTurbulenceReadable(float dtOrg, float* xvel, float* yvel, ////////////////////////////////////////////////////////////////////// void WTURBULENCE::stepTurbulenceFull(float dtOrg, float* xvel, float* yvel, float* zvel, unsigned char *obstacles) { - // enlarge timestep to match grid - const float dt = dtOrg * _amplify; - const float invAmp = 1.0f / _amplify; - float *tempBig1 = new float[_totalCellsBig]; - float *tempBig2 = new float[_totalCellsBig]; - float *bigUx = new float[_totalCellsBig]; - float *bigUy = new float[_totalCellsBig]; - float *bigUz = new float[_totalCellsBig]; - float *_energy = new float[_totalCellsSm]; - float *highFreqEnergy = new float[_totalCellsSm]; - float *eigMin = new float[_totalCellsSm]; - float *eigMax = new float[_totalCellsSm]; - - memset(highFreqEnergy, 0, sizeof(float)*_totalCellsSm); - memset(eigMin, 0, sizeof(float)*_totalCellsSm); - memset(eigMax, 0, sizeof(float)*_totalCellsSm); - - // prepare textures - advectTextureCoordinates(dtOrg, xvel,yvel,zvel, tempBig1, tempBig2); - - // do wavelet decomposition of energy - computeEnergy(_energy, xvel, yvel, zvel, obstacles); - - for (int x = 0; x < _totalCellsSm; x++) - if (obstacles[x]) _energy[x] = 0.f; - - decomposeEnergy(_energy, highFreqEnergy); - - // zero out coefficients inside of the obstacle - for (int x = 0; x < _totalCellsSm; x++) - if (obstacles[x]) highFreqEnergy[x] = 0.f; - - Vec3Int ressm(_xResSm, _yResSm, _zResSm); - FLUID_3D::setNeumannX(highFreqEnergy, ressm); - FLUID_3D::setNeumannY(highFreqEnergy, ressm); - FLUID_3D::setNeumannZ(highFreqEnergy, ressm); + // enlarge timestep to match grid + const float dt = dtOrg * _amplify; + const float invAmp = 1.0f / _amplify; + + // prepare textures + advectTextureCoordinates(dtOrg, xvel,yvel,zvel); + + // do wavelet decomposition of energy + computeEnergy(xvel, yvel, zvel, obstacles); + decomposeEnergy(); + + // zero out coefficients inside of the obstacle + for (int x = 0; x < _totalCellsSm; x++) + if (obstacles[x]) _energy[x] = 0.f; // parallel region setup float maxVelMagThreads[8] = { -1., -1., -1., -1., -1., -1., -1., -1. }; @@ -820,8 +818,8 @@ void WTURBULENCE::stepTurbulenceFull(float dtOrg, float* xvel, float* yvel, floa // compute the eigenvalues while we have the Jacobian available Vec3 eigenvalues = Vec3(1.); computeEigenvalues3x3( &eigenvalues[0], jacobian); - eigMax[indexSmall] = MAX3V(eigenvalues); - eigMin[indexSmall] = MIN3V(eigenvalues); + _eigMax[indexSmall] = MAX3V(eigenvalues); + _eigMin[indexSmall] = MIN3V(eigenvalues); } // make sure to skip one on the beginning and end @@ -863,7 +861,7 @@ void WTURBULENCE::stepTurbulenceFull(float dtOrg, float* xvel, float* yvel, floa // retrieve wavelet energy at highest frequency float energy = INTERPOLATE::lerp3d( - highFreqEnergy, posSm[0],posSm[1],posSm[2], _xResSm, _yResSm, _zResSm); + _highFreqEnergy, posSm[0],posSm[1],posSm[2], _xResSm, _yResSm, _zResSm); // base amplitude for octave 0 float coefficient = sqrtf(2.0f * fabs(energy)); @@ -872,8 +870,8 @@ void WTURBULENCE::stepTurbulenceFull(float dtOrg, float* xvel, float* yvel, floa // add noise to velocity, but only if the turbulence is // sufficiently undeformed, and the energy is large enough // to make a difference - const bool addNoise = eigMax[indexSmall] < 2. && - eigMin[indexSmall] > 0.5; + const bool addNoise = _eigMax[indexSmall] < 2. && + _eigMin[indexSmall] > 0.5; if (addNoise && amplitude > _cullingThreshold) { // base amplitude for octave 0 float amplitudeScaled = amplitude; @@ -895,21 +893,21 @@ void WTURBULENCE::stepTurbulenceFull(float dtOrg, float* xvel, float* yvel, floa // If you wanted to save memory, you would instead perform a // semi-Lagrangian backtrace for the current grid cell here. Then // you could just throw the velocity away. - bigUx[index] = vel[0]; - bigUy[index] = vel[1]; - bigUz[index] = vel[2]; + _bigUx[index] = vel[0]; + _bigUy[index] = vel[1]; + _bigUz[index] = vel[2]; // compute the velocity magnitude for substepping later - const float velMag = bigUx[index] * bigUx[index] + - bigUy[index] * bigUy[index] + - bigUz[index] * bigUz[index]; + const float velMag = _bigUx[index] * _bigUx[index] + + _bigUy[index] * _bigUy[index] + + _bigUz[index] * _bigUz[index]; if (velMag > maxVelMag1) maxVelMag1 = velMag; // zero out velocity inside obstacles float obsCheck = INTERPOLATE::lerp3dToFloat( obstacles, posSm[0], posSm[1], posSm[2], _xResSm, _yResSm, _zResSm); if (obsCheck > 0.95) - bigUx[index] = bigUy[index] = bigUz[index] = 0.; + _bigUx[index] = _bigUy[index] = _bigUz[index] = 0.; } // xyz #if PARALLEL==1 @@ -943,27 +941,19 @@ void WTURBULENCE::stepTurbulenceFull(float dtOrg, float* xvel, float* yvel, floa const float dtSubdiv = dt / (float)totalSubsteps; // set boundaries of big velocity grid - FLUID_3D::setZeroX(bigUx, _resBig); - FLUID_3D::setZeroY(bigUy, _resBig); - FLUID_3D::setZeroZ(bigUz, _resBig); + FLUID_3D::setZeroX(_bigUx, _resBig); + FLUID_3D::setZeroY(_bigUy, _resBig); + FLUID_3D::setZeroZ(_bigUz, _resBig); // do the MacCormack advection, with substepping if necessary for(int substep = 0; substep < totalSubsteps; substep++) { - FLUID_3D::advectFieldMacCormack(dtSubdiv, bigUx, bigUy, bigUz, - _densityBigOld, _densityBig, tempBig1, tempBig2, _resBig, NULL); + FLUID_3D::advectFieldMacCormack(dtSubdiv, _bigUx, _bigUy, _bigUz, + _densityBigOld, _densityBig, _tempBig1, _tempBig2, _resBig, NULL); if (substep < totalSubsteps - 1) SWAP_POINTERS(_densityBig, _densityBigOld); } // substep - - delete[] tempBig1; - delete[] tempBig2; - delete[] bigUx; - delete[] bigUy; - delete[] bigUz; - delete[] _energy; - delete[] highFreqEnergy; // wipe the density borders FLUID_3D::setZeroBorder(_densityBig, _resBig); @@ -971,10 +961,7 @@ void WTURBULENCE::stepTurbulenceFull(float dtOrg, float* xvel, float* yvel, floa // reset texture coordinates now in preparation for next timestep // Shouldn't do this before generating the noise because then the // eigenvalues stored do not reflect the underlying texture coordinates - resetTextureCoordinates(eigMin, eigMax); - - delete[] eigMin; - delete[] eigMax; + resetTextureCoordinates(); // output files // string prefix = string("./amplified.preview/density_bigxy_"); |