Alembic: add support to interpolate transform matrices in-between
frames.
This commit is contained in:
parent
386da0cc77
commit
f3b94a54bc
|
@ -1104,44 +1104,20 @@ void AbcMeshReader::readFaceSetsSample(Main *bmain, Mesh *mesh, size_t poly_star
|
|||
utils::assign_materials(bmain, m_object, mat_map);
|
||||
}
|
||||
|
||||
typedef std::pair<Alembic::AbcCoreAbstract::index_t, float> index_time_pair_t;
|
||||
|
||||
static void get_weight_and_index(CDStreamConfig &config,
|
||||
Alembic::AbcCoreAbstract::TimeSamplingPtr time_sampling,
|
||||
size_t samples_number)
|
||||
{
|
||||
if (samples_number == 0) {
|
||||
samples_number = 1;
|
||||
}
|
||||
Alembic::AbcGeom::index_t i0, i1;
|
||||
|
||||
index_time_pair_t floor_index = time_sampling->getFloorIndex(config.time, samples_number);
|
||||
config.weight = get_weight_and_index(config.time,
|
||||
time_sampling,
|
||||
samples_number,
|
||||
i0,
|
||||
i1);
|
||||
|
||||
config.index = floor_index.first;
|
||||
config.ceil_index = config.index;
|
||||
|
||||
if (fabs(config.time - floor_index.second) < 0.0001f) {
|
||||
config.weight = 0.0f;
|
||||
return;
|
||||
}
|
||||
|
||||
index_time_pair_t ceil_index = time_sampling->getCeilIndex(config.time, samples_number);
|
||||
|
||||
if (config.index == ceil_index.first) {
|
||||
config.weight = 0.0f;
|
||||
return;
|
||||
}
|
||||
|
||||
config.ceil_index = ceil_index.first;
|
||||
|
||||
float alpha = (config.time - floor_index.second) / (ceil_index.second - floor_index.second);
|
||||
|
||||
/* Since we so closely match the ceiling, we'll just use it. */
|
||||
if (fabs(1.0f - alpha) < 0.0001f) {
|
||||
config.index = config.ceil_index;
|
||||
alpha = 0.0f;
|
||||
}
|
||||
|
||||
config.weight = alpha;
|
||||
config.index = i0;
|
||||
config.ceil_index = i1;
|
||||
}
|
||||
|
||||
void read_mesh_sample(ImportSettings *settings,
|
||||
|
|
|
@ -153,6 +153,61 @@ Object *AbcObjectReader::object() const
|
|||
return m_object;
|
||||
}
|
||||
|
||||
static Imath::M44d blend_matrices(const Imath::M44d &m0, const Imath::M44d &m1, const float weight)
|
||||
{
|
||||
float mat0[4][4], mat1[4][4], ret[4][4];
|
||||
|
||||
/* Cannot use Imath::M44d::getValue() since this returns a pointer to
|
||||
* doubles and interp_m4_m4m4 expects pointers to floats. So need to convert
|
||||
* the matrices manually.
|
||||
*/
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
mat0[i][j] = m0[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
mat1[i][j] = m1[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
interp_m4_m4m4(ret, mat0, mat1, weight);
|
||||
|
||||
Imath::M44d m;
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
m[i][j] = ret[i][j];
|
||||
}
|
||||
}
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
Imath::M44d get_matrix(const IXformSchema &schema, const float time)
|
||||
{
|
||||
Alembic::AbcGeom::index_t i0, i1;
|
||||
Alembic::AbcGeom::XformSample s0, s1;
|
||||
|
||||
const float weight = get_weight_and_index(time,
|
||||
schema.getTimeSampling(),
|
||||
schema.getNumSamples(),
|
||||
i0,
|
||||
i1);
|
||||
|
||||
schema.get(s0, Alembic::AbcGeom::ISampleSelector(i0));
|
||||
|
||||
if (i0 != i1) {
|
||||
schema.get(s1, Alembic::AbcGeom::ISampleSelector(i1));
|
||||
return blend_matrices(s0.getMatrix(), s1.getMatrix(), weight);
|
||||
}
|
||||
|
||||
return s0.getMatrix();
|
||||
}
|
||||
|
||||
void AbcObjectReader::readObjectMatrix(const float time)
|
||||
{
|
||||
IXform ixform;
|
||||
|
@ -194,11 +249,8 @@ void AbcObjectReader::readObjectMatrix(const float time)
|
|||
return;
|
||||
}
|
||||
|
||||
Alembic::AbcGeom::ISampleSelector sample_sel(time);
|
||||
Alembic::AbcGeom::XformSample xs;
|
||||
schema.get(xs, sample_sel);
|
||||
|
||||
create_input_transform(sample_sel, ixform, m_object, m_object->obmat, m_settings->scale, has_alembic_parent);
|
||||
const Imath::M44d matrix = get_matrix(schema, time);
|
||||
convert_matrix(matrix, m_object, m_object->obmat, m_settings->scale, has_alembic_parent);
|
||||
|
||||
invert_m4_m4(m_object->imat, m_object->obmat);
|
||||
|
||||
|
|
|
@ -166,4 +166,6 @@ public:
|
|||
chrono_t maxTime() const;
|
||||
};
|
||||
|
||||
Imath::M44d get_matrix(const Alembic::AbcGeom::IXformSchema &schema, const float time);
|
||||
|
||||
#endif /* __ABC_OBJECT_H__ */
|
||||
|
|
|
@ -201,16 +201,9 @@ void create_transform_matrix(float r_mat[4][4])
|
|||
copy_m4_m4(r_mat, transform_mat);
|
||||
}
|
||||
|
||||
void create_input_transform(const Alembic::AbcGeom::ISampleSelector &sample_sel,
|
||||
const Alembic::AbcGeom::IXform &ixform, Object *ob,
|
||||
float r_mat[4][4], float scale, bool has_alembic_parent)
|
||||
void convert_matrix(const Imath::M44d &xform, Object *ob,
|
||||
float r_mat[4][4], float scale, bool has_alembic_parent)
|
||||
{
|
||||
|
||||
const Alembic::AbcGeom::IXformSchema &ixform_schema = ixform.getSchema();
|
||||
Alembic::AbcGeom::XformSample xs;
|
||||
ixform_schema.get(xs, sample_sel);
|
||||
const Imath::M44d &xform = xs.getMatrix();
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
r_mat[i][j] = xform[i][j];
|
||||
|
@ -435,3 +428,37 @@ bool has_property(const Alembic::Abc::ICompoundProperty &prop, const std::string
|
|||
|
||||
return prop.getPropertyHeader(name) != NULL;
|
||||
}
|
||||
|
||||
typedef std::pair<Alembic::AbcCoreAbstract::index_t, float> index_time_pair_t;
|
||||
|
||||
float get_weight_and_index(float time,
|
||||
const Alembic::AbcCoreAbstract::TimeSamplingPtr &time_sampling,
|
||||
int samples_number,
|
||||
Alembic::AbcGeom::index_t &i0,
|
||||
Alembic::AbcGeom::index_t &i1)
|
||||
{
|
||||
samples_number = std::max(samples_number, 1);
|
||||
|
||||
index_time_pair_t t0 = time_sampling->getFloorIndex(time, samples_number);
|
||||
i0 = i1 = t0.first;
|
||||
|
||||
if (samples_number == 1 || (fabs(time - t0.second) < 0.0001f)) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
index_time_pair_t t1 = time_sampling->getCeilIndex(time, samples_number);
|
||||
i1 = t1.first;
|
||||
|
||||
if (i0 == i1) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
const float bias = (time - t0.second) / (t1.second - t0.second);
|
||||
|
||||
if (fabs(1.0f - bias) < 0.0001f) {
|
||||
i0 = i1;
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
return bias;
|
||||
}
|
||||
|
|
|
@ -59,9 +59,8 @@ bool begins_with(const TContainer &input, const TContainer &match)
|
|||
&& std::equal(match.begin(), match.end(), input.begin());
|
||||
}
|
||||
|
||||
void create_input_transform(const Alembic::AbcGeom::ISampleSelector &sample_sel,
|
||||
const Alembic::AbcGeom::IXform &ixform, Object *ob,
|
||||
float r_mat[4][4], float scale, bool has_alembic_parent = false);
|
||||
void convert_matrix(const Imath::M44d &xform, Object *ob,
|
||||
float r_mat[4][4], float scale, bool has_alembic_parent = false);
|
||||
|
||||
template <typename Schema>
|
||||
void get_min_max_time_ex(const Schema &schema, chrono_t &min, chrono_t &max)
|
||||
|
@ -95,6 +94,12 @@ void get_min_max_time(const Alembic::AbcGeom::IObject &object, const Schema &sch
|
|||
|
||||
bool has_property(const Alembic::Abc::ICompoundProperty &prop, const std::string &name);
|
||||
|
||||
float get_weight_and_index(float time,
|
||||
const Alembic::AbcCoreAbstract::TimeSamplingPtr &time_sampling,
|
||||
int samples_number,
|
||||
Alembic::AbcGeom::index_t &i0,
|
||||
Alembic::AbcGeom::index_t &i1);
|
||||
|
||||
/* ************************** */
|
||||
|
||||
/* TODO(kevin): for now keeping these transformations hardcoded to make sure
|
||||
|
|
|
@ -799,9 +799,8 @@ void ABC_get_transform(AbcArchiveHandle *handle, Object *ob, const char *object_
|
|||
return;
|
||||
}
|
||||
|
||||
ISampleSelector sample_sel(time);
|
||||
|
||||
create_input_transform(sample_sel, ixform, ob, r_mat, scale);
|
||||
const Imath::M44d matrix = get_matrix(schema, time);
|
||||
convert_matrix(matrix, ob, r_mat, scale);
|
||||
}
|
||||
|
||||
/* ***************************************** */
|
||||
|
|
Loading…
Reference in New Issue