Blender V2.61 - r43446

FLUID_3D_STATIC.cpp

Go to the documentation of this file.
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 // FLUID_3D.cpp: implementation of the static functions of the FLUID_3D class.
00023 //
00025 // Heavy parallel optimization done. Many of the old functions now
00026 // take begin and end parameters and process only specified part of the data.
00027 // Some functions were divided into multiple ones.
00028 //      - MiikaH
00030 
00031 #include <zlib.h>
00032 #include "FLUID_3D.h"
00033 #include "IMAGE.h"
00034 #include "WTURBULENCE.h"
00035 #include "INTERPOLATE.h"
00036 
00038 // add a test cube of density to the center
00040 /*
00041 void FLUID_3D::addSmokeColumn() {
00042     addSmokeTestCase(_density, _res, 1.0);
00043     // addSmokeTestCase(_zVelocity, _res, 1.0);
00044     addSmokeTestCase(_heat, _res, 1.0);
00045     if (_wTurbulence) {
00046         addSmokeTestCase(_wTurbulence->getDensityBig(), _wTurbulence->getResBig(), 1.0);
00047     }
00048 }
00049 */
00050 
00052 // generic static version, so that it can be applied to the
00053 // WTURBULENCE grid as well
00055 
00056 void FLUID_3D::addSmokeTestCase(float* field, Vec3Int res)
00057 {
00058     const int slabSize = res[0]*res[1]; int maxRes = (int)MAX3V(res);
00059     float dx = 1.0f / (float)maxRes;
00060 
00061     float xTotal = dx * res[0];
00062     float yTotal = dx * res[1];
00063 
00064     float heighMin = 0.05;
00065     float heighMax = 0.10;
00066 
00067     for (int y = 0; y < res[2]; y++)
00068         for (int z = (int)(heighMin*res[2]); z <= (int)(heighMax * res[2]); z++)
00069             for (int x = 0; x < res[0]; x++) {
00070                 float xLength = x * dx - xTotal * 0.4f;
00071                 float yLength = y * dx - yTotal * 0.5f;
00072                 float radius = sqrtf(xLength * xLength + yLength * yLength);
00073 
00074                 if (radius < 0.075f * xTotal) {
00075                     int index = x + y * res[0] + z * slabSize;
00076                     field[index] = 1.0f;
00077                 }
00078             }
00079 }
00080 
00081 
00083 // set x direction to Neumann boundary conditions
00085 void FLUID_3D::setNeumannX(float* field, Vec3Int res, int zBegin, int zEnd)
00086 {
00087     const int slabSize = res[0] * res[1];
00088     int index;
00089     for (int z = zBegin; z < zEnd; z++)
00090         for (int y = 0; y < res[1]; y++)
00091         {
00092             // left slab
00093             index = y * res[0] + z * slabSize;
00094             field[index] = field[index + 2];
00095 
00096             // right slab
00097             index += res[0] - 1;
00098             field[index] = field[index - 2];
00099         }
00100 
00101     // fix, force top slab to only allow outwards flux
00102     for (int y = 0; y < res[1]; y++)
00103         for (int z = zBegin; z < zEnd; z++)
00104         {
00105             // top slab
00106             index = y * res[0] + z * slabSize;
00107             index += res[0] - 1;
00108             if(field[index]<0.) field[index] = 0.;
00109             index -= 1;
00110             if(field[index]<0.) field[index] = 0.;
00111         }
00112  }
00113 
00115 // set y direction to Neumann boundary conditions
00117 void FLUID_3D::setNeumannY(float* field, Vec3Int res, int zBegin, int zEnd)
00118 {
00119     const int slabSize = res[0] * res[1];
00120     int index;
00121     for (int z = zBegin; z < zEnd; z++)
00122         for (int x = 0; x < res[0]; x++)
00123         {
00124             // bottom slab
00125             index = x + z * slabSize;
00126             field[index] = field[index + 2 * res[0]];
00127 
00128             // top slab
00129             index += slabSize - res[0];
00130             field[index] = field[index - 2 * res[0]];
00131         }
00132 
00133     // fix, force top slab to only allow outwards flux
00134     for (int z = zBegin; z < zEnd; z++)
00135         for (int x = 0; x < res[0]; x++)
00136         {
00137             // top slab
00138             index = x + z * slabSize;
00139             index += slabSize - res[0];
00140             if(field[index]<0.) field[index] = 0.;
00141             index -= res[0];
00142             if(field[index]<0.) field[index] = 0.;
00143         }
00144         
00145 }
00146 
00148 // set z direction to Neumann boundary conditions
00150 void FLUID_3D::setNeumannZ(float* field, Vec3Int res, int zBegin, int zEnd)
00151 {
00152     const int slabSize = res[0] * res[1];
00153     const int totalCells = res[0] * res[1] * res[2];
00154     const int cellsslab = totalCells - slabSize;
00155     int index;
00156 
00157     index = 0;
00158     if (zBegin == 0)
00159     for (int y = 0; y < res[1]; y++)
00160         for (int x = 0; x < res[0]; x++, index++)
00161         {
00162             // front slab
00163             field[index] = field[index + 2 * slabSize];
00164         }
00165 
00166     if (zEnd == res[2])
00167     {
00168     index = 0;
00169     int indexx = 0;
00170 
00171     for (int y = 0; y < res[1]; y++)
00172         for (int x = 0; x < res[0]; x++, index++)
00173         {
00174 
00175             // back slab
00176             indexx = index + cellsslab;
00177             field[indexx] = field[indexx - 2 * slabSize];
00178         }
00179     
00180 
00181     // fix, force top slab to only allow outwards flux
00182     for (int y = 0; y < res[1]; y++)
00183         for (int x = 0; x < res[0]; x++)
00184         {
00185             // top slab
00186             index = x + y * res[0];
00187             index += cellsslab;
00188             if(field[index]<0.) field[index] = 0.;
00189             index -= slabSize;
00190             if(field[index]<0.) field[index] = 0.;
00191         }
00192 
00193     }   // zEnd == res[2]
00194         
00195 }
00196 
00198 // set x direction to zero
00200 void FLUID_3D::setZeroX(float* field, Vec3Int res, int zBegin, int zEnd)
00201 {
00202     const int slabSize = res[0] * res[1];
00203     int index;
00204     for (int z = zBegin; z < zEnd; z++)
00205         for (int y = 0; y < res[1]; y++)
00206         {
00207             // left slab
00208             index = y * res[0] + z * slabSize;
00209             field[index] = 0.0f;
00210 
00211             // right slab
00212             index += res[0] - 1;
00213             field[index] = 0.0f;
00214         }
00215 }
00216 
00218 // set y direction to zero
00220 void FLUID_3D::setZeroY(float* field, Vec3Int res, int zBegin, int zEnd)
00221 {
00222     const int slabSize = res[0] * res[1];
00223     int index;
00224     for (int z = zBegin; z < zEnd; z++)
00225         for (int x = 0; x < res[0]; x++)
00226         {
00227             // bottom slab
00228             index = x + z * slabSize;
00229             field[index] = 0.0f;
00230 
00231             // top slab
00232             index += slabSize - res[0];
00233             field[index] = 0.0f;
00234         }
00235 }
00236 
00238 // set z direction to zero
00240 void FLUID_3D::setZeroZ(float* field, Vec3Int res, int zBegin, int zEnd)
00241 {
00242     const int slabSize = res[0] * res[1];
00243     const int totalCells = res[0] * res[1] * res[2];
00244 
00245     int index = 0;
00246     if ((zBegin == 0))
00247     for (int y = 0; y < res[1]; y++)
00248         for (int x = 0; x < res[0]; x++, index++)
00249         {
00250             // front slab
00251             field[index] = 0.0f;
00252     }
00253 
00254     if (zEnd == res[2])
00255     {
00256         index=0;
00257         int indexx=0;
00258         const int cellsslab = totalCells - slabSize;
00259 
00260         for (int y = 0; y < res[1]; y++)
00261             for (int x = 0; x < res[0]; x++, index++)
00262             {
00263 
00264                 // back slab
00265                 indexx = index + cellsslab;
00266                 field[indexx] = 0.0f;
00267             }
00268     }
00269  }
00271 // copy grid boundary
00273 void FLUID_3D::copyBorderX(float* field, Vec3Int res, int zBegin, int zEnd)
00274 {
00275     const int slabSize = res[0] * res[1];
00276     int index;
00277     for (int z = zBegin; z < zEnd; z++)
00278         for (int y = 0; y < res[1]; y++)
00279         {
00280             // left slab
00281             index = y * res[0] + z * slabSize;
00282             field[index] = field[index + 1];
00283 
00284             // right slab
00285             index += res[0] - 1;
00286             field[index] = field[index - 1];
00287         }
00288 }
00289 void FLUID_3D::copyBorderY(float* field, Vec3Int res, int zBegin, int zEnd)
00290 {
00291     const int slabSize = res[0] * res[1];
00292     //const int totalCells = res[0] * res[1] * res[2];
00293     int index;
00294     for (int z = zBegin; z < zEnd; z++)
00295         for (int x = 0; x < res[0]; x++)
00296         {
00297             // bottom slab
00298             index = x + z * slabSize;
00299             field[index] = field[index + res[0]]; 
00300             // top slab
00301             index += slabSize - res[0];
00302             field[index] = field[index - res[0]];
00303         }
00304 }
00305 void FLUID_3D::copyBorderZ(float* field, Vec3Int res, int zBegin, int zEnd)
00306 {
00307     const int slabSize = res[0] * res[1];
00308     const int totalCells = res[0] * res[1] * res[2];
00309     int index=0;
00310 
00311     if ((zBegin == 0))
00312     for (int y = 0; y < res[1]; y++)
00313         for (int x = 0; x < res[0]; x++, index++)
00314         {
00315             field[index] = field[index + slabSize]; 
00316         }
00317 
00318     if ((zEnd == res[2]))
00319     {
00320 
00321     index=0;
00322     int indexx=0;
00323     const int cellsslab = totalCells - slabSize;
00324 
00325     for (int y = 0; y < res[1]; y++)
00326         for (int x = 0; x < res[0]; x++, index++)
00327         {
00328             // back slab
00329             indexx = index + cellsslab;
00330             field[indexx] = field[indexx - slabSize];
00331         }
00332     }
00333 }
00334 
00336 // advect field with the semi lagrangian method
00338 void FLUID_3D::advectFieldSemiLagrange(const float dt, const float* velx, const float* vely,  const float* velz,
00339         float* oldField, float* newField, Vec3Int res, int zBegin, int zEnd)
00340 {
00341     const int xres = res[0];
00342     const int yres = res[1];
00343     const int zres = res[2];
00344     const int slabSize = res[0] * res[1];
00345 
00346 
00347     for (int z = zBegin; z < zEnd; z++)
00348         for (int y = 0; y < yres; y++)
00349             for (int x = 0; x < xres; x++)
00350             {
00351                 const int index = x + y * xres + z * xres*yres;
00352                 
00353         // backtrace
00354                 float xTrace = x - dt * velx[index];
00355                 float yTrace = y - dt * vely[index];
00356                 float zTrace = z - dt * velz[index];
00357 
00358                 // clamp backtrace to grid boundaries
00359                 if (xTrace < 0.5) xTrace = 0.5;
00360                 if (xTrace > xres - 1.5) xTrace = xres - 1.5;
00361                 if (yTrace < 0.5) yTrace = 0.5;
00362                 if (yTrace > yres - 1.5) yTrace = yres - 1.5;
00363                 if (zTrace < 0.5) zTrace = 0.5;
00364                 if (zTrace > zres - 1.5) zTrace = zres - 1.5;
00365 
00366                 // locate neighbors to interpolate
00367                 const int x0 = (int)xTrace;
00368                 const int x1 = x0 + 1;
00369                 const int y0 = (int)yTrace;
00370                 const int y1 = y0 + 1;
00371                 const int z0 = (int)zTrace;
00372                 const int z1 = z0 + 1;
00373 
00374                 // get interpolation weights
00375                 const float s1 = xTrace - x0;
00376                 const float s0 = 1.0f - s1;
00377                 const float t1 = yTrace - y0;
00378                 const float t0 = 1.0f - t1;
00379                 const float u1 = zTrace - z0;
00380                 const float u0 = 1.0f - u1;
00381 
00382                 const int i000 = x0 + y0 * xres + z0 * slabSize;
00383                 const int i010 = x0 + y1 * xres + z0 * slabSize;
00384                 const int i100 = x1 + y0 * xres + z0 * slabSize;
00385                 const int i110 = x1 + y1 * xres + z0 * slabSize;
00386                 const int i001 = x0 + y0 * xres + z1 * slabSize;
00387                 const int i011 = x0 + y1 * xres + z1 * slabSize;
00388                 const int i101 = x1 + y0 * xres + z1 * slabSize;
00389                 const int i111 = x1 + y1 * xres + z1 * slabSize;
00390 
00391                 // interpolate
00392                 // (indices could be computed once)
00393                 newField[index] = u0 * (s0 * (t0 * oldField[i000] +
00394                             t1 * oldField[i010]) +
00395                         s1 * (t0 * oldField[i100] +
00396                             t1 * oldField[i110])) +
00397                     u1 * (s0 * (t0 * oldField[i001] +
00398                                 t1 * oldField[i011]) +
00399                             s1 * (t0 * oldField[i101] +
00400                                 t1 * oldField[i111]));
00401             }
00402 }
00403 
00404 
00406 // advect field with the maccormack method
00407 //
00408 // comments are the pseudocode from selle's paper
00410 void FLUID_3D::advectFieldMacCormack1(const float dt, const float* xVelocity, const float* yVelocity, const float* zVelocity, 
00411                 float* oldField, float* tempResult, Vec3Int res, int zBegin, int zEnd)
00412 {
00413     /*const int sx= res[0];
00414     const int sy= res[1];
00415     const int sz= res[2];
00416 
00417     for (int x = 0; x < sx * sy * sz; x++)
00418         phiHatN[x] = phiHatN1[x] = oldField[x];*/   // not needed as all the values are written first
00419 
00420     float*& phiN    = oldField;
00421     float*& phiN1   = tempResult;
00422 
00423 
00424 
00425     // phiHatN1 = A(phiN)
00426     advectFieldSemiLagrange(  dt, xVelocity, yVelocity, zVelocity, phiN, phiN1, res, zBegin, zEnd);     // uses wide data from old field and velocities (both are whole)
00427 }
00428 
00429 
00430 
00431 void FLUID_3D::advectFieldMacCormack2(const float dt, const float* xVelocity, const float* yVelocity, const float* zVelocity, 
00432                 float* oldField, float* newField, float* tempResult, float* temp1, Vec3Int res, const unsigned char* obstacles, int zBegin, int zEnd)
00433 {
00434     float* phiHatN  = tempResult;
00435     float* t1  = temp1;
00436     const int sx= res[0];
00437     const int sy= res[1];
00438 
00439     float*& phiN    = oldField;
00440     float*& phiN1   = newField;
00441 
00442 
00443 
00444     // phiHatN = A^R(phiHatN1)
00445     advectFieldSemiLagrange( -1.0*dt, xVelocity, yVelocity, zVelocity, phiHatN, t1, res, zBegin, zEnd);     // uses wide data from old field and velocities (both are whole)
00446 
00447     // phiN1 = phiHatN1 + (phiN - phiHatN) / 2
00448     const int border = 0; 
00449     for (int z = zBegin+border; z < zEnd-border; z++)
00450         for (int y = border; y < sy-border; y++)
00451             for (int x = border; x < sx-border; x++) {
00452                 int index = x + y * sx + z * sx*sy;
00453                 phiN1[index] = phiHatN[index] + (phiN[index] - t1[index]) * 0.50f;
00454                 //phiN1[index] = phiHatN1[index]; // debug, correction off
00455             }
00456     copyBorderX(phiN1, res, zBegin, zEnd);
00457     copyBorderY(phiN1, res, zBegin, zEnd);
00458     copyBorderZ(phiN1, res, zBegin, zEnd);
00459 
00460     // clamp any newly created extrema
00461     clampExtrema(dt, xVelocity, yVelocity, zVelocity, oldField, newField, res, zBegin, zEnd);       // uses wide data from old field and velocities (both are whole)
00462 
00463     // if the error estimate was bad, revert to first order
00464     clampOutsideRays(dt, xVelocity, yVelocity, zVelocity, oldField, newField, res, obstacles, phiHatN, zBegin, zEnd);   // phiHatN is only used at cells within thread range, so its ok
00465 
00466 } 
00467 
00468 
00470 // Clamp the extrema generated by the BFECC error correction
00472 void FLUID_3D::clampExtrema(const float dt, const float* velx, const float* vely,  const float* velz,
00473         float* oldField, float* newField, Vec3Int res, int zBegin, int zEnd)
00474 {
00475     const int xres= res[0];
00476     const int yres= res[1];
00477     const int zres= res[2];
00478     const int slabSize = res[0] * res[1];
00479 
00480     int bb=0;
00481     int bt=0;
00482 
00483     if (zBegin == 0) {bb = 1;}
00484     if (zEnd == res[2]) {bt = 1;}
00485 
00486 
00487     for (int z = zBegin+bb; z < zEnd-bt; z++)
00488         for (int y = 1; y < yres-1; y++)
00489             for (int x = 1; x < xres-1; x++)
00490             {
00491                 const int index = x + y * xres+ z * xres*yres;
00492                 // backtrace
00493                 float xTrace = x - dt * velx[index];
00494                 float yTrace = y - dt * vely[index];
00495                 float zTrace = z - dt * velz[index];
00496 
00497                 // clamp backtrace to grid boundaries
00498                 if (xTrace < 0.5) xTrace = 0.5;
00499                 if (xTrace > xres - 1.5) xTrace = xres - 1.5;
00500                 if (yTrace < 0.5) yTrace = 0.5;
00501                 if (yTrace > yres - 1.5) yTrace = yres - 1.5;
00502                 if (zTrace < 0.5) zTrace = 0.5;
00503                 if (zTrace > zres - 1.5) zTrace = zres - 1.5;
00504 
00505                 // locate neighbors to interpolate
00506                 const int x0 = (int)xTrace;
00507                 const int x1 = x0 + 1;
00508                 const int y0 = (int)yTrace;
00509                 const int y1 = y0 + 1;
00510                 const int z0 = (int)zTrace;
00511                 const int z1 = z0 + 1;
00512 
00513                 const int i000 = x0 + y0 * xres + z0 * slabSize;
00514                 const int i010 = x0 + y1 * xres + z0 * slabSize;
00515                 const int i100 = x1 + y0 * xres + z0 * slabSize;
00516                 const int i110 = x1 + y1 * xres + z0 * slabSize;
00517                 const int i001 = x0 + y0 * xres + z1 * slabSize;
00518                 const int i011 = x0 + y1 * xres + z1 * slabSize;
00519                 const int i101 = x1 + y0 * xres + z1 * slabSize;
00520                 const int i111 = x1 + y1 * xres + z1 * slabSize;
00521 
00522                 float minField = oldField[i000];
00523                 float maxField = oldField[i000];
00524 
00525                 minField = (oldField[i010] < minField) ? oldField[i010] : minField;
00526                 maxField = (oldField[i010] > maxField) ? oldField[i010] : maxField;
00527 
00528                 minField = (oldField[i100] < minField) ? oldField[i100] : minField;
00529                 maxField = (oldField[i100] > maxField) ? oldField[i100] : maxField;
00530 
00531                 minField = (oldField[i110] < minField) ? oldField[i110] : minField;
00532                 maxField = (oldField[i110] > maxField) ? oldField[i110] : maxField;
00533 
00534                 minField = (oldField[i001] < minField) ? oldField[i001] : minField;
00535                 maxField = (oldField[i001] > maxField) ? oldField[i001] : maxField;
00536 
00537                 minField = (oldField[i011] < minField) ? oldField[i011] : minField;
00538                 maxField = (oldField[i011] > maxField) ? oldField[i011] : maxField;
00539 
00540                 minField = (oldField[i101] < minField) ? oldField[i101] : minField;
00541                 maxField = (oldField[i101] > maxField) ? oldField[i101] : maxField;
00542 
00543                 minField = (oldField[i111] < minField) ? oldField[i111] : minField;
00544                 maxField = (oldField[i111] > maxField) ? oldField[i111] : maxField;
00545 
00546                 newField[index] = (newField[index] > maxField) ? maxField : newField[index];
00547                 newField[index] = (newField[index] < minField) ? minField : newField[index];
00548             }
00549 }
00550 
00552 // Reverts any backtraces that go into boundaries back to first 
00553 // order -- in this case the error correction term was totally
00554 // incorrect
00556 void FLUID_3D::clampOutsideRays(const float dt, const float* velx, const float* vely,  const float* velz,
00557                 float* oldField, float* newField, Vec3Int res, const unsigned char* obstacles, const float *oldAdvection, int zBegin, int zEnd)
00558 {
00559     const int sx= res[0];
00560     const int sy= res[1];
00561     const int sz= res[2];
00562     const int slabSize = res[0] * res[1];
00563 
00564     int bb=0;
00565     int bt=0;
00566 
00567     if (zBegin == 0) {bb = 1;}
00568     if (zEnd == res[2]) {bt = 1;}
00569 
00570     for (int z = zBegin+bb; z < zEnd-bt; z++)
00571         for (int y = 1; y < sy-1; y++)
00572             for (int x = 1; x < sx-1; x++)
00573             {
00574                 const int index = x + y * sx+ z * slabSize;
00575                 // backtrace
00576                 float xBackward = x + dt * velx[index];
00577                 float yBackward = y + dt * vely[index];
00578                 float zBackward = z + dt * velz[index];
00579                 float xTrace    = x - dt * velx[index];
00580                 float yTrace    = y - dt * vely[index];
00581                 float zTrace    = z - dt * velz[index];
00582 
00583                 // see if it goes outside the boundaries
00584                 bool hasObstacle = 
00585                     (zTrace < 1.0f)    || (zTrace > sz - 2.0f) ||
00586                     (yTrace < 1.0f)    || (yTrace > sy - 2.0f) ||
00587                     (xTrace < 1.0f)    || (xTrace > sx - 2.0f) ||
00588                     (zBackward < 1.0f) || (zBackward > sz - 2.0f) ||
00589                     (yBackward < 1.0f) || (yBackward > sy - 2.0f) ||
00590                     (xBackward < 1.0f) || (xBackward > sx - 2.0f);
00591                 // reuse old advection instead of doing another one...
00592                 if(hasObstacle) { newField[index] = oldAdvection[index]; continue; }
00593 
00594                 // clamp to prevent an out of bounds access when looking into
00595                 // the _obstacles array
00596                 zTrace = (zTrace < 0.5f) ? 0.5f : zTrace;
00597                 zTrace = (zTrace > sz - 1.5f) ? sz - 1.5f : zTrace;
00598                 yTrace = (yTrace < 0.5f) ? 0.5f : yTrace;
00599                 yTrace = (yTrace > sy - 1.5f) ? sy - 1.5f : yTrace;
00600                 xTrace = (xTrace < 0.5f) ? 0.5f : xTrace;
00601                 xTrace = (xTrace > sx - 1.5f) ? sx - 1.5f : xTrace;
00602 
00603                 // locate neighbors to interpolate,
00604                 // do backward first since we will use the forward indices if a
00605                 // reversion is actually necessary
00606                 zBackward = (zBackward < 0.5f) ? 0.5f : zBackward;
00607                 zBackward = (zBackward > sz - 1.5f) ? sz - 1.5f : zBackward;
00608                 yBackward = (yBackward < 0.5f) ? 0.5f : yBackward;
00609                 yBackward = (yBackward > sy - 1.5f) ? sy - 1.5f : yBackward;
00610                 xBackward = (xBackward < 0.5f) ? 0.5f : xBackward;
00611                 xBackward = (xBackward > sx - 1.5f) ? sx - 1.5f : xBackward;
00612 
00613                 int x0 = (int)xBackward;
00614                 int x1 = x0 + 1;
00615                 int y0 = (int)yBackward;
00616                 int y1 = y0 + 1;
00617                 int z0 = (int)zBackward;
00618                 int z1 = z0 + 1;
00619                 if(obstacles && !hasObstacle) {
00620                     hasObstacle = hasObstacle || 
00621                         obstacles[x0 + y0 * sx + z0*slabSize] ||
00622                         obstacles[x0 + y1 * sx + z0*slabSize] ||
00623                         obstacles[x1 + y0 * sx + z0*slabSize] ||
00624                         obstacles[x1 + y1 * sx + z0*slabSize] ||
00625                         obstacles[x0 + y0 * sx + z1*slabSize] ||
00626                         obstacles[x0 + y1 * sx + z1*slabSize] ||
00627                         obstacles[x1 + y0 * sx + z1*slabSize] ||
00628                         obstacles[x1 + y1 * sx + z1*slabSize] ;
00629                 }
00630                 // reuse old advection instead of doing another one...
00631                 if(hasObstacle) { newField[index] = oldAdvection[index]; continue; }
00632 
00633                 x0 = (int)xTrace;
00634                 x1 = x0 + 1;
00635                 y0 = (int)yTrace;
00636                 y1 = y0 + 1;
00637                 z0 = (int)zTrace;
00638                 z1 = z0 + 1;
00639                 if(obstacles && !hasObstacle) {
00640                     hasObstacle = hasObstacle || 
00641                         obstacles[x0 + y0 * sx + z0*slabSize] ||
00642                         obstacles[x0 + y1 * sx + z0*slabSize] ||
00643                         obstacles[x1 + y0 * sx + z0*slabSize] ||
00644                         obstacles[x1 + y1 * sx + z0*slabSize] ||
00645                         obstacles[x0 + y0 * sx + z1*slabSize] ||
00646                         obstacles[x0 + y1 * sx + z1*slabSize] ||
00647                         obstacles[x1 + y0 * sx + z1*slabSize] ||
00648                         obstacles[x1 + y1 * sx + z1*slabSize] ;
00649                 } // obstacle array
00650                 // reuse old advection instead of doing another one...
00651                 if(hasObstacle) { newField[index] = oldAdvection[index]; continue; }
00652 
00653                 // see if either the forward or backward ray went into
00654                 // a boundary
00655                 if (hasObstacle) {
00656                     // get interpolation weights
00657                     float s1 = xTrace - x0;
00658                     float s0 = 1.0f - s1;
00659                     float t1 = yTrace - y0;
00660                     float t0 = 1.0f - t1;
00661                     float u1 = zTrace - z0;
00662                     float u0 = 1.0f - u1;
00663 
00664                     const int i000 = x0 + y0 * sx + z0 * slabSize;
00665                     const int i010 = x0 + y1 * sx + z0 * slabSize;
00666                     const int i100 = x1 + y0 * sx + z0 * slabSize;
00667                     const int i110 = x1 + y1 * sx + z0 * slabSize;
00668                     const int i001 = x0 + y0 * sx + z1 * slabSize;
00669                     const int i011 = x0 + y1 * sx + z1 * slabSize;
00670                     const int i101 = x1 + y0 * sx + z1 * slabSize;
00671                     const int i111 = x1 + y1 * sx + z1 * slabSize;
00672 
00673                     // interpolate, (indices could be computed once)
00674                     newField[index] = u0 * (s0 * (
00675                                 t0 * oldField[i000] +
00676                                 t1 * oldField[i010]) +
00677                             s1 * (t0 * oldField[i100] +
00678                                 t1 * oldField[i110])) +
00679                         u1 * (s0 * (t0 * oldField[i001] +
00680                                     t1 * oldField[i011]) +
00681                                 s1 * (t0 * oldField[i101] +
00682                                     t1 * oldField[i111])); 
00683                 }
00684             } // xyz
00685 }