Fix T52022 Alembic Inherits transform not taken into account
Alembic's "inherits transform" flag wasn't taken into account when constructing the parent object relations.
This commit is contained in:
@@ -140,6 +140,38 @@ AbcObjectReader::AbcObjectReader(const IObject &object, ImportSettings &settings
|
|||||||
else {
|
else {
|
||||||
m_object_name = m_data_name = parts[parts.size() - 1];
|
m_object_name = m_data_name = parts[parts.size() - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
determine_inherits_xform();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Determine whether we can inherit our parent's XForm */
|
||||||
|
void AbcObjectReader::determine_inherits_xform()
|
||||||
|
{
|
||||||
|
m_inherits_xform = false;
|
||||||
|
|
||||||
|
IXform ixform = xform();
|
||||||
|
if (!ixform) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const IXformSchema & schema(ixform.getSchema());
|
||||||
|
if (!schema.valid()) {
|
||||||
|
std::cerr << "Alembic object " << ixform.getFullName()
|
||||||
|
<< " has an invalid schema." << std::endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_inherits_xform = schema.getInheritsXforms();
|
||||||
|
|
||||||
|
IObject ixform_parent = ixform.getParent();
|
||||||
|
if (!ixform_parent.getParent()) {
|
||||||
|
/* The archive top object certainly is not a transform itself, so handle
|
||||||
|
* it as "no parent". */
|
||||||
|
m_inherits_xform = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_inherits_xform = ixform_parent && m_inherits_xform;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AbcObjectReader::~AbcObjectReader()
|
AbcObjectReader::~AbcObjectReader()
|
||||||
@@ -286,32 +318,10 @@ void AbcObjectReader::read_matrix(float r_mat[4][4], const float time,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool has_alembic_parent;
|
|
||||||
IObject ixform_parent = ixform.getParent();
|
|
||||||
if (!ixform_parent.getParent()) {
|
|
||||||
/* The archive top object certainly is not a transform itself, so handle
|
|
||||||
* it as "no parent". */
|
|
||||||
has_alembic_parent = false;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
has_alembic_parent = ixform_parent && schema.getInheritsXforms();
|
|
||||||
|
|
||||||
if (has_alembic_parent && m_object->parent == NULL) {
|
|
||||||
/* TODO Sybren: This happened in some files. I think I solved it,
|
|
||||||
* but I'll leave this check in here anyway until we've tested it
|
|
||||||
* more thoroughly. Better than crashing on a null parent anyway. */
|
|
||||||
std::cerr << "Alembic object " << m_iobject.getFullName()
|
|
||||||
<< " with transform " << ixform.getFullName()
|
|
||||||
<< " has an Alembic parent but no parent Blender object."
|
|
||||||
<< std::endl;
|
|
||||||
has_alembic_parent = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const Imath::M44d matrix = get_matrix(schema, time);
|
const Imath::M44d matrix = get_matrix(schema, time);
|
||||||
convert_matrix(matrix, m_object, r_mat);
|
convert_matrix(matrix, m_object, r_mat);
|
||||||
|
|
||||||
if (has_alembic_parent) {
|
if (m_inherits_xform) {
|
||||||
/* In this case, the matrix in Alembic is in local coordinates, so
|
/* In this case, the matrix in Alembic is in local coordinates, so
|
||||||
* convert to world matrix. To prevent us from reading and accumulating
|
* convert to world matrix. To prevent us from reading and accumulating
|
||||||
* all parent matrices in the Alembic file, we assume that the Blender
|
* all parent matrices in the Alembic file, we assume that the Blender
|
||||||
|
|||||||
@@ -143,6 +143,8 @@ protected:
|
|||||||
* modifiers and/or constraints. */
|
* modifiers and/or constraints. */
|
||||||
int m_refcount;
|
int m_refcount;
|
||||||
|
|
||||||
|
bool m_inherits_xform;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AbcObjectReader *parent_reader;
|
AbcObjectReader *parent_reader;
|
||||||
|
|
||||||
@@ -167,6 +169,7 @@ public:
|
|||||||
const std::string & name() const { return m_name; }
|
const std::string & name() const { return m_name; }
|
||||||
const std::string & object_name() const { return m_object_name; }
|
const std::string & object_name() const { return m_object_name; }
|
||||||
const std::string & data_name() const { return m_data_name; }
|
const std::string & data_name() const { return m_data_name; }
|
||||||
|
bool inherits_xform() const { return m_inherits_xform; }
|
||||||
|
|
||||||
virtual bool valid() const = 0;
|
virtual bool valid() const = 0;
|
||||||
virtual bool accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header,
|
virtual bool accepts_object_type(const Alembic::AbcCoreAbstract::ObjectHeader &alembic_header,
|
||||||
@@ -194,6 +197,9 @@ public:
|
|||||||
|
|
||||||
void read_matrix(float r_mat[4][4], const float time,
|
void read_matrix(float r_mat[4][4], const float time,
|
||||||
const float scale, bool &is_constant);
|
const float scale, bool &is_constant);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void determine_inherits_xform();
|
||||||
};
|
};
|
||||||
|
|
||||||
Imath::M44d get_matrix(const Alembic::AbcGeom::IXformSchema &schema, const float time);
|
Imath::M44d get_matrix(const Alembic::AbcGeom::IXformSchema &schema, const float time);
|
||||||
|
|||||||
@@ -760,7 +760,7 @@ static void import_startjob(void *user_data, short *stop, short *do_update, floa
|
|||||||
const AbcObjectReader *parent_reader = reader->parent_reader;
|
const AbcObjectReader *parent_reader = reader->parent_reader;
|
||||||
Object *ob = reader->object();
|
Object *ob = reader->object();
|
||||||
|
|
||||||
if (parent_reader == NULL) {
|
if (parent_reader == NULL || !reader->inherits_xform()) {
|
||||||
ob->parent = NULL;
|
ob->parent = NULL;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
@@ -75,6 +75,39 @@ class SimpleImportTest(AbstractAlembicTest):
|
|||||||
self.assertEqual(objects['Cube_003'], objects['Cube_005'].parent)
|
self.assertEqual(objects['Cube_003'], objects['Cube_005'].parent)
|
||||||
self.assertEqual(objects['Cube_003'], objects['Cube_006'].parent)
|
self.assertEqual(objects['Cube_003'], objects['Cube_006'].parent)
|
||||||
|
|
||||||
|
def test_inherit_or_not(self):
|
||||||
|
res = bpy.ops.wm.alembic_import(
|
||||||
|
filepath=str(self.testdir / "T52022-inheritance.abc"),
|
||||||
|
as_background_job=False)
|
||||||
|
self.assertEqual({'FINISHED'}, res)
|
||||||
|
|
||||||
|
# The objects should be linked to scene_collection in Blender 2.8,
|
||||||
|
# and to scene in Blender 2.7x.
|
||||||
|
objects = bpy.context.scene.objects
|
||||||
|
|
||||||
|
# ABC parent is top-level object, which translates to nothing in Blender
|
||||||
|
self.assertIsNone(objects['locator1'].parent)
|
||||||
|
|
||||||
|
# ABC parent is locator1, but locator2 has "inherits Xforms" = false, which
|
||||||
|
# translates to "no parent" in Blender.
|
||||||
|
self.assertIsNone(objects['locator2'].parent)
|
||||||
|
|
||||||
|
# Shouldn't have inherited the ABC parent's transform.
|
||||||
|
x, y, z = objects['locator2'].matrix_world.to_translation()
|
||||||
|
self.assertAlmostEqual(0, x)
|
||||||
|
self.assertAlmostEqual(0, y)
|
||||||
|
self.assertAlmostEqual(2, z)
|
||||||
|
|
||||||
|
# ABC parent is inherited and translates to normal parent in Blender.
|
||||||
|
self.assertEqual(objects['locator2'], objects['locatorShape2'].parent)
|
||||||
|
|
||||||
|
# Should have inherited its ABC parent's transform.
|
||||||
|
x, y, z = objects['locatorShape2'].matrix_world.to_translation()
|
||||||
|
self.assertAlmostEqual(0, x)
|
||||||
|
self.assertAlmostEqual(0, y)
|
||||||
|
self.assertAlmostEqual(2, z)
|
||||||
|
|
||||||
|
|
||||||
def test_select_after_import(self):
|
def test_select_after_import(self):
|
||||||
# Add a sphere, so that there is something in the scene, selected, and active,
|
# Add a sphere, so that there is something in the scene, selected, and active,
|
||||||
# before we do the Alembic import.
|
# before we do the Alembic import.
|
||||||
|
|||||||
Reference in New Issue
Block a user