diff --git a/source/blender/io/usd/intern/usd_capi_import.cc b/source/blender/io/usd/intern/usd_capi_import.cc index 600d1f0a9eb..5fe25973ac7 100644 --- a/source/blender/io/usd/intern/usd_capi_import.cc +++ b/source/blender/io/usd/intern/usd_capi_import.cc @@ -468,9 +468,8 @@ static USDPrimReader *get_usd_reader(CacheReader *reader, struct Mesh *USD_read_mesh(struct CacheReader *reader, struct Object *ob, struct Mesh *existing_mesh, - const double time, - const char **err_str, - const int read_flag) + const USDMeshReadParams params, + const char **err_str) { USDGeomReader *usd_reader = dynamic_cast(get_usd_reader(reader, ob, err_str)); @@ -478,7 +477,7 @@ struct Mesh *USD_read_mesh(struct CacheReader *reader, return nullptr; } - return usd_reader->read_mesh(existing_mesh, time, read_flag, err_str); + return usd_reader->read_mesh(existing_mesh, params, err_str); } bool USD_mesh_topology_changed(CacheReader *reader, diff --git a/source/blender/io/usd/intern/usd_reader_curve.cc b/source/blender/io/usd/intern/usd_reader_curve.cc index ca48f3c2391..32bbfc83c17 100644 --- a/source/blender/io/usd/intern/usd_reader_curve.cc +++ b/source/blender/io/usd/intern/usd_reader_curve.cc @@ -162,8 +162,7 @@ void USDCurvesReader::read_curve_sample(Curve *cu, const double motionSampleTime } Mesh *USDCurvesReader::read_mesh(struct Mesh *existing_mesh, - const double motionSampleTime, - const int /* read_flag */, + const USDMeshReadParams params, const char ** /* err_str */) { if (!curve_prim_) { @@ -176,11 +175,11 @@ Mesh *USDCurvesReader::read_mesh(struct Mesh *existing_mesh, pxr::VtIntArray usdCounts; - vertexAttr.Get(&usdCounts, motionSampleTime); + vertexAttr.Get(&usdCounts, params.motion_sample_time); int num_subcurves = usdCounts.size(); pxr::VtVec3fArray usdPoints; - pointsAttr.Get(&usdPoints, motionSampleTime); + pointsAttr.Get(&usdPoints, params.motion_sample_time); int vertex_idx = 0; int curve_idx; @@ -204,7 +203,7 @@ Mesh *USDCurvesReader::read_mesh(struct Mesh *existing_mesh, if (!same_topology) { BKE_nurbList_free(&curve->nurb); - read_curve_sample(curve, motionSampleTime); + read_curve_sample(curve, params.motion_sample_time); } else { Nurb *nurbs = static_cast(curve->nurb.first); diff --git a/source/blender/io/usd/intern/usd_reader_curve.h b/source/blender/io/usd/intern/usd_reader_curve.h index 48fb2c5e2d1..e15b73a8e0c 100644 --- a/source/blender/io/usd/intern/usd_reader_curve.h +++ b/source/blender/io/usd/intern/usd_reader_curve.h @@ -36,8 +36,7 @@ class USDCurvesReader : public USDGeomReader { void read_curve_sample(Curve *cu, double motionSampleTime); Mesh *read_mesh(struct Mesh *existing_mesh, - double motionSampleTime, - int read_flag, + const USDMeshReadParams params, const char **err_str) override; }; diff --git a/source/blender/io/usd/intern/usd_reader_geom.h b/source/blender/io/usd/intern/usd_reader_geom.h index b73279250f2..6d94dcec5cc 100644 --- a/source/blender/io/usd/intern/usd_reader_geom.h +++ b/source/blender/io/usd/intern/usd_reader_geom.h @@ -20,8 +20,7 @@ class USDGeomReader : public USDXformReader { } virtual Mesh *read_mesh(struct Mesh *existing_mesh, - double motionSampleTime, - int read_flag, + const USDMeshReadParams params, const char **err_str) = 0; virtual bool topology_changed(const Mesh * /* existing_mesh */, double /* motionSampleTime */) diff --git a/source/blender/io/usd/intern/usd_reader_mesh.cc b/source/blender/io/usd/intern/usd_reader_mesh.cc index f961fa64a05..ec4e735f698 100644 --- a/source/blender/io/usd/intern/usd_reader_mesh.cc +++ b/source/blender/io/usd/intern/usd_reader_mesh.cc @@ -244,8 +244,13 @@ void USDMeshReader::read_object_data(Main *bmain, const double motionSampleTime) Mesh *mesh = (Mesh *)object_->data; is_initial_load_ = true; - Mesh *read_mesh = this->read_mesh( - mesh, motionSampleTime, import_params_.mesh_read_flag, nullptr); + USDMeshReadParams params = {}; + params.motion_sample_time = motionSampleTime; + params.read_flags = import_params_.mesh_read_flag; + params.velocity_name = ""; + params.velocity_scale = 0.0; + + Mesh *read_mesh = this->read_mesh(mesh, params, nullptr); is_initial_load_ = false; if (read_mesh != mesh) { @@ -272,7 +277,7 @@ void USDMeshReader::read_object_data(Main *bmain, const double motionSampleTime) } USDXformReader::read_object_data(bmain, motionSampleTime); -} +} // namespace blender::io::usd bool USDMeshReader::valid() const { @@ -727,6 +732,31 @@ void USDMeshReader::read_mesh_sample(ImportSettings *settings, if ((settings->read_flag & MOD_MESHSEQ_READ_COLOR) != 0) { read_colors(mesh, motionSampleTime); } + + if (!settings->velocity_name.empty() && settings->velocity_scale != 0.0f) { + read_velocities(mesh, motionSampleTime); + } +} + +void USDMeshReader::read_velocities(Mesh *mesh, double motionSampleTime) +{ + pxr::VtVec3fArray usd_velocities; + mesh_prim_.GetVelocitiesAttr().Get(&usd_velocities, motionSampleTime); + + const int num_velocity_vectors = static_cast(usd_velocities.size()); + if (num_velocity_vectors != mesh->totvert) { + /* Files containing videogrammetry data may be malformed and export velocity data on missing + * frames (most likely by copying the last valid data). */ + return; + } + + CustomDataLayer *velocity_layer = BKE_id_attribute_new( + &mesh->id, "velocity", CD_PROP_FLOAT3, ATTR_DOMAIN_POINT, nullptr); + float(*velocity)[3] = (float(*)[3])velocity_layer->data; + + for (int vertex_idx = 0, totvert = mesh->totvert; vertex_idx < totvert; ++vertex_idx) { + copy_v3_v3(velocity[vertex_idx], usd_velocities[vertex_idx].data()); + } } void USDMeshReader::assign_facesets_to_material_indices(double motionSampleTime, @@ -817,8 +847,7 @@ void USDMeshReader::readFaceSetsSample(Main *bmain, Mesh *mesh, const double mot } Mesh *USDMeshReader::read_mesh(Mesh *existing_mesh, - const double motionSampleTime, - const int read_flag, + const USDMeshReadParams params, const char ** /* err_str */) { if (!mesh_prim_) { @@ -835,7 +864,7 @@ Mesh *USDMeshReader::read_mesh(Mesh *existing_mesh, std::vector uv_tokens; /* Currently we only handle UV primvars. */ - if (read_flag & MOD_MESHSEQ_READ_UV) { + if (params.read_flags & MOD_MESHSEQ_READ_UV) { std::vector primvars = primvarsAPI.GetPrimvars(); @@ -888,9 +917,11 @@ Mesh *USDMeshReader::read_mesh(Mesh *existing_mesh, * the topology is consistent, as in the Alembic importer. */ ImportSettings settings; - settings.read_flag |= read_flag; + settings.read_flag |= params.read_flags; + settings.velocity_name = params.velocity_name; + settings.velocity_scale = params.velocity_scale; - if (topology_changed(existing_mesh, motionSampleTime)) { + if (topology_changed(existing_mesh, params.motion_sample_time)) { new_mesh = true; active_mesh = BKE_mesh_new_nomain_from_template( existing_mesh, positions_.size(), 0, 0, face_indices_.size(), face_counts_.size()); @@ -900,7 +931,8 @@ Mesh *USDMeshReader::read_mesh(Mesh *existing_mesh, } } - read_mesh_sample(&settings, active_mesh, motionSampleTime, new_mesh || is_initial_load_); + read_mesh_sample( + &settings, active_mesh, params.motion_sample_time, new_mesh || is_initial_load_); if (new_mesh) { /* Here we assume that the number of materials doesn't change, i.e. that @@ -912,7 +944,8 @@ Mesh *USDMeshReader::read_mesh(Mesh *existing_mesh, bke::MutableAttributeAccessor attributes = active_mesh->attributes_for_write(); bke::SpanAttributeWriter material_indices = attributes.lookup_or_add_for_write_span("material_index", ATTR_DOMAIN_FACE); - assign_facesets_to_material_indices(motionSampleTime, material_indices.span, &mat_map); + assign_facesets_to_material_indices( + params.motion_sample_time, material_indices.span, &mat_map); material_indices.finish(); } } diff --git a/source/blender/io/usd/intern/usd_reader_mesh.h b/source/blender/io/usd/intern/usd_reader_mesh.h index 181fd5ebf79..376263be2ee 100644 --- a/source/blender/io/usd/intern/usd_reader_mesh.h +++ b/source/blender/io/usd/intern/usd_reader_mesh.h @@ -49,8 +49,7 @@ class USDMeshReader : public USDGeomReader { void read_object_data(Main *bmain, double motionSampleTime) override; struct Mesh *read_mesh(struct Mesh *existing_mesh, - double motionSampleTime, - int read_flag, + const USDMeshReadParams params, const char **err_str) override; bool topology_changed(const Mesh *existing_mesh, double motionSampleTime) override; @@ -67,6 +66,7 @@ class USDMeshReader : public USDGeomReader { void read_mpolys(Mesh *mesh); void read_uvs(Mesh *mesh, double motionSampleTime, bool load_uvs = false); + void read_velocities(Mesh *mesh, double motionSampleTime); void read_colors(Mesh *mesh, double motionSampleTime); void read_vertex_creases(Mesh *mesh, double motionSampleTime); diff --git a/source/blender/io/usd/intern/usd_reader_nurbs.cc b/source/blender/io/usd/intern/usd_reader_nurbs.cc index 0a7058fb100..8e070dea915 100644 --- a/source/blender/io/usd/intern/usd_reader_nurbs.cc +++ b/source/blender/io/usd/intern/usd_reader_nurbs.cc @@ -165,8 +165,7 @@ void USDNurbsReader::read_curve_sample(Curve *cu, const double motionSampleTime) } Mesh *USDNurbsReader::read_mesh(struct Mesh * /* existing_mesh */, - const double motionSampleTime, - const int /* read_flag */, + const USDMeshReadParams params, const char ** /* err_str */) { pxr::UsdGeomCurves curve_prim_(prim_); @@ -177,11 +176,11 @@ Mesh *USDNurbsReader::read_mesh(struct Mesh * /* existing_mesh */, pxr::VtIntArray usdCounts; - vertexAttr.Get(&usdCounts, motionSampleTime); + vertexAttr.Get(&usdCounts, params.motion_sample_time); int num_subcurves = usdCounts.size(); pxr::VtVec3fArray usdPoints; - pointsAttr.Get(&usdPoints, motionSampleTime); + pointsAttr.Get(&usdPoints, params.motion_sample_time); int vertex_idx = 0; int curve_idx; @@ -205,7 +204,7 @@ Mesh *USDNurbsReader::read_mesh(struct Mesh * /* existing_mesh */, if (!same_topology) { BKE_nurbList_free(&curve->nurb); - read_curve_sample(curve, motionSampleTime); + read_curve_sample(curve, params.motion_sample_time); } else { Nurb *nurbs = static_cast(curve->nurb.first); diff --git a/source/blender/io/usd/intern/usd_reader_nurbs.h b/source/blender/io/usd/intern/usd_reader_nurbs.h index aa3940dc540..0376a5476ec 100644 --- a/source/blender/io/usd/intern/usd_reader_nurbs.h +++ b/source/blender/io/usd/intern/usd_reader_nurbs.h @@ -36,8 +36,7 @@ class USDNurbsReader : public USDGeomReader { void read_curve_sample(Curve *cu, double motionSampleTime); Mesh *read_mesh(struct Mesh *existing_mesh, - double motionSampleTime, - int read_flag, + const USDMeshReadParams params, const char **err_str) override; }; diff --git a/source/blender/io/usd/intern/usd_reader_prim.h b/source/blender/io/usd/intern/usd_reader_prim.h index 377228929ff..96663afa6c4 100644 --- a/source/blender/io/usd/intern/usd_reader_prim.h +++ b/source/blender/io/usd/intern/usd_reader_prim.h @@ -34,6 +34,10 @@ struct ImportSettings { /* From MeshSeqCacheModifierData.read_flag */ int read_flag; + /* From CacheFile and MeshSeqCacheModifierData */ + std::string velocity_name; + float velocity_scale; + bool validate_meshes; CacheFile *cache_file; @@ -59,6 +63,8 @@ struct ImportSettings { sequence_len(1), sequence_offset(0), read_flag(0), + velocity_name(""), + velocity_scale(1.0f), validate_meshes(false), cache_file(NULL) { diff --git a/source/blender/io/usd/usd.h b/source/blender/io/usd/usd.h index 9d5cda64424..af8aec339bd 100644 --- a/source/blender/io/usd/usd.h +++ b/source/blender/io/usd/usd.h @@ -66,6 +66,16 @@ struct USDImportParams { eUSDMtlNameCollisionMode mtl_name_collision_mode; }; +/* This struct is in place to store the mesh sequence parameters needed when reading a data from a + * usd file for the mesh sequence cache. + */ +typedef struct USDMeshReadParams { + double motion_sample_time; /* Read USD TimeCode in frames. */ + int read_flags; /* MOD_MESHSEQ_xxx value that is set from MeshSeqCacheModifierData.read_flag. */ + const char *velocity_name; /* From CacheFile and MeshSeqCacheModifierData */ + float velocity_scale; /* From CacheFile and MeshSeqCacheModifierData */ +} USDMeshReadParams; + /* The USD_export takes a as_background_job parameter, and returns a boolean. * * When as_background_job=true, returns false immediately after scheduling @@ -101,9 +111,8 @@ void USD_get_transform(struct CacheReader *reader, float r_mat[4][4], float time struct Mesh *USD_read_mesh(struct CacheReader *reader, struct Object *ob, struct Mesh *existing_mesh, - double time, - const char **err_str, - int read_flag); + const USDMeshReadParams params, + const char **err_str); bool USD_mesh_topology_changed(struct CacheReader *reader, const struct Object *ob, diff --git a/source/blender/modifiers/intern/MOD_meshsequencecache.cc b/source/blender/modifiers/intern/MOD_meshsequencecache.cc index c8628a7693e..ec5bf45c12d 100644 --- a/source/blender/modifiers/intern/MOD_meshsequencecache.cc +++ b/source/blender/modifiers/intern/MOD_meshsequencecache.cc @@ -245,12 +245,18 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * # endif break; } - case CACHEFILE_TYPE_USD: + case CACHEFILE_TYPE_USD: { # ifdef WITH_USD - result = USD_read_mesh( - mcmd->reader, ctx->object, mesh, time * FPS, &err_str, mcmd->read_flag); + USDMeshReadParams params = {}; + params.motion_sample_time = time * FPS; + params.read_flags = mcmd->read_flag; + params.velocity_name = mcmd->cache_file->velocity_name; + params.velocity_scale = mcmd->velocity_scale; + + result = USD_read_mesh(mcmd->reader, ctx->object, mesh, params, &err_str); # endif break; + } case CACHE_FILE_TYPE_INVALID: break; }