Alembic: read velocities on Points #116749
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue