The existing Volume export, which already supports VDB file sequences and static volumes created inside Blender, is now extended to handle dynamically created and modified volumes. This allows scenarios where a Volume Displace modifier is placed over-top an existing VDB sequence or when Geometry Nodes is used to create animated volumes procedurally. Detection of what counts as animation is simplistic and mimics what has been used for Meshes. Essentially if there are any modifiers on the volume we assume that the volume is "varying" in some way. This can lead to situations where new volume files are written unnecessarily. Volume import was also adjusted to correctly set the sequence "offset" value. This is required to properly handle the case when a VDB sequence begins animating at a different frame than what's implied by the file name. For example, a VDB file sequence with file names containing 14-19 but the user wants to animate on frames 8-13 instead. Tests are added which cover: - Animated VDB file sequences - Animated Mesh To Volume where the mesh has been animated - Animated Volume Displacement where displacement settings are animated - Animated Volumes created with a Geometry Nodes simulation ---- New test data has been checked in: `tests/data/usd/usd_volumes.blend` and files inside `tests/data/usd/volume-data/` Pull Request: https://projects.blender.org/blender/blender/pulls/128907
83 lines
2.2 KiB
C++
83 lines
2.2 KiB
C++
/* SPDX-FileCopyrightText: 2021 Tangent Animation. All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
#include "usd_reader_volume.hh"
|
|
|
|
#include "BLI_path_utils.hh"
|
|
#include "BLI_string.h"
|
|
|
|
#include "BKE_object.hh"
|
|
#include "BKE_volume.hh"
|
|
|
|
#include "DNA_object_types.h"
|
|
#include "DNA_volume_types.h"
|
|
|
|
#include <pxr/usd/usdVol/openVDBAsset.h>
|
|
#include <pxr/usd/usdVol/volume.h>
|
|
|
|
namespace usdtokens {
|
|
|
|
static const pxr::TfToken density("density", pxr::TfToken::Immortal);
|
|
|
|
}
|
|
|
|
namespace blender::io::usd {
|
|
|
|
void USDVolumeReader::create_object(Main *bmain, const double /*motionSampleTime*/)
|
|
{
|
|
Volume *volume = BKE_volume_add(bmain, name_.c_str());
|
|
|
|
object_ = BKE_object_add_only_object(bmain, OB_VOLUME, name_.c_str());
|
|
object_->data = volume;
|
|
}
|
|
|
|
void USDVolumeReader::read_object_data(Main *bmain, const double motionSampleTime)
|
|
{
|
|
Volume *volume = static_cast<Volume *>(object_->data);
|
|
|
|
pxr::UsdVolVolume::FieldMap fields = volume_.GetFieldPaths();
|
|
|
|
for (pxr::UsdVolVolume::FieldMap::const_iterator it = fields.begin(); it != fields.end(); ++it) {
|
|
|
|
pxr::UsdPrim fieldPrim = prim_.GetStage()->GetPrimAtPath(it->second);
|
|
|
|
if (!fieldPrim.IsA<pxr::UsdVolOpenVDBAsset>()) {
|
|
continue;
|
|
}
|
|
|
|
pxr::UsdVolOpenVDBAsset fieldBase(fieldPrim);
|
|
|
|
pxr::UsdAttribute filepathAttr = fieldBase.GetFilePathAttr();
|
|
|
|
if (filepathAttr.IsAuthored()) {
|
|
pxr::SdfAssetPath fp;
|
|
filepathAttr.Get(&fp, motionSampleTime);
|
|
|
|
const std::string filepath = fp.GetResolvedPath();
|
|
STRNCPY(volume->filepath, filepath.c_str());
|
|
|
|
if (filepathAttr.ValueMightBeTimeVarying()) {
|
|
std::vector<double> filePathTimes;
|
|
filepathAttr.GetTimeSamples(&filePathTimes);
|
|
|
|
if (!filePathTimes.empty()) {
|
|
const int start = int(filePathTimes.front());
|
|
const int end = int(filePathTimes.back());
|
|
const int offset = BLI_path_sequence_decode(
|
|
volume->filepath, nullptr, 0, nullptr, 0, nullptr);
|
|
|
|
volume->is_sequence = char(true);
|
|
volume->frame_start = start;
|
|
volume->frame_duration = (end - start) + 1;
|
|
volume->frame_offset = offset - 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
USDXformReader::read_object_data(bmain, motionSampleTime);
|
|
}
|
|
|
|
} // namespace blender::io::usd
|