WIP: USD: add velocity to USD importer #104462

Draft
Sonny Campbell wants to merge 3 commits from SonnyCampbell_Unity/blender:unity/T96182-usd-reader-velocity into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
11 changed files with 86 additions and 38 deletions

View File

@ -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<USDGeomReader *>(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,

View File

@ -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<Nurb *>(curve->nurb.first);

View File

@ -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;
};

View File

@ -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 */)

View File

@ -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<int>(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<pxr::TfToken> 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<pxr::UsdGeomPrimvar> 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<int> material_indices =
attributes.lookup_or_add_for_write_span<int>("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();
}
}

View File

@ -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);

View File

@ -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<Nurb *>(curve->nurb.first);

View File

@ -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;
};

View File

@ -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)
{

View File

@ -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,

View File

@ -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;
}