diff options
Diffstat (limited to 'intern/cycles/scene')
-rw-r--r-- | intern/cycles/scene/attribute.cpp | 9 | ||||
-rw-r--r-- | intern/cycles/scene/camera.cpp | 1 | ||||
-rw-r--r-- | intern/cycles/scene/camera.h | 12 | ||||
-rw-r--r-- | intern/cycles/scene/geometry.cpp | 2 | ||||
-rw-r--r-- | intern/cycles/scene/geometry.h | 2 | ||||
-rw-r--r-- | intern/cycles/scene/image_vdb.cpp | 5 | ||||
-rw-r--r-- | intern/cycles/scene/image_vdb.h | 3 | ||||
-rw-r--r-- | intern/cycles/scene/object.cpp | 8 | ||||
-rw-r--r-- | intern/cycles/scene/scene.cpp | 6 | ||||
-rw-r--r-- | intern/cycles/scene/scene.h | 2 | ||||
-rw-r--r-- | intern/cycles/scene/volume.cpp | 152 | ||||
-rw-r--r-- | intern/cycles/scene/volume.h | 1 |
12 files changed, 182 insertions, 21 deletions
diff --git a/intern/cycles/scene/attribute.cpp b/intern/cycles/scene/attribute.cpp index 0ca602362bc..df01189a54b 100644 --- a/intern/cycles/scene/attribute.cpp +++ b/intern/cycles/scene/attribute.cpp @@ -360,6 +360,12 @@ const char *Attribute::standard_name(AttributeStandard std) return "temperature"; case ATTR_STD_VOLUME_VELOCITY: return "velocity"; + case ATTR_STD_VOLUME_VELOCITY_X: + return "velocity_x"; + case ATTR_STD_VOLUME_VELOCITY_Y: + return "velocity_y"; + case ATTR_STD_VOLUME_VELOCITY_Z: + return "velocity_z"; case ATTR_STD_POINTINESS: return "pointiness"; case ATTR_STD_RANDOM_PER_ISLAND: @@ -587,6 +593,9 @@ Attribute *AttributeSet::add(AttributeStandard std, ustring name) case ATTR_STD_VOLUME_FLAME: case ATTR_STD_VOLUME_HEAT: case ATTR_STD_VOLUME_TEMPERATURE: + case ATTR_STD_VOLUME_VELOCITY_X: + case ATTR_STD_VOLUME_VELOCITY_Y: + case ATTR_STD_VOLUME_VELOCITY_Z: attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_VOXEL); break; case ATTR_STD_VOLUME_COLOR: diff --git a/intern/cycles/scene/camera.cpp b/intern/cycles/scene/camera.cpp index 6aca2fcbb81..710f1c5ee90 100644 --- a/intern/cycles/scene/camera.cpp +++ b/intern/cycles/scene/camera.cpp @@ -397,6 +397,7 @@ void Camera::update(Scene *scene) /* motion blur */ kcam->shuttertime = (need_motion == Scene::MOTION_BLUR) ? shuttertime : -1.0f; + kcam->motion_position = motion_position; /* type */ kcam->type = camera_type; diff --git a/intern/cycles/scene/camera.h b/intern/cycles/scene/camera.h index 97bee430588..c150405acc2 100644 --- a/intern/cycles/scene/camera.h +++ b/intern/cycles/scene/camera.h @@ -30,18 +30,6 @@ class Camera : public Node { public: NODE_DECLARE - /* Specifies an offset for the shutter's time interval. */ - enum MotionPosition { - /* Shutter opens at the current frame. */ - MOTION_POSITION_START = 0, - /* Shutter is fully open at the current frame. */ - MOTION_POSITION_CENTER = 1, - /* Shutter closes at the current frame. */ - MOTION_POSITION_END = 2, - - MOTION_NUM_POSITIONS, - }; - /* Specifies rolling shutter effect. */ enum RollingShutterType { /* No rolling shutter effect. */ diff --git a/intern/cycles/scene/geometry.cpp b/intern/cycles/scene/geometry.cpp index 351ec4f09ae..349d8ad39c7 100644 --- a/intern/cycles/scene/geometry.cpp +++ b/intern/cycles/scene/geometry.cpp @@ -1541,7 +1541,7 @@ void GeometryManager::device_update_preprocess(Device *device, Scene *scene, Pro } Volume *volume = static_cast<Volume *>(geom); - create_volume_mesh(volume, progress); + create_volume_mesh(scene, volume, progress); /* always reallocate when we have a volume, as we need to rebuild the BVH */ device_update_flags |= DEVICE_MESH_DATA_NEEDS_REALLOC; diff --git a/intern/cycles/scene/geometry.h b/intern/cycles/scene/geometry.h index 0c2e70d483d..6210a64509a 100644 --- a/intern/cycles/scene/geometry.h +++ b/intern/cycles/scene/geometry.h @@ -216,7 +216,7 @@ class GeometryManager { protected: bool displace(Device *device, Scene *scene, Mesh *mesh, Progress &progress); - void create_volume_mesh(Volume *volume, Progress &progress); + void create_volume_mesh(const Scene *scene, Volume *volume, Progress &progress); /* Attributes */ void update_osl_attributes(Device *device, diff --git a/intern/cycles/scene/image_vdb.cpp b/intern/cycles/scene/image_vdb.cpp index 9906606a959..b6f0911fa2c 100644 --- a/intern/cycles/scene/image_vdb.cpp +++ b/intern/cycles/scene/image_vdb.cpp @@ -64,6 +64,11 @@ struct ToNanoOp { } }; # endif + +VDBImageLoader::VDBImageLoader(openvdb::GridBase::ConstPtr grid_, const string &grid_name) + : grid_name(grid_name), grid(grid_) +{ +} #endif VDBImageLoader::VDBImageLoader(const string &grid_name) : grid_name(grid_name) diff --git a/intern/cycles/scene/image_vdb.h b/intern/cycles/scene/image_vdb.h index c851ef6250d..a5fd51915ef 100644 --- a/intern/cycles/scene/image_vdb.h +++ b/intern/cycles/scene/image_vdb.h @@ -17,6 +17,9 @@ CCL_NAMESPACE_BEGIN class VDBImageLoader : public ImageLoader { public: +#ifdef WITH_OPENVDB + VDBImageLoader(openvdb::GridBase::ConstPtr grid_, const string &grid_name); +#endif VDBImageLoader(const string &grid_name); ~VDBImageLoader(); diff --git a/intern/cycles/scene/object.cpp b/intern/cycles/scene/object.cpp index 55d89fc3673..676cc78a11f 100644 --- a/intern/cycles/scene/object.cpp +++ b/intern/cycles/scene/object.cpp @@ -439,6 +439,14 @@ void ObjectManager::device_update_object_transform(UpdateObjectTransformState *s flag |= SD_OBJECT_HAS_VERTEX_MOTION; } } + else if (geom->is_volume()) { + Volume *volume = static_cast<Volume *>(geom); + if (volume->attributes.find(ATTR_STD_VOLUME_VELOCITY) && + volume->get_velocity_scale() != 0.0f) { + flag |= SD_OBJECT_HAS_VOLUME_MOTION; + kobject.velocity_scale = volume->get_velocity_scale(); + } + } if (state->need_motion == Scene::MOTION_PASS) { /* Clear motion array if there is no actual motion. */ diff --git a/intern/cycles/scene/scene.cpp b/intern/cycles/scene/scene.cpp index b6b53004816..b35242139ea 100644 --- a/intern/cycles/scene/scene.cpp +++ b/intern/cycles/scene/scene.cpp @@ -381,7 +381,7 @@ void Scene::device_update(Device *device_, Progress &progress) } } -Scene::MotionType Scene::need_motion() +Scene::MotionType Scene::need_motion() const { if (integrator->get_motion_blur()) return MOTION_BLUR; @@ -407,6 +407,10 @@ bool Scene::need_global_attribute(AttributeStandard std) return need_motion() != MOTION_NONE; else if (std == ATTR_STD_MOTION_VERTEX_NORMAL) return need_motion() == MOTION_BLUR; + else if (std == ATTR_STD_VOLUME_VELOCITY || std == ATTR_STD_VOLUME_VELOCITY_X || + std == ATTR_STD_VOLUME_VELOCITY_Y || std == ATTR_STD_VOLUME_VELOCITY_Z) { + return need_motion() != MOTION_NONE; + } return false; } diff --git a/intern/cycles/scene/scene.h b/intern/cycles/scene/scene.h index 54c7d9d93ea..a0d2f4a6c06 100644 --- a/intern/cycles/scene/scene.h +++ b/intern/cycles/scene/scene.h @@ -257,7 +257,7 @@ class Scene : public NodeOwner { void need_global_attributes(AttributeRequestSet &attributes); enum MotionType { MOTION_NONE = 0, MOTION_PASS, MOTION_BLUR }; - MotionType need_motion(); + MotionType need_motion() const; float motion_shutter_time(); bool need_update(); diff --git a/intern/cycles/scene/volume.cpp b/intern/cycles/scene/volume.cpp index 0555fdd2fad..39e9b0bbbf4 100644 --- a/intern/cycles/scene/volume.cpp +++ b/intern/cycles/scene/volume.cpp @@ -10,9 +10,9 @@ # include <openvdb/tools/Dense.h> # include <openvdb/tools/GridTransformer.h> # include <openvdb/tools/Morphology.h> +# include <openvdb/tools/Statistics.h> #endif -#include "util/foreach.h" #include "util/hash.h" #include "util/log.h" #include "util/openvdb.h" @@ -28,6 +28,7 @@ NODE_DEFINE(Volume) SOCKET_FLOAT(clipping, "Clipping", 0.001f); SOCKET_FLOAT(step_size, "Step Size", 0.0f); SOCKET_BOOLEAN(object_space, "Object Space", false); + SOCKET_FLOAT(velocity_scale, "Velocity Scale", 1.0f); return type; } @@ -258,7 +259,8 @@ void VolumeMeshBuilder::add_grid(openvdb::GridBase::ConstPtr grid, void VolumeMeshBuilder::add_padding(int pad_size) { #ifdef WITH_OPENVDB - openvdb::tools::dilateVoxels(topology_grid->tree(), pad_size); + openvdb::tools::dilateActiveValues( + topology_grid->tree(), pad_size, openvdb::tools::NN_FACE, openvdb::tools::IGNORE_TILES); #else (void)pad_size; #endif @@ -482,11 +484,141 @@ static openvdb::GridBase::ConstPtr openvdb_grid_from_device_texture(device_textu return sparse; } + +static int estimate_required_velocity_padding(openvdb::GridBase::ConstPtr grid, + float velocity_scale) +{ + /* TODO: we may need to also find outliers and clamp them to avoid adding too much padding. */ + openvdb::math::Extrema extrema; + openvdb::Vec3d voxel_size; + + /* External .vdb files have a vec3 type for velocity, but the Blender exporter creates a vec4. */ + if (grid->isType<openvdb::Vec3fGrid>()) { + openvdb::Vec3fGrid::ConstPtr vel_grid = openvdb::gridConstPtrCast<openvdb::Vec3fGrid>(grid); + extrema = openvdb::tools::extrema(vel_grid->cbeginValueOn()); + voxel_size = vel_grid->voxelSize(); + } + else if (grid->isType<openvdb::Vec4fGrid>()) { + openvdb::Vec4fGrid::ConstPtr vel_grid = openvdb::gridConstPtrCast<openvdb::Vec4fGrid>(grid); + extrema = openvdb::tools::extrema(vel_grid->cbeginValueOn()); + voxel_size = vel_grid->voxelSize(); + } + else { + assert(0); + return 0; + } + + /* We should only have uniform grids, so x = y = z, but we never know. */ + const double max_voxel_size = openvdb::math::Max(voxel_size.x(), voxel_size.y(), voxel_size.z()); + if (max_voxel_size == 0.0) { + return 0; + } + + const double estimated_padding = extrema.max() * static_cast<double>(velocity_scale) / + max_voxel_size; + + return static_cast<int>(std::ceil(estimated_padding)); +} + +static openvdb::FloatGrid::ConstPtr get_vdb_for_attribute(Volume *volume, AttributeStandard std) +{ + Attribute *attr = volume->attributes.find(std); + if (!attr) { + return nullptr; + } + + ImageHandle &handle = attr->data_voxel(); + VDBImageLoader *vdb_loader = handle.vdb_loader(); + if (!vdb_loader) { + return nullptr; + } + + openvdb::GridBase::ConstPtr grid = vdb_loader->get_grid(); + if (!grid) { + return nullptr; + } + + if (!grid->isType<openvdb::FloatGrid>()) { + return nullptr; + } + + return openvdb::gridConstPtrCast<openvdb::FloatGrid>(grid); +} + +class MergeScalarGrids { + typedef openvdb::FloatTree ScalarTree; + + openvdb::tree::ValueAccessor<const ScalarTree> m_acc_x, m_acc_y, m_acc_z; + + public: + MergeScalarGrids(const ScalarTree *x_tree, const ScalarTree *y_tree, const ScalarTree *z_tree) + : m_acc_x(*x_tree), m_acc_y(*y_tree), m_acc_z(*z_tree) + { + } + + MergeScalarGrids(const MergeScalarGrids &other) + : m_acc_x(other.m_acc_x), m_acc_y(other.m_acc_y), m_acc_z(other.m_acc_z) + { + } + + void operator()(const openvdb::Vec3STree::ValueOnIter &it) const + { + using namespace openvdb; + + const math::Coord xyz = it.getCoord(); + float x = m_acc_x.getValue(xyz); + float y = m_acc_y.getValue(xyz); + float z = m_acc_z.getValue(xyz); + + it.setValue(math::Vec3s(x, y, z)); + } +}; + +static void merge_scalar_grids_for_velocity(const Scene *scene, Volume *volume) +{ + if (volume->attributes.find(ATTR_STD_VOLUME_VELOCITY)) { + /* A vector grid for velocity is already available. */ + return; + } + + openvdb::FloatGrid::ConstPtr vel_x_grid = get_vdb_for_attribute(volume, + ATTR_STD_VOLUME_VELOCITY_X); + openvdb::FloatGrid::ConstPtr vel_y_grid = get_vdb_for_attribute(volume, + ATTR_STD_VOLUME_VELOCITY_Y); + openvdb::FloatGrid::ConstPtr vel_z_grid = get_vdb_for_attribute(volume, + ATTR_STD_VOLUME_VELOCITY_Z); + + if (!(vel_x_grid && vel_y_grid && vel_z_grid)) { + return; + } + + openvdb::Vec3fGrid::Ptr vecgrid = openvdb::Vec3SGrid::create(openvdb::Vec3s(0.0f)); + + /* Activate voxels in the vector grid based on the scalar grids to ensure thread safety during + * the merge. */ + vecgrid->tree().topologyUnion(vel_x_grid->tree()); + vecgrid->tree().topologyUnion(vel_y_grid->tree()); + vecgrid->tree().topologyUnion(vel_z_grid->tree()); + + MergeScalarGrids op(&vel_x_grid->tree(), &vel_y_grid->tree(), &vel_z_grid->tree()); + openvdb::tools::foreach (vecgrid->beginValueOn(), op, true, false); + + /* Assume all grids have the same transformation. */ + openvdb::math::Transform::Ptr transform = openvdb::ConstPtrCast<openvdb::math::Transform>( + vel_x_grid->transformPtr()); + vecgrid->setTransform(transform); + + /* Make an attribute for it. */ + Attribute *attr = volume->attributes.add(ATTR_STD_VOLUME_VELOCITY); + ImageLoader *loader = new VDBImageLoader(vecgrid, "merged_velocity"); + ImageParams params; + attr->data_voxel() = scene->image_manager->add_image(loader, params); +} #endif /* ************************************************************************** */ -void GeometryManager::create_volume_mesh(Volume *volume, Progress &progress) +void GeometryManager::create_volume_mesh(const Scene *scene, Volume *volume, Progress &progress) { string msg = string_printf("Computing Volume Mesh %s", volume->name.c_str()); progress.set_status("Updating Mesh", msg); @@ -495,7 +627,7 @@ void GeometryManager::create_volume_mesh(Volume *volume, Progress &progress) Shader *volume_shader = NULL; int pad_size = 0; - foreach (Node *node, volume->get_used_shaders()) { + for (Node *node : volume->get_used_shaders()) { Shader *shader = static_cast<Shader *>(node); if (!shader->has_volume) { @@ -529,7 +661,9 @@ void GeometryManager::create_volume_mesh(Volume *volume, Progress &progress) VolumeMeshBuilder builder; #ifdef WITH_OPENVDB - foreach (Attribute &attr, volume->attributes.attributes) { + merge_scalar_grids_for_velocity(scene, volume); + + for (Attribute &attr : volume->attributes.attributes) { if (attr.element != ATTR_ELEMENT_VOXEL) { continue; } @@ -567,9 +701,17 @@ void GeometryManager::create_volume_mesh(Volume *volume, Progress &progress) } if (grid) { + /* Add padding based on the maximum velocity vector. */ + if (attr.std == ATTR_STD_VOLUME_VELOCITY && scene->need_motion() != Scene::MOTION_NONE) { + pad_size = max(pad_size, + estimate_required_velocity_padding(grid, volume->get_velocity_scale())); + } + builder.add_grid(grid, do_clipping, volume->get_clipping()); } } +#else + (void)scene; #endif /* If nothing to build, early out. */ diff --git a/intern/cycles/scene/volume.h b/intern/cycles/scene/volume.h index cae0f5f5bce..2b94aaf5253 100644 --- a/intern/cycles/scene/volume.h +++ b/intern/cycles/scene/volume.h @@ -18,6 +18,7 @@ class Volume : public Mesh { NODE_SOCKET_API(float, clipping) NODE_SOCKET_API(float, step_size) NODE_SOCKET_API(bool, object_space) + NODE_SOCKET_API(float, velocity_scale) virtual void clear(bool preserve_shaders = false) override; }; |