2019-02-18 08:08:12 +11:00
/** \file
* \ ingroup smoke
2011-02-25 11:50:46 +00:00
*/
2009-07-30 15:00:26 +00:00
//////////////////////////////////////////////////////////////////////
// This file is part of Wavelet Turbulence.
//
// Wavelet Turbulence is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Wavelet Turbulence is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Wavelet Turbulence. If not, see <http://www.gnu.org/licenses/>.
//
// Copyright 2008 Theodore Kim and Nils Thuerey
//
// FLUID_3D.cpp: implementation of the static functions of the FLUID_3D class.
//
//////////////////////////////////////////////////////////////////////
2010-01-25 15:10:14 +00:00
// Heavy parallel optimization done. Many of the old functions now
// take begin and end parameters and process only specified part of the data.
// Some functions were divided into multiple ones.
// - MiikaH
//////////////////////////////////////////////////////////////////////
2009-07-30 15:00:26 +00:00
# include <zlib.h>
# include "FLUID_3D.h"
# include "IMAGE.h"
# include "WTURBULENCE.h"
# include "INTERPOLATE.h"
//////////////////////////////////////////////////////////////////////
// add a test cube of density to the center
//////////////////////////////////////////////////////////////////////
2009-07-30 20:12:40 +00:00
/*
2009-07-30 15:00:26 +00:00
void FLUID_3D : : addSmokeColumn ( ) {
addSmokeTestCase ( _density , _res , 1.0 ) ;
// addSmokeTestCase(_zVelocity, _res, 1.0);
addSmokeTestCase ( _heat , _res , 1.0 ) ;
if ( _wTurbulence ) {
addSmokeTestCase ( _wTurbulence - > getDensityBig ( ) , _wTurbulence - > getResBig ( ) , 1.0 ) ;
}
}
2009-07-30 20:12:40 +00:00
*/
2009-07-30 15:00:26 +00:00
//////////////////////////////////////////////////////////////////////
// generic static version, so that it can be applied to the
// WTURBULENCE grid as well
//////////////////////////////////////////////////////////////////////
2009-09-14 00:01:08 +00:00
void FLUID_3D : : addSmokeTestCase ( float * field , Vec3Int res )
2009-07-30 15:00:26 +00:00
{
const int slabSize = res [ 0 ] * res [ 1 ] ; int maxRes = ( int ) MAX3V ( res ) ;
float dx = 1.0f / ( float ) maxRes ;
float xTotal = dx * res [ 0 ] ;
float yTotal = dx * res [ 1 ] ;
2009-09-24 16:18:17 +00:00
float heighMin = 0.05 ;
float heighMax = 0.10 ;
for ( int y = 0 ; y < res [ 2 ] ; y + + )
for ( int z = ( int ) ( heighMin * res [ 2 ] ) ; z < = ( int ) ( heighMax * res [ 2 ] ) ; z + + )
for ( int x = 0 ; x < res [ 0 ] ; x + + ) {
float xLength = x * dx - xTotal * 0.4f ;
float yLength = y * dx - yTotal * 0.5f ;
float radius = sqrtf ( xLength * xLength + yLength * yLength ) ;
if ( radius < 0.075f * xTotal ) {
int index = x + y * res [ 0 ] + z * slabSize ;
field [ index ] = 1.0f ;
}
}
2009-07-30 15:00:26 +00:00
}
2009-09-14 00:01:08 +00:00
2009-07-30 15:00:26 +00:00
//////////////////////////////////////////////////////////////////////
// set x direction to Neumann boundary conditions
//////////////////////////////////////////////////////////////////////
2010-01-25 15:10:14 +00:00
void FLUID_3D : : setNeumannX ( float * field , Vec3Int res , int zBegin , int zEnd )
2009-07-30 15:00:26 +00:00
{
const int slabSize = res [ 0 ] * res [ 1 ] ;
2009-09-09 18:39:40 +00:00
int index ;
2010-01-25 15:10:14 +00:00
for ( int z = zBegin ; z < zEnd ; z + + )
2009-07-30 15:00:26 +00:00
for ( int y = 0 ; y < res [ 1 ] ; y + + )
{
// left slab
index = y * res [ 0 ] + z * slabSize ;
field [ index ] = field [ index + 2 ] ;
// right slab
2012-05-26 21:36:19 +00:00
index = y * res [ 0 ] + z * slabSize + res [ 0 ] - 1 ;
2009-07-30 15:00:26 +00:00
field [ index ] = field [ index - 2 ] ;
2009-09-09 18:39:40 +00:00
}
2009-07-30 15:00:26 +00:00
}
//////////////////////////////////////////////////////////////////////
// set y direction to Neumann boundary conditions
//////////////////////////////////////////////////////////////////////
2010-01-25 15:10:14 +00:00
void FLUID_3D : : setNeumannY ( float * field , Vec3Int res , int zBegin , int zEnd )
2009-07-30 15:00:26 +00:00
{
const int slabSize = res [ 0 ] * res [ 1 ] ;
2009-09-09 18:39:40 +00:00
int index ;
2010-01-25 15:10:14 +00:00
for ( int z = zBegin ; z < zEnd ; z + + )
2009-07-30 15:00:26 +00:00
for ( int x = 0 ; x < res [ 0 ] ; x + + )
{
2012-05-26 21:36:19 +00:00
// front slab
2009-07-30 15:00:26 +00:00
index = x + z * slabSize ;
field [ index ] = field [ index + 2 * res [ 0 ] ] ;
2012-05-26 21:36:19 +00:00
// back slab
index = x + z * slabSize + slabSize - res [ 0 ] ;
2009-07-30 15:00:26 +00:00
field [ index ] = field [ index - 2 * res [ 0 ] ] ;
2009-09-09 18:39:40 +00:00
}
2009-07-30 15:00:26 +00:00
}
//////////////////////////////////////////////////////////////////////
// set z direction to Neumann boundary conditions
//////////////////////////////////////////////////////////////////////
2010-01-25 15:10:14 +00:00
void FLUID_3D : : setNeumannZ ( float * field , Vec3Int res , int zBegin , int zEnd )
2009-07-30 15:00:26 +00:00
{
const int slabSize = res [ 0 ] * res [ 1 ] ;
const int totalCells = res [ 0 ] * res [ 1 ] * res [ 2 ] ;
2010-01-25 15:10:14 +00:00
const int cellsslab = totalCells - slabSize ;
2009-09-09 18:39:40 +00:00
int index ;
2010-01-25 15:10:14 +00:00
2012-05-26 21:36:19 +00:00
if ( zBegin = = 0 ) {
for ( int y = 0 ; y < res [ 1 ] ; y + + )
for ( int x = 0 ; x < res [ 0 ] ; x + + )
{
// front slab
index = x + y * res [ 0 ] ;
field [ index ] = field [ index + 2 * slabSize ] ;
}
}
2010-01-25 15:10:14 +00:00
2012-05-26 21:36:19 +00:00
if ( zEnd = = res [ 2 ] ) {
for ( int y = 0 ; y < res [ 1 ] ; y + + )
for ( int x = 0 ; x < res [ 0 ] ; x + + )
{
// back slab
index = x + y * res [ 0 ] + cellsslab ;
field [ index ] = field [ index - 2 * slabSize ] ;
}
}
2009-08-06 16:50:02 +00:00
2009-07-30 15:00:26 +00:00
}
//////////////////////////////////////////////////////////////////////
// set x direction to zero
//////////////////////////////////////////////////////////////////////
2010-01-25 15:10:14 +00:00
void FLUID_3D : : setZeroX ( float * field , Vec3Int res , int zBegin , int zEnd )
2009-07-30 15:00:26 +00:00
{
const int slabSize = res [ 0 ] * res [ 1 ] ;
int index ;
2010-01-25 15:10:14 +00:00
for ( int z = zBegin ; z < zEnd ; z + + )
2009-07-30 15:00:26 +00:00
for ( int y = 0 ; y < res [ 1 ] ; y + + )
{
// left slab
index = y * res [ 0 ] + z * slabSize ;
field [ index ] = 0.0f ;
// right slab
index + = res [ 0 ] - 1 ;
field [ index ] = 0.0f ;
}
}
//////////////////////////////////////////////////////////////////////
// set y direction to zero
//////////////////////////////////////////////////////////////////////
2010-01-25 15:10:14 +00:00
void FLUID_3D : : setZeroY ( float * field , Vec3Int res , int zBegin , int zEnd )
2009-07-30 15:00:26 +00:00
{
const int slabSize = res [ 0 ] * res [ 1 ] ;
int index ;
2010-01-25 15:10:14 +00:00
for ( int z = zBegin ; z < zEnd ; z + + )
2009-07-30 15:00:26 +00:00
for ( int x = 0 ; x < res [ 0 ] ; x + + )
{
// bottom slab
index = x + z * slabSize ;
field [ index ] = 0.0f ;
// top slab
index + = slabSize - res [ 0 ] ;
field [ index ] = 0.0f ;
}
}
//////////////////////////////////////////////////////////////////////
// set z direction to zero
//////////////////////////////////////////////////////////////////////
2010-01-25 15:10:14 +00:00
void FLUID_3D : : setZeroZ ( float * field , Vec3Int res , int zBegin , int zEnd )
2009-07-30 15:00:26 +00:00
{
const int slabSize = res [ 0 ] * res [ 1 ] ;
const int totalCells = res [ 0 ] * res [ 1 ] * res [ 2 ] ;
2010-01-25 15:10:14 +00:00
int index = 0 ;
2013-02-26 21:58:06 +00:00
if ( zBegin = = 0 )
{
for ( int y = 0 ; y < res [ 1 ] ; y + + )
for ( int x = 0 ; x < res [ 0 ] ; x + + , index + + )
{
// front slab
field [ index ] = 0.0f ;
}
}
2009-07-30 15:00:26 +00:00
2010-01-25 15:10:14 +00:00
if ( zEnd = = res [ 2 ] )
{
index = 0 ;
int indexx = 0 ;
const int cellsslab = totalCells - slabSize ;
for ( int y = 0 ; y < res [ 1 ] ; y + + )
for ( int x = 0 ; x < res [ 0 ] ; x + + , index + + )
{
2009-07-30 15:00:26 +00:00
2010-01-25 15:10:14 +00:00
// back slab
indexx = index + cellsslab ;
field [ indexx ] = 0.0f ;
}
}
}
2009-07-30 15:00:26 +00:00
//////////////////////////////////////////////////////////////////////
// copy grid boundary
//////////////////////////////////////////////////////////////////////
2010-01-25 15:10:14 +00:00
void FLUID_3D : : copyBorderX ( float * field , Vec3Int res , int zBegin , int zEnd )
2009-07-30 15:00:26 +00:00
{
const int slabSize = res [ 0 ] * res [ 1 ] ;
int index ;
2010-01-25 15:10:14 +00:00
for ( int z = zBegin ; z < zEnd ; z + + )
2009-07-30 15:00:26 +00:00
for ( int y = 0 ; y < res [ 1 ] ; y + + )
{
// left slab
index = y * res [ 0 ] + z * slabSize ;
field [ index ] = field [ index + 1 ] ;
// right slab
index + = res [ 0 ] - 1 ;
field [ index ] = field [ index - 1 ] ;
}
}
2010-01-25 15:10:14 +00:00
void FLUID_3D : : copyBorderY ( float * field , Vec3Int res , int zBegin , int zEnd )
2009-07-30 15:00:26 +00:00
{
const int slabSize = res [ 0 ] * res [ 1 ] ;
2010-01-25 15:10:14 +00:00
//const int totalCells = res[0] * res[1] * res[2];
2009-07-30 15:00:26 +00:00
int index ;
2010-01-25 15:10:14 +00:00
for ( int z = zBegin ; z < zEnd ; z + + )
2009-07-30 15:00:26 +00:00
for ( int x = 0 ; x < res [ 0 ] ; x + + )
{
// bottom slab
index = x + z * slabSize ;
2009-09-09 18:39:40 +00:00
field [ index ] = field [ index + res [ 0 ] ] ;
2009-07-30 15:00:26 +00:00
// top slab
index + = slabSize - res [ 0 ] ;
field [ index ] = field [ index - res [ 0 ] ] ;
}
}
2010-01-25 15:10:14 +00:00
void FLUID_3D : : copyBorderZ ( float * field , Vec3Int res , int zBegin , int zEnd )
2009-07-30 15:00:26 +00:00
{
const int slabSize = res [ 0 ] * res [ 1 ] ;
const int totalCells = res [ 0 ] * res [ 1 ] * res [ 2 ] ;
2010-01-25 15:10:14 +00:00
int index = 0 ;
2013-02-26 21:58:06 +00:00
if ( zBegin = = 0 )
{
for ( int y = 0 ; y < res [ 1 ] ; y + + )
for ( int x = 0 ; x < res [ 0 ] ; x + + , index + + )
{
field [ index ] = field [ index + slabSize ] ;
}
}
2010-01-25 15:10:14 +00:00
2013-02-26 21:58:06 +00:00
if ( zEnd = = res [ 2 ] )
2010-01-25 15:10:14 +00:00
{
2013-02-26 21:58:06 +00:00
index = 0 ;
int indexx = 0 ;
const int cellsslab = totalCells - slabSize ;
2010-01-25 15:10:14 +00:00
2013-02-26 21:58:06 +00:00
for ( int y = 0 ; y < res [ 1 ] ; y + + )
for ( int x = 0 ; x < res [ 0 ] ; x + + , index + + )
{
// back slab
indexx = index + cellsslab ;
field [ indexx ] = field [ indexx - slabSize ] ;
}
2010-01-25 15:10:14 +00:00
}
2009-07-30 15:00:26 +00:00
}
/////////////////////////////////////////////////////////////////////
// advect field with the semi lagrangian method
//////////////////////////////////////////////////////////////////////
void FLUID_3D : : advectFieldSemiLagrange ( const float dt , const float * velx , const float * vely , const float * velz ,
2010-01-25 15:10:14 +00:00
float * oldField , float * newField , Vec3Int res , int zBegin , int zEnd )
2009-07-30 15:00:26 +00:00
{
const int xres = res [ 0 ] ;
const int yres = res [ 1 ] ;
const int zres = res [ 2 ] ;
const int slabSize = res [ 0 ] * res [ 1 ] ;
2010-01-25 15:10:14 +00:00
for ( int z = zBegin ; z < zEnd ; z + + )
2009-07-30 15:00:26 +00:00
for ( int y = 0 ; y < yres ; y + + )
for ( int x = 0 ; x < xres ; x + + )
{
const int index = x + y * xres + z * xres * yres ;
2009-09-09 18:39:40 +00:00
2009-07-30 15:00:26 +00:00
// backtrace
float xTrace = x - dt * velx [ index ] ;
float yTrace = y - dt * vely [ index ] ;
float zTrace = z - dt * velz [ index ] ;
// clamp backtrace to grid boundaries
2013-04-16 09:04:34 +00:00
if ( xTrace < 0.5f ) xTrace = 0.5f ;
if ( xTrace > xres - 1.5f ) xTrace = xres - 1.5f ;
if ( yTrace < 0.5f ) yTrace = 0.5f ;
if ( yTrace > yres - 1.5f ) yTrace = yres - 1.5f ;
if ( zTrace < 0.5f ) zTrace = 0.5f ;
if ( zTrace > zres - 1.5f ) zTrace = zres - 1.5f ;
2009-07-30 15:00:26 +00:00
// locate neighbors to interpolate
const int x0 = ( int ) xTrace ;
const int x1 = x0 + 1 ;
const int y0 = ( int ) yTrace ;
const int y1 = y0 + 1 ;
const int z0 = ( int ) zTrace ;
const int z1 = z0 + 1 ;
// get interpolation weights
const float s1 = xTrace - x0 ;
const float s0 = 1.0f - s1 ;
const float t1 = yTrace - y0 ;
const float t0 = 1.0f - t1 ;
const float u1 = zTrace - z0 ;
const float u0 = 1.0f - u1 ;
const int i000 = x0 + y0 * xres + z0 * slabSize ;
const int i010 = x0 + y1 * xres + z0 * slabSize ;
const int i100 = x1 + y0 * xres + z0 * slabSize ;
const int i110 = x1 + y1 * xres + z0 * slabSize ;
const int i001 = x0 + y0 * xres + z1 * slabSize ;
const int i011 = x0 + y1 * xres + z1 * slabSize ;
const int i101 = x1 + y0 * xres + z1 * slabSize ;
const int i111 = x1 + y1 * xres + z1 * slabSize ;
// interpolate
// (indices could be computed once)
newField [ index ] = u0 * ( s0 * ( t0 * oldField [ i000 ] +
t1 * oldField [ i010 ] ) +
s1 * ( t0 * oldField [ i100 ] +
t1 * oldField [ i110 ] ) ) +
u1 * ( s0 * ( t0 * oldField [ i001 ] +
t1 * oldField [ i011 ] ) +
s1 * ( t0 * oldField [ i101 ] +
t1 * oldField [ i111 ] ) ) ;
}
}
2010-01-25 15:10:14 +00:00
2009-07-30 15:00:26 +00:00
/////////////////////////////////////////////////////////////////////
// advect field with the maccormack method
//
// comments are the pseudocode from selle's paper
//////////////////////////////////////////////////////////////////////
2010-01-25 15:10:14 +00:00
void FLUID_3D : : advectFieldMacCormack1 ( const float dt , const float * xVelocity , const float * yVelocity , const float * zVelocity ,
float * oldField , float * tempResult , Vec3Int res , int zBegin , int zEnd )
2009-07-30 15:00:26 +00:00
{
2010-02-08 13:55:31 +00:00
/*const int sx= res[0];
2009-07-30 15:00:26 +00:00
const int sy = res [ 1 ] ;
const int sz = res [ 2 ] ;
2010-02-08 13:55:31 +00:00
for ( int x = 0 ; x < sx * sy * sz ; x + + )
2010-01-25 15:10:14 +00:00
phiHatN [ x ] = phiHatN1 [ x ] = oldField [ x ] ; */ // not needed as all the values are written first
2009-07-30 15:00:26 +00:00
float * & phiN = oldField ;
2010-01-25 15:10:14 +00:00
float * & phiN1 = tempResult ;
2009-07-30 15:00:26 +00:00
// phiHatN1 = A(phiN)
2010-01-25 15:10:14 +00:00
advectFieldSemiLagrange ( dt , xVelocity , yVelocity , zVelocity , phiN , phiN1 , res , zBegin , zEnd ) ; // uses wide data from old field and velocities (both are whole)
}
void FLUID_3D : : advectFieldMacCormack2 ( const float dt , const float * xVelocity , const float * yVelocity , const float * zVelocity ,
float * oldField , float * newField , float * tempResult , float * temp1 , Vec3Int res , const unsigned char * obstacles , int zBegin , int zEnd )
{
float * phiHatN = tempResult ;
float * t1 = temp1 ;
const int sx = res [ 0 ] ;
const int sy = res [ 1 ] ;
float * & phiN = oldField ;
float * & phiN1 = newField ;
2009-07-30 15:00:26 +00:00
// phiHatN = A^R(phiHatN1)
2013-04-16 09:04:34 +00:00
advectFieldSemiLagrange ( - 1.0f * dt , xVelocity , yVelocity , zVelocity , phiHatN , t1 , res , zBegin , zEnd ) ; // uses wide data from old field and velocities (both are whole)
2009-07-30 15:00:26 +00:00
// phiN1 = phiHatN1 + (phiN - phiHatN) / 2
2009-09-09 18:39:40 +00:00
const int border = 0 ;
2010-01-25 15:10:14 +00:00
for ( int z = zBegin + border ; z < zEnd - border ; z + + )
2009-07-30 15:00:26 +00:00
for ( int y = border ; y < sy - border ; y + + )
for ( int x = border ; x < sx - border ; x + + ) {
int index = x + y * sx + z * sx * sy ;
2010-01-25 15:10:14 +00:00
phiN1 [ index ] = phiHatN [ index ] + ( phiN [ index ] - t1 [ index ] ) * 0.50f ;
2009-07-30 15:00:26 +00:00
//phiN1[index] = phiHatN1[index]; // debug, correction off
}
2010-01-25 15:10:14 +00:00
copyBorderX ( phiN1 , res , zBegin , zEnd ) ;
copyBorderY ( phiN1 , res , zBegin , zEnd ) ;
copyBorderZ ( phiN1 , res , zBegin , zEnd ) ;
2009-07-30 15:00:26 +00:00
// clamp any newly created extrema
2010-01-25 15:10:14 +00:00
clampExtrema ( dt , xVelocity , yVelocity , zVelocity , oldField , newField , res , zBegin , zEnd ) ; // uses wide data from old field and velocities (both are whole)
2009-07-30 15:00:26 +00:00
// if the error estimate was bad, revert to first order
2010-01-25 15:10:14 +00:00
clampOutsideRays ( dt , xVelocity , yVelocity , zVelocity , oldField , newField , res , obstacles , phiHatN , zBegin , zEnd ) ; // phiHatN is only used at cells within thread range, so its ok
2009-09-09 18:39:40 +00:00
}
2009-07-30 15:00:26 +00:00
//////////////////////////////////////////////////////////////////////
// Clamp the extrema generated by the BFECC error correction
//////////////////////////////////////////////////////////////////////
void FLUID_3D : : clampExtrema ( const float dt , const float * velx , const float * vely , const float * velz ,
2010-01-25 15:10:14 +00:00
float * oldField , float * newField , Vec3Int res , int zBegin , int zEnd )
2009-07-30 15:00:26 +00:00
{
const int xres = res [ 0 ] ;
const int yres = res [ 1 ] ;
const int zres = res [ 2 ] ;
const int slabSize = res [ 0 ] * res [ 1 ] ;
2010-01-25 15:10:14 +00:00
int bb = 0 ;
int bt = 0 ;
if ( zBegin = = 0 ) { bb = 1 ; }
if ( zEnd = = res [ 2 ] ) { bt = 1 ; }
for ( int z = zBegin + bb ; z < zEnd - bt ; z + + )
2009-07-30 15:00:26 +00:00
for ( int y = 1 ; y < yres - 1 ; y + + )
for ( int x = 1 ; x < xres - 1 ; x + + )
{
const int index = x + y * xres + z * xres * yres ;
// backtrace
float xTrace = x - dt * velx [ index ] ;
float yTrace = y - dt * vely [ index ] ;
float zTrace = z - dt * velz [ index ] ;
// clamp backtrace to grid boundaries
2013-04-16 09:04:34 +00:00
if ( xTrace < 0.5f ) xTrace = 0.5f ;
if ( xTrace > xres - 1.5f ) xTrace = xres - 1.5f ;
if ( yTrace < 0.5f ) yTrace = 0.5f ;
if ( yTrace > yres - 1.5f ) yTrace = yres - 1.5f ;
if ( zTrace < 0.5f ) zTrace = 0.5f ;
if ( zTrace > zres - 1.5f ) zTrace = zres - 1.5f ;
2009-07-30 15:00:26 +00:00
// locate neighbors to interpolate
const int x0 = ( int ) xTrace ;
const int x1 = x0 + 1 ;
const int y0 = ( int ) yTrace ;
const int y1 = y0 + 1 ;
const int z0 = ( int ) zTrace ;
const int z1 = z0 + 1 ;
const int i000 = x0 + y0 * xres + z0 * slabSize ;
const int i010 = x0 + y1 * xres + z0 * slabSize ;
const int i100 = x1 + y0 * xres + z0 * slabSize ;
const int i110 = x1 + y1 * xres + z0 * slabSize ;
const int i001 = x0 + y0 * xres + z1 * slabSize ;
const int i011 = x0 + y1 * xres + z1 * slabSize ;
const int i101 = x1 + y0 * xres + z1 * slabSize ;
const int i111 = x1 + y1 * xres + z1 * slabSize ;
float minField = oldField [ i000 ] ;
float maxField = oldField [ i000 ] ;
minField = ( oldField [ i010 ] < minField ) ? oldField [ i010 ] : minField ;
maxField = ( oldField [ i010 ] > maxField ) ? oldField [ i010 ] : maxField ;
minField = ( oldField [ i100 ] < minField ) ? oldField [ i100 ] : minField ;
maxField = ( oldField [ i100 ] > maxField ) ? oldField [ i100 ] : maxField ;
minField = ( oldField [ i110 ] < minField ) ? oldField [ i110 ] : minField ;
maxField = ( oldField [ i110 ] > maxField ) ? oldField [ i110 ] : maxField ;
minField = ( oldField [ i001 ] < minField ) ? oldField [ i001 ] : minField ;
maxField = ( oldField [ i001 ] > maxField ) ? oldField [ i001 ] : maxField ;
minField = ( oldField [ i011 ] < minField ) ? oldField [ i011 ] : minField ;
maxField = ( oldField [ i011 ] > maxField ) ? oldField [ i011 ] : maxField ;
minField = ( oldField [ i101 ] < minField ) ? oldField [ i101 ] : minField ;
maxField = ( oldField [ i101 ] > maxField ) ? oldField [ i101 ] : maxField ;
minField = ( oldField [ i111 ] < minField ) ? oldField [ i111 ] : minField ;
maxField = ( oldField [ i111 ] > maxField ) ? oldField [ i111 ] : maxField ;
newField [ index ] = ( newField [ index ] > maxField ) ? maxField : newField [ index ] ;
newField [ index ] = ( newField [ index ] < minField ) ? minField : newField [ index ] ;
}
}
//////////////////////////////////////////////////////////////////////
2009-09-09 18:39:40 +00:00
// Reverts any backtraces that go into boundaries back to first
2009-07-30 15:00:26 +00:00
// order -- in this case the error correction term was totally
// incorrect
//////////////////////////////////////////////////////////////////////
2009-09-09 18:39:40 +00:00
void FLUID_3D : : clampOutsideRays ( const float dt , const float * velx , const float * vely , const float * velz ,
2010-01-25 15:10:14 +00:00
float * oldField , float * newField , Vec3Int res , const unsigned char * obstacles , const float * oldAdvection , int zBegin , int zEnd )
2009-07-30 15:00:26 +00:00
{
const int sx = res [ 0 ] ;
const int sy = res [ 1 ] ;
const int sz = res [ 2 ] ;
const int slabSize = res [ 0 ] * res [ 1 ] ;
2009-09-09 18:39:40 +00:00
2010-01-25 15:10:14 +00:00
int bb = 0 ;
int bt = 0 ;
if ( zBegin = = 0 ) { bb = 1 ; }
if ( zEnd = = res [ 2 ] ) { bt = 1 ; }
for ( int z = zBegin + bb ; z < zEnd - bt ; z + + )
2009-07-30 15:00:26 +00:00
for ( int y = 1 ; y < sy - 1 ; y + + )
for ( int x = 1 ; x < sx - 1 ; x + + )
{
const int index = x + y * sx + z * slabSize ;
// backtrace
float xBackward = x + dt * velx [ index ] ;
float yBackward = y + dt * vely [ index ] ;
float zBackward = z + dt * velz [ index ] ;
float xTrace = x - dt * velx [ index ] ;
float yTrace = y - dt * vely [ index ] ;
float zTrace = z - dt * velz [ index ] ;
// see if it goes outside the boundaries
2009-09-09 18:39:40 +00:00
bool hasObstacle =
2009-07-30 15:00:26 +00:00
( zTrace < 1.0f ) | | ( zTrace > sz - 2.0f ) | |
( yTrace < 1.0f ) | | ( yTrace > sy - 2.0f ) | |
( xTrace < 1.0f ) | | ( xTrace > sx - 2.0f ) | |
( zBackward < 1.0f ) | | ( zBackward > sz - 2.0f ) | |
( yBackward < 1.0f ) | | ( yBackward > sy - 2.0f ) | |
( xBackward < 1.0f ) | | ( xBackward > sx - 2.0f ) ;
// reuse old advection instead of doing another one...
if ( hasObstacle ) { newField [ index ] = oldAdvection [ index ] ; continue ; }
// clamp to prevent an out of bounds access when looking into
// the _obstacles array
zTrace = ( zTrace < 0.5f ) ? 0.5f : zTrace ;
zTrace = ( zTrace > sz - 1.5f ) ? sz - 1.5f : zTrace ;
yTrace = ( yTrace < 0.5f ) ? 0.5f : yTrace ;
yTrace = ( yTrace > sy - 1.5f ) ? sy - 1.5f : yTrace ;
xTrace = ( xTrace < 0.5f ) ? 0.5f : xTrace ;
xTrace = ( xTrace > sx - 1.5f ) ? sx - 1.5f : xTrace ;
// locate neighbors to interpolate,
// do backward first since we will use the forward indices if a
// reversion is actually necessary
zBackward = ( zBackward < 0.5f ) ? 0.5f : zBackward ;
zBackward = ( zBackward > sz - 1.5f ) ? sz - 1.5f : zBackward ;
yBackward = ( yBackward < 0.5f ) ? 0.5f : yBackward ;
yBackward = ( yBackward > sy - 1.5f ) ? sy - 1.5f : yBackward ;
xBackward = ( xBackward < 0.5f ) ? 0.5f : xBackward ;
xBackward = ( xBackward > sx - 1.5f ) ? sx - 1.5f : xBackward ;
int x0 = ( int ) xBackward ;
int x1 = x0 + 1 ;
int y0 = ( int ) yBackward ;
int y1 = y0 + 1 ;
int z0 = ( int ) zBackward ;
int z1 = z0 + 1 ;
if ( obstacles & & ! hasObstacle ) {
2009-09-09 18:39:40 +00:00
hasObstacle = hasObstacle | |
2009-07-30 15:00:26 +00:00
obstacles [ x0 + y0 * sx + z0 * slabSize ] | |
obstacles [ x0 + y1 * sx + z0 * slabSize ] | |
obstacles [ x1 + y0 * sx + z0 * slabSize ] | |
obstacles [ x1 + y1 * sx + z0 * slabSize ] | |
obstacles [ x0 + y0 * sx + z1 * slabSize ] | |
obstacles [ x0 + y1 * sx + z1 * slabSize ] | |
obstacles [ x1 + y0 * sx + z1 * slabSize ] | |
obstacles [ x1 + y1 * sx + z1 * slabSize ] ;
}
// reuse old advection instead of doing another one...
if ( hasObstacle ) { newField [ index ] = oldAdvection [ index ] ; continue ; }
x0 = ( int ) xTrace ;
x1 = x0 + 1 ;
y0 = ( int ) yTrace ;
y1 = y0 + 1 ;
z0 = ( int ) zTrace ;
z1 = z0 + 1 ;
if ( obstacles & & ! hasObstacle ) {
2009-09-09 18:39:40 +00:00
hasObstacle = hasObstacle | |
2009-07-30 15:00:26 +00:00
obstacles [ x0 + y0 * sx + z0 * slabSize ] | |
obstacles [ x0 + y1 * sx + z0 * slabSize ] | |
obstacles [ x1 + y0 * sx + z0 * slabSize ] | |
obstacles [ x1 + y1 * sx + z0 * slabSize ] | |
obstacles [ x0 + y0 * sx + z1 * slabSize ] | |
obstacles [ x0 + y1 * sx + z1 * slabSize ] | |
obstacles [ x1 + y0 * sx + z1 * slabSize ] | |
obstacles [ x1 + y1 * sx + z1 * slabSize ] ;
} // obstacle array
// reuse old advection instead of doing another one...
if ( hasObstacle ) { newField [ index ] = oldAdvection [ index ] ; continue ; }
// see if either the forward or backward ray went into
// a boundary
if ( hasObstacle ) {
// get interpolation weights
float s1 = xTrace - x0 ;
float s0 = 1.0f - s1 ;
float t1 = yTrace - y0 ;
float t0 = 1.0f - t1 ;
float u1 = zTrace - z0 ;
float u0 = 1.0f - u1 ;
const int i000 = x0 + y0 * sx + z0 * slabSize ;
const int i010 = x0 + y1 * sx + z0 * slabSize ;
const int i100 = x1 + y0 * sx + z0 * slabSize ;
const int i110 = x1 + y1 * sx + z0 * slabSize ;
const int i001 = x0 + y0 * sx + z1 * slabSize ;
const int i011 = x0 + y1 * sx + z1 * slabSize ;
const int i101 = x1 + y0 * sx + z1 * slabSize ;
const int i111 = x1 + y1 * sx + z1 * slabSize ;
// interpolate, (indices could be computed once)
newField [ index ] = u0 * ( s0 * (
t0 * oldField [ i000 ] +
t1 * oldField [ i010 ] ) +
s1 * ( t0 * oldField [ i100 ] +
t1 * oldField [ i110 ] ) ) +
u1 * ( s0 * ( t0 * oldField [ i001 ] +
t1 * oldField [ i011 ] ) +
s1 * ( t0 * oldField [ i101 ] +
2009-09-09 18:39:40 +00:00
t1 * oldField [ i111 ] ) ) ;
2009-07-30 15:00:26 +00:00
}
} // xyz
}