Alembic: read velocities on Points #116749

Merged
Philipp Oeser merged 1 commits from lichtwerk/blender:109185_alembic_read_points_velocities into main 2024-01-04 09:25:38 +01:00
7 changed files with 90 additions and 62 deletions

View File

@ -18,8 +18,10 @@
#include "DNA_meshdata_types.h"
#include "BLI_math_base.h"
#include "BLI_math_geom.h"
#include "BLI_utildefines.h"
#include "BKE_attribute.hh"
#include "BKE_customdata.hh"
#include "BKE_mesh.hh"
@ -503,6 +505,28 @@ static void read_custom_data_uvs(const ICompoundProperty &prop,
read_uvs(config, cd_data, uv_scope, sample.getVals(), uvs_indices);
}
void read_velocity(const V3fArraySamplePtr &velocities,
const CDStreamConfig &config,
const float velocity_scale)
{
const int num_velocity_vectors = int(velocities->size());
if (num_velocity_vectors != config.mesh->verts_num) {
/* 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(
&config.mesh->id, "velocity", CD_PROP_FLOAT3, bke::AttrDomain::Point, nullptr);
float(*velocity)[3] = (float(*)[3])velocity_layer->data;
for (int i = 0; i < num_velocity_vectors; i++) {
const Imath::V3f &vel_in = (*velocities)[i];
copy_zup_from_yup(velocity[i], vel_in.getValue());
mul_v3_fl(velocity[i], velocity_scale);
}
}
void read_generated_coordinates(const ICompoundProperty &prop,
const CDStreamConfig &config,
const Alembic::Abc::ISampleSelector &iss)

View File

@ -21,6 +21,7 @@ struct Mesh;
using Alembic::Abc::ICompoundProperty;
using Alembic::Abc::OCompoundProperty;
using Alembic::Abc::V3fArraySamplePtr;
namespace blender::io::alembic {
struct UVSample {
@ -90,6 +91,10 @@ const char *get_uv_sample(UVSample &sample, const CDStreamConfig &config, Custom
void write_generated_coordinates(const OCompoundProperty &prop, CDStreamConfig &config);
void read_velocity(const V3fArraySamplePtr &velocities,
const CDStreamConfig &config,
const float velocity_scale);
void read_generated_coordinates(const ICompoundProperty &prop,
const CDStreamConfig &config,
const Alembic::Abc::ISampleSelector &iss);

View File

@ -402,63 +402,6 @@ static void *add_customdata_cb(Mesh *mesh, const char *name, int data_type)
return cd_ptr;
}
static V3fArraySamplePtr get_velocity_prop(const ICompoundProperty &schema,
const ISampleSelector &selector,
const std::string &name)
{
for (size_t i = 0; i < schema.getNumProperties(); i++) {
const PropertyHeader &header = schema.getPropertyHeader(i);
if (header.isCompound()) {
const ICompoundProperty &prop = ICompoundProperty(schema, header.getName());
if (has_property(prop, name)) {
/* Header cannot be null here, as its presence is checked via has_property, so it is safe
* to dereference. */
const PropertyHeader *header = prop.getPropertyHeader(name);
if (!IV3fArrayProperty::matches(*header)) {
continue;
}
const IV3fArrayProperty &velocity_prop = IV3fArrayProperty(prop, name, 0);
if (velocity_prop) {
return velocity_prop.getValue(selector);
}
}
}
else if (header.isArray()) {
if (header.getName() == name && IV3fArrayProperty::matches(header)) {
const IV3fArrayProperty &velocity_prop = IV3fArrayProperty(schema, name, 0);
return velocity_prop.getValue(selector);
}
}
}
return V3fArraySamplePtr();
}
static void read_velocity(const V3fArraySamplePtr &velocities,
const CDStreamConfig &config,
const float velocity_scale)
{
const int num_velocity_vectors = int(velocities->size());
if (num_velocity_vectors != config.mesh->verts_num) {
/* 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(
&config.mesh->id, "velocity", CD_PROP_FLOAT3, bke::AttrDomain::Point, nullptr);
float(*velocity)[3] = (float(*)[3])velocity_layer->data;
for (int i = 0; i < num_velocity_vectors; i++) {
const Imath::V3f &vel_in = (*velocities)[i];
copy_zup_from_yup(velocity[i], vel_in.getValue());
mul_v3_fl(velocity[i], velocity_scale);
}
}
template<typename SampleType>
static bool samples_have_same_topology(const SampleType &sample, const SampleType &ceil_sample)
{

View File

@ -89,7 +89,8 @@ void AbcPointsReader::readObjectData(Main *bmain, const Alembic::Abc::ISampleSel
void read_points_sample(const IPointsSchema &schema,
const ISampleSelector &selector,
CDStreamConfig &config)
CDStreamConfig &config,
ImportSettings *settings)
{
Alembic::AbcGeom::IPointsSchema::Sample sample = schema.getValue(selector);
@ -109,13 +110,20 @@ void read_points_sample(const IPointsSchema &schema,
}
read_mverts(*config.mesh, positions, vnormals);
if (!settings->velocity_name.empty() && settings->velocity_scale != 0.0f) {
V3fArraySamplePtr velocities = get_velocity_prop(schema, selector, settings->velocity_name);
if (velocities) {
read_velocity(velocities, config, settings->velocity_scale);
}
}
}
Mesh *AbcPointsReader::read_mesh(Mesh *existing_mesh,
const ISampleSelector &sample_sel,
int /*read_flag*/,
const char * /*velocity_name*/,
const float /*velocity_scale*/,
const char *velocity_name,
const float velocity_scale,
const char **err_str)
{
IPointsSchema::Sample sample;
@ -140,9 +148,13 @@ Mesh *AbcPointsReader::read_mesh(Mesh *existing_mesh,
new_mesh = BKE_mesh_new_nomain(positions->size(), 0, 0, 0);
}
ImportSettings settings;
settings.velocity_name = velocity_name;
settings.velocity_scale = velocity_scale;
Mesh *mesh_to_export = new_mesh ? new_mesh : existing_mesh;
CDStreamConfig config = get_config(mesh_to_export);
read_points_sample(m_schema, sample_sel, config);
read_points_sample(m_schema, sample_sel, config, &settings);
return mesh_to_export;
}

View File

@ -36,6 +36,7 @@ class AbcPointsReader final : public AbcObjectReader {
void read_points_sample(const Alembic::AbcGeom::IPointsSchema &schema,
const Alembic::AbcGeom::ISampleSelector &selector,
CDStreamConfig &config);
CDStreamConfig &config,
ImportSettings *settings);
} // namespace blender::io::alembic

