From a0ebfab4f3a31f08da651cf129982cbb419e0603 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastia=CC=81n=20Barschkis?= Date: Tue, 6 Oct 2020 18:17:20 +0200 Subject: Fluid: Updated Mantaflow source files Among code cleanups, this update includes a new flood-fill helper function for levelsets. --- extern/mantaflow/preprocessed/fileio/iovdb.cpp | 2 + extern/mantaflow/preprocessed/gitinfo.h | 2 +- extern/mantaflow/preprocessed/grid.h | 2 - extern/mantaflow/preprocessed/levelset.cpp | 199 +++++++++++++++++++++ extern/mantaflow/preprocessed/levelset.h | 29 +++ extern/mantaflow/preprocessed/levelset.h.reg.cpp | 2 + .../mantaflow/preprocessed/plugin/initplugins.cpp | 7 +- 7 files changed, 239 insertions(+), 4 deletions(-) (limited to 'extern/mantaflow/preprocessed') diff --git a/extern/mantaflow/preprocessed/fileio/iovdb.cpp b/extern/mantaflow/preprocessed/fileio/iovdb.cpp index b31f7e0e760..b990274e1c4 100644 --- a/extern/mantaflow/preprocessed/fileio/iovdb.cpp +++ b/extern/mantaflow/preprocessed/fileio/iovdb.cpp @@ -405,6 +405,7 @@ int writeObjectsVDB(const string &filename, vdb_flags = openvdb::io::COMPRESS_NONE; break; } + default: case COMPRESSION_ZIP: { vdb_flags |= openvdb::io::COMPRESS_ZIP; break; @@ -445,6 +446,7 @@ int readObjectsVDB(const string &filename, std::vector *objects, floa (void)metadata; // Unused for now } catch (const openvdb::IoError &e) { + (void)e; // Unused for now debMsg("readObjectsVDB: Could not open vdb file " << filename, 1); file.close(); return 0; diff --git a/extern/mantaflow/preprocessed/gitinfo.h b/extern/mantaflow/preprocessed/gitinfo.h index e87c8739cf4..64367e0e096 100644 --- a/extern/mantaflow/preprocessed/gitinfo.h +++ b/extern/mantaflow/preprocessed/gitinfo.h @@ -1,3 +1,3 @@ -#define MANTA_GIT_VERSION "commit e2f6e59e3679f88e5100ae2145410cca4971b9df" +#define MANTA_GIT_VERSION "commit b8e557707805720ff00a8eb946db2ee5b9361b5a" diff --git a/extern/mantaflow/preprocessed/grid.h b/extern/mantaflow/preprocessed/grid.h index 9bd4e5d72d9..ec70cc953ff 100644 --- a/extern/mantaflow/preprocessed/grid.h +++ b/extern/mantaflow/preprocessed/grid.h @@ -355,7 +355,6 @@ class GridBase : public PbClass { return isInBounds(Vec3i(i, j, k), bnd); } -#ifdef BLENDER //! expose name field to Python for Blender void setName(const std::string &name) { @@ -386,7 +385,6 @@ class GridBase : public PbClass { } } -#endif protected: GridType mType; Vec3i mSize; diff --git a/extern/mantaflow/preprocessed/levelset.cpp b/extern/mantaflow/preprocessed/levelset.cpp index a6f9fb40f3f..122f71917eb 100644 --- a/extern/mantaflow/preprocessed/levelset.cpp +++ b/extern/mantaflow/preprocessed/levelset.cpp @@ -639,8 +639,207 @@ void LevelsetGrid::initFromFlags(const FlagGrid &flags, bool ignoreWalls) } } +/* Helper variables that are used in flood-fill functions. */ +static const int ID_UNKNOWN = 0; +static const int ID_VISITED = 1; + +/* Fills all cells in the target grid that have not been marked during a flood-fill. */ + +struct KnFillApply : public KernelBase { + KnFillApply(Grid &target, + Grid &visited, + const Real value, + const int boundaryWidth, + const bool outside) + : KernelBase(&target, boundaryWidth), + target(target), + visited(visited), + value(value), + boundaryWidth(boundaryWidth), + outside(outside) + { + runMessage(); + run(); + } + inline void op(int i, + int j, + int k, + Grid &target, + Grid &visited, + const Real value, + const int boundaryWidth, + const bool outside) const + { + + if (visited(i, j, k) == ID_VISITED) + return; + if (outside && target(i, j, k) < 0) + return; + if (!outside && target(i, j, k) >= 0) + return; + + /* Actual flood-fill override. */ + target(i, j, k) = value; + } + inline Grid &getArg0() + { + return target; + } + typedef Grid type0; + inline Grid &getArg1() + { + return visited; + } + typedef Grid type1; + inline const Real &getArg2() + { + return value; + } + typedef Real type2; + inline const int &getArg3() + { + return boundaryWidth; + } + typedef int type3; + inline const bool &getArg4() + { + return outside; + } + typedef bool type4; + void runMessage() + { + debMsg("Executing kernel KnFillApply ", 3); + debMsg("Kernel range" + << " x " << maxX << " y " << maxY << " z " << minZ << " - " << maxZ << " ", + 4); + }; + void operator()(const tbb::blocked_range &__r) const + { + const int _maxX = maxX; + const int _maxY = maxY; + if (maxZ > 1) { + for (int k = __r.begin(); k != (int)__r.end(); k++) + for (int j = boundaryWidth; j < _maxY; j++) + for (int i = boundaryWidth; i < _maxX; i++) + op(i, j, k, target, visited, value, boundaryWidth, outside); + } + else { + const int k = 0; + for (int j = __r.begin(); j != (int)__r.end(); j++) + for (int i = boundaryWidth; i < _maxX; i++) + op(i, j, k, target, visited, value, boundaryWidth, outside); + } + } + void run() + { + if (maxZ > 1) + tbb::parallel_for(tbb::blocked_range(minZ, maxZ), *this); + else + tbb::parallel_for(tbb::blocked_range(boundaryWidth, maxY), *this); + } + Grid ⌖ + Grid &visited; + const Real value; + const int boundaryWidth; + const bool outside; +}; + +/* Basic flood fill implementation used to fill inside / outside areas of levelset. + * Calling this function will ensure that there are no fluid cells inside obstacles. + * I.e. starting from walls, cells will be tagged in flood-fill fashion, stopping at 0 borders. + * All remaining cells will be filled with the fill value. Outside mode inverts search behavior. */ +void LevelsetGrid::floodFill(const Real value, const bool outside, const int boundaryWidth) +{ + + /* Sanity check: Filling mode and filling value need to "match". */ + if (outside) { + assertMsg(value < 0, "Cannot fill outside with (positive) value " << value); + } + else { + assertMsg(value >= 0, "Cannot fill inside with (negative) value " << value); + } + + Grid levelsetCopy(this->getParent()); + Grid visited(this->getParent()); + std::stack todoPos; + + const int maxNeighbors = this->is3D() ? 6 : 4; + const Vec3i maxSize(this->getSize() - 1); + + Vec3i bnd(2 * boundaryWidth); + if (!this->is3D()) + bnd.z = 0; + const int cellCntNoBnd = (this->getSizeX() - bnd.x) * (this->getSizeY() - bnd.y) * + (this->getSizeZ() - bnd.z); + + /* Initialize temporary helper grids. */ + levelsetCopy.copyFrom(*this); + visited.setConst(ID_UNKNOWN); + + FOR_IJK_BND(visited, boundaryWidth) + { + + /* Skip inside / outside cells depending on search mode. */ + if (outside && levelsetCopy(i, j, k) < 0) + continue; + if (!outside && levelsetCopy(i, j, k) >= 0) + continue; + /* Skip cell if it already has been visited. */ + if (visited(i, j, k) == ID_VISITED) + continue; + + Vec3i c(i, j, k); + + bool isWallCell = (c.x - boundaryWidth == 0 || c.x == maxSize.x - boundaryWidth); + isWallCell |= (c.y - boundaryWidth == 0 || c.y == maxSize.y - boundaryWidth); + if (this->is3D()) + isWallCell |= (c.z - boundaryWidth == 0 || c.z == maxSize.z - boundaryWidth); + + /* Only start searching from borders. */ + if (!isWallCell) + continue; + + /* Start flood-fill loop by initializing todo stack with current cell. */ + todoPos.push(c); + visited(c) = ID_VISITED; + + while (!todoPos.empty()) { + c = todoPos.top(); + todoPos.pop(); + + /* Add all neighbor cells to search stack. */ + for (int nb = 0; nb < maxNeighbors; nb++) { + const Vec3i neigh(c + neighbors[nb]); + + if (!visited.isInBounds(neigh, boundaryWidth)) + continue; + /* Skip inside / outside area depening on what we search for. */ + if (outside && levelsetCopy(neigh) < 0) + continue; + if (!outside && levelsetCopy(neigh) >= 0) + continue; + /* Skip neighbor if it already has been visited. */ + if (visited(neigh) == ID_VISITED) + continue; + + assertMsg(visited(neigh) == ID_UNKNOWN, + "Cell must be of type 'unknown' at this point in the loop"); + todoPos.push(neigh); + visited(neigh) = ID_VISITED; + } + assertMsg(todoPos.size() <= cellCntNoBnd, + "Flood-fill todo stack cannot be greater than domain cell count - " + << todoPos.size() << " vs " << cellCntNoBnd); + } + } + KnFillApply(*this, visited, value, boundaryWidth, outside); +} + +/* Deprecated: Use floodFill() function instead. */ void LevelsetGrid::fillHoles(int maxDepth, int boundaryWidth) { + debMsg("Deprecated - do not use fillHoles() ... use floodFill() instead", 1); + Real curVal, i1, i2, j1, j2, k1, k2; Vec3i c, cTmp; std::stack undoPos; diff --git a/extern/mantaflow/preprocessed/levelset.h b/extern/mantaflow/preprocessed/levelset.h index ab36ac24903..ff47cf7c8d2 100644 --- a/extern/mantaflow/preprocessed/levelset.h +++ b/extern/mantaflow/preprocessed/levelset.h @@ -234,6 +234,35 @@ class LevelsetGrid : public Grid { } } + //! flood-fill the levelset to ensure that closed obstacles are filled inside + void floodFill(const Real value = -0.5, const bool outside = true, const int boundaryWidth = 1); + static PyObject *_W_7(PyObject *_self, PyObject *_linargs, PyObject *_kwds) + { + try { + PbArgs _args(_linargs, _kwds); + LevelsetGrid *pbo = dynamic_cast(Pb::objFromPy(_self)); + bool noTiming = _args.getOpt("notiming", -1, 0); + pbPreparePlugin(pbo->getParent(), "LevelsetGrid::floodFill", !noTiming); + PyObject *_retval = 0; + { + ArgLocker _lock; + const Real value = _args.getOpt("value", 0, -0.5, &_lock); + const bool outside = _args.getOpt("outside", 1, true, &_lock); + const int boundaryWidth = _args.getOpt("boundaryWidth", 2, 1, &_lock); + pbo->_args.copy(_args); + _retval = getPyNone(); + pbo->floodFill(value, outside, boundaryWidth); + pbo->_args.check(); + } + pbFinalizePlugin(pbo->getParent(), "LevelsetGrid::floodFill", !noTiming); + return _retval; + } + catch (std::exception &e) { + pbSetError("LevelsetGrid::floodFill", e.what()); + return 0; + } + } + static Real invalidTimeValue(); public: PbArgs _args; diff --git a/extern/mantaflow/preprocessed/levelset.h.reg.cpp b/extern/mantaflow/preprocessed/levelset.h.reg.cpp index dc6669b5da3..f780e0933f9 100644 --- a/extern/mantaflow/preprocessed/levelset.h.reg.cpp +++ b/extern/mantaflow/preprocessed/levelset.h.reg.cpp @@ -15,6 +15,7 @@ static const Pb::Register _R_15("LevelsetGrid", "join", LevelsetGrid::_W_3); static const Pb::Register _R_16("LevelsetGrid", "subtract", LevelsetGrid::_W_4); static const Pb::Register _R_17("LevelsetGrid", "initFromFlags", LevelsetGrid::_W_5); static const Pb::Register _R_18("LevelsetGrid", "fillHoles", LevelsetGrid::_W_6); +static const Pb::Register _R_19("LevelsetGrid", "floodFill", LevelsetGrid::_W_7); #endif extern "C" { void PbRegister_file_11() @@ -27,6 +28,7 @@ void PbRegister_file_11() KEEP_UNUSED(_R_16); KEEP_UNUSED(_R_17); KEEP_UNUSED(_R_18); + KEEP_UNUSED(_R_19); } } } // namespace Manta \ No newline at end of file diff --git a/extern/mantaflow/preprocessed/plugin/initplugins.cpp b/extern/mantaflow/preprocessed/plugin/initplugins.cpp index 6ccd3afc8d1..6e8a3580d93 100644 --- a/extern/mantaflow/preprocessed/plugin/initplugins.cpp +++ b/extern/mantaflow/preprocessed/plugin/initplugins.cpp @@ -695,7 +695,12 @@ struct KnApplyEmission : public KernelBase { // (important for emit from particles) bool isInflow = (type & FlagGrid::TypeInflow && flags.isInflow(i, j, k)); bool isOutflow = (type & FlagGrid::TypeOutflow && flags.isOutflow(i, j, k)); - if ((type && !isInflow && !isOutflow) && (emissionTexture && !(*emissionTexture)(i, j, k))) + + if (type && !isInflow) + return; + if (type && isOutflow) + return; + if (emissionTexture && !(*emissionTexture)(i, j, k)) return; if (isAbsolute) -- cgit v1.2.3