// DO NOT EDIT ! // This file is generated using the MantaFlow preprocessor (prep generate). /****************************************************************************** * * MantaFlow fluid solver framework * Copyright 2020 Sebastian Barschkis, Nils Thuerey * * This program is free software, distributed under the terms of the * Apache License, Version 2.0 * http://www.apache.org/licenses/LICENSE-2.0 * * Loading and writing grids and particles from and to OpenVDB files. * ******************************************************************************/ #include #include #include #include #include "mantaio.h" #include "grid.h" #include "vector4d.h" #include "grid4d.h" #include "particle.h" #if OPENVDB == 1 # include "openvdb/openvdb.h" # include # include # include # include #endif #define POSITION_NAME "P" #define FLAG_NAME "U" #define META_BASE_RES "file_base_resolution" #define META_VOXEL_SIZE "file_voxel_size" #define META_BBOX_MAX "file_bbox_max" #define META_BBOX_MIN "file_bbox_min" using namespace std; namespace Manta { #if OPENVDB == 1 template void importVDB(typename GridType::Ptr from, Grid *to) { using ValueT = typename GridType::ValueType; // Check if current grid is to be read as a sparse grid, active voxels (only) will be copied if (to->saveSparse()) { to->clear(); // Ensure that destination grid is empty before writing for (typename GridType::ValueOnCIter iter = from->cbeginValueOn(); iter.test(); ++iter) { ValueT vdbValue = *iter; openvdb::Coord coord = iter.getCoord(); T toMantaValue; convertFrom(vdbValue, &toMantaValue); to->set(coord.x(), coord.y(), coord.z(), toMantaValue); } } // When importing all grid cells, using a grid accessor is usually faster than a value iterator else { typename GridType::Accessor accessor = from->getAccessor(); FOR_IJK(*to) { openvdb::Coord xyz(i, j, k); ValueT vdbValue = accessor.getValue(xyz); T toMantaValue; convertFrom(vdbValue, &toMantaValue); to->set(i, j, k, toMantaValue); } } } template void importVDB(VDBType vdbValue, ParticleDataImpl *to, int index, float voxelSize) { unusedParameter(voxelSize); // Unused for now T toMantaValue; convertFrom(vdbValue, &toMantaValue); to->set(index, toMantaValue); } void importVDB(openvdb::points::PointDataGrid::Ptr from, BasicParticleSystem *to, std::vector &toPData, float voxelSize) { openvdb::Index64 count = openvdb::points::pointCount(from->tree()); to->resizeAll(count); int cnt = 0; for (auto leafIter = from->tree().cbeginLeaf(); leafIter; ++leafIter) { const openvdb::points::AttributeArray &positionArray = leafIter->constAttributeArray( POSITION_NAME); const openvdb::points::AttributeArray &flagArray = leafIter->constAttributeArray(FLAG_NAME); openvdb::points::AttributeHandle positionHandle(positionArray); openvdb::points::AttributeHandle flagHandle(flagArray); // Get vdb handles to pdata objects in pdata list std::vector>> pDataHandlesInt; std::vector>> pDataHandlesReal; std::vector>> pDataHandlesVec3; int pDataIndex = 0; for (ParticleDataBase *pdb : toPData) { std::string name = pdb->getName(); const openvdb::points::AttributeArray &pDataArray = leafIter->constAttributeArray(name); if (pdb->getType() == ParticleDataBase::TypeInt) { openvdb::points::AttributeHandle intHandle(pDataArray); std::tuple> tuple = std::make_tuple(pDataIndex, intHandle); pDataHandlesInt.push_back(tuple); } else if (pdb->getType() == ParticleDataBase::TypeReal) { openvdb::points::AttributeHandle floatHandle(pDataArray); std::tuple> tuple = std::make_tuple( pDataIndex, floatHandle); pDataHandlesReal.push_back(tuple); } else if (pdb->getType() == ParticleDataBase::TypeVec3) { openvdb::points::AttributeHandle vec3Handle(pDataArray); std::tuple> tuple = std::make_tuple( pDataIndex, vec3Handle); pDataHandlesVec3.push_back(tuple); } else { errMsg("importVDB: unknown ParticleDataBase type"); } ++pDataIndex; } for (auto indexIter = leafIter->beginIndexOn(); indexIter; ++indexIter) { // Extract the voxel-space position of the point (always between (-0.5, -0.5, -0.5) and (0.5, // 0.5, 0.5)). openvdb::Vec3s voxelPosition = positionHandle.get(*indexIter); const openvdb::Vec3d xyz = indexIter.getCoord().asVec3d(); // Compute the world-space position of the point. openvdb::Vec3f worldPosition = from->transform().indexToWorld(voxelPosition + xyz); int flag = flagHandle.get(*indexIter); Vec3 toMantaValue; convertFrom(worldPosition, &toMantaValue); (*to)[cnt].pos = toMantaValue; (*to)[cnt].pos /= voxelSize; // convert from world space to grid space (*to)[cnt].flag = flag; for (std::tuple> tuple : pDataHandlesInt) { int pDataIndex = std::get<0>(tuple); int vdbValue = std::get<1>(tuple).get(*indexIter); ParticleDataImpl *pdi = dynamic_cast *>(toPData[pDataIndex]); importVDB(vdbValue, pdi, cnt, voxelSize); } for (std::tuple> tuple : pDataHandlesReal) { int pDataIndex = std::get<0>(tuple); float vdbValue = std::get<1>(tuple).get(*indexIter); ParticleDataImpl *pdi = dynamic_cast *>(toPData[pDataIndex]); importVDB(vdbValue, pdi, cnt, voxelSize); } for (std::tuple> tuple : pDataHandlesVec3) { int pDataIndex = std::get<0>(tuple); openvdb::Vec3f voxelPosition = std::get<1>(tuple).get(*indexIter); ParticleDataImpl *pdi = dynamic_cast *>(toPData[pDataIndex]); importVDB(voxelPosition, pdi, cnt, voxelSize); } ++cnt; } } } template static void setGridOptions(typename GridType::Ptr grid, string name, openvdb::GridClass cls, float voxelSize, int precision) { grid->setTransform(openvdb::math::Transform::createLinearTransform(voxelSize)); grid->setGridClass(cls); grid->setName(name); grid->setSaveFloatAsHalf(precision == PRECISION_MINI || precision == PRECISION_HALF); } template typename GridType::Ptr exportVDB(Grid *from, float clip, openvdb::FloatGrid::Ptr clipGrid) { using ValueT = typename GridType::ValueType; typename GridType::Ptr to = GridType::create(ValueT(0)); // Copy data from grid by creating a vdb dense structure and then copying that into a vdb grid // This is the fastest way to copy data for both dense and sparse grids -> if (true) if (true) { ValueT *data = (ValueT *)from->getData(); openvdb::math::CoordBBox bbox( openvdb::Coord(0), openvdb::Coord(from->getSizeX() - 1, from->getSizeY() - 1, from->getSizeZ() - 1)); openvdb::tools::Dense dense(bbox, data); // Use clip value, or (when not exporting in sparse mode) clear it in order to copy all values // of dense grid ValueT tmpClip = (from->saveSparse()) ? ValueT(clip) : ValueT(0); // Copy from dense to sparse grid structure considering clip value openvdb::tools::copyFromDense(dense, *to, tmpClip); // If present, use clip grid to trim down current vdb grid even more if (from->saveSparse() && clipGrid && !clipGrid->empty()) { to = openvdb::tools::clip(*to, *clipGrid); } } // Alternatively, reading all grid cells with an accessor (slightly slower) is possible like this else { typename GridType::Accessor accessor = to->getAccessor(); FOR_IJK(*from) { openvdb::Coord xyz(i, j, k); T fromMantaValue = (*from)(i, j, k); ValueT vdbValue; convertTo(&vdbValue, fromMantaValue); accessor.setValue(xyz, vdbValue); } } return to; } template void exportVDB(ParticleDataImpl *from, openvdb::points::PointDataGrid::Ptr to, openvdb::tools::PointIndexGrid::Ptr pIndex, bool skipDeletedParts, int precision) { std::vector vdbValues; std::string name = from->getName(); BasicParticleSystem *pp = dynamic_cast(from->getParticleSys()); FOR_PARTS(*from) { // Optionally, skip exporting particles that have been marked as deleted if (skipDeletedParts && !pp->isActive(idx)) { continue; } MantaType fromMantaValue = (*from)[idx]; VDBType vdbValue; convertTo(&vdbValue, fromMantaValue); vdbValues.push_back(vdbValue); } // Use custom codec for precision of the attribute openvdb::NamePair attribute; if (precision == PRECISION_FULL) { attribute = openvdb::points::TypedAttributeArray::attributeType(); } else if (precision == PRECISION_HALF || precision == PRECISION_MINI) { // Mini uses same precision as half for now attribute = openvdb::points::TypedAttributeArray::attributeType(); } else { errMsg("exportVDB: invalid precision level"); } openvdb::points::appendAttribute(to->tree(), name, attribute); // Create a wrapper around the vdb values vector. const openvdb::points::PointAttributeVector wrapper(vdbValues); // Populate the attribute on the points openvdb::points::populateAttribute>( to->tree(), pIndex->tree(), name, wrapper); } openvdb::points::PointDataGrid::Ptr exportVDB(BasicParticleSystem *from, std::vector &fromPData, bool skipDeletedParts, float voxelSize, int precision) { std::vector positions; std::vector flags; FOR_PARTS(*from) { // Optionally, skip exporting particles that have been marked as deleted if (skipDeletedParts && !from->isActive(idx)) { continue; } Vector3D pos = toVec3f((*from)[idx].pos); pos *= voxelSize; // convert from grid space to world space openvdb::Vec3s posVDB(pos.x, pos.y, pos.z); positions.push_back(posVDB); int flag = (*from)[idx].flag; flags.push_back(flag); } const openvdb::points::PointAttributeVector positionsWrapper(positions); openvdb::math::Transform::Ptr transform = openvdb::math::Transform::createLinearTransform( voxelSize); openvdb::tools::PointIndexGrid::Ptr pointIndexGrid = openvdb::tools::createPointIndexGrid(positionsWrapper, *transform); openvdb::points::PointDataGrid::Ptr to; openvdb::NamePair flagAttribute; using CodecNull = openvdb::points::NullCodec; using CodecTrunc = openvdb::points::TruncateCodec; using CodecFixPoint = openvdb::points::FixedPointCodec; // Use custom codec for precision of the particle position and the flag attribute if (precision == PRECISION_FULL) { to = openvdb::points::createPointDataGrid( *pointIndexGrid, positionsWrapper, *transform); flagAttribute = openvdb::points::TypedAttributeArray::attributeType(); } else if (precision == PRECISION_HALF) { to = openvdb::points::createPointDataGrid( *pointIndexGrid, positionsWrapper, *transform); flagAttribute = openvdb::points::TypedAttributeArray::attributeType(); } else if (precision == PRECISION_MINI) { to = openvdb::points::createPointDataGrid( *pointIndexGrid, positionsWrapper, *transform); flagAttribute = openvdb::points::TypedAttributeArray:: attributeType(); // Use 16 bit trunc for flag for now } else { errMsg("exportVDB: invalid precision level"); } openvdb::points::appendAttribute(to->tree(), FLAG_NAME, flagAttribute); // Create a wrapper around the flag vector. openvdb::points::PointAttributeVector flagWrapper(flags); // Populate the "flag" attribute on the points openvdb::points::populateAttribute>( to->tree(), pointIndexGrid->tree(), FLAG_NAME, flagWrapper); // Add all already buffered pdata to this particle grid for (ParticleDataBase *pdb : fromPData) { if (pdb->getType() == ParticleDataBase::TypeInt) { debMsg("Writing int particle data '" << pdb->getName() << "'", 1); ParticleDataImpl *pdi = dynamic_cast *>(pdb); exportVDB(pdi, to, pointIndexGrid, skipDeletedParts, precision); } else if (pdb->getType() == ParticleDataBase::TypeReal) { debMsg("Writing real particle data '" << pdb->getName() << "'", 1); ParticleDataImpl *pdi = dynamic_cast *>(pdb); exportVDB(pdi, to, pointIndexGrid, skipDeletedParts, precision); } else if (pdb->getType() == ParticleDataBase::TypeVec3) { debMsg("Writing Vec3 particle data '" << pdb->getName() << "'", 1); ParticleDataImpl *pdi = dynamic_cast *>(pdb); exportVDB(pdi, to, pointIndexGrid, skipDeletedParts, precision); } else { errMsg("exportVDB: unknown ParticleDataBase type"); } } return to; } static void registerCustomCodecs() { openvdb::points::TypedAttributeArray::registerType(); openvdb::points::TypedAttributeArray::registerType(); openvdb::points::TypedAttributeArray::registerType(); } int writeObjectsVDB(const string &filename, std::vector *objects, float worldSize, bool skipDeletedParts, int compression, int precision, float clip, const Grid *clipGrid, const bool meta) { openvdb::initialize(); openvdb::io::File file(filename); openvdb::GridPtrVec gridsVDB; // Register custom codecs, this makes sure custom attributes can be read registerCustomCodecs(); std::vector pdbBuffer; // Convert given clip grid to vdb clip grid openvdb::FloatGrid::Ptr vdbClipGrid = nullptr; if (clipGrid) { vdbClipGrid = openvdb::FloatGrid::create(); Real *data = (Real *)clipGrid->getData(); openvdb::math::CoordBBox bbox(openvdb::Coord(0), openvdb::Coord(clipGrid->getSizeX() - 1, clipGrid->getSizeY() - 1, clipGrid->getSizeZ() - 1)); openvdb::tools::Dense dense(bbox, data); openvdb::tools::copyFromDense(dense, *vdbClipGrid, clip); } for (std::vector::iterator iter = objects->begin(); iter != objects->end(); ++iter) { openvdb::GridClass gClass = openvdb::GRID_UNKNOWN; openvdb::GridBase::Ptr vdbGrid; PbClass *object = dynamic_cast(*iter); const Real dx = object->getParent()->getDx(); const Real voxelSize = worldSize * dx; const string objectName = object->getName(); if (GridBase *mantaGrid = dynamic_cast(*iter)) { if (mantaGrid->getType() & GridBase::TypeInt) { debMsg("Writing int grid '" << mantaGrid->getName() << "' to vdb file " << filename, 1); Grid *mantaIntGrid = (Grid *)mantaGrid; if (clipGrid && mantaIntGrid->saveSparse()) { assertMsg(clipGrid->getSize() == mantaGrid->getSize(), "writeObjectsVDB: Clip grid and exported grid must have the same size " << clipGrid->getSize() << " vs " << mantaGrid->getSize()); } vdbGrid = exportVDB(mantaIntGrid, clip, vdbClipGrid); gridsVDB.push_back(vdbGrid); } else if (mantaGrid->getType() & GridBase::TypeReal) { debMsg("Writing real grid '" << mantaGrid->getName() << "' to vdb file " << filename, 1); gClass = (mantaGrid->getType() & GridBase::TypeLevelset) ? openvdb::GRID_LEVEL_SET : openvdb::GRID_FOG_VOLUME; Grid *mantaRealGrid = (Grid *)mantaGrid; // Only supply clip grid if real grid is not equal to the clip grid openvdb::FloatGrid::Ptr tmpClipGrid = (mantaRealGrid == clipGrid) ? nullptr : vdbClipGrid; if (clipGrid && mantaRealGrid->saveSparse()) { assertMsg(clipGrid->getSize() == mantaGrid->getSize(), "writeObjectsVDB: Clip grid and exported grid must have the same size " << clipGrid->getSize() << " vs " << mantaGrid->getSize()); } vdbGrid = exportVDB(mantaRealGrid, clip, tmpClipGrid); gridsVDB.push_back(vdbGrid); } else if (mantaGrid->getType() & GridBase::TypeVec3) { debMsg("Writing vec3 grid '" << mantaGrid->getName() << "' to vdb file " << filename, 1); gClass = (mantaGrid->getType() & GridBase::TypeMAC) ? openvdb::GRID_STAGGERED : openvdb::GRID_UNKNOWN; Grid *mantaVec3Grid = (Grid *)mantaGrid; if (clipGrid && mantaVec3Grid->saveSparse()) { assertMsg(clipGrid->getSize() == mantaGrid->getSize(), "writeObjectsVDB: Clip grid and exported grid must have the same size " << clipGrid->getSize() << " vs " << mantaGrid->getSize()); } vdbGrid = exportVDB(mantaVec3Grid, clip, vdbClipGrid); gridsVDB.push_back(vdbGrid); } else { errMsg("writeObjectsVDB: unknown grid type"); return 0; } } else if (BasicParticleSystem *mantaPP = dynamic_cast(*iter)) { debMsg("Writing particle system '" << mantaPP->getName() << "' (and buffered pData) to vdb file " << filename, 1); vdbGrid = exportVDB(mantaPP, pdbBuffer, skipDeletedParts, voxelSize, precision); gridsVDB.push_back(vdbGrid); pdbBuffer.clear(); } // Particle data will only be saved if there is a particle system too. else if (ParticleDataBase *mantaPPImpl = dynamic_cast(*iter)) { debMsg("Buffering particle data '" << mantaPPImpl->getName() << "' to vdb file " << filename, 1); pdbBuffer.push_back(mantaPPImpl); } else { errMsg("writeObjectsVDB: Unsupported Python object. Cannot write to .vdb file " << filename); return 0; } // Set additional grid attributes, e.g. name, grid class, compression level, etc. if (vdbGrid) { setGridOptions(vdbGrid, objectName, gClass, voxelSize, precision); // Optional metadata: Save additional simulation information per vdb object if (meta) { const Vec3i size = object->getParent()->getGridSize(); // The (dense) resolution of this grid vdbGrid->insertMeta(META_BASE_RES, openvdb::Vec3IMetadata(openvdb::Vec3i(size.x, size.y, size.z))); // Length of one voxel side vdbGrid->insertMeta(META_VOXEL_SIZE, openvdb::FloatMetadata(voxelSize)); } } } // Give out a warning if pData items were present but could not be saved due to missing particle // system. if (!pdbBuffer.empty()) { for (ParticleDataBase *pdb : pdbBuffer) { debMsg("writeObjectsVDB Warning: Particle data '" << pdb->getName() << "' has not been saved. It's parent particle system was needs to be given too.", 1); } } // Write only if the is at least one grid, optionally write with compression. if (gridsVDB.size()) { int vdb_flags = openvdb::io::COMPRESS_ACTIVE_MASK; switch (compression) { case COMPRESSION_NONE: { vdb_flags = openvdb::io::COMPRESS_NONE; break; } default: case COMPRESSION_ZIP: { vdb_flags |= openvdb::io::COMPRESS_ZIP; break; } case COMPRESSION_BLOSC: { # if OPENVDB_BLOSC == 1 vdb_flags |= openvdb::io::COMPRESS_BLOSC; # else debMsg("OpenVDB was built without Blosc support, using Zip compression instead", 1); vdb_flags |= openvdb::io::COMPRESS_ZIP; # endif // OPENVDB_BLOSC==1 break; } } file.setCompression(vdb_flags); file.write(gridsVDB); } file.close(); return 1; } static void clearAll(std::vector *objects, std::vector pdbBuffer) { // Clear all data loaded into manta objects (e.g. during IO error) for (std::vector::iterator iter = objects->begin(); iter != objects->end(); ++iter) { if (GridBase *mantaGrid = dynamic_cast(*iter)) { if (mantaGrid->getType() & GridBase::TypeInt) { Grid *mantaIntGrid = (Grid *)mantaGrid; mantaIntGrid->clear(); } else if (mantaGrid->getType() & GridBase::TypeReal) { Grid *mantaRealGrid = (Grid *)mantaGrid; mantaRealGrid->clear(); } else if (mantaGrid->getType() & GridBase::TypeVec3) { Grid *mantaVec3Grid = (Grid *)mantaGrid; mantaVec3Grid->clear(); } } else if (BasicParticleSystem *mantaPP = dynamic_cast(*iter)) { mantaPP->clear(); } } for (ParticleDataBase *pdb : pdbBuffer) { if (pdb->getType() == ParticleDataBase::TypeInt) { ParticleDataImpl *mantaPDataInt = (ParticleDataImpl *)pdb; mantaPDataInt->clear(); } else if (pdb->getType() == ParticleDataBase::TypeReal) { ParticleDataImpl *mantaPDataReal = (ParticleDataImpl *)pdb; mantaPDataReal->clear(); } else if (pdb->getType() == ParticleDataBase::TypeVec3) { ParticleDataImpl *mantaPDataVec3 = (ParticleDataImpl *)pdb; mantaPDataVec3->clear(); } } } int readObjectsVDB(const string &filename, std::vector *objects, float worldSize) { openvdb::initialize(); openvdb::io::File file(filename); openvdb::GridPtrVec gridsVDB; // Register custom codecs, this makes sure custom attributes can be read registerCustomCodecs(); try { file.setCopyMaxBytes(0); file.open(); gridsVDB = *(file.getGrids()); openvdb::MetaMap::Ptr metadata = file.getMetadata(); unusedParameter(metadata); // Unused for now } catch (const openvdb::IoError &e) { unusedParameter(e); // Unused for now debMsg("readObjectsVDB: Could not open vdb file " << filename, 1); file.close(); return 0; } file.close(); // A buffer to store a handle to pData objects. These will be read alongside a particle system. std::vector pdbBuffer; // Count how many objects could not be read correctly int readFailure = 0; for (std::vector::iterator iter = objects->begin(); iter != objects->end(); ++iter) { if (gridsVDB.empty()) { debMsg("readObjectsVDB: No vdb grids in file " << filename, 1); } // If there is just one grid in this file, load it regardless of name match (to vdb caches per // grid). const bool onlyGrid = (gridsVDB.size() == 1); PbClass *object = dynamic_cast(*iter); const Real dx = object->getParent()->getDx(); const Vec3i origRes = object->getParent()->getGridSize(); Real voxelSize = worldSize * dx; // Particle data objects are treated separately - buffered and inserted when reading the // particle system if (ParticleDataBase *mantaPPImpl = dynamic_cast(*iter)) { debMsg("Buffering particle data '" << mantaPPImpl->getName() << "' from vdb file " << filename, 1); pdbBuffer.push_back(mantaPPImpl); continue; } // For every manta object, we loop through the vdb grid list and check for a match for (const openvdb::GridBase::Ptr &vdbGrid : gridsVDB) { bool nameMatch = (vdbGrid->getName() == (*iter)->getName()); // Sanity checks: Only load valid grids and make sure names match. if (!vdbGrid) { debMsg("Skipping invalid vdb grid '" << vdbGrid->getName() << "' in file " << filename, 1); continue; } if (!nameMatch && !onlyGrid) { continue; } // Metadata: If present in the file, meta data will be parsed into these fields Real metaVoxelSize(0); Vec3i metaRes(0), metaBBoxMax(0), metaBBoxMin(0); // Loop to load all meta data that we care about for (openvdb::MetaMap::MetaIterator iter = vdbGrid->beginMeta(); iter != vdbGrid->endMeta(); ++iter) { const std::string &name = iter->first; const openvdb::Metadata::Ptr value = iter->second; if (name.compare(META_BASE_RES) == 0) { openvdb::Vec3i tmp = static_cast(*value).value(); convertFrom(tmp, &metaRes); } else if (name.compare(META_VOXEL_SIZE) == 0) { float tmp = static_cast(*value).value(); convertFrom(tmp, &metaVoxelSize); voxelSize = metaVoxelSize; // Make sure to update voxel size variable (used in // pointgrid's importVDB()) if (worldSize != 1.0) debMsg( "readObjectsVDB: Found voxel size in meta data. worldSize parameter will be " "ignored!", 1); } else if (name.compare(META_BBOX_MAX) == 0) { openvdb::Vec3i tmp = static_cast(*value).value(); convertFrom(tmp, &metaBBoxMax); } else if (name.compare(META_BBOX_MIN) == 0) { openvdb::Vec3i tmp = static_cast(*value).value(); convertFrom(tmp, &metaBBoxMin); } else { debMsg("readObjectsVDB: Skipping unknown meta information '" << name << "'", 1); } } // Compare metadata with allocated grid setup. This prevents invalid index access. if (notZero(metaRes) && metaRes != origRes) { debMsg("readObjectsVDB Warning: Grid '" << vdbGrid->getName() << "' has not been read. Meta grid res " << metaRes << " vs " << origRes << " current grid size", 1); readFailure++; break; } if (notZero(metaVoxelSize) && metaVoxelSize != voxelSize) { debMsg("readObjectsVDB Warning: Grid '" << vdbGrid->getName() << "' has not been read. Meta voxel size " << metaVoxelSize << " vs " << voxelSize << " current voxel size", 1); readFailure++; break; } if (metaBBoxMax.x > origRes.x || metaBBoxMax.y > origRes.y || metaBBoxMax.z > origRes.z) { debMsg("readObjectsVDB Warning: Grid '" << vdbGrid->getName() << "' has not been read. Vdb bbox max " << metaBBoxMax << " vs " << origRes << " current grid size", 1); readFailure++; break; } const Vec3i origOrigin(0); if (metaBBoxMin.x < origOrigin.x || metaBBoxMin.y < origOrigin.y || metaBBoxMin.z < origOrigin.z) { debMsg("readObjectsVDB Warning: Grid '" << vdbGrid->getName() << "' has not been read. Vdb bbox min " << metaBBoxMin << " vs " << origOrigin << " current grid origin", 1); readFailure++; break; } if (GridBase *mantaGrid = dynamic_cast(*iter)) { if (mantaGrid->getType() & GridBase::TypeInt) { openvdb::Int32Grid::Ptr vdbIntGrid = openvdb::gridPtrCast(vdbGrid); if (!vdbIntGrid) continue; // Sanity check: Cast can fail if onlyGrid is true but object count > 1 Grid *mantaIntGrid = (Grid *)mantaGrid; debMsg("Reading into grid '" << mantaGrid->getName() << "' from int grid '" << vdbGrid->getName() << "' in vdb file " << filename, 1); importVDB(vdbIntGrid, mantaIntGrid); } else if (mantaGrid->getType() & GridBase::TypeReal) { openvdb::FloatGrid::Ptr vdbFloatGrid = openvdb::gridPtrCast(vdbGrid); if (!vdbFloatGrid) continue; // Sanity check: Cast can fail if onlyGrid is true but object count > 1 Grid *mantaRealGrid = (Grid *)mantaGrid; debMsg("Reading into grid '" << mantaGrid->getName() << "' from real grid '" << vdbGrid->getName() << "' in vdb file " << filename, 1); importVDB(vdbFloatGrid, mantaRealGrid); } else if (mantaGrid->getType() & GridBase::TypeVec3) { openvdb::Vec3SGrid::Ptr vdbVec3Grid = openvdb::gridPtrCast(vdbGrid); if (!vdbVec3Grid) continue; // Sanity check: Cast can fail if onlyGrid is true but object count > 1 Grid *mantaVec3Grid = (Grid *)mantaGrid; debMsg("Reading into grid '" << mantaGrid->getName() << "' from vec3 grid '" << vdbGrid->getName() << "' in vdb file " << filename, 1); importVDB(vdbVec3Grid, mantaVec3Grid); } else { errMsg("readObjectsVDB: unknown grid type"); return 0; } } else if (BasicParticleSystem *mantaPP = dynamic_cast(*iter)) { openvdb::points::PointDataGrid::Ptr vdbPointGrid = openvdb::gridPtrCast(vdbGrid); if (!vdbPointGrid) continue; // Sanity check: Cast can fail if onlyGrid is true but objects > 1 debMsg("Reading into particle system '" << mantaPP->getName() << "' from particle system '" << vdbGrid->getName() << "' in vdb file " << filename, 1); importVDB(vdbPointGrid, mantaPP, pdbBuffer, voxelSize); pdbBuffer.clear(); } else { errMsg("readObjectsVDB: Unsupported Python object. Cannot read from .vdb file " << filename); return 0; } } // Do not continue loading objects in this loop if there was a read error if (readFailure > 0) { break; } } if (readFailure > 0) { // Clear all data that has already been loaded into simulation objects clearAll(objects, pdbBuffer); pdbBuffer.clear(); return 0; } // Give out a warning if pData items were present but could not be read due to missing particle // system. if (!pdbBuffer.empty()) { for (ParticleDataBase *pdb : pdbBuffer) { debMsg("readObjectsVDB Warning: Particle data '" << pdb->getName() << "' has not been read. The parent particle system needs to be given too.", 1); } } return 1; } template void importVDB(int vdbValue, ParticleDataImpl *to, int index, float voxelSize = 1.0); template void importVDB(float vdbValue, ParticleDataImpl *to, int index, float voxelSize = 1.0); template void importVDB(openvdb::Vec3s vdbValue, ParticleDataImpl *to, int index, float voxelSize = 1.0); void importVDB(openvdb::points::PointDataGrid::Ptr from, BasicParticleSystem *to, std::vector &toPData, float voxelSize = 1.0); template void importVDB(openvdb::Int32Grid::Ptr from, Grid *to); template void importVDB(openvdb::FloatGrid::Ptr from, Grid *to); template void importVDB(openvdb::Vec3SGrid::Ptr from, Grid *to); template openvdb::Int32Grid::Ptr exportVDB( Grid *from, float clip = 1e-4, openvdb::FloatGrid::Ptr clipGrid = nullptr); template openvdb::FloatGrid::Ptr exportVDB( Grid *from, float clip = 1e-4, openvdb::FloatGrid::Ptr clipGrid = nullptr); template openvdb::Vec3SGrid::Ptr exportVDB( Grid *from, float clip = 1e-4, openvdb::FloatGrid::Ptr clipGrid = nullptr); openvdb::points::PointDataGrid::Ptr exportVDB(BasicParticleSystem *from, std::vector &fromPData, bool skipDeletedParts = false, float voxelSize = 1.0, int precision = PRECISION_HALF); template void exportVDB(ParticleDataImpl *from, openvdb::points::PointDataGrid::Ptr to, openvdb::tools::PointIndexGrid::Ptr pIndex, bool skipDeletedParts = false, int precision = PRECISION_HALF); template void exportVDB(ParticleDataImpl *from, openvdb::points::PointDataGrid::Ptr to, openvdb::tools::PointIndexGrid::Ptr pIndex, bool skipDeletedParts = false, int precision = PRECISION_HALF); template void exportVDB(ParticleDataImpl *from, openvdb::points::PointDataGrid::Ptr to, openvdb::tools::PointIndexGrid::Ptr pIndex, bool skipDeletedParts = false, int precision = PRECISION_HALF); #else int writeObjectsVDB(const string &filename, std::vector *objects, float worldSize, bool skipDeletedParts, int compression, int precision, float clip, const Grid *clipGrid, const bool meta) { errMsg("Cannot save to .vdb file. Mantaflow has not been built with OpenVDB support."); return 0; } int readObjectsVDB(const string &filename, std::vector *objects, float worldSize) { errMsg("Cannot load from .vdb file. Mantaflow has not been built with OpenVDB support."); return 0; } #endif // OPENVDB==1 } // namespace Manta