/** \file smoke/intern/INTERPOLATE.h * \ingroup smoke */ ////////////////////////////////////////////////////////////////////// // 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 . // // Copyright 2008 Theodore Kim and Nils Thuerey // ////////////////////////////////////////////////////////////////////// #ifndef INTERPOLATE_H #define INTERPOLATE_H #include #include namespace INTERPOLATE { ////////////////////////////////////////////////////////////////////// // linear interpolators ////////////////////////////////////////////////////////////////////// static inline float lerp(float t, float a, float b) { return ( a + t * (b - a) ); } static inline float lerp(float* field, float x, float y, int res) { // clamp backtrace to grid boundaries if (x < 0.5f) x = 0.5f; if (x > res - 1.5f) x = res - 1.5f; if (y < 0.5f) y = 0.5f; if (y > res - 1.5f) y = res - 1.5f; const int x0 = (int)x; const int y0 = (int)y; x -= x0; y -= y0; float d00, d10, d01, d11; // lerp the velocities d00 = field[x0 + y0 * res]; d10 = field[(x0 + 1) + y0 * res]; d01 = field[x0 + (y0 + 1) * res]; d11 = field[(x0 + 1) + (y0 + 1) * res]; return lerp(y, lerp(x, d00, d10), lerp(x, d01, d11)); } ////////////////////////////////////////////////////////////////////////////////////////// // 3d linear interpolation ////////////////////////////////////////////////////////////////////////////////////////// static inline float lerp3d(float* field, float x, float y, float z, int xres, int yres, int zres) { // clamp pos to grid boundaries if (x < 0.5f) x = 0.5f; if (x > xres - 1.5f) x = xres - 1.5f; if (y < 0.5f) y = 0.5f; if (y > yres - 1.5f) y = yres - 1.5f; if (z < 0.5f) z = 0.5f; if (z > zres - 1.5f) z = zres - 1.5f; // locate neighbors to interpolate const int x0 = (int)x; const int x1 = x0 + 1; const int y0 = (int)y; const int y1 = y0 + 1; const int z0 = (int)z; const int z1 = z0 + 1; // get interpolation weights const float s1 = x - (float)x0; const float s0 = 1.0f - s1; const float t1 = y - (float)y0; const float t0 = 1.0f - t1; const float u1 = z - (float)z0; const float u0 = 1.0f - u1; const int slabSize = xres*yres; 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) return ( u0 * (s0 * (t0 * field[i000] + t1 * field[i010]) + s1 * (t0 * field[i100] + t1 * field[i110])) + u1 * (s0 * (t0 * field[i001] + t1 * field[i011]) + s1 * (t0 * field[i101] + t1 * field[i111])) ); } ////////////////////////////////////////////////////////////////////////////////////////// // convert field entries of type T to floats, then interpolate ////////////////////////////////////////////////////////////////////////////////////////// template static inline float lerp3dToFloat(T* field1, float x, float y, float z, int xres, int yres, int zres) { // clamp pos to grid boundaries if (x < 0.5f) x = 0.5f; if (x > xres - 1.5f) x = xres - 1.5f; if (y < 0.5f) y = 0.5f; if (y > yres - 1.5f) y = yres - 1.5f; if (z < 0.5f) z = 0.5f; if (z > zres - 1.5f) z = zres - 1.5f; // locate neighbors to interpolate const int x0 = (int)x; const int x1 = x0 + 1; const int y0 = (int)y; const int y1 = y0 + 1; const int z0 = (int)z; const int z1 = z0 + 1; // get interpolation weights const float s1 = x - (float)x0; const float s0 = 1.0f - s1; const float t1 = y - (float)y0; const float t0 = 1.0f - t1; const float u1 = z - (float)z0; const float u0 = 1.0f - u1; const int slabSize = xres*yres; 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) return (float)( ( u0 * (s0 * (t0 * (float)field1[i000] + t1 * (float)field1[i010]) + s1 * (t0 * (float)field1[i100] + t1 * (float)field1[i110])) + u1 * (s0 * (t0 * (float)field1[i001] + t1 * (float)field1[i011]) + s1 * (t0 * (float)field1[i101] + t1 * (float)field1[i111])) ) ); } ////////////////////////////////////////////////////////////////////////////////////////// // interpolate a vector from 3 fields ////////////////////////////////////////////////////////////////////////////////////////// static inline Vec3 lerp3dVec(float* field1, float* field2, float* field3, float x, float y, float z, int xres, int yres, int zres) { // clamp pos to grid boundaries if (x < 0.5f) x = 0.5f; if (x > xres - 1.5f) x = xres - 1.5f; if (y < 0.5f) y = 0.5f; if (y > yres - 1.5f) y = yres - 1.5f; if (z < 0.5f) z = 0.5f; if (z > zres - 1.5f) z = zres - 1.5f; // locate neighbors to interpolate const int x0 = (int)x; const int x1 = x0 + 1; const int y0 = (int)y; const int y1 = y0 + 1; const int z0 = (int)z; const int z1 = z0 + 1; // get interpolation weights const float s1 = x - (float)x0; const float s0 = 1.0f - s1; const float t1 = y - (float)y0; const float t0 = 1.0f - t1; const float u1 = z - (float)z0; const float u0 = 1.0f - u1; const int slabSize = xres*yres; 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) return Vec3( ( u0 * (s0 * (t0 * field1[i000] + t1 * field1[i010]) + s1 * (t0 * field1[i100] + t1 * field1[i110])) + u1 * (s0 * (t0 * field1[i001] + t1 * field1[i011]) + s1 * (t0 * field1[i101] + t1 * field1[i111])) ) , ( u0 * (s0 * (t0 * field2[i000] + t1 * field2[i010]) + s1 * (t0 * field2[i100] + t1 * field2[i110])) + u1 * (s0 * (t0 * field2[i001] + t1 * field2[i011]) + s1 * (t0 * field2[i101] + t1 * field2[i111])) ) , ( u0 * (s0 * (t0 * field3[i000] + t1 * field3[i010]) + s1 * (t0 * field3[i100] + t1 * field3[i110])) + u1 * (s0 * (t0 * field3[i001] + t1 * field3[i011]) + s1 * (t0 * field3[i101] + t1 * field3[i111])) ) ); } }; #endif