View File

@ -26,6 +26,10 @@
#include "PIL_time.h"
using Alembic::Abc::IV3fArrayProperty;
using Alembic::Abc::PropertyHeader;
using Alembic::Abc::V3fArraySamplePtr;
namespace blender::io::alembic {
std::string get_id_name(const Object *const ob)
@ -114,6 +118,41 @@ bool has_property(const Alembic::Abc::ICompoundProperty &prop, const std::string
return prop.getPropertyHeader(name) != nullptr;
}
V3fArraySamplePtr get_velocity_prop(const Alembic::Abc::ICompoundProperty &schema,
const Alembic::AbcGeom::ISampleSelector &selector,
const std::string &name)
{
for (size_t i = 0; i < schema.getNumProperties(); i++) {
const PropertyHeader &header = schema.getPropertyHeader(i);
if (header.isCompound()) {
const ICompoundProperty &prop = ICompoundProperty(schema, header.getName());
if (has_property(prop, name)) {
/* Header cannot be null here, as its presence is checked via has_property, so it is safe
* to dereference. */
const PropertyHeader *header = prop.getPropertyHeader(name);
if (!IV3fArrayProperty::matches(*header)) {
continue;
}
const IV3fArrayProperty &velocity_prop = IV3fArrayProperty(prop, name, 0);
if (velocity_prop) {
return velocity_prop.getValue(selector);
}
}
}
else if (header.isArray()) {
if (header.getName() == name && IV3fArrayProperty::matches(header)) {
const IV3fArrayProperty &velocity_prop = IV3fArrayProperty(schema, name, 0);
return velocity_prop.getValue(selector);
}
}
}
return V3fArraySamplePtr();
}
using index_time_pair_t = std::pair<Alembic::AbcCoreAbstract::index_t, Alembic::AbcGeom::chrono_t>;
std::optional<SampleInterpolationSettings> get_sample_interpolation_settings(

View File

@ -13,6 +13,7 @@
#include <optional>
using Alembic::Abc::chrono_t;
using Alembic::Abc::V3fArraySamplePtr;
struct ID;
struct Object;
@ -82,6 +83,9 @@ void get_min_max_time(const Alembic::AbcGeom::IObject &object,
}
bool has_property(const Alembic::Abc::ICompoundProperty &prop, const std::string &name);
V3fArraySamplePtr get_velocity_prop(const Alembic::Abc::ICompoundProperty &schema,
const Alembic::AbcGeom::ISampleSelector &selector,
const std::string &name);
/**
* The SampleInterpolationSettings struct holds information for interpolating data between